/* $Id: sfskeyfetch.C,v 1.29 2000/03/21 19:43:11 dm Exp $ */

/*
 *
 * Copyright (C) 1999 David Mazieres (dm@uun.org)
 * Copyright (C) 1999 Michael Kaminsky (kaminsky@lcs.mit.edu)
 *
 * 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"

bool
isremote (str keyname)
{
  return !strchr (keyname, '/') && strchr (keyname, '@');
}

static void
keyfetch_srp_cb (ptr<sfscon> *scp, str *errp, ptr<sfscon> sc, str err)
{
  if (sc) {
    *scp = sc;
    *errp = "";
  }
  else
    *errp = err;
}
static str
keyfetch_srp (sfskey *sk, str keyname, ptr<sfscon> *scp)
{
  static bool srpprimed;
  if (!srpprimed) {
    srpprimed = true;
    bigint N, g;
    if (str srpfile = sfsconst_etcfile ("sfs_srp_parms"))
      if (str parms = file2str (srpfile))
	if (import_srp_params (parms, &N, &g) && !srp_base::seedparam (N, g))
	  warn << "DANGER: " << srpfile << " contains bogus parameters!\n";
  }

  ptr<sfscon> sc;
  srp_client srp;
  str serr;
  str pwd;

  sfs_connect_srp (sk->keyname, &srp, wrap (keyfetch_srp_cb, &sc, &serr),
		   &sk->keyname, &pwd);
  while (!serr)
    acheck ();
  if (serr.len ())
    return serr;

  ref<aclnt> c (aclnt::alloc (sc->x, sfsauth_program_1));
  sfsauth_fetchres fetchres;
  if (clnt_stat err = c->scall (SFSAUTHPROC_FETCH, NULL, &fetchres))
    return sk->keyname << ": fetch: " << err;
  if (fetchres.status != SFSAUTH_OK)
    return sk->keyname << ": server refused key fetch request";
  sk->key = import_rabin_decrypt_sec (fetchres.resok->privkey, &srp.eksb);
  if (!sk->key)
    return sk->keyname << ": server returned undecryptable private key";

  sk->cost = srp.cost;
  sk->pwd = pwd;
  sk->srpparms = New sfssrp_parms;
  sk->srpparms->N = srp.N;
  sk->srpparms->g = srp.g;

  if (!sc->hostid_valid) {
    warn << "Warning: host for " << sk->keyname << " is actually server\n"
	 << "        " << sc->path << "\n";
    sc = NULL;
  }
  else if (fetchres.resok->hostid != sc->hostid) {
    warnx << sc->path << " returned incorrect hostid in fetch\n";
    sc = NULL;
  }

  if (scp)
    *scp = sc;
  return NULL;
}

str
keyfetch (sfskey *sk, str keyname, ptr<sfscon> *scp)
{
  sk->key = NULL;
  sk->keyname = keyname;
  sk->pwd = NULL;
  sk->cost = 0;
  if (scp)
    *scp = NULL;

  if (isremote (keyname))
    return keyfetch_srp (sk, keyname, scp);

  str ske = file2wstr (keyname);
  if (!ske)
    return keyname << ": " << strerror (errno);
  
  if (import_rabin_priv_need_pwd (ske, &sk->cost))
    sk->pwd = getpwd ("Passphrase for " << sk->keyname << ": ");
  sk->key = import_rabin_priv (ske, sk->pwd, &sk->keyname);
  if (!sk->key) {
    sk->key = NULL;
    return "Bad passphrase.";
  }

  if (!sk->keyname || !sk->keyname.len ())
    sk->keyname = keyname;
  return NULL;
}
