/* $Id: sfs_prot.x,v 1.64 2002/01/11 16:33:17 fubob Exp $ */

/*
 * This file was written by David Mazieres.  Its contents is
 * uncopyrighted and in the public domain.  Of course, standards of
 * academic honesty nonetheless prevent anyone in research from
 * falsely claiming credit for this work.
 */

%#include "bigint.h"

#ifdef SFSSVC
%#include "nfs3exp_prot.h"
#else /* !SFSSVC */
%#include "nfs3_prot.h"
const ex_NFS_PROGRAM = 344444;
const ex_NFS_V3 = 3;
#endif

#ifdef RPCC
# ifndef UNION_ONLY_DEFAULT
#  define UNION_ONLY_DEFAULT 1
# endif /* UNION_ONLY_DEFAULT */
#endif

#ifndef FSINFO
#define FSINFO sfs_fsinfo
#endif /* !FSINFO */

const SFS_PORT = 4;
const SFS_RELEASE = 5;		/* 100 * release no. where protocol changed */

enum sfsstat {
  SFS_OK = 0,
  SFS_BADLOGIN = 1,
  SFS_NOSUCHHOST = 2,
  SFS_NOTSUPP = 10004,
  SFS_TEMPERR = 10008,
  SFS_REDIRECT = 10020
};

/* Types of hashed or signed messages */
enum sfs_msgtype {
  SFS_HOSTINFO = 1,
  SFS_KSC = 2,
  SFS_KCS = 3,
  SFS_SESSINFO = 4,
  SFS_AUTHINFO = 5,
  SFS_SIGNED_AUTHREQ = 6,
  SFS_AUTHREGISTER = 7,
  SFS_AUTHUPDATE = 8,
  SFS_PATHREVOKE = 9,
  SFS_KEYCERT = 10,
  SFS_ROFSINFO = 11,
  SFS_UPDATEREQ = 12
};

/* Type of service requested by clients */
enum sfs_service {
  SFS_SFS = 1,			/* File system service */
  SFS_AUTHSERV = 2,		/* Crypto key server */
  SFS_REX = 3			/* Remote execution */
};

typedef string sfs_extension<>;
typedef string sfs_hostname<222>;
typedef opaque sfs_hash[20];
typedef opaque sfs_secret[16];
typedef unsigned hyper sfs_seqno;
typedef unsigned hyper sfs_time;

typedef bigint sfs_pubkey;
typedef bigint sfs_ctext;
typedef bigint sfs_sig;

struct sfs_hashcharge {
  unsigned int bitcost;
  sfs_hash target;
};
typedef opaque sfs_hashpay[64];


/*
 * Hashed structures
 */

/* Two, identical copies of of the sfs_hostinfo structure are
 * concatenated and then hashed with SHA-1 to form the hostid. */
struct sfs_hostinfo {
  sfs_msgtype type;		/* = SFS_HOSTINFO */
  sfs_hostname hostname;
  sfs_pubkey pubkey;
};

struct sfs_connectinfo_4 {
  sfs_service service;
  sfs_hostname name;		/* Server hostname */
  sfs_hash hostid;		/* = SHA1 (sfs_hostinfo, sfs_hostinfo) */
  sfs_extension extensions<>;
};

struct sfs_connectinfo_5 {
  unsigned release;		/* 100 times release when protocol changed */
  sfs_service service;
  filename3 sname;		/* Self-certifying name */
  sfs_extension extensions<>;
};

union sfs_connectinfo switch (unsigned civers) {
 case 4:
   sfs_connectinfo_4 ci4;
 case 5:
   sfs_connectinfo_5 ci5;
};

struct sfs_servinfo {
  unsigned release;		/* Server release */
  sfs_hostinfo host;		/* Server hostinfo */
  unsigned prog;
  unsigned vers;
};

/* The two shared session keys, ksc and kcs, are the SHA-1 hashes of
 * sfs_sesskeydat with type = SFS_KCS or SFS_KSC.  */
struct sfs_sesskeydat {
  sfs_msgtype type;		/* = SFS_KSC or SFS_KCS */
  sfs_servinfo si;
  sfs_secret sshare;		/* Server's share of session key */
  sfs_connectinfo ci;
  sfs_pubkey kc;
  sfs_secret cshare;		/* Client's share of session key */
};

/* The sessinfo structure is hashed to produce a session ID--a
 * structure both the client and server know to be fresh, but which,
 * unlike the session keys, can safely be divulged to 3rd parties
 * during user authentication.  */
struct sfs_sessinfo {
  sfs_msgtype type;		/* = SFS_SESSINFO */
  opaque ksc<>;			/* = SHA-1 ({SFS_KSC, ...}) */
  opaque kcs<>;			/* = SHA-1 ({SFS_KCS, ...}) */
};

/* The authinfo structure is hashed to produce an authentication ID.
 * The authentication ID can be computed by an untrusted party (such
 * as a user's unprivileged authentication agent), but allows that
 * third party to verify or log the hostname and hostid to which
 * authentication is taking place.  */
struct sfs_authinfo {
  sfs_msgtype type;		/* = SFS_AUTHINFO */
  sfs_service service;
  sfs_hostname name;
  sfs_hash hostid;		/* = SHA-1 (sfs_hostinfo, sfs_hostinfo) */
  sfs_hash sessid;		/* = SHA-1 (sfs_sessinfo) */
};

/*
 * Public key ciphertexts
 */

struct sfs_kmsg {
  sfs_secret kcs_share;
  sfs_secret ksc_share;
};

/*
 * Signed messages
 */

struct sfs_keycert_msg {
  sfs_msgtype type;		/* = SFS_KEYCERT */
  unsigned duration;		/* Lifetime of certificate */
  sfs_time start;		/* Time of signature */
  sfs_pubkey key;		/* Temporary public key */
};

struct sfs_keycert {
  sfs_keycert_msg msg;
  sfs_sig sig;
};

struct sfs_signed_authreq {
  sfs_msgtype type;		/* = SFS_SIGNED_AUTHREQ */
  sfs_hash authid;		/* SHA-1 (sfs_authinfo) */
  sfs_seqno seqno;		/* Counter, value unique per authid */
  opaque usrinfo[16];		/* All 0s, or <= 15 character logname */
};

struct sfs_redirect {
  sfs_time serial;
  sfs_time expire;
  sfs_hostinfo hostinfo;
};

/* Note: an sfs_signed_pathrevoke with a NULL redirect (i.e. a
 * revocation certificate) always takes precedence over one with a
 * non-NULL redirect (a forwarding pointer). */
struct sfs_pathrevoke_msg {
  sfs_msgtype type;		/* = SFS_PATHREVOKE */
  sfs_hostinfo path;		/* Hostinfo of old self-certifying pathname */
  sfs_redirect *redirect;	/* Optional forwarding pointer */
};

struct sfs_pathrevoke {
  sfs_pathrevoke_msg msg;
  sfs_sig sig;
};

/*
 * RPC arguments and results
 */

typedef sfs_connectinfo sfs_connectarg;

struct sfs_connectok {
  sfs_servinfo servinfo;
  sfs_hashcharge charge;
};

union sfs_connectres switch (sfsstat status) {
 case SFS_OK:
   sfs_connectok reply;
 case SFS_REDIRECT:
   sfs_pathrevoke revoke;
 default:
   void;
};

struct sfs_encryptarg {
  sfs_hashpay payment;
  sfs_ctext kmsg;
  sfs_pubkey pubkey;
};
typedef sfs_ctext sfs_encryptres;

struct sfs_nfs3_subfs {
  nfspath3 path;
  nfs_fh3 fh;
};
struct sfs_nfs3_fsinfo {
  nfs_fh3 root;
  sfs_nfs3_subfs subfs<>;
};

union sfs_nfs_fsinfo switch (int vers) {
 case ex_NFS_V3:
   sfs_nfs3_fsinfo v3;
};


const SFSRO_IVSIZE = 20;

#define SFSRO_PROGRAM 344446
#define SFSRO_VERSION 1

struct sfsro1_signed_fsinfo {
  sfs_msgtype type; /* = SFS_ROFSINFO */
  sfs_time start;       /* In seconds since UNIX epoch */
  unsigned duration;	/* seconds */
  opaque iv[SFSRO_IVSIZE];
  sfs_hash rootfh;
  sfs_hash fhdb;
  int blocksize;
};

struct sfsro1_fsinfo {
  sfsro1_signed_fsinfo info;
  sfs_sig sig;
};

union sfsro_fsinfo switch (int vers) {
 case SFSRO_VERSION:
   sfsro1_fsinfo v1;
};

union sfs_fsinfo switch (int prog) {
 case ex_NFS_PROGRAM:
   sfs_nfs_fsinfo nfs;
 case SFSRO_PROGRAM:
   sfsro_fsinfo sfsro;
 default:
   void;
};


typedef string sfs_idname<32>;

union sfs_opt_idname switch (bool present) {
 case TRUE:
   sfs_idname name;
 case FALSE:
   void;
};

struct sfs_idnums {
  int uid;
  int gid;
};

struct sfs_idnames {
  sfs_opt_idname uidname;
  sfs_opt_idname gidname;
};

enum sfs_loginstat {
  SFSLOGIN_OK = 0,		/* Login succeeded */
  SFSLOGIN_MORE = 1,		/* More communication with client needed */
  SFSLOGIN_BAD = 2,		/* Invalid login */
  SFSLOGIN_ALLBAD = 3,		/* Invalid login don't try again */
  SFSLOGIN_AGAIN = 4		/* Repeat request & seqno, server will
                                 * proceed differently */
};
/* TODO:  Rerturn last login information with good login, and perhaps
 * reason with bad login. */
union sfs_loginres switch (sfs_loginstat status) {
 case SFSLOGIN_OK:
   unsigned authno;
 case SFSLOGIN_MORE:
   opaque resmore<>;
 case SFSLOGIN_BAD:
 case SFSLOGIN_ALLBAD:
 case SFSLOGIN_AGAIN:
   void;
};

struct sfs_loginarg {
  sfs_seqno seqno;
  opaque certificate<>;		/* marshalled sfs_autharg */
};


/*
 * User-authentication structures
 */

enum sfsauth_stat {
  SFSAUTH_OK = 0,
  SFSAUTH_LOGINMORE = 1,	/* More communication with client needed */
  SFSAUTH_FAILED = 2,
  SFSAUTH_LOGINALLBAD = 3,	/* Invalid login don't try again */
  SFSAUTH_NOTSOCK = 4,
  SFSAUTH_BADUSERNAME = 5,
  SFSAUTH_WRONGUID = 6,
  SFSAUTH_DENYROOT = 7,
  SFSAUTH_BADSHELL = 8,
  SFSAUTH_DENYFILE = 9,
  SFSAUTH_BADPASSWORD = 10,
  SFSAUTH_USEREXISTS = 11,
  SFSAUTH_NOCHANGES = 12,
  SFSAUTH_NOSRP = 13,
  SFSAUTH_BADSIGNATURE = 14,
  SFSAUTH_PROTOERR = 15,
  SFSAUTH_NOTTHERE = 16,
  SFSAUTH_BADAUTHID = 17,
  SFSAUTH_KEYEXISTS = 18,
  SFSAUTH_BADKEYNAME = 19
};

enum sfs_authtype {
  SFS_NOAUTH = 0,
  SFS_AUTHREQ = 1,
  SFS_SRPAUTH = 2,
  SFS_UNIXPWAUTH = 3
};

struct sfs_authreq {
  sfs_pubkey usrkey;		/* Key with which signed_req signed */
  sfs_sig signed_req;		/* Recoveraby signed sfs_signed_authreq */
};

union sfs_autharg switch (sfs_authtype type) {
 case SFS_NOAUTH:
   void;
 case SFS_AUTHREQ:
   sfs_authreq req;
};

enum sfs_credtype {
  SFS_NOCRED = 0,
  SFS_UNIXCRED = 1
};

struct sfs_unixcred {
  string username<>;
  string homedir<>;
  string shell<>;
  unsigned uid;
  unsigned gid;
  unsigned groups<>;
};

union sfsauth_cred switch (sfs_credtype type) {
 case SFS_NOCRED:
   void;
 case SFS_UNIXCRED:
   sfs_unixcred unixcred;
};

struct sfsauth_loginokres {
  sfsauth_cred cred;
  sfs_hash authid;
  sfs_seqno seqno;
};


union sfsauth_loginres switch (sfs_loginstat status) {
 case SFSLOGIN_OK:
   sfsauth_loginokres resok;
 case SFSLOGIN_MORE:
   opaque resmore<>;
 default:
   void;
};


/*
 * Secure Remote Password (SRP) protocol
 */

struct sfssrp_parms {
  bigint N;			/* Prime */
  bigint g;			/* Generator */
};

union sfsauth_srpparmsres switch (sfsauth_stat status) {
 case SFSAUTH_OK:
   sfssrp_parms parms;
 default:
   void;
};

typedef opaque sfssrp_bytes<>;
struct sfssrp_init_arg {
  string username<>;
  sfssrp_bytes msg;
};

union sfsauth_srpres switch (sfsauth_stat status) {
 case SFSAUTH_OK:
   sfssrp_bytes msg;
 default:
   void;
};

struct sfsauth_fetchresok {
  string privkey<>;
  sfs_hash hostid;
};

union sfsauth_fetchres switch (sfsauth_stat status) {
 case SFSAUTH_OK:
   sfsauth_fetchresok resok;
 default:
   void;
};

struct sfsauth_srpinfo {
  string info<>;
  string privkey<>;
};

struct sfsauth_registermsg {
  sfs_msgtype type;		/* = SFS_AUTHREGISTER */
  string username<>;		/* logname */
  string password<>;		/* password for an add */
  sfs_pubkey pubkey;
  sfsauth_srpinfo *srpinfo;
};

struct sfsauth_registerarg {
  sfsauth_registermsg msg;
  sfs_sig sig;
};

enum sfsauth_registerres {
  SFSAUTH_REGISTER_OK = 0,
  SFSAUTH_REGISTER_NOTSOCK = 1,
  SFSAUTH_REGISTER_BADUSERNAME = 2,
  SFSAUTH_REGISTER_WRONGUID = 3,
  SFSAUTH_REGISTER_DENYROOT = 4,
  SFSAUTH_REGISTER_BADSHELL = 5,
  SFSAUTH_REGISTER_DENYFILE = 6,
  SFSAUTH_REGISTER_BADPASSWORD = 7,
  SFSAUTH_REGISTER_USEREXISTS = 8,
  SFSAUTH_REGISTER_FAILED = 9,
  SFSAUTH_REGISTER_NOCHANGES = 10,
  SFSAUTH_REGISTER_NOSRP = 11,
  SFSAUTH_REGISTER_BADSIG = 12
};

struct sfsauth_updatemsg {
  sfs_msgtype type;		/* = SFS_AUTHUPDATE */
  sfs_hash authid;		/* SHA-1 (sfs_authinfo);
				   service is SFS_AUTHSERV */
  sfs_pubkey oldkey;
  sfs_pubkey newkey;
  sfsauth_srpinfo *srpinfo;
  /* maybe username? */
};

struct sfsauth_updatearg {
  sfsauth_updatemsg msg;
  sfs_sig osig;			/* computed with sfsauth_updatereq.oldkey */
  sfs_sig nsig;			/* computed with sfsauth_updatereq.newkey */
};

program SFS_PROGRAM {
	version SFS_VERSION {
		void 
		SFSPROC_NULL (void) = 0;

		sfs_connectres
		SFSPROC_CONNECT (sfs_connectarg) = 1;

		sfs_encryptres
		SFSPROC_ENCRYPT (sfs_encryptarg) = 2;

		FSINFO
		SFSPROC_GETFSINFO (void) = 3;

		sfs_loginres
		SFSPROC_LOGIN (sfs_loginarg) = 4;

		void
		SFSPROC_LOGOUT (unsigned) = 5;

		sfs_idnames
		SFSPROC_IDNAMES (sfs_idnums) = 6;

		sfs_idnums
		SFSPROC_IDNUMS (sfs_idnames) = 7;

		sfsauth_cred
		SFSPROC_GETCRED (void) = 8;
	} = 1;
} = 344440;

program SFSCB_PROGRAM {
	version SFSCB_VERSION {
		void 
		SFSCBPROC_NULL(void) = 0;
	} = 1;
} = 344441;

program SFSAUTH_PROGRAM {
	version SFSAUTH_VERSION {
		void 
		SFSAUTHPROC_NULL (void) = 0;

		sfsauth_loginres
		SFSAUTHPROC_LOGIN (sfs_loginarg) = 1;

		sfsauth_stat
		SFSAUTHPROC_REGISTER (sfsauth_registerarg) = 2;

		sfsauth_stat
		SFSAUTHPROC_UPDATE (sfsauth_updatearg) = 3;

		sfsauth_srpparmsres
		SFSAUTHPROC_SRP_GETPARAMS (void) = 4;

		sfsauth_srpres
		SFSAUTHPROC_SRP_INIT (sfssrp_init_arg) = 5;

		sfsauth_srpres
		SFSAUTHPROC_SRP_MORE (sfssrp_bytes) = 6;

		sfsauth_fetchres
		SFSAUTHPROC_FETCH (void) = 7;
	} = 1;
} = 344442;

#undef SFSRO_VERSION
#undef SFSRO_PROGRAM
