// -*-c++-*-
/* $Id: sfsauthd.h,v 1.21 2002/11/12 23:07:46 max Exp $ */

/*
 *
 * Copyright (C) 2002 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
 *
 */

#ifndef _SFSAUTHD_SFSAUTHD_H
#define _SFSAUTHD_SFSAUTHD_H

#include "sfscrypt.h"
#include "sfsserv.h"
#include "sfsauth_prot.h"
#include "authdb.h"
#include "srp.h"

struct dbfile;

class sprivk_tab_t {
public:
  sprivk_tab_t () : nentries (0) {}

  struct sprivk_t {
    sprivk_t () : refs (1), valid (true) {}
    int refs;
    bool valid;
  };

  bool is_valid (const str &hv);
  bool invalidate (const str &hv);
  void bind (const str &hv);
  void release (const str &hv, sprivk_t *s = NULL);

private:
  u_int nentries;
  qhash<str, sprivk_t> keys;
};

class authclnt : public sfsserv {
  rpc_ptr<u_int32_t> uid;
  const ref<asrv> authsrv;
  const bool sfsauth_login_srp;	// true if client is a trusted root daemon

  struct urec_t {
    urec_t (u_int32_t a, sfs_authtype t, const sfsauth_dbrec &dbr);
    ~urec_t ();

    u_int32_t authno;
    sfs_authtype authtype;
    sfsauth_keyhalf kh;
    sfs_idname uname;
    
    list_entry<urec_t> link;
    ihash_entry<urec_t> hlink;
  };

  void urecfree (urec_t *u);

  srp_server srp;
  u_int64_t srp_seqno;
  sfs_hash srp_authid;
  dbfile *srp_dbp;
  ptr<authcursor> srp_ac;
  ihash<u_int32_t, authclnt::urec_t, &authclnt::urec_t::authno, 
	&authclnt::urec_t::hlink> utab;
  list<authclnt::urec_t, &authclnt::urec_t::link> ulist;

protected:
  ptr<sfspriv> doconnect (const sfs_connectarg *, sfs_servinfo *);
  bool setuser (sfsauth2_loginres *resp, const sfsauth_dbrec &ae,
		const dbfile *dbp);
  static bool checkreq (sfsauth2_loginres *resp, const sfsauth2_loginarg *lap,
			const sfs_authreq2 *reqp);
  static void findgroups (vec<u_int32_t> *groups, str name);

  void utab_insert (u_int32_t authno, sfs_authtype t, const sfsauth_dbrec &d);
  str update_srv_keyhalf (const sfsauth_keyhalf &deltakh,
			  sfsauth_keyhalf &newkh,
			  const sfsauth_keyhalf &oldkh, 
			  bool oldsig, urec_t *ur);

  str siglogline (const sfsauth2_sign_arg &arg, const str &uname);

public:
  vec<sfsauth_dbrec> dbrtab;

  authclnt (ref<axprt_crypt> x, const authunix_parms *aup = NULL);
  ~authclnt ();
  void dispatch (svccb *sbp);

  //ptr<aclnt> getauthclnt ();
  void sfs_login (svccb *sbp);
  
  virtual void sfsauth_login (sfsauth2_loginres *resp,
			      const sfsauth2_loginarg *lap,
			      bool srp_ok, sfsauth_dbrec *dbp = NULL,
			      sfs_authtype *atp = NULL);

  void sfs_logout (svccb *sbp);
  void authreq (sfsauth2_loginres *resp,
		const sfsauth2_loginarg *lap, const sfs_autharg2 *aap,
		sfsauth_dbrec *dbp = NULL);
  void unixpwauth (sfsauth2_loginres *resp,
		   const sfsauth2_loginarg *lap, const sfs_autharg2 *aap,
		   bool root_su_ok = false,
		   sfsauth_dbrec *dbp = NULL);
  void srpauth (sfsauth2_loginres *resp,
		const sfsauth2_loginarg *lap, const sfs_autharg2 *aap,
		sfsauth_dbrec *dbp = NULL);

  bool get_user_cursor (dbfile **dbp, ptr<authcursor> *acp,
			sfsauth_dbrec *dbrp, const sfsauth_dbkey &k,
			bool writable = false);

  virtual void sfsauth_query (svccb *sbp);
  void query_user (svccb *sbp);
  void query_group (svccb *sbp);
  void query_certinfo (svccb *sbp);
  void query_srpparms (svccb *sbp);

  virtual void sfsauth_update (svccb *sbp);
  virtual void sfsauth_sign (svccb *sbp);
};

const u_int32_t badid = (u_int32_t) -1;

struct idmap {
  virtual u_int32_t map (u_int32_t id) = 0;
  virtual u_int32_t unmap (u_int32_t id) = 0;
};
struct idmap_id : public idmap {
  u_int32_t map (u_int32_t id) { return id; }
  u_int32_t unmap (u_int32_t id) { return id; }
};
struct idmap_const : public idmap {
  const u_int32_t id;
  idmap_const (u_int32_t id) : id (id) {}
  u_int32_t map (u_int32_t) { return id; }
  u_int32_t unmap (u_int32_t) { return badid; }
};
struct idmap_range : public idmap {
  const u_int32_t id_min;
  const u_int32_t id_max;
  const u_int32_t id_offset;

  idmap_range (u_int32_t imin, u_int32_t imax, u_int32_t ioff)
    : id_min (imin), id_max (imax), id_offset (ioff) {
    assert (id_max >= id_min);
    assert (!id_max || !id_offset || id_max - 1 + id_offset > id_max);
  }
  u_int32_t map (u_int32_t id) {
    if (id < id_min || id >= id_max)
      return badid;
    return (id + id_offset);
  }
  u_int32_t unmap (u_int32_t mid) {
    if (mid < id_offset || mid >= id_offset + id_max)
      return badid;
    return mid - id_offset;
  }
};

class xfer : public virtual refcount {
  pid_t pid;

  void stop (int) { pid = -1; }
public:
  const str src;
  const str dst;

  xfer (str s, str d) : pid (-1), src (s), dst (d) {}
  void start ();
};

struct dbfile {
  ptr<authdb> db;
  str prefix;
  ptr<idmap> uidmap;
  ptr<idmap> gidmap;
  vec<str> pubfiles;
  bool allow_update;
  bool allow_unix_pwd;
  bool allow_admin;
  bool allow_userdir_shell;
  bool allow_create;
  cbv::ptr refresh;
  dbfile ()
    : allow_update (false), allow_unix_pwd (false),  allow_admin (false),
    allow_userdir_shell (false), allow_create (false) {}
  void mkpub ();
  str strip_prefix (str name);
};

#define USERDIR_HOMEDIR "/sfs/HOMEDIR";
#define USERDIR_SHELL   "/sfs/SHELL";

extern ptr<sfspriv> myprivkey;
extern sfs_servinfo myservinfo;
extern ptr<sfs_servinfo_w> siw;
extern sfs_hash myhostid;
extern vec<dbfile> dbfiles;
extern str sfsauthrealm ;
extern vec<sfsauth_certpath> sfsauthcertpaths;
extern str logfile;
extern str srpparms;
extern int logfd;

bool siglog (const str &line);
str  siglog_startup_msg ();
void siglogv ();

#endif /* _SFSAUTHD_SFSAUTHD_H */
