/* $Id: sfskeyupdate.C,v 1.30 2001/01/13 19:46:09 dm Exp $ */ /* * * Copyright (C) 1999 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 "sfskey.h" #include "srp.h" struct updatecmd { bool opt_nosrp; vec authservers; str oldkeyname; str newkeyname; ptr oldkey; ptr newkey; sfsauth_srpparmsres srpparms; u_int npending; bool errors; updatecmd () : opt_nosrp (false), errors (false) { srpparms.set_status (SFSAUTH_FAILED); } void setsrp () { if (opt_nosrp) { srpparms.set_status (SFSAUTH_FAILED); return; } if (srpparms.status != SFSAUTH_OK) { if (str srpfile = sfsconst_etcfile ("sfs_srp_parms")) if (str parms = file2str (srpfile)) { srpparms.set_status (SFSAUTH_OK); if (!import_srp_params (parms, &srpparms.parms->N, &srpparms.parms->g)) fatal ("%s: cannot parse srp parameters\n", srpfile.cstr ()); } else fatal ("%s: %m\n", srpfile.cstr ()); } if (!srp_base::checkparam (srpparms.parms->N, srpparms.parms->g)) fatal ("invalid SRP parameters!\n"); } void done (bool ok) { if (!ok) errors = true; if (!--npending) exit (errors); } bool setuparg (sfsauth_updatearg *arg, ref sc) const { arg->msg.type = SFS_AUTHUPDATE; arg->msg.authid = sc->authid; arg->msg.oldkey = oldkey->key->n; arg->msg.newkey = newkey->key->n; if (srpparms.status == SFSAUTH_OK) { srp_client srpc; arg->msg.srpinfo.alloc (); arg->msg.srpinfo->info = srpc.create (srpparms.parms->N, srpparms.parms->g, newkey->pwd, sc->servinfo.host.hostname, newkey->cost, 0); if (!arg->msg.srpinfo->info) { warn << sc->servinfo.host.hostname << ": could not create SRP info\n"; return false; } arg->msg.srpinfo->privkey = export_rabin_encrypt_sec (*newkey->key, &srpc.eksb); if (!arg->msg.srpinfo->privkey) { warn << sc->servinfo.host.hostname << ": encrypt private key\n"; return false; } } else arg->msg.srpinfo.clear (); str rawmsg (xdr2str (arg->msg, true)); if (!rawmsg) { warn << sc->servinfo.host.hostname << ": could not marshal update arg\n"; return false; } arg->osig = oldkey->key->sign (rawmsg); arg->nsig = newkey->key->sign (rawmsg); return true; } void start () { fetchkey (newkeyname, wrap (this, &updatecmd::getnewkey)); } void getnewkey (ptr sk, str err, ptr sc) { if (!sk) fatal << err << "\n"; newkey = sk; if (!opt_nosrp && !newkey->pwd) fatal << "New key must have passphrase when using SRP\n"; if (!opt_nosrp && srpparms.status != SFSAUTH_OK && sc && sc->hostid_valid) { ref c (aclnt::alloc (sc->x, sfsauth_program_1)); c->scall (SFSAUTHPROC_SRP_GETPARAMS, NULL, &srpparms); } if (oldkeyname == newkeyname) getoldkey (sk, err, sc); else fetchkey (oldkeyname, wrap (this, &updatecmd::getoldkey)); } void getoldkey (ptr sk, str err, ptr sc) { if (!sk) fatal << err << "\n"; oldkey = sk; if (!opt_nosrp && srpparms.status != SFSAUTH_OK && sc && sc->hostid_valid) { ref c (aclnt::alloc (sc->x, sfsauth_program_1)); c->scall (SFSAUTHPROC_SRP_GETPARAMS, NULL, &srpparms); } setsrp (); if (authservers.empty ()) { if (!sc) fatal ("must specify authserver -a if SRP fails on old key\n"); npending = 1; getcon (sc->path, sc, NULL); } else { npending = authservers.size (); for (const str *sp = authservers.base (); sp < authservers.lim (); sp++) sfs_connect_path (*sp, SFS_AUTHSERV, wrap (this, &updatecmd::getcon, *sp)); } } void getcon (str path, ptr sc, str err) { if (!sc) { if (path == "-") path = "localhost"; warnx << path << ": FAILED (" << err << ")\n"; done (false); return; } if (path == "-") path = sc->path; sfsauth_updatearg arg; if (!setuparg (&arg, sc)) { warnx << path << ": FAILED (could not set up args)\n"; done (false); return; } sfsauth_stat *resp = New sfsauth_stat; ref c (aclnt::alloc (sc->x, sfsauth_program_1)); c->call (SFSAUTHPROC_UPDATE, &arg, resp, wrap (this, &updatecmd::getres, path, resp)); } void getres (str path, sfsauth_stat *resp, clnt_stat err) { sfsauth_stat stat = *resp; delete resp; if (err) { warnx << path << ": FAILED (" << err << ")\n"; done (false); } else if (stat != SFSAUTH_OK) { // XXX warnx << path << ": FAILED (update err " << int (stat) << ")\n"; done (false); } else { warnx << path << ": updated\n"; done (true); } } }; void sfskey_update (int argc, char **argv) { updatecmd *uc = New updatecmd (); int ch; while ((ch = getopt (argc, argv, "Ss:a:")) != -1) switch (ch) { case 'S': uc->opt_nosrp = true; if (uc->srpparms.status == SFSAUTH_OK) usage (); break; case 's': { if (uc->opt_nosrp) usage (); if (str parms = file2str (optarg)) { uc->srpparms.set_status (SFSAUTH_OK); if (!import_srp_params (parms, &uc->srpparms.parms->N, &uc->srpparms.parms->g)) fatal ("%s: cannot parse srp parameters\n", optarg); } else fatal ("%s: %m\n", optarg); break; } case 'a': uc->authservers.push_back (optarg); break; default: usage (); break; } if (optind + 2 < argc || optind >= argc) usage (); uc->oldkeyname = argv[optind++]; if (optind < argc) uc->newkeyname = argv[optind]; else uc->newkeyname = defkey (); if (uc->authservers.empty () && !isremote (uc->oldkeyname)) fatal ("must specify authserver -a if old key not via SRP\n"); uc->start (); }