/* $Id: sfskey.C,v 1.57 2001/08/24 23:03:01 ericp 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 "xdr_suio.h" #include "srp.h" bool opt_pwd_fd; vec pwd_fds; static ptr agentclnt; static ptr sfscdxprt; static ptr sfscdclnt; void setbool (bool *bp) { *bp = true; } void rndaskcd () { static bool done; if (done) return; done = true; int fd; sfsagent_seed seed; ptr c; if ((fd = suidgetfd ("agent")) >= 0 && (c = aclnt::alloc (axprt_stream::alloc (fd), agent_prog_1)) && !c->scall (AGENT_RNDSEED, NULL, &seed)) rnd_input.update (seed.base (), seed.size ()); else warn ("sfscd not running, limiting sources of entropy\n"); } void rndkbd () { warnx << "\nsfskey needs secret bits with which to" " seed the random number generator.\n" "Please type some random or unguessable text until you hear a beep:\n"; bool finished = false; if (!getkbdnoise (64, &rnd_input, wrap (&setbool, &finished))) fatal << "no tty\n"; while (!finished) acheck (); } static void getstr (str *outp, str in) { *outp = in ? in : str (""); } str getpwd (str prompt) { if (!pwd_fds.empty ()) { const int fd = pwd_fds.pop_front (); scrubbed_suio uio; make_sync (fd); while (uio.input (fd) > 0) ; close (fd); if (!uio.resid ()) fatal ("could not read passphrase from fd %d\n", fd); wmstr m (uio.resid ()); uio.copyout (m, m.len ()); return m; } else if (opt_pwd_fd) fatal ("bad passphrase\n"); str out; if (!getkbdpwd (prompt, &rnd_input, wrap (getstr, &out))) fatal ("no tty\n"); while (!out) acheck (); return out; } str getpwdconfirm (str prompt) { str prompt2 (strbuf ("%*s", int (prompt.len ()), "Again: ")); bool again = pwd_fds.empty (); for (;;) { str p = getpwd (prompt); if (!p.len ()) return NULL; if (!again || p == getpwd (prompt2)) return p; warnx << "Mismatch; try again, or RETURN to quit.\n"; } } str getline (str prompt, str def) { str out; if (!getkbdline (prompt, &rnd_input, wrap (getstr, &out), def)) fatal ("no tty\n"); while (!out) acheck (); return out; } str myusername () { if (const char *p = getlogin ()) return p; else if ((p = getenv ("USER"))) return p; else if (struct passwd *pw = getpwuid (getuid ())) return pw->pw_name; else return NULL; } void nularg (int argc, char **argv) { if (getopt (argc, argv, "") != -1 || optind < argc) usage (); } ref ccd () { if (sfscdclnt) return sfscdclnt; int fd = suidgetfd_required ("agent"); sfscdxprt = axprt_unix::alloc (fd); sfscdclnt = aclnt::alloc (sfscdxprt, agent_prog_1); return sfscdclnt; } ref cagent () { if (agentclnt) return agentclnt; static rxx sockfdre ("^-(\\d+)?$"); int fd; if (agentsock && sockfdre.search (agentsock)) { if (sockfdre[1]) fd = atoi (sockfdre[1]); else fd = 0; if (!isunixsocket (fd)) fatal << "fd specified with '-S' not unix domain socket\n"; } else if (agentsock) { fd = unixsocket_connect (agentsock); if (fd < 0) fatal ("%s: %m\n", agentsock.cstr ()); } else { int32_t res; if (clnt_stat err = ccd ()->scall (AGENT_GETAGENT, NULL, &res)) fatal << "sfscd: " << err << "\n"; if (res) fatal << "connecting to agent via sfscd: " << strerror (res) << "\n"; if ((fd = sfscdxprt->recvfd ()) < 0) fatal << "connecting to agent via sfscd: could not get file dexriptor\n"; } agentclnt = aclnt::alloc (axprt_stream::alloc (fd), agentctl_prog_1); return agentclnt; } str defkey () { agent_ckdir (); return dotsfs << "/identity"; } void sfskey_kill (int argc, char **argv) { nularg (argc, argv); int res; if (clnt_stat err = ccd ()->scall (AGENT_KILL, NULL, &res)) fatal << "sfscd: " << err << "\n"; else if (res) fatal << "sfscd: " << strerror (res) << "\n"; exit (0); } void sfskey_help (int argc, char **argv); struct modevec { const char *name; void (*fn) (int argc, char **argv); const char *usage; }; const modevec modes[] = { { "add", sfskey_add, "add [-t [hrs:]min] [keyfile | [user]@authservhostname]" }, { "certclear", sfskey_certclear, "certclear" }, { "certlist", sfskey_certlist, "certlist [-q]" }, { "certprog", sfskey_certprog, "certprog [-s suffix] [-f filter] [-e exclude] prog [arg ...]"}, { "delete", sfskey_delete, "delete keyname" }, { "del", sfskey_delete, NULL }, { "deleteall", sfskey_clear, "deleteall" }, { "delall", sfskey_clear, NULL }, { "edit", sfskey_edit, "edit [-P] [-o outfile] [-c cost] [-n name] [keyname]" }, { "gen", sfskey_gen, "gen [-KP] [-b nbits] [-c cost] [-n name] [keyfile]" }, { "generate", sfskey_gen, NULL }, { "help", sfskey_help, "help" }, { "hostid", sfskey_hostid, "hostid {hostname | -}" }, { "kill", sfskey_kill, "kill" }, { "list", sfskey_list, "list [-lq]" }, { "ls", sfskey_list, NULL }, { "norevokeset", sfskey_norevokeset, "norevokeset hostid ... "}, { "norevokelist", sfskey_norevokelist, "norevokelist"}, { "register", sfskey_reg, "register [-KS] [-b nbits] [-c pwdcost] [keyfile]" }, { "reg", sfskey_reg, NULL }, { "reset", sfskey_reset, "reset" }, { "revoke", sfskey_revoke, "revoke {certfile | -}" }, { "revokegen", sfskey_revokegen, "revokegen [-r newkeyfile [-n newhost]] [-o oldhost] oldkeyfile"}, { "revokelist", sfskey_revokelist, "revokelist"}, { "revokeclear", sfskey_revokeclear, "revokeclear"}, { "revokeprog", sfskey_revokeprog, "revokeprog [-b [-f filter] [-e exclude]] prog [arg ...]"}, { "sesskill", sfskey_sesskill, "sesskill hostid" }, { "sesslist", sfskey_sesslist, "sesslist"}, { "srpgen", sfskey_srpgen, "srpgen [-b nbits] file" }, { "update", sfskey_update, "update [-S | -s srp_parm_file] [-a {server | -}] oldkey [newkey]" }, { "up", sfskey_update, NULL }, { NULL, NULL, NULL } }; static const modevec *sfskey_mode; void usage () { if (!sfskey_mode) warnx << "usage: " << progname << " [-S sock] [-p pwfd] command [args]\n" << " " << progname << " help\n"; else { while (!sfskey_mode->usage) sfskey_mode--; warnx << "usage: " << progname << " " << sfskey_mode->usage << "\n"; } exit (1); } void sfskey_help (int argc, char **argv) { strbuf msg; msg << "usage: " << progname << " [-S sock] [-p pwfd] command [args]\n"; for (const modevec *mp = modes; mp->name; mp++) if (mp->usage) msg << " " << progname << " " << mp->usage << "\n"; make_sync (1); msg.tosuio ()->output (1); exit (0); } int main (int argc, char **argv) { setprogname (argv[0]); putenv ("POSIXLY_CORRECT=1"); // Prevents Linux from reordering options sfsconst_init (); srp_base::minprimsize = sfs_minpubkeysize; int ch; while ((ch = getopt (argc, argv, "S:p:")) != -1) switch (ch) { case 'S': agentsock = optarg; break; case 'p': { int fd; if (!convertint (optarg, &fd)) usage (); opt_pwd_fd = true; close_on_exec (fd); // Paranoia pwd_fds.push_back (fd); break; } default: usage (); break; } if (optind >= argc) usage (); const modevec *mp; for (mp = modes; mp->name; mp++) if (!strcmp (argv[optind], mp->name)) break; if (!mp->name) usage (); sfskey_mode = mp; optind++; mp->fn (argc, argv); amain (); } #ifdef XXX_EXIT #undef exit /* XXX - gcc-2.95.2 bug on alpha */ void XXX_call_exit (int code) { exit (code); } #endif /* XXX_EXIT */