/* $Id: sfsclientauth.C,v 1.4 2001/03/16 03:53:58 dm Exp $ */ /* * * Copyright (C) 1999, 2000 David Mazieres (dm@uun.org) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * */ #include "crypt.h" #include "sfsclient.h" #include "sfscd_prot.h" ptr sfsserver_auth::key; timecb_t *sfsserver_auth::keytmo; void sfsserver_auth::keyexpire () { keytmo = NULL; keygen (); } void sfsserver_auth::keygen () { key = New refcounted (rabin_keygen (sfs_pubkeysize)); if (!keytmo) keytmo = delaycb (3536 + (rnd.getword () & 0x3f), 0, wrap (&keyexpire)); } void sfsserver_auth::crypt (sfs_connectok cres, sfsserver::crypt_cb cb) { if (!key) keygen (); sfs_client_crypt (sfsc, key, carg, cres, cb, xc); } bool sfsserver_auth::authok (nfscall *nc) { sfs_aid aid = nc->getaid (); if (sfs_specaid (aid) || authnos[aid]) return true; ptr uap = authpending[aid]; if (!uap) uap = New refcounted (aid, mkref (this)); uap->pushreq (nc); return false; } void sfsserver_auth::flushstate () { seqno = 0; authnos.clear (); authpending.clear (); } void sfsserver_auth::authclear (sfs_aid aid) { if (AUTH *a = authnos[aid]) { if (sfsc) { u_int32_t authno = authuint_getval (a); sfsc->call (SFSPROC_LOGOUT, &authno, NULL, aclnt_cb_null); } authnos.remove (aid); } else if (ptr uap = authpending[aid]) { authpending.remove (aid); uap->abort (); } } sfsserver_auth::userauth::userauth (sfs_aid a, const ref &s) : aid (a), sp (s), cbase (NULL), aborted (false), ntries (0) { sp->authpending.insert (aid, mkref (this)); tmo = delaycb (3, 0, wrap (this, &sfsserver_auth::userauth::timeout)); sendreq (); } sfsserver_auth::userauth::~userauth () { abort (); } void sfsserver_auth::userauth::timeout () { tmo = NULL; while (!ncvec.empty ()) ncvec.pop_front ()->error (NFS3ERR_JUKEBOX); } void sfsserver_auth::userauth::pushreq (nfscall *nc) { if (tmo) ncvec.push_back (nc); else nc->error (NFS3ERR_JUKEBOX); } void sfsserver_auth::userauth::abort () { if (!aborted) { aborted = true; if (tmo) { timecb_remove (tmo); tmo = NULL; } if (cbase) { cbase->cancel (); cbase = NULL; } while (!ncvec.empty ()) sp->getnfscall (ncvec.pop_front ()); } } void sfsserver_auth::userauth::sendreq () { if (!ntries) seqno = ++sp->seqno; sfscd_agentreq_arg arg; arg.aid = aid; arg.agentreq.set_type (AGENTCB_AUTHINIT); arg.agentreq.init->ntries = ntries; arg.agentreq.init->requestor = ""; arg.agentreq.init->authinfo = sp->authinfo; arg.agentreq.init->seqno = seqno; cbase = sp->prog.cdc->call (SFSCDCBPROC_AGENTREQ, &arg, &ares, wrap (this, &sfsserver_auth::userauth::aresult)); } void sfsserver_auth::userauth::aresult (clnt_stat err) { cbase = NULL; if (err) { warn << "sfscd: " << err << "\n"; finish (0); } else if (!ares.authenticate) finish (0); else { sfs_loginarg arg; arg.seqno = seqno; arg.certificate = *ares.certificate; sp->sfsc->call (SFSPROC_LOGIN, &arg, &sres, wrap (mkref (this), &sfsserver_auth::userauth::sresult)); } } void sfsserver_auth::userauth::sresult (clnt_stat err) { cbase = NULL; if (err) finish (0); else if (aborted) { if (sres.status == SFSLOGIN_OK && sp->x && !sp->x->ateof () && sp->sfsc) sp->sfsc->call (SFSPROC_LOGOUT, sres.authno.addr (), NULL, aclnt_cb_null); } else switch (sres.status) { case SFSLOGIN_OK: finish (*sres.authno); break; case SFSLOGIN_MORE: { sfscd_agentreq_arg arg; arg.aid = aid; arg.agentreq.set_type (AGENTCB_AUTHMORE); arg.agentreq.more->authinfo = sp->authinfo; arg.agentreq.more->seqno = seqno; arg.agentreq.more->challenge = *sres.resmore; cbase = sp->prog.cdc->call (SFSCDCBPROC_AGENTREQ, &arg, &ares, wrap (this, &sfsserver_auth::userauth::aresult)); break; } case SFSLOGIN_BAD: ntries++; sendreq (); break; case SFSLOGIN_ALLBAD: finish (0); break; default: warn << "userauth: bad status in loginres!\n"; finish (0); } } void sfsserver_auth::userauth::finish (u_int32_t authno) { assert (!aborted); auto_auth aa (authuint_create (authno)); sp->authnos.insert (aid, aa); sp->authpending.remove (aid); }