Small tweaks
Lots of new code imported.
This commit is contained in:
parent
a770daa795
commit
2277c5d7bb
244
include/9p.h
Normal file
244
include/9p.h
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
#ifndef __9P_H__
|
||||||
|
#define __9P_H__ 1
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
#pragma src "/sys/src/lib9p"
|
||||||
|
#pragma lib "lib9p.a"
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Maps from ulongs to void*s.
|
||||||
|
*/
|
||||||
|
typedef struct Intmap Intmap;
|
||||||
|
|
||||||
|
Intmap* allocmap(void (*inc)(void*));
|
||||||
|
void freemap(Intmap*, void (*destroy)(void*));
|
||||||
|
void* lookupkey(Intmap*, ulong);
|
||||||
|
void* insertkey(Intmap*, ulong, void*);
|
||||||
|
int caninsertkey(Intmap*, ulong, void*);
|
||||||
|
void* deletekey(Intmap*, ulong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fid and Request structures.
|
||||||
|
*/
|
||||||
|
typedef struct Fid Fid;
|
||||||
|
typedef struct Req Req;
|
||||||
|
typedef struct Fidpool Fidpool;
|
||||||
|
typedef struct Reqpool Reqpool;
|
||||||
|
typedef struct File File;
|
||||||
|
typedef struct Filelist Filelist;
|
||||||
|
typedef struct Tree Tree;
|
||||||
|
typedef struct Readdir Readdir;
|
||||||
|
typedef struct Srv Srv;
|
||||||
|
|
||||||
|
struct Fid
|
||||||
|
{
|
||||||
|
ulong fid;
|
||||||
|
char omode; /* -1 = not open */
|
||||||
|
File* file;
|
||||||
|
char* uid;
|
||||||
|
Qid qid;
|
||||||
|
void* aux;
|
||||||
|
|
||||||
|
/* below is implementation-specific; don't use */
|
||||||
|
Readdir* rdir;
|
||||||
|
Ref ref;
|
||||||
|
Fidpool* pool;
|
||||||
|
vlong diroffset;
|
||||||
|
long dirindex;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Req
|
||||||
|
{
|
||||||
|
ulong tag;
|
||||||
|
void* aux;
|
||||||
|
Fcall ifcall;
|
||||||
|
Fcall ofcall;
|
||||||
|
Dir d;
|
||||||
|
Req* oldreq;
|
||||||
|
Fid* fid;
|
||||||
|
Fid* afid;
|
||||||
|
Fid* newfid;
|
||||||
|
Srv* srv;
|
||||||
|
|
||||||
|
/* below is implementation-specific; don't use */
|
||||||
|
QLock lk;
|
||||||
|
Ref ref;
|
||||||
|
Reqpool* pool;
|
||||||
|
uchar* buf;
|
||||||
|
uchar type;
|
||||||
|
uchar responded;
|
||||||
|
char* error;
|
||||||
|
void* rbuf;
|
||||||
|
Req** flush;
|
||||||
|
int nflush;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pools to maintain Fid <-> fid and Req <-> tag maps.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct Fidpool {
|
||||||
|
Intmap *map;
|
||||||
|
void (*destroy)(Fid*);
|
||||||
|
Srv *srv;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Reqpool {
|
||||||
|
Intmap *map;
|
||||||
|
void (*destroy)(Req*);
|
||||||
|
Srv *srv;
|
||||||
|
};
|
||||||
|
|
||||||
|
Fidpool* allocfidpool(void (*destroy)(Fid*));
|
||||||
|
void freefidpool(Fidpool*);
|
||||||
|
Fid* allocfid(Fidpool*, ulong);
|
||||||
|
Fid* lookupfid(Fidpool*, ulong);
|
||||||
|
void closefid(Fid*);
|
||||||
|
Fid* removefid(Fidpool*, ulong);
|
||||||
|
|
||||||
|
Reqpool* allocreqpool(void (*destroy)(Req*));
|
||||||
|
void freereqpool(Reqpool*);
|
||||||
|
Req* allocreq(Reqpool*, ulong);
|
||||||
|
Req* lookupreq(Reqpool*, ulong);
|
||||||
|
void closereq(Req*);
|
||||||
|
Req* removereq(Reqpool*, ulong);
|
||||||
|
|
||||||
|
typedef int Dirgen(int, Dir*, void*);
|
||||||
|
void dirread9p(Req*, Dirgen*, void*);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* File trees.
|
||||||
|
*/
|
||||||
|
struct File {
|
||||||
|
Ref ref;
|
||||||
|
Dir dir;
|
||||||
|
File *parent;
|
||||||
|
void *aux;
|
||||||
|
|
||||||
|
/* below is implementation-specific; don't use */
|
||||||
|
RWLock rwlock;
|
||||||
|
Filelist *filelist;
|
||||||
|
Tree *tree;
|
||||||
|
int nchild;
|
||||||
|
int allocd;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Tree {
|
||||||
|
File *root;
|
||||||
|
void (*destroy)(File *file);
|
||||||
|
|
||||||
|
/* below is implementation-specific; don't use */
|
||||||
|
Lock genlock;
|
||||||
|
ulong qidgen;
|
||||||
|
ulong dirqidgen;
|
||||||
|
};
|
||||||
|
|
||||||
|
Tree* alloctree(char*, char*, ulong, void(*destroy)(File*));
|
||||||
|
void freetree(Tree*);
|
||||||
|
File* createfile(File*, char*, char*, ulong, void*);
|
||||||
|
int removefile(File*);
|
||||||
|
void closefile(File*);
|
||||||
|
File* walkfile(File*, char*);
|
||||||
|
Readdir* opendirfile(File*);
|
||||||
|
long readdirfile(Readdir*, uchar*, long);
|
||||||
|
void closedirfile(Readdir*);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Kernel-style command parser
|
||||||
|
*/
|
||||||
|
typedef struct Cmdbuf Cmdbuf;
|
||||||
|
typedef struct Cmdtab Cmdtab;
|
||||||
|
Cmdbuf* parsecmd(char *a, int n);
|
||||||
|
void respondcmderror(Req*, Cmdbuf*, char*, ...);
|
||||||
|
Cmdtab* lookupcmd(Cmdbuf*, Cmdtab*, int);
|
||||||
|
/*
|
||||||
|
#pragma varargck argpos respondcmderr 3
|
||||||
|
*/
|
||||||
|
struct Cmdbuf
|
||||||
|
{
|
||||||
|
char *buf;
|
||||||
|
char **f;
|
||||||
|
int nf;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Cmdtab
|
||||||
|
{
|
||||||
|
int index; /* used by client to switch on result */
|
||||||
|
char *cmd; /* command name */
|
||||||
|
int narg; /* expected #args; 0 ==> variadic */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* File service loop.
|
||||||
|
*/
|
||||||
|
struct Srv {
|
||||||
|
Tree* tree;
|
||||||
|
void (*destroyfid)(Fid*);
|
||||||
|
void (*destroyreq)(Req*);
|
||||||
|
void (*end)(Srv*);
|
||||||
|
void* aux;
|
||||||
|
|
||||||
|
void (*attach)(Req*);
|
||||||
|
void (*auth)(Req*);
|
||||||
|
void (*open)(Req*);
|
||||||
|
void (*create)(Req*);
|
||||||
|
void (*read)(Req*);
|
||||||
|
void (*write)(Req*);
|
||||||
|
void (*remove)(Req*);
|
||||||
|
void (*flush)(Req*);
|
||||||
|
void (*stat)(Req*);
|
||||||
|
void (*wstat)(Req*);
|
||||||
|
void (*walk)(Req*);
|
||||||
|
char* (*clone)(Fid*, Fid*);
|
||||||
|
char* (*walk1)(Fid*, char*, Qid*);
|
||||||
|
|
||||||
|
int infd;
|
||||||
|
int outfd;
|
||||||
|
int nopipe;
|
||||||
|
int srvfd;
|
||||||
|
int leavefdsopen; /* magic for acme win */
|
||||||
|
|
||||||
|
/* below is implementation-specific; don't use */
|
||||||
|
Fidpool* fpool;
|
||||||
|
Reqpool* rpool;
|
||||||
|
uint msize;
|
||||||
|
|
||||||
|
uchar* rbuf;
|
||||||
|
QLock rlock;
|
||||||
|
uchar* wbuf;
|
||||||
|
QLock wlock;
|
||||||
|
};
|
||||||
|
|
||||||
|
void srv(Srv*);
|
||||||
|
void postmountsrv(Srv*, char*, char*, int);
|
||||||
|
int postfd(char*, int);
|
||||||
|
int chatty9p;
|
||||||
|
void respond(Req*, char*);
|
||||||
|
void threadpostmountsrv(Srv*, char*, char*, int);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper. Assumes user is same as group.
|
||||||
|
*/
|
||||||
|
int hasperm(File*, char*, int);
|
||||||
|
|
||||||
|
void* emalloc9p(ulong);
|
||||||
|
void* erealloc9p(void*, ulong);
|
||||||
|
char* estrdup9p(char*);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
OMASK = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
void readstr(Req*, char*);
|
||||||
|
void readbuf(Req*, void*, long);
|
||||||
|
void walkandclone(Req*, char*(*walk1)(Fid*,char*,void*), char*(*clone)(Fid*,Fid*,void*), void*);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
159
include/auth.h
Normal file
159
include/auth.h
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
#ifndef __AUTH_H__
|
||||||
|
#define __AUTH_H__ 1
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
#pragma src "/sys/src/libauth"
|
||||||
|
#pragma lib "libauth.a"
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interface for typical callers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct AuthInfo AuthInfo;
|
||||||
|
typedef struct Chalstate Chalstate;
|
||||||
|
typedef struct Chapreply Chapreply;
|
||||||
|
typedef struct MSchapreply MSchapreply;
|
||||||
|
typedef struct UserPasswd UserPasswd;
|
||||||
|
typedef struct AuthRpc AuthRpc;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
MAXCHLEN= 256, /* max challenge length */
|
||||||
|
MAXNAMELEN= 256, /* maximum name length */
|
||||||
|
MD5LEN= 16,
|
||||||
|
|
||||||
|
ARok = 0, /* rpc return values */
|
||||||
|
ARdone,
|
||||||
|
ARerror,
|
||||||
|
ARneedkey,
|
||||||
|
ARbadkey,
|
||||||
|
ARwritenext,
|
||||||
|
ARtoosmall,
|
||||||
|
ARtoobig,
|
||||||
|
ARrpcfailure,
|
||||||
|
ARphase,
|
||||||
|
|
||||||
|
AuthRpcMax = 4096,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AuthRpc
|
||||||
|
{
|
||||||
|
int afd;
|
||||||
|
char ibuf[AuthRpcMax];
|
||||||
|
char obuf[AuthRpcMax];
|
||||||
|
char *arg;
|
||||||
|
uint narg;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AuthInfo
|
||||||
|
{
|
||||||
|
char *cuid; /* caller id */
|
||||||
|
char *suid; /* server id */
|
||||||
|
char *cap; /* capability (only valid on server side) */
|
||||||
|
int nsecret; /* length of secret */
|
||||||
|
uchar *secret; /* secret */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Chalstate
|
||||||
|
{
|
||||||
|
char *user;
|
||||||
|
char chal[MAXCHLEN];
|
||||||
|
int nchal;
|
||||||
|
void *resp;
|
||||||
|
int nresp;
|
||||||
|
|
||||||
|
/* for implementation only */
|
||||||
|
int afd; /* to factotum */
|
||||||
|
AuthRpc *rpc; /* to factotum */
|
||||||
|
char userbuf[MAXNAMELEN]; /* temp space if needed */
|
||||||
|
int userinchal; /* user was sent to obtain challenge */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Chapreply /* for protocol "chap" */
|
||||||
|
{
|
||||||
|
uchar id;
|
||||||
|
char resp[MD5LEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MSchapreply /* for protocol "mschap" */
|
||||||
|
{
|
||||||
|
char LMresp[24]; /* Lan Manager response */
|
||||||
|
char NTresp[24]; /* NT response */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UserPasswd
|
||||||
|
{
|
||||||
|
char *user;
|
||||||
|
char *passwd;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern int newns(char*, char*);
|
||||||
|
extern int addns(char*, char*);
|
||||||
|
|
||||||
|
extern int noworld(char*);
|
||||||
|
extern int amount(int, char*, int, char*);
|
||||||
|
|
||||||
|
/* these two may get generalized away -rsc */
|
||||||
|
extern int login(char*, char*, char*);
|
||||||
|
extern int httpauth(char*, char*);
|
||||||
|
|
||||||
|
typedef struct Attr Attr;
|
||||||
|
enum {
|
||||||
|
AttrNameval, /* name=val -- when matching, must have name=val */
|
||||||
|
AttrQuery, /* name? -- when matching, must be present */
|
||||||
|
AttrDefault, /* name:=val -- when matching, if present must match INTERNAL */
|
||||||
|
};
|
||||||
|
struct Attr
|
||||||
|
{
|
||||||
|
int type;
|
||||||
|
Attr *next;
|
||||||
|
char *name;
|
||||||
|
char *val;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef int AuthGetkey(char*);
|
||||||
|
|
||||||
|
int _attrfmt(Fmt*);
|
||||||
|
Attr *_copyattr(Attr*);
|
||||||
|
Attr *_delattr(Attr*, char*);
|
||||||
|
Attr *_findattr(Attr*, char*);
|
||||||
|
void _freeattr(Attr*);
|
||||||
|
Attr *_mkattr(int, char*, char*, Attr*);
|
||||||
|
Attr *_parseattr(char*);
|
||||||
|
char *_strfindattr(Attr*, char*);
|
||||||
|
/*
|
||||||
|
#pragma varargck type "A" Attr*
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern AuthInfo* fauth_proxy(int, AuthRpc *rpc, AuthGetkey *getkey, char *params);
|
||||||
|
extern AuthInfo* auth_proxy(int fd, AuthGetkey *getkey, char *fmt, ...);
|
||||||
|
extern int auth_getkey(char*);
|
||||||
|
extern int (*amount_getkey)(char*);
|
||||||
|
extern void auth_freeAI(AuthInfo *ai);
|
||||||
|
extern int auth_chuid(AuthInfo *ai, char *ns);
|
||||||
|
extern Chalstate *auth_challenge(char*, ...);
|
||||||
|
extern AuthInfo* auth_response(Chalstate*);
|
||||||
|
extern int auth_respond(void*, uint, char*, uint, void*, uint, AuthGetkey *getkey, char*, ...);
|
||||||
|
extern void auth_freechal(Chalstate*);
|
||||||
|
extern AuthInfo* auth_userpasswd(char *user, char *passwd);
|
||||||
|
extern UserPasswd* auth_getuserpasswd(AuthGetkey *getkey, char*, ...);
|
||||||
|
extern AuthInfo* auth_getinfo(AuthRpc *rpc);
|
||||||
|
extern AuthRpc* auth_allocrpc(int afd);
|
||||||
|
extern Attr* auth_attr(AuthRpc *rpc);
|
||||||
|
extern void auth_freerpc(AuthRpc *rpc);
|
||||||
|
extern uint auth_rpc(AuthRpc *rpc, char *verb, void *a, int n);
|
||||||
|
extern int auth_wep(char*, char*, ...);
|
||||||
|
/*
|
||||||
|
#pragma varargck argpos auth_proxy 3
|
||||||
|
#pragma varargck argpos auth_challenge 1
|
||||||
|
#pragma varargck argpos auth_respond 3
|
||||||
|
#pragma varargck argpos auth_getuserpasswd 2
|
||||||
|
*/
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
177
include/authsrv.h
Normal file
177
include/authsrv.h
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
#ifndef __AUTHSRV_H__
|
||||||
|
#define __AUTHSRV_H__ 1
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
#pragma src "/sys/src/libauthsrv"
|
||||||
|
#pragma lib "libauthsrv.a"
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interface for talking to authentication server.
|
||||||
|
*/
|
||||||
|
typedef struct Ticket Ticket;
|
||||||
|
typedef struct Ticketreq Ticketreq;
|
||||||
|
typedef struct Authenticator Authenticator;
|
||||||
|
typedef struct Nvrsafe Nvrsafe;
|
||||||
|
typedef struct Passwordreq Passwordreq;
|
||||||
|
typedef struct OChapreply OChapreply;
|
||||||
|
typedef struct OMSchapreply OMSchapreply;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
ANAMELEN= 28, /* maximum size of name in previous proto */
|
||||||
|
AERRLEN= 64, /* maximum size of errstr in previous proto */
|
||||||
|
DOMLEN= 48, /* length of an authentication domain name */
|
||||||
|
DESKEYLEN= 7, /* length of a des key for encrypt/decrypt */
|
||||||
|
CHALLEN= 8, /* length of a plan9 sk1 challenge */
|
||||||
|
NETCHLEN= 16, /* max network challenge length (used in AS protocol) */
|
||||||
|
CONFIGLEN= 14,
|
||||||
|
SECRETLEN= 32, /* max length of a secret */
|
||||||
|
|
||||||
|
KEYDBOFF= 8, /* length of random data at the start of key file */
|
||||||
|
OKEYDBLEN= ANAMELEN+DESKEYLEN+4+2, /* length of an entry in old key file */
|
||||||
|
KEYDBLEN= OKEYDBLEN+SECRETLEN, /* length of an entry in key file */
|
||||||
|
OMD5LEN= 16,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* encryption numberings (anti-replay) */
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
AuthTreq=1, /* ticket request */
|
||||||
|
AuthChal=2, /* challenge box request */
|
||||||
|
AuthPass=3, /* change password */
|
||||||
|
AuthOK=4, /* fixed length reply follows */
|
||||||
|
AuthErr=5, /* error follows */
|
||||||
|
AuthMod=6, /* modify user */
|
||||||
|
AuthApop=7, /* apop authentication for pop3 */
|
||||||
|
AuthOKvar=9, /* variable length reply follows */
|
||||||
|
AuthChap=10, /* chap authentication for ppp */
|
||||||
|
AuthMSchap=11, /* MS chap authentication for ppp */
|
||||||
|
AuthCram=12, /* CRAM verification for IMAP (RFC2195 & rfc2104) */
|
||||||
|
AuthHttp=13, /* http domain login */
|
||||||
|
AuthVNC=14, /* VNC server login (deprecated) */
|
||||||
|
|
||||||
|
|
||||||
|
AuthTs=64, /* ticket encrypted with server's key */
|
||||||
|
AuthTc, /* ticket encrypted with client's key */
|
||||||
|
AuthAs, /* server generated authenticator */
|
||||||
|
AuthAc, /* client generated authenticator */
|
||||||
|
AuthTp, /* ticket encrypted with client's key for password change */
|
||||||
|
AuthHr, /* http reply */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Ticketreq
|
||||||
|
{
|
||||||
|
char type;
|
||||||
|
char authid[ANAMELEN]; /* server's encryption id */
|
||||||
|
char authdom[DOMLEN]; /* server's authentication domain */
|
||||||
|
char chal[CHALLEN]; /* challenge from server */
|
||||||
|
char hostid[ANAMELEN]; /* host's encryption id */
|
||||||
|
char uid[ANAMELEN]; /* uid of requesting user on host */
|
||||||
|
};
|
||||||
|
#define TICKREQLEN (3*ANAMELEN+CHALLEN+DOMLEN+1)
|
||||||
|
|
||||||
|
struct Ticket
|
||||||
|
{
|
||||||
|
char num; /* replay protection */
|
||||||
|
char chal[CHALLEN]; /* server challenge */
|
||||||
|
char cuid[ANAMELEN]; /* uid on client */
|
||||||
|
char suid[ANAMELEN]; /* uid on server */
|
||||||
|
char key[DESKEYLEN]; /* nonce DES key */
|
||||||
|
};
|
||||||
|
#define TICKETLEN (CHALLEN+2*ANAMELEN+DESKEYLEN+1)
|
||||||
|
|
||||||
|
struct Authenticator
|
||||||
|
{
|
||||||
|
char num; /* replay protection */
|
||||||
|
char chal[CHALLEN];
|
||||||
|
ulong id; /* authenticator id, ++'d with each auth */
|
||||||
|
};
|
||||||
|
#define AUTHENTLEN (CHALLEN+4+1)
|
||||||
|
|
||||||
|
struct Passwordreq
|
||||||
|
{
|
||||||
|
char num;
|
||||||
|
char old[ANAMELEN];
|
||||||
|
char new[ANAMELEN];
|
||||||
|
char changesecret;
|
||||||
|
char secret[SECRETLEN]; /* new secret */
|
||||||
|
};
|
||||||
|
#define PASSREQLEN (2*ANAMELEN+1+1+SECRETLEN)
|
||||||
|
|
||||||
|
struct OChapreply
|
||||||
|
{
|
||||||
|
uchar id;
|
||||||
|
char uid[ANAMELEN];
|
||||||
|
char resp[OMD5LEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OMSchapreply
|
||||||
|
{
|
||||||
|
char uid[ANAMELEN];
|
||||||
|
char LMresp[24]; /* Lan Manager response */
|
||||||
|
char NTresp[24]; /* NT response */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* convert to/from wire format
|
||||||
|
*/
|
||||||
|
extern int convT2M(Ticket*, char*, char*);
|
||||||
|
extern void convM2T(char*, Ticket*, char*);
|
||||||
|
extern void convM2Tnoenc(char*, Ticket*);
|
||||||
|
extern int convA2M(Authenticator*, char*, char*);
|
||||||
|
extern void convM2A(char*, Authenticator*, char*);
|
||||||
|
extern int convTR2M(Ticketreq*, char*);
|
||||||
|
extern void convM2TR(char*, Ticketreq*);
|
||||||
|
extern int convPR2M(Passwordreq*, char*, char*);
|
||||||
|
extern void convM2PR(char*, Passwordreq*, char*);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* convert ascii password to DES key
|
||||||
|
*/
|
||||||
|
extern int opasstokey(char*, char*);
|
||||||
|
extern int passtokey(char*, char*);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Nvram interface
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
NVwrite = 1<<0, /* always prompt and rewrite nvram */
|
||||||
|
NVwriteonerr = 1<<1, /* prompt and rewrite nvram when corrupt */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nvrsafe
|
||||||
|
{
|
||||||
|
char machkey[DESKEYLEN];
|
||||||
|
uchar machsum;
|
||||||
|
char authkey[DESKEYLEN];
|
||||||
|
uchar authsum;
|
||||||
|
char config[CONFIGLEN];
|
||||||
|
uchar configsum;
|
||||||
|
char authid[ANAMELEN];
|
||||||
|
uchar authidsum;
|
||||||
|
char authdom[DOMLEN];
|
||||||
|
uchar authdomsum;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern uchar nvcsum(void*, int);
|
||||||
|
extern int readnvram(Nvrsafe*, int);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call up auth server
|
||||||
|
*/
|
||||||
|
extern int authdial(char *netroot, char *authdom);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* exchange messages with auth server
|
||||||
|
*/
|
||||||
|
extern int _asgetticket(int, char*, char*);
|
||||||
|
extern int _asrdresp(int, char*, int);
|
||||||
|
extern int sslnegotiate(int, Ticket*, char**, char**);
|
||||||
|
extern int srvsslnegotiate(int, Ticket*, char**, char**);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
153
include/mp.h
Normal file
153
include/mp.h
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
#ifndef __MP_H__
|
||||||
|
#define __MP_H__ 1
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
#pragma src "/sys/src/libmp"
|
||||||
|
#pragma lib "libmp.a"
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _MPINT 1
|
||||||
|
|
||||||
|
typedef long mpdigit;
|
||||||
|
|
||||||
|
// the code assumes mpdigit to be at least an int
|
||||||
|
// mpdigit must be an atomic type. mpdigit is defined
|
||||||
|
// in the architecture specific u.h
|
||||||
|
|
||||||
|
typedef struct mpint mpint;
|
||||||
|
|
||||||
|
struct mpint
|
||||||
|
{
|
||||||
|
int sign; // +1 or -1
|
||||||
|
int size; // allocated digits
|
||||||
|
int top; // significant digits
|
||||||
|
mpdigit *p;
|
||||||
|
char flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
MPstatic= 0x01,
|
||||||
|
Dbytes= sizeof(mpdigit), // bytes per digit
|
||||||
|
Dbits= Dbytes*8 // bits per digit
|
||||||
|
};
|
||||||
|
|
||||||
|
// allocation
|
||||||
|
void mpsetminbits(int n); // newly created mpint's get at least n bits
|
||||||
|
mpint* mpnew(int n); // create a new mpint with at least n bits
|
||||||
|
void mpfree(mpint *b);
|
||||||
|
void mpbits(mpint *b, int n); // ensure that b has at least n bits
|
||||||
|
void mpnorm(mpint *b); // dump leading zeros
|
||||||
|
mpint* mpcopy(mpint *b);
|
||||||
|
void mpassign(mpint *old, mpint *new);
|
||||||
|
|
||||||
|
// random bits
|
||||||
|
mpint* mprand(int bits, void (*gen)(uchar*, int), mpint *b);
|
||||||
|
|
||||||
|
// conversion
|
||||||
|
mpint* strtomp(char*, char**, int, mpint*); // ascii
|
||||||
|
int mpfmt(Fmt*);
|
||||||
|
char* mptoa(mpint*, int, char*, int);
|
||||||
|
mpint* letomp(uchar*, uint, mpint*); // byte array, little-endian
|
||||||
|
int mptole(mpint*, uchar*, uint, uchar**);
|
||||||
|
mpint* betomp(uchar*, uint, mpint*); // byte array, little-endian
|
||||||
|
int mptobe(mpint*, uchar*, uint, uchar**);
|
||||||
|
uint mptoui(mpint*); // unsigned int
|
||||||
|
mpint* uitomp(uint, mpint*);
|
||||||
|
int mptoi(mpint*); // int
|
||||||
|
mpint* itomp(int, mpint*);
|
||||||
|
uvlong mptouv(mpint*); // unsigned vlong
|
||||||
|
mpint* uvtomp(uvlong, mpint*);
|
||||||
|
vlong mptov(mpint*); // vlong
|
||||||
|
mpint* vtomp(vlong, mpint*);
|
||||||
|
|
||||||
|
// divide 2 digits by one
|
||||||
|
void mpdigdiv(mpdigit *dividend, mpdigit divisor, mpdigit *quotient);
|
||||||
|
|
||||||
|
// in the following, the result mpint may be
|
||||||
|
// the same as one of the inputs.
|
||||||
|
void mpadd(mpint *b1, mpint *b2, mpint *sum); // sum = b1+b2
|
||||||
|
void mpsub(mpint *b1, mpint *b2, mpint *diff); // diff = b1-b2
|
||||||
|
void mpleft(mpint *b, int shift, mpint *res); // res = b<<shift
|
||||||
|
void mpright(mpint *b, int shift, mpint *res); // res = b>>shift
|
||||||
|
void mpmul(mpint *b1, mpint *b2, mpint *prod); // prod = b1*b2
|
||||||
|
void mpexp(mpint *b, mpint *e, mpint *m, mpint *res); // res = b**e mod m
|
||||||
|
void mpmod(mpint *b, mpint *m, mpint *remainder); // remainder = b mod m
|
||||||
|
|
||||||
|
// quotient = dividend/divisor, remainder = dividend % divisor
|
||||||
|
void mpdiv(mpint *dividend, mpint *divisor, mpint *quotient, mpint *remainder);
|
||||||
|
|
||||||
|
// return neg, 0, pos as b1-b2 is neg, 0, pos
|
||||||
|
int mpcmp(mpint *b1, mpint *b2);
|
||||||
|
|
||||||
|
// extended gcd return d, x, and y, s.t. d = gcd(a,b) and ax+by = d
|
||||||
|
void mpextendedgcd(mpint *a, mpint *b, mpint *d, mpint *x, mpint *y);
|
||||||
|
|
||||||
|
// res = b**-1 mod m
|
||||||
|
void mpinvert(mpint *b, mpint *m, mpint *res);
|
||||||
|
|
||||||
|
// bit counting
|
||||||
|
int mpsignif(mpint*); // number of sigificant bits in mantissa
|
||||||
|
int mplowbits0(mpint*); // k, where n = 2**k * q for odd q
|
||||||
|
|
||||||
|
// well known constants
|
||||||
|
extern mpint *mpzero, *mpone, *mptwo;
|
||||||
|
|
||||||
|
// sum[0:alen] = a[0:alen-1] + b[0:blen-1]
|
||||||
|
// prereq: alen >= blen, sum has room for alen+1 digits
|
||||||
|
void mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum);
|
||||||
|
|
||||||
|
// diff[0:alen-1] = a[0:alen-1] - b[0:blen-1]
|
||||||
|
// prereq: alen >= blen, diff has room for alen digits
|
||||||
|
void mpvecsub(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *diff);
|
||||||
|
|
||||||
|
// p[0:n] += m * b[0:n-1]
|
||||||
|
// prereq: p has room for n+1 digits
|
||||||
|
void mpvecdigmuladd(mpdigit *b, int n, mpdigit m, mpdigit *p);
|
||||||
|
|
||||||
|
// p[0:n] -= m * b[0:n-1]
|
||||||
|
// prereq: p has room for n+1 digits
|
||||||
|
int mpvecdigmulsub(mpdigit *b, int n, mpdigit m, mpdigit *p);
|
||||||
|
|
||||||
|
// p[0:alen*blen-1] = a[0:alen-1] * b[0:blen-1]
|
||||||
|
// prereq: alen >= blen, p has room for m*n digits
|
||||||
|
void mpvecmul(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *p);
|
||||||
|
|
||||||
|
// sign of a - b or zero if the same
|
||||||
|
int mpveccmp(mpdigit *a, int alen, mpdigit *b, int blen);
|
||||||
|
|
||||||
|
// divide the 2 digit dividend by the one digit divisor and stick in quotient
|
||||||
|
// we assume that the result is one digit - overflow is all 1's
|
||||||
|
void mpdigdiv(mpdigit *dividend, mpdigit divisor, mpdigit *quotient);
|
||||||
|
|
||||||
|
// playing with magnitudes
|
||||||
|
int mpmagcmp(mpint *b1, mpint *b2);
|
||||||
|
void mpmagadd(mpint *b1, mpint *b2, mpint *sum); // sum = b1+b2
|
||||||
|
void mpmagsub(mpint *b1, mpint *b2, mpint *sum); // sum = b1+b2
|
||||||
|
|
||||||
|
// chinese remainder theorem
|
||||||
|
typedef struct CRTpre CRTpre; // precomputed values for converting
|
||||||
|
// twixt residues and mpint
|
||||||
|
typedef struct CRTres CRTres; // residue form of an mpint
|
||||||
|
|
||||||
|
struct CRTres
|
||||||
|
{
|
||||||
|
int n; // number of residues
|
||||||
|
mpint *r[1]; // residues
|
||||||
|
};
|
||||||
|
|
||||||
|
CRTpre* crtpre(int, mpint**); // precompute conversion values
|
||||||
|
CRTres* crtin(CRTpre*, mpint*); // convert mpint to residues
|
||||||
|
void crtout(CRTpre*, CRTres*, mpint*); // convert residues to mpint
|
||||||
|
void crtprefree(CRTpre*);
|
||||||
|
void crtresfree(CRTres*);
|
||||||
|
|
||||||
|
|
||||||
|
/* #pragma varargck type "B" mpint* */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
801
include/nfs3.h
Normal file
801
include/nfs3.h
Normal file
@ -0,0 +1,801 @@
|
|||||||
|
/*
|
||||||
|
* NFS mounter V3; see RFC 1813
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
#pragma lib "libsunrpc.a"
|
||||||
|
#pragma src "/sys/src/libsunrpc"
|
||||||
|
*/
|
||||||
|
#define _NFS3H_ /* sorry */
|
||||||
|
|
||||||
|
enum {
|
||||||
|
NfsMount1HandleSize = 32,
|
||||||
|
NfsMount3MaxPathSize = 1024,
|
||||||
|
NfsMount3MaxNameSize = 255,
|
||||||
|
NfsMount3MaxHandleSize = 64,
|
||||||
|
NfsMount3Program = 100005,
|
||||||
|
NfsMount3Version = 3,
|
||||||
|
NfsMount1Program = 100005,
|
||||||
|
NfsMount1Version = 1
|
||||||
|
};
|
||||||
|
typedef struct NfsMount3TNull NfsMount3TNull;
|
||||||
|
typedef struct NfsMount3RNull NfsMount3RNull;
|
||||||
|
typedef struct NfsMount3TMnt NfsMount3TMnt;
|
||||||
|
typedef struct NfsMount3RMnt NfsMount3RMnt;
|
||||||
|
typedef struct NfsMount3TDump NfsMount3TDump;
|
||||||
|
typedef struct NfsMount3Entry NfsMount3Entry;
|
||||||
|
typedef struct NfsMount3RDump NfsMount3RDump;
|
||||||
|
typedef struct NfsMount3TUmnt NfsMount3TUmnt;
|
||||||
|
typedef struct NfsMount3RUmnt NfsMount3RUmnt;
|
||||||
|
typedef struct NfsMount3Export NfsMount3Export;
|
||||||
|
typedef struct NfsMount3TUmntall NfsMount3TUmntall;
|
||||||
|
typedef struct NfsMount3RUmntall NfsMount3RUmntall;
|
||||||
|
typedef struct NfsMount3TExport NfsMount3TExport;
|
||||||
|
typedef struct NfsMount3RExport NfsMount3RExport;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
NfsMount3CallTNull,
|
||||||
|
NfsMount3CallRNull,
|
||||||
|
NfsMount3CallTMnt,
|
||||||
|
NfsMount3CallRMnt,
|
||||||
|
NfsMount3CallTDump,
|
||||||
|
NfsMount3CallRDump,
|
||||||
|
NfsMount3CallTUmnt,
|
||||||
|
NfsMount3CallRUmnt,
|
||||||
|
NfsMount3CallTUmntall,
|
||||||
|
NfsMount3CallRUmntall,
|
||||||
|
NfsMount3CallTExport,
|
||||||
|
NfsMount3CallRExport
|
||||||
|
} NfsMount3CallType;
|
||||||
|
|
||||||
|
struct NfsMount3TNull {
|
||||||
|
SunCall call;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NfsMount3RNull {
|
||||||
|
SunCall call;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NfsMount3TMnt {
|
||||||
|
SunCall call;
|
||||||
|
char *path;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NfsMount3RMnt {
|
||||||
|
SunCall call;
|
||||||
|
uint status;
|
||||||
|
uchar *handle;
|
||||||
|
uint len;
|
||||||
|
u32int *auth;
|
||||||
|
u32int nauth;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NfsMount3TDump {
|
||||||
|
SunCall call;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NfsMount3Entry {
|
||||||
|
char *host;
|
||||||
|
char *path;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NfsMount3RDump {
|
||||||
|
SunCall call;
|
||||||
|
uchar *data;
|
||||||
|
u32int count;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NfsMount3TUmnt {
|
||||||
|
SunCall call;
|
||||||
|
char *path;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NfsMount3RUmnt {
|
||||||
|
SunCall call;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NfsMount3Export {
|
||||||
|
char *path;
|
||||||
|
char **g;
|
||||||
|
u32int ng;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NfsMount3TUmntall {
|
||||||
|
SunCall call;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NfsMount3RUmntall {
|
||||||
|
SunCall call;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NfsMount3TExport {
|
||||||
|
SunCall call;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NfsMount3RExport {
|
||||||
|
SunCall call;
|
||||||
|
uchar *data;
|
||||||
|
u32int count;
|
||||||
|
};
|
||||||
|
|
||||||
|
uint nfsmount3exportgroupsize(uchar*);
|
||||||
|
uint nfsmount3exportsize(NfsMount3Export*);
|
||||||
|
int nfsmount3exportpack(uchar*, uchar*, uchar**, NfsMount3Export*);
|
||||||
|
int nfsmount3exportunpack(uchar*, uchar*, uchar**, char**, char***, NfsMount3Export*);
|
||||||
|
int nfsmount3entrypack(uchar*, uchar*, uchar**, NfsMount3Entry*);
|
||||||
|
int nfsmount3entryunpack(uchar*, uchar*, uchar**, NfsMount3Entry*);
|
||||||
|
uint nfsmount3entrysize(NfsMount3Entry*);
|
||||||
|
|
||||||
|
extern SunProg nfsmount3prog;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NFS V3; see RFC 1813
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
Nfs3MaxHandleSize = 64,
|
||||||
|
Nfs3CookieVerfSize = 8,
|
||||||
|
Nfs3CreateVerfSize = 8,
|
||||||
|
Nfs3WriteVerfSize = 8,
|
||||||
|
Nfs3AccessRead = 1,
|
||||||
|
Nfs3AccessLookup = 2,
|
||||||
|
Nfs3AccessModify = 4,
|
||||||
|
Nfs3AccessExtend = 8,
|
||||||
|
Nfs3AccessDelete = 16,
|
||||||
|
Nfs3AccessExecute = 32,
|
||||||
|
Nfs3FsHasLinks = 1,
|
||||||
|
Nfs3FsHasSymlinks = 2,
|
||||||
|
Nfs3FsHomogeneous = 8,
|
||||||
|
Nfs3FsCanSetTime = 16,
|
||||||
|
|
||||||
|
Nfs3Version = 3,
|
||||||
|
Nfs3Program = 100003,
|
||||||
|
};
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
Nfs3Ok = 0,
|
||||||
|
Nfs3ErrNotOwner = 1,
|
||||||
|
Nfs3ErrNoEnt = 2,
|
||||||
|
Nfs3ErrIo = 5,
|
||||||
|
Nfs3ErrNxio = 6,
|
||||||
|
Nfs3ErrNoMem = 12,
|
||||||
|
Nfs3ErrAcces = 13,
|
||||||
|
Nfs3ErrExist = 17,
|
||||||
|
Nfs3ErrXDev = 18,
|
||||||
|
Nfs3ErrNoDev = 19,
|
||||||
|
Nfs3ErrNotDir = 20,
|
||||||
|
Nfs3ErrIsDir = 21,
|
||||||
|
Nfs3ErrInval = 22,
|
||||||
|
Nfs3ErrFbig = 27,
|
||||||
|
Nfs3ErrNoSpc = 28,
|
||||||
|
Nfs3ErrRoFs = 30,
|
||||||
|
Nfs3ErrMLink = 31,
|
||||||
|
Nfs3ErrNameTooLong = 63,
|
||||||
|
Nfs3ErrNotEmpty = 66,
|
||||||
|
Nfs3ErrDQuot = 69,
|
||||||
|
Nfs3ErrStale = 70,
|
||||||
|
Nfs3ErrRemote = 71,
|
||||||
|
Nfs3ErrBadHandle = 10001,
|
||||||
|
Nfs3ErrNotSync = 10002,
|
||||||
|
Nfs3ErrBadCookie = 10003,
|
||||||
|
Nfs3ErrNotSupp = 10004,
|
||||||
|
Nfs3ErrTooSmall = 10005,
|
||||||
|
Nfs3ErrServerFault = 10006,
|
||||||
|
Nfs3ErrBadType = 10007,
|
||||||
|
Nfs3ErrJukebox = 10008,
|
||||||
|
Nfs3ErrFprintNotFound = 10009,
|
||||||
|
Nfs3ErrAborted = 10010,
|
||||||
|
} Nfs3Status;
|
||||||
|
|
||||||
|
void nfs3Errstr(Nfs3Status);
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
Nfs3FileReg = 1,
|
||||||
|
Nfs3FileDir = 2,
|
||||||
|
Nfs3FileBlock = 3,
|
||||||
|
Nfs3FileChar = 4,
|
||||||
|
Nfs3FileSymlink = 5,
|
||||||
|
Nfs3FileSocket = 6,
|
||||||
|
Nfs3FileFifo = 7,
|
||||||
|
} Nfs3FileType;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
Nfs3ModeSetUid = 0x800,
|
||||||
|
Nfs3ModeSetGid = 0x400,
|
||||||
|
Nfs3ModeSticky = 0x200,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
Nfs3CallTNull,
|
||||||
|
Nfs3CallRNull,
|
||||||
|
Nfs3CallTGetattr,
|
||||||
|
Nfs3CallRGetattr,
|
||||||
|
Nfs3CallTSetattr,
|
||||||
|
Nfs3CallRSetattr,
|
||||||
|
Nfs3CallTLookup,
|
||||||
|
Nfs3CallRLookup,
|
||||||
|
Nfs3CallTAccess,
|
||||||
|
Nfs3CallRAccess,
|
||||||
|
Nfs3CallTReadlink,
|
||||||
|
Nfs3CallRReadlink,
|
||||||
|
Nfs3CallTRead,
|
||||||
|
Nfs3CallRRead,
|
||||||
|
Nfs3CallTWrite,
|
||||||
|
Nfs3CallRWrite,
|
||||||
|
Nfs3CallTCreate,
|
||||||
|
Nfs3CallRCreate,
|
||||||
|
Nfs3CallTMkdir,
|
||||||
|
Nfs3CallRMkdir,
|
||||||
|
Nfs3CallTSymlink,
|
||||||
|
Nfs3CallRSymlink,
|
||||||
|
Nfs3CallTMknod,
|
||||||
|
Nfs3CallRMknod,
|
||||||
|
Nfs3CallTRemove,
|
||||||
|
Nfs3CallRRemove,
|
||||||
|
Nfs3CallTRmdir,
|
||||||
|
Nfs3CallRRmdir,
|
||||||
|
Nfs3CallTRename,
|
||||||
|
Nfs3CallRRename,
|
||||||
|
Nfs3CallTLink,
|
||||||
|
Nfs3CallRLink,
|
||||||
|
Nfs3CallTReadDir,
|
||||||
|
Nfs3CallRReadDir,
|
||||||
|
Nfs3CallTReadDirPlus,
|
||||||
|
Nfs3CallRReadDirPlus,
|
||||||
|
Nfs3CallTFsStat,
|
||||||
|
Nfs3CallRFsStat,
|
||||||
|
Nfs3CallTFsInfo,
|
||||||
|
Nfs3CallRFsInfo,
|
||||||
|
Nfs3CallTPathconf,
|
||||||
|
Nfs3CallRPathconf,
|
||||||
|
Nfs3CallTCommit,
|
||||||
|
Nfs3CallRCommit,
|
||||||
|
} Nfs3CallType;
|
||||||
|
|
||||||
|
typedef struct Nfs3Handle Nfs3Handle;
|
||||||
|
typedef struct Nfs3Time Nfs3Time;
|
||||||
|
typedef struct Nfs3Attr Nfs3Attr;
|
||||||
|
typedef struct Nfs3WccAttr Nfs3WccAttr;
|
||||||
|
typedef struct Nfs3Wcc Nfs3Wcc;
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
Nfs3SetTimeDont = 0,
|
||||||
|
Nfs3SetTimeServer = 1,
|
||||||
|
Nfs3SetTimeClient = 2,
|
||||||
|
} Nfs3SetTime;
|
||||||
|
|
||||||
|
typedef struct Nfs3SetAttr Nfs3SetAttr;
|
||||||
|
typedef struct Nfs3TNull Nfs3TNull;
|
||||||
|
typedef struct Nfs3RNull Nfs3RNull;
|
||||||
|
typedef struct Nfs3TGetattr Nfs3TGetattr;
|
||||||
|
typedef struct Nfs3RGetattr Nfs3RGetattr;
|
||||||
|
typedef struct Nfs3TSetattr Nfs3TSetattr;
|
||||||
|
typedef struct Nfs3RSetattr Nfs3RSetattr;
|
||||||
|
typedef struct Nfs3TLookup Nfs3TLookup;
|
||||||
|
typedef struct Nfs3RLookup Nfs3RLookup;
|
||||||
|
typedef struct Nfs3TAccess Nfs3TAccess;
|
||||||
|
typedef struct Nfs3RAccess Nfs3RAccess;
|
||||||
|
typedef struct Nfs3TReadlink Nfs3TReadlink;
|
||||||
|
typedef struct Nfs3RReadlink Nfs3RReadlink;
|
||||||
|
typedef struct Nfs3TRead Nfs3TRead;
|
||||||
|
typedef struct Nfs3RRead Nfs3RRead;
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
Nfs3SyncNone = 0,
|
||||||
|
Nfs3SyncData = 1,
|
||||||
|
Nfs3SyncFile = 2,
|
||||||
|
} Nfs3Sync;
|
||||||
|
|
||||||
|
typedef struct Nfs3TWrite Nfs3TWrite;
|
||||||
|
typedef struct Nfs3RWrite Nfs3RWrite;
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
Nfs3CreateUnchecked = 0,
|
||||||
|
Nfs3CreateGuarded = 1,
|
||||||
|
Nfs3CreateExclusive = 2,
|
||||||
|
} Nfs3Create;
|
||||||
|
|
||||||
|
typedef struct Nfs3TCreate Nfs3TCreate;
|
||||||
|
typedef struct Nfs3RCreate Nfs3RCreate;
|
||||||
|
typedef struct Nfs3TMkdir Nfs3TMkdir;
|
||||||
|
typedef struct Nfs3RMkdir Nfs3RMkdir;
|
||||||
|
typedef struct Nfs3TSymlink Nfs3TSymlink;
|
||||||
|
typedef struct Nfs3RSymlink Nfs3RSymlink;
|
||||||
|
typedef struct Nfs3TMknod Nfs3TMknod;
|
||||||
|
typedef struct Nfs3RMknod Nfs3RMknod;
|
||||||
|
typedef struct Nfs3TRemove Nfs3TRemove;
|
||||||
|
typedef struct Nfs3RRemove Nfs3RRemove;
|
||||||
|
typedef struct Nfs3TRmdir Nfs3TRmdir;
|
||||||
|
typedef struct Nfs3RRmdir Nfs3RRmdir;
|
||||||
|
typedef struct Nfs3TRename Nfs3TRename;
|
||||||
|
typedef struct Nfs3RRename Nfs3RRename;
|
||||||
|
typedef struct Nfs3TLink Nfs3TLink;
|
||||||
|
typedef struct Nfs3RLink Nfs3RLink;
|
||||||
|
typedef struct Nfs3TReadDir Nfs3TReadDir;
|
||||||
|
typedef struct Nfs3Entry Nfs3Entry;
|
||||||
|
typedef struct Nfs3RReadDir Nfs3RReadDir;
|
||||||
|
typedef struct Nfs3TReadDirPlus Nfs3TReadDirPlus;
|
||||||
|
typedef struct Nfs3EntryPlus Nfs3EntryPlus;
|
||||||
|
typedef struct Nfs3RReadDirPlus Nfs3RReadDirPlus;
|
||||||
|
typedef struct Nfs3TFsStat Nfs3TFsStat;
|
||||||
|
typedef struct Nfs3RFsStat Nfs3RFsStat;
|
||||||
|
typedef struct Nfs3TFsInfo Nfs3TFsInfo;
|
||||||
|
typedef struct Nfs3RFsInfo Nfs3RFsInfo;
|
||||||
|
typedef struct Nfs3TPathconf Nfs3TPathconf;
|
||||||
|
typedef struct Nfs3RPathconf Nfs3RPathconf;
|
||||||
|
typedef struct Nfs3TCommit Nfs3TCommit;
|
||||||
|
typedef struct Nfs3RCommit Nfs3RCommit;
|
||||||
|
|
||||||
|
struct Nfs3Handle {
|
||||||
|
uchar h[Nfs3MaxHandleSize];
|
||||||
|
u32int len;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3Time {
|
||||||
|
u32int sec;
|
||||||
|
u32int nsec;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3Attr {
|
||||||
|
Nfs3FileType type;
|
||||||
|
u32int mode;
|
||||||
|
u32int nlink;
|
||||||
|
u32int uid;
|
||||||
|
u32int gid;
|
||||||
|
u64int size;
|
||||||
|
u64int used;
|
||||||
|
u32int major;
|
||||||
|
u32int minor;
|
||||||
|
u64int fsid;
|
||||||
|
u64int fileid;
|
||||||
|
Nfs3Time atime;
|
||||||
|
Nfs3Time mtime;
|
||||||
|
Nfs3Time ctime;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3WccAttr {
|
||||||
|
u64int size;
|
||||||
|
Nfs3Time mtime;
|
||||||
|
Nfs3Time ctime;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3Wcc {
|
||||||
|
u1int haveWccAttr;
|
||||||
|
Nfs3WccAttr wccAttr;
|
||||||
|
u1int haveAttr;
|
||||||
|
Nfs3Attr attr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3SetAttr {
|
||||||
|
u1int setMode;
|
||||||
|
u32int mode;
|
||||||
|
u1int setUid;
|
||||||
|
u32int uid;
|
||||||
|
u1int setGid;
|
||||||
|
u32int gid;
|
||||||
|
u1int setSize;
|
||||||
|
u64int size;
|
||||||
|
Nfs3SetTime setAtime;
|
||||||
|
Nfs3Time atime;
|
||||||
|
Nfs3SetTime setMtime;
|
||||||
|
Nfs3Time mtime;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3TNull {
|
||||||
|
SunCall call;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3RNull {
|
||||||
|
SunCall call;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3TGetattr {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Handle handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3RGetattr {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Status status;
|
||||||
|
Nfs3Attr attr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3TSetattr {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Handle handle;
|
||||||
|
Nfs3SetAttr attr;
|
||||||
|
u1int checkCtime;
|
||||||
|
Nfs3Time ctime;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3RSetattr {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Status status;
|
||||||
|
Nfs3Wcc wcc;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3TLookup {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Handle handle;
|
||||||
|
char *name;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3RLookup {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Status status;
|
||||||
|
Nfs3Handle handle;
|
||||||
|
u1int haveAttr;
|
||||||
|
Nfs3Attr attr;
|
||||||
|
u1int haveDirAttr;
|
||||||
|
Nfs3Attr dirAttr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3TAccess {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Handle handle;
|
||||||
|
u32int access;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3RAccess {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Status status;
|
||||||
|
u1int haveAttr;
|
||||||
|
Nfs3Attr attr;
|
||||||
|
u32int access;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3TReadlink {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Handle handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3RReadlink {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Status status;
|
||||||
|
u1int haveAttr;
|
||||||
|
Nfs3Attr attr;
|
||||||
|
char *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3TRead {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Handle handle;
|
||||||
|
u64int offset;
|
||||||
|
u32int count;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3RRead {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Status status;
|
||||||
|
u1int haveAttr;
|
||||||
|
Nfs3Attr attr;
|
||||||
|
u32int count;
|
||||||
|
u1int eof;
|
||||||
|
uchar *data;
|
||||||
|
u32int ndata;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3TWrite {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Handle handle;
|
||||||
|
u64int offset;
|
||||||
|
u32int count;
|
||||||
|
Nfs3Sync stable;
|
||||||
|
uchar *data;
|
||||||
|
u32int ndata;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3RWrite {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Status status;
|
||||||
|
Nfs3Wcc wcc;
|
||||||
|
u32int count;
|
||||||
|
Nfs3Sync committed;
|
||||||
|
uchar verf[Nfs3WriteVerfSize];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3TCreate {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Handle handle;
|
||||||
|
char *name;
|
||||||
|
Nfs3Create mode;
|
||||||
|
Nfs3SetAttr attr;
|
||||||
|
uchar verf[Nfs3CreateVerfSize];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3RCreate {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Status status;
|
||||||
|
u1int haveHandle;
|
||||||
|
Nfs3Handle handle;
|
||||||
|
u1int haveAttr;
|
||||||
|
Nfs3Attr attr;
|
||||||
|
Nfs3Wcc dirWcc;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3TMkdir {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Handle handle;
|
||||||
|
char *name;
|
||||||
|
Nfs3SetAttr attr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3RMkdir {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Status status;
|
||||||
|
u1int haveHandle;
|
||||||
|
Nfs3Handle handle;
|
||||||
|
u1int haveAttr;
|
||||||
|
Nfs3Attr attr;
|
||||||
|
Nfs3Wcc dirWcc;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3TSymlink {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Handle handle;
|
||||||
|
char *name;
|
||||||
|
Nfs3SetAttr attr;
|
||||||
|
char *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3RSymlink {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Status status;
|
||||||
|
u1int haveHandle;
|
||||||
|
Nfs3Handle handle;
|
||||||
|
u1int haveAttr;
|
||||||
|
Nfs3Attr attr;
|
||||||
|
Nfs3Wcc dirWcc;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3TMknod {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Handle handle;
|
||||||
|
char *name;
|
||||||
|
Nfs3FileType type;
|
||||||
|
Nfs3SetAttr attr;
|
||||||
|
u32int major;
|
||||||
|
u32int minor;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3RMknod {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Status status;
|
||||||
|
u1int haveHandle;
|
||||||
|
Nfs3Handle handle;
|
||||||
|
u1int haveAttr;
|
||||||
|
Nfs3Attr attr;
|
||||||
|
Nfs3Wcc dirWcc;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3TRemove {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Handle handle;
|
||||||
|
char *name;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3RRemove {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Status status;
|
||||||
|
Nfs3Wcc wcc;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3TRmdir {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Handle handle;
|
||||||
|
char *name;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3RRmdir {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Status status;
|
||||||
|
Nfs3Wcc wcc;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3TRename {
|
||||||
|
SunCall call;
|
||||||
|
struct {
|
||||||
|
Nfs3Handle handle;
|
||||||
|
char *name;
|
||||||
|
} from;
|
||||||
|
struct {
|
||||||
|
Nfs3Handle handle;
|
||||||
|
char *name;
|
||||||
|
} to;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3RRename {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Status status;
|
||||||
|
Nfs3Wcc fromWcc;
|
||||||
|
Nfs3Wcc toWcc;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3TLink {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Handle handle;
|
||||||
|
struct {
|
||||||
|
Nfs3Handle handle;
|
||||||
|
char *name;
|
||||||
|
} link;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3RLink {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Status status;
|
||||||
|
u1int haveAttr;
|
||||||
|
Nfs3Attr attr;
|
||||||
|
Nfs3Wcc dirWcc;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3TReadDir {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Handle handle;
|
||||||
|
u64int cookie;
|
||||||
|
uchar verf[Nfs3CookieVerfSize];
|
||||||
|
u32int count;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3RReadDir {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Status status;
|
||||||
|
u1int haveAttr;
|
||||||
|
Nfs3Attr attr;
|
||||||
|
uchar verf[Nfs3CookieVerfSize];
|
||||||
|
uchar *data;
|
||||||
|
u32int count;
|
||||||
|
u1int eof;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3TReadDirPlus {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Handle handle;
|
||||||
|
u64int cookie;
|
||||||
|
uchar verf[Nfs3CookieVerfSize];
|
||||||
|
u32int dirCount;
|
||||||
|
u32int maxCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3Entry {
|
||||||
|
u64int fileid;
|
||||||
|
char *name;
|
||||||
|
u64int cookie;
|
||||||
|
u1int haveAttr;
|
||||||
|
Nfs3Attr attr;
|
||||||
|
u1int haveHandle;
|
||||||
|
Nfs3Handle handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3RReadDirPlus {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Status status;
|
||||||
|
u1int haveAttr;
|
||||||
|
Nfs3Attr attr;
|
||||||
|
uchar verf[Nfs3CookieVerfSize];
|
||||||
|
uchar *data;
|
||||||
|
u32int count;
|
||||||
|
u1int eof;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3TFsStat {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Handle handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3RFsStat {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Status status;
|
||||||
|
u1int haveAttr;
|
||||||
|
Nfs3Attr attr;
|
||||||
|
u64int totalBytes;
|
||||||
|
u64int freeBytes;
|
||||||
|
u64int availBytes;
|
||||||
|
u64int totalFiles;
|
||||||
|
u64int freeFiles;
|
||||||
|
u64int availFiles;
|
||||||
|
u32int invarSec;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3TFsInfo {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Handle handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3RFsInfo {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Status status;
|
||||||
|
u1int haveAttr;
|
||||||
|
Nfs3Attr attr;
|
||||||
|
u32int readMax;
|
||||||
|
u32int readPref;
|
||||||
|
u32int readMult;
|
||||||
|
u32int writeMax;
|
||||||
|
u32int writePref;
|
||||||
|
u32int writeMult;
|
||||||
|
u32int readDirPref;
|
||||||
|
u64int maxFileSize;
|
||||||
|
Nfs3Time timePrec;
|
||||||
|
u32int flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3TPathconf {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Handle handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3RPathconf {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Status status;
|
||||||
|
u1int haveAttr;
|
||||||
|
Nfs3Attr attr;
|
||||||
|
u32int maxLink;
|
||||||
|
u32int maxName;
|
||||||
|
u1int noTrunc;
|
||||||
|
u1int chownRestricted;
|
||||||
|
u1int caseInsensitive;
|
||||||
|
u1int casePreserving;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3TCommit {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Handle handle;
|
||||||
|
u64int offset;
|
||||||
|
u32int count;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Nfs3RCommit {
|
||||||
|
SunCall call;
|
||||||
|
Nfs3Status status;
|
||||||
|
Nfs3Wcc wcc;
|
||||||
|
uchar verf[Nfs3WriteVerfSize];
|
||||||
|
};
|
||||||
|
|
||||||
|
char *nfs3statusstr(Nfs3Status);
|
||||||
|
char *nfs3typestr(SunCallType);
|
||||||
|
char *nfs3settimestr(Nfs3SetTime);
|
||||||
|
char *nfs3syncstr(Nfs3Sync);
|
||||||
|
|
||||||
|
void nfs3handleprint(Fmt*, Nfs3Handle*);
|
||||||
|
u32int nfs3handlesize(Nfs3Handle*);
|
||||||
|
int nfs3handlepack(uchar*, uchar*, uchar**, Nfs3Handle*);
|
||||||
|
int nfs3handleunpack(uchar*, uchar*, uchar**, Nfs3Handle*);
|
||||||
|
|
||||||
|
void nfs3timeprint(Fmt*, Nfs3Time*);
|
||||||
|
u32int nfs3timesize(Nfs3Time*);
|
||||||
|
int nfs3timepack(uchar*, uchar*, uchar**, Nfs3Time*);
|
||||||
|
int nfs3timeunpack(uchar*, uchar*, uchar**, Nfs3Time*);
|
||||||
|
|
||||||
|
void nfs3attrprint(Fmt*, Nfs3Attr*);
|
||||||
|
u32int nfs3attrsize(Nfs3Attr*);
|
||||||
|
int nfs3attrpack(uchar*, uchar*, uchar**, Nfs3Attr*);
|
||||||
|
int nfs3attrunpack(uchar*, uchar*, uchar**, Nfs3Attr*);
|
||||||
|
|
||||||
|
void nfs3wccattrprint(Fmt*, Nfs3WccAttr*);
|
||||||
|
u32int nfs3wccattrsize(Nfs3WccAttr*);
|
||||||
|
int nfs3wccattrpack(uchar*, uchar*, uchar**, Nfs3WccAttr*);
|
||||||
|
int nfs3wccattrunpack(uchar*, uchar*, uchar**, Nfs3WccAttr*);
|
||||||
|
|
||||||
|
void nfs3wccprint(Fmt*, Nfs3Wcc*);
|
||||||
|
u32int nfs3wccsize(Nfs3Wcc*);
|
||||||
|
int nfs3wccpack(uchar*, uchar*, uchar**, Nfs3Wcc*);
|
||||||
|
int nfs3wccunpack(uchar*, uchar*, uchar**, Nfs3Wcc*);
|
||||||
|
|
||||||
|
void nfs3setattrprint(Fmt*, Nfs3SetAttr*);
|
||||||
|
u32int nfs3setattrsize(Nfs3SetAttr*);
|
||||||
|
int nfs3setattrpack(uchar*, uchar*, uchar**, Nfs3SetAttr*);
|
||||||
|
int nfs3setattrunpack(uchar*, uchar*, uchar**, Nfs3SetAttr*);
|
||||||
|
|
||||||
|
extern SunProg nfs3prog;
|
||||||
|
|
||||||
|
void nfs3entryprint(Fmt*, Nfs3Entry*);
|
||||||
|
u32int nfs3entrysize(Nfs3Entry*);
|
||||||
|
int nfs3entrypack(uchar*, uchar*, uchar**, Nfs3Entry*);
|
||||||
|
int nfs3entryunpack(uchar*, uchar*, uchar**, Nfs3Entry*);
|
||||||
|
|
||||||
|
void nfs3entryplusprint(Fmt*, Nfs3Entry*);
|
||||||
|
u32int nfs3entryplussize(Nfs3Entry*);
|
||||||
|
int nfs3entrypluspack(uchar*, uchar*, uchar**, Nfs3Entry*);
|
||||||
|
int nfs3entryplusunpack(uchar*, uchar*, uchar**, Nfs3Entry*);
|
||||||
|
|
||||||
400
include/sunrpc.h
Normal file
400
include/sunrpc.h
Normal file
@ -0,0 +1,400 @@
|
|||||||
|
/*
|
||||||
|
* Sun RPC; see RFC 1057
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
#pragma lib "libsunrpc.a"
|
||||||
|
#pragma src "/sys/src/libsunrpc"
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef uchar u1int;
|
||||||
|
|
||||||
|
typedef struct SunAuthInfo SunAuthInfo;
|
||||||
|
typedef struct SunAuthUnix SunAuthUnix;
|
||||||
|
typedef struct SunRpc SunRpc;
|
||||||
|
typedef struct SunCall SunCall;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
/* Authinfo.flavor */
|
||||||
|
SunAuthNone = 0,
|
||||||
|
SunAuthSys,
|
||||||
|
SunAuthShort,
|
||||||
|
SunAuthDes,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SunAcceptError = 0x10000,
|
||||||
|
SunRejectError = 0x20000,
|
||||||
|
SunAuthError = 0x40000,
|
||||||
|
|
||||||
|
/* Reply.status */
|
||||||
|
SunSuccess = 0,
|
||||||
|
|
||||||
|
SunProgUnavail = SunAcceptError | 1,
|
||||||
|
SunProgMismatch,
|
||||||
|
SunProcUnavail,
|
||||||
|
SunGarbageArgs,
|
||||||
|
SunSystemErr,
|
||||||
|
|
||||||
|
SunRpcMismatch = SunRejectError | 0,
|
||||||
|
|
||||||
|
SunAuthBadCred = SunAuthError | 1,
|
||||||
|
SunAuthRejectedCred,
|
||||||
|
SunAuthBadVerf,
|
||||||
|
SunAuthRejectedVerf,
|
||||||
|
SunAuthTooWeak,
|
||||||
|
SunAuthInvalidResp,
|
||||||
|
SunAuthFailed,
|
||||||
|
} SunStatus;
|
||||||
|
|
||||||
|
struct SunAuthInfo
|
||||||
|
{
|
||||||
|
uint flavor;
|
||||||
|
uchar *data;
|
||||||
|
uint ndata;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SunAuthUnix
|
||||||
|
{
|
||||||
|
u32int stamp;
|
||||||
|
char *sysname;
|
||||||
|
u32int uid;
|
||||||
|
u32int gid;
|
||||||
|
u32int g[16];
|
||||||
|
u32int ng;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SunRpc
|
||||||
|
{
|
||||||
|
u32int xid;
|
||||||
|
uint iscall;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* only sent on wire in call
|
||||||
|
* caller fills in for the reply unpackers.
|
||||||
|
*/
|
||||||
|
u32int proc;
|
||||||
|
|
||||||
|
/* call */
|
||||||
|
// uint proc;
|
||||||
|
u32int prog, vers;
|
||||||
|
SunAuthInfo cred;
|
||||||
|
SunAuthInfo verf;
|
||||||
|
uchar *data;
|
||||||
|
uint ndata;
|
||||||
|
|
||||||
|
/* reply */
|
||||||
|
u32int status;
|
||||||
|
// SunAuthInfo verf;
|
||||||
|
u32int low, high;
|
||||||
|
// uchar *data;
|
||||||
|
// uint ndata;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
SunCallTypeTNull,
|
||||||
|
SunCallTypeRNull,
|
||||||
|
} SunCallType;
|
||||||
|
|
||||||
|
struct SunCall
|
||||||
|
{
|
||||||
|
SunRpc rpc;
|
||||||
|
SunCallType type;
|
||||||
|
};
|
||||||
|
|
||||||
|
void sunerrstr(SunStatus);
|
||||||
|
|
||||||
|
void sunrpcprint(Fmt*, SunRpc*);
|
||||||
|
uint sunrpcsize(SunRpc*);
|
||||||
|
SunStatus sunrpcpack(uchar*, uchar*, uchar**, SunRpc*);
|
||||||
|
SunStatus sunrpcunpack(uchar*, uchar*, uchar**, SunRpc*);
|
||||||
|
|
||||||
|
void sunauthinfoprint(Fmt*, SunAuthInfo*);
|
||||||
|
uint sunauthinfosize(SunAuthInfo*);
|
||||||
|
int sunauthinfopack(uchar*, uchar*, uchar**, SunAuthInfo*);
|
||||||
|
int sunauthinfounpack(uchar*, uchar*, uchar**, SunAuthInfo*);
|
||||||
|
|
||||||
|
void sunauthunixprint(Fmt*, SunAuthUnix*);
|
||||||
|
uint sunauthunixsize(SunAuthUnix*);
|
||||||
|
int sunauthunixpack(uchar*, uchar*, uchar**, SunAuthUnix*);
|
||||||
|
int sunauthunixunpack(uchar*, uchar*, uchar**, SunAuthUnix*);
|
||||||
|
|
||||||
|
int sunenumpack(uchar*, uchar*, uchar**, int*);
|
||||||
|
int sunenumunpack(uchar*, uchar*, uchar**, int*);
|
||||||
|
int sunuint1pack(uchar*, uchar*, uchar**, u1int*);
|
||||||
|
int sunuint1unpack(uchar*, uchar*, uchar**, u1int*);
|
||||||
|
|
||||||
|
int sunstringpack(uchar*, uchar*, uchar**, char**, u32int);
|
||||||
|
int sunstringunpack(uchar*, uchar*, uchar**, char**, u32int);
|
||||||
|
uint sunstringsize(char*);
|
||||||
|
|
||||||
|
int sunuint32pack(uchar*, uchar*, uchar**, u32int*);
|
||||||
|
int sunuint32unpack(uchar*, uchar*, uchar**, u32int*);
|
||||||
|
int sunuint64pack(uchar*, uchar*, uchar**, u64int*);
|
||||||
|
int sunuint64unpack(uchar*, uchar*, uchar**, u64int*);
|
||||||
|
|
||||||
|
int sunvaropaquepack(uchar*, uchar*, uchar**, uchar**, u32int*, u32int);
|
||||||
|
int sunvaropaqueunpack(uchar*, uchar*, uchar**, uchar**, u32int*, u32int);
|
||||||
|
uint sunvaropaquesize(u32int);
|
||||||
|
|
||||||
|
int sunfixedopaquepack(uchar*, uchar*, uchar**, uchar*, u32int);
|
||||||
|
int sunfixedopaqueunpack(uchar*, uchar*, uchar**, uchar*, u32int);
|
||||||
|
uint sunfixedopaquesize(u32int);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sun RPC Program
|
||||||
|
*/
|
||||||
|
typedef struct SunProc SunProc;
|
||||||
|
typedef struct SunProg SunProg;
|
||||||
|
struct SunProg
|
||||||
|
{
|
||||||
|
uint prog;
|
||||||
|
uint vers;
|
||||||
|
SunProc *proc;
|
||||||
|
int nproc;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SunProc
|
||||||
|
{
|
||||||
|
int (*pack)(uchar*, uchar*, uchar**, SunCall*);
|
||||||
|
int (*unpack)(uchar*, uchar*, uchar**, SunCall*);
|
||||||
|
uint (*size)(SunCall*);
|
||||||
|
void (*fmt)(Fmt*, SunCall*);
|
||||||
|
uint sizeoftype;
|
||||||
|
};
|
||||||
|
|
||||||
|
SunStatus suncallpack(SunProg*, uchar*, uchar*, uchar**, SunCall*);
|
||||||
|
SunStatus suncallunpack(SunProg*, uchar*, uchar*, uchar**, SunCall*);
|
||||||
|
SunStatus suncallunpackalloc(SunProg*, SunCallType, uchar*, uchar*, uchar**, SunCall**);
|
||||||
|
void suncallsetup(SunCall*, SunProg*, uint);
|
||||||
|
uint suncallsize(SunProg*, SunCall*);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Formatting
|
||||||
|
#pragma varargck type "B" SunRpc*
|
||||||
|
#pragma varargck type "C" SunCall*
|
||||||
|
*/
|
||||||
|
|
||||||
|
int sunrpcfmt(Fmt*);
|
||||||
|
int suncallfmt(Fmt*);
|
||||||
|
void sunfmtinstall(SunProg*);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sun RPC Server
|
||||||
|
*/
|
||||||
|
typedef struct SunMsg SunMsg;
|
||||||
|
typedef struct SunSrv SunSrv;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
SunStackSize = 32768,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SunMsg
|
||||||
|
{
|
||||||
|
uchar *data;
|
||||||
|
int count;
|
||||||
|
SunSrv *srv;
|
||||||
|
SunRpc rpc;
|
||||||
|
SunProg *pg;
|
||||||
|
SunCall *call;
|
||||||
|
Channel *creply; /* chan(SunMsg*) */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SunSrv
|
||||||
|
{
|
||||||
|
int chatty;
|
||||||
|
int cachereplies;
|
||||||
|
int alwaysreject;
|
||||||
|
int localonly;
|
||||||
|
int localparanoia;
|
||||||
|
SunProg **map;
|
||||||
|
Channel *crequest;
|
||||||
|
|
||||||
|
/* implementation use only */
|
||||||
|
Channel **cdispatch;
|
||||||
|
SunProg **prog;
|
||||||
|
int nprog;
|
||||||
|
void *cache;
|
||||||
|
Channel *creply;
|
||||||
|
Channel *cthread;
|
||||||
|
};
|
||||||
|
|
||||||
|
SunSrv *sunsrv(void);
|
||||||
|
|
||||||
|
void sunsrvprog(SunSrv *srv, SunProg *prog, Channel *c);
|
||||||
|
int sunsrvannounce(SunSrv *srv, char *address);
|
||||||
|
int sunsrvudp(SunSrv *srv, char *address);
|
||||||
|
int sunsrvnet(SunSrv *srv, char *address);
|
||||||
|
int sunsrvfd(SunSrv *srv, int fd);
|
||||||
|
void sunsrvthreadcreate(SunSrv *srv, void (*fn)(void*), void*);
|
||||||
|
void sunsrvclose(SunSrv*);
|
||||||
|
|
||||||
|
int sunmsgreply(SunMsg*, SunCall*);
|
||||||
|
int sunmsgdrop(SunMsg*);
|
||||||
|
int sunmsgreplyerror(SunMsg*, SunStatus);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sun RPC Client
|
||||||
|
*/
|
||||||
|
typedef struct SunClient SunClient;
|
||||||
|
|
||||||
|
struct SunClient
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
int chatty;
|
||||||
|
int needcount;
|
||||||
|
ulong maxwait;
|
||||||
|
ulong xidgen;
|
||||||
|
int nsend;
|
||||||
|
int nresend;
|
||||||
|
struct {
|
||||||
|
ulong min;
|
||||||
|
ulong max;
|
||||||
|
ulong avg;
|
||||||
|
} rtt;
|
||||||
|
Channel *dying;
|
||||||
|
Channel *rpcchan;
|
||||||
|
Channel *timerchan;
|
||||||
|
Channel *flushchan;
|
||||||
|
Channel *readchan;
|
||||||
|
SunProg **prog;
|
||||||
|
int nprog;
|
||||||
|
int timertid;
|
||||||
|
int nettid;
|
||||||
|
};
|
||||||
|
|
||||||
|
SunClient *sundial(char*);
|
||||||
|
|
||||||
|
int sunclientrpc(SunClient*, ulong, SunCall*, SunCall*, uchar**);
|
||||||
|
void sunclientclose(SunClient*);
|
||||||
|
void sunclientflushrpc(SunClient*, ulong);
|
||||||
|
void sunclientprog(SunClient*, SunProg*);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Provided by callers.
|
||||||
|
* Should remove dependence on this, but hard.
|
||||||
|
*/
|
||||||
|
void *emalloc(ulong);
|
||||||
|
void *erealloc(void*, ulong);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sun RPC port mapper; see RFC 1057 Appendix A
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct PortMap PortMap;
|
||||||
|
typedef struct PortTNull PortTNull;
|
||||||
|
typedef struct PortRNull PortRNull;
|
||||||
|
typedef struct PortTSet PortTSet;
|
||||||
|
typedef struct PortRSet PortRSet;
|
||||||
|
typedef struct PortTUnset PortTUnset;
|
||||||
|
typedef struct PortRUnset PortRUnset;
|
||||||
|
typedef struct PortTGetport PortTGetport;
|
||||||
|
typedef struct PortRGetport PortRGetport;
|
||||||
|
typedef struct PortTDump PortTDump;
|
||||||
|
typedef struct PortRDump PortRDump;
|
||||||
|
typedef struct PortTCallit PortTCallit;
|
||||||
|
typedef struct PortRCallit PortRCallit;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
PortCallTNull,
|
||||||
|
PortCallRNull,
|
||||||
|
PortCallTSet,
|
||||||
|
PortCallRSet,
|
||||||
|
PortCallTUnset,
|
||||||
|
PortCallRUnset,
|
||||||
|
PortCallTGetport,
|
||||||
|
PortCallRGetport,
|
||||||
|
PortCallTDump,
|
||||||
|
PortCallRDump,
|
||||||
|
PortCallTCallit,
|
||||||
|
PortCallRCallit,
|
||||||
|
} PortCallType;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
PortProgram = 100000,
|
||||||
|
PortVersion = 2,
|
||||||
|
|
||||||
|
PortProtoTcp = 6, /* protocol number for TCP/IP */
|
||||||
|
PortProtoUdp = 17 /* protocol number for UDP/IP */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PortMap {
|
||||||
|
u32int prog;
|
||||||
|
u32int vers;
|
||||||
|
u32int prot;
|
||||||
|
u32int port;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PortTNull {
|
||||||
|
SunCall call;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PortRNull {
|
||||||
|
SunCall call;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PortTSet {
|
||||||
|
SunCall call;
|
||||||
|
PortMap map;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PortRSet {
|
||||||
|
SunCall call;
|
||||||
|
u1int b;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PortTUnset {
|
||||||
|
SunCall call;
|
||||||
|
PortMap map;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PortRUnset {
|
||||||
|
SunCall call;
|
||||||
|
u1int b;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PortTGetport {
|
||||||
|
SunCall call;
|
||||||
|
PortMap map;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PortRGetport {
|
||||||
|
SunCall call;
|
||||||
|
u32int port;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PortTDump {
|
||||||
|
SunCall call;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PortRDump {
|
||||||
|
SunCall call;
|
||||||
|
PortMap *map;
|
||||||
|
int nmap;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PortTCallit {
|
||||||
|
SunCall call;
|
||||||
|
u32int prog;
|
||||||
|
u32int vers;
|
||||||
|
u32int proc;
|
||||||
|
uchar *data;
|
||||||
|
u32int count;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PortRCallit {
|
||||||
|
SunCall call;
|
||||||
|
u32int port;
|
||||||
|
uchar *data;
|
||||||
|
u32int count;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern SunProg portprog;
|
||||||
@ -27,8 +27,6 @@ char wdir[512] = ".";
|
|||||||
Reffont *reffonts[2];
|
Reffont *reffonts[2];
|
||||||
int snarffd = -1;
|
int snarffd = -1;
|
||||||
int mainpid;
|
int mainpid;
|
||||||
int plumbsendfd;
|
|
||||||
int plumbeditfd;
|
|
||||||
|
|
||||||
enum{
|
enum{
|
||||||
NSnarf = 1000 /* less than 1024, I/O buffer size */
|
NSnarf = 1000 /* less than 1024, I/O buffer size */
|
||||||
@ -180,6 +178,8 @@ threadmain(int argc, char *argv[])
|
|||||||
exits("keyboard");
|
exits("keyboard");
|
||||||
}
|
}
|
||||||
mainpid = getpid();
|
mainpid = getpid();
|
||||||
|
startplumbing();
|
||||||
|
/*
|
||||||
plumbeditfd = plumbopen("edit", OREAD|OCEXEC);
|
plumbeditfd = plumbopen("edit", OREAD|OCEXEC);
|
||||||
if(plumbeditfd < 0)
|
if(plumbeditfd < 0)
|
||||||
fprint(2, "acme: can't initialize plumber: %r\n");
|
fprint(2, "acme: can't initialize plumber: %r\n");
|
||||||
@ -188,6 +188,7 @@ threadmain(int argc, char *argv[])
|
|||||||
threadcreate(plumbproc, nil, STACK);
|
threadcreate(plumbproc, nil, STACK);
|
||||||
}
|
}
|
||||||
plumbsendfd = plumbopen("send", OWRITE|OCEXEC);
|
plumbsendfd = plumbopen("send", OWRITE|OCEXEC);
|
||||||
|
*/
|
||||||
|
|
||||||
fsysinit();
|
fsysinit();
|
||||||
|
|
||||||
@ -355,6 +356,7 @@ acmeerrorinit(void)
|
|||||||
threadcreate(acmeerrorproc, nil, STACK);
|
threadcreate(acmeerrorproc, nil, STACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
void
|
void
|
||||||
plumbproc(void *v)
|
plumbproc(void *v)
|
||||||
{
|
{
|
||||||
@ -369,6 +371,7 @@ plumbproc(void *v)
|
|||||||
sendp(cplumb, m);
|
sendp(cplumb, m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
keyboardthread(void *v)
|
keyboardthread(void *v)
|
||||||
@ -674,7 +677,7 @@ waitthread(void *v)
|
|||||||
textsetselect(t, 0, 0);
|
textsetselect(t, 0, 0);
|
||||||
}
|
}
|
||||||
if(w->msg[0])
|
if(w->msg[0])
|
||||||
warning(c->md, "%s: %s\n", c->name, w->msg);
|
warning(c->md, "%S: %s\n", c->name, w->msg);
|
||||||
flushimage(display, 1);
|
flushimage(display, 1);
|
||||||
}
|
}
|
||||||
qunlock(&row.lk);
|
qunlock(&row.lk);
|
||||||
|
|||||||
@ -524,8 +524,6 @@ char *home;
|
|||||||
char *fontnames[2];
|
char *fontnames[2];
|
||||||
Image *tagcols[NCOL];
|
Image *tagcols[NCOL];
|
||||||
Image *textcols[NCOL];
|
Image *textcols[NCOL];
|
||||||
int plumbsendfd;
|
|
||||||
int plumbeditfd;
|
|
||||||
extern char wdir[]; /* must use extern because no dimension given */
|
extern char wdir[]; /* must use extern because no dimension given */
|
||||||
int editing;
|
int editing;
|
||||||
int erroutfd;
|
int erroutfd;
|
||||||
|
|||||||
@ -170,7 +170,7 @@ eloginsert(File *f, int q0, Rune *r, int nr)
|
|||||||
elogflush(f);
|
elogflush(f);
|
||||||
}
|
}
|
||||||
/* try to merge with previous */
|
/* try to merge with previous */
|
||||||
if(f->elog.type==Insert && q0==f->elog.q0 && (q0+nr)-f->elog.q0<Maxstring){
|
if(f->elog.type==Insert && q0==f->elog.q0 && f->elog.nr+nr<Maxstring){
|
||||||
runemove(f->elog.r+f->elog.nr, r, nr);
|
runemove(f->elog.r+f->elog.nr, r, nr);
|
||||||
f->elog.nr += nr;
|
f->elog.nr += nr;
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -1472,6 +1472,7 @@ Hard:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
threadexecl(cpid, sfd, "rc", "rc", "-c", t, nil);
|
threadexecl(cpid, sfd, "rc", "rc", "-c", t, nil);
|
||||||
|
warning(nil, "exec rc: %r\n");
|
||||||
|
|
||||||
Fail:
|
Fail:
|
||||||
/* threadexec hasn't happened, so send a zero */
|
/* threadexec hasn't happened, so send a zero */
|
||||||
|
|||||||
@ -87,6 +87,7 @@ Rune* skipbl(Rune*, int, int*);
|
|||||||
Rune* findbl(Rune*, int, int*);
|
Rune* findbl(Rune*, int, int*);
|
||||||
char* edittext(Window*, int, Rune*, int);
|
char* edittext(Window*, int, Rune*, int);
|
||||||
void flushwarnings(int);
|
void flushwarnings(int);
|
||||||
|
void startplumbing(void);
|
||||||
|
|
||||||
#define runemalloc(a) (Rune*)emalloc((a)*sizeof(Rune))
|
#define runemalloc(a) (Rune*)emalloc((a)*sizeof(Rune))
|
||||||
#define runerealloc(a, b) (Rune*)erealloc((a), (b)*sizeof(Rune))
|
#define runerealloc(a, b) (Rune*)erealloc((a), (b)*sizeof(Rune))
|
||||||
|
|||||||
@ -8,14 +8,49 @@
|
|||||||
#include <frame.h>
|
#include <frame.h>
|
||||||
#include <fcall.h>
|
#include <fcall.h>
|
||||||
#include <regexp.h>
|
#include <regexp.h>
|
||||||
|
#define Fid FsFid
|
||||||
|
#include <fs.h>
|
||||||
#include <plumb.h>
|
#include <plumb.h>
|
||||||
|
#undef Fid
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
|
FsFid *plumbsendfid;
|
||||||
|
FsFid *plumbeditfid;
|
||||||
|
|
||||||
Window* openfile(Text*, Expand*);
|
Window* openfile(Text*, Expand*);
|
||||||
|
|
||||||
int nuntitled;
|
int nuntitled;
|
||||||
|
|
||||||
|
void
|
||||||
|
plumbproc(void *v)
|
||||||
|
{
|
||||||
|
Plumbmsg *m;
|
||||||
|
|
||||||
|
USED(v);
|
||||||
|
threadsetname("plumbproc");
|
||||||
|
for(;;){
|
||||||
|
m = plumbrecvfid(plumbeditfid);
|
||||||
|
if(m == nil)
|
||||||
|
threadexits(nil);
|
||||||
|
sendp(cplumb, m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
startplumbing(void)
|
||||||
|
{
|
||||||
|
plumbeditfid = plumbopenfid("edit", OREAD|OCEXEC);
|
||||||
|
if(plumbeditfid == nil)
|
||||||
|
fprint(2, "acme: can't initialize plumber: %r\n");
|
||||||
|
else{
|
||||||
|
cplumb = chancreate(sizeof(Plumbmsg*), 0);
|
||||||
|
threadcreate(plumbproc, nil, STACK);
|
||||||
|
}
|
||||||
|
plumbsendfid = plumbopenfid("send", OWRITE|OCEXEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
look3(Text *t, uint q0, uint q1, int external)
|
look3(Text *t, uint q0, uint q1, int external)
|
||||||
{
|
{
|
||||||
@ -79,7 +114,7 @@ look3(Text *t, uint q0, uint q1, int external)
|
|||||||
free(r);
|
free(r);
|
||||||
goto Return;
|
goto Return;
|
||||||
}
|
}
|
||||||
if(plumbsendfd >= 0){
|
if(plumbsendfid != nil){
|
||||||
/* send whitespace-delimited word to plumber */
|
/* send whitespace-delimited word to plumber */
|
||||||
m = emalloc(sizeof(Plumbmsg));
|
m = emalloc(sizeof(Plumbmsg));
|
||||||
m->src = estrdup("acme");
|
m->src = estrdup("acme");
|
||||||
@ -121,7 +156,7 @@ look3(Text *t, uint q0, uint q1, int external)
|
|||||||
m->data = runetobyte(r, q1-q0);
|
m->data = runetobyte(r, q1-q0);
|
||||||
m->ndata = strlen(m->data);
|
m->ndata = strlen(m->data);
|
||||||
free(r);
|
free(r);
|
||||||
if(m->ndata<messagesize-1024 && plumbsend(plumbsendfd, m) >= 0){
|
if(m->ndata<messagesize-1024 && plumbsendtofid(plumbsendfid, m) >= 0){
|
||||||
plumbfree(m);
|
plumbfree(m);
|
||||||
goto Return;
|
goto Return;
|
||||||
}
|
}
|
||||||
|
|||||||
1
src/cmd/factotum/BUGS
Normal file
1
src/cmd/factotum/BUGS
Normal file
@ -0,0 +1 @@
|
|||||||
|
key, delkey, wipe should be in ctl not rpc.
|
||||||
348
src/cmd/factotum/apop.c
Normal file
348
src/cmd/factotum/apop.c
Normal file
@ -0,0 +1,348 @@
|
|||||||
|
/*
|
||||||
|
* APOP, CRAM - MD5 challenge/response authentication
|
||||||
|
*
|
||||||
|
* The client does not authenticate the server, hence no CAI.
|
||||||
|
*
|
||||||
|
* Protocol:
|
||||||
|
*
|
||||||
|
* S -> C: random@domain
|
||||||
|
* C -> S: hex-response
|
||||||
|
* S -> C: ok
|
||||||
|
*
|
||||||
|
* Note that this is the protocol between factotum and the local
|
||||||
|
* program, not between the two factotums. The information
|
||||||
|
* exchanged here is wrapped in the APOP protocol by the local
|
||||||
|
* programs.
|
||||||
|
*
|
||||||
|
* If S sends "bad [msg]" instead of "ok", that is a hint that the key is bad.
|
||||||
|
* The protocol goes back to "C -> S: user".
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "std.h"
|
||||||
|
#include "dat.h"
|
||||||
|
|
||||||
|
static int
|
||||||
|
apopcheck(Key *k)
|
||||||
|
{
|
||||||
|
if(!strfindattr(k->attr, "user") || !strfindattr(k->privattr, "!password")){
|
||||||
|
werrstr("need user and !password attributes");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
apopclient(Conv *c)
|
||||||
|
{
|
||||||
|
char *chal, *pw, *res;
|
||||||
|
int astype, nchal, npw, ntry, ret;
|
||||||
|
uchar resp[MD5dlen];
|
||||||
|
Attr *attr;
|
||||||
|
DigestState *ds;
|
||||||
|
Key *k;
|
||||||
|
|
||||||
|
chal = nil;
|
||||||
|
k = nil;
|
||||||
|
res = nil;
|
||||||
|
ret = -1;
|
||||||
|
attr = c->attr;
|
||||||
|
|
||||||
|
if(c->proto == &apop)
|
||||||
|
astype = AuthApop;
|
||||||
|
else if(c->proto == &cram)
|
||||||
|
astype = AuthCram;
|
||||||
|
else{
|
||||||
|
werrstr("bad proto");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->state = "find key";
|
||||||
|
k = keyfetch(c, "%A %s", attr, c->proto->keyprompt);
|
||||||
|
if(k == nil)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
c->state = "read challenge";
|
||||||
|
if((nchal = convreadm(c, &chal)) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
for(ntry=1;; ntry++){
|
||||||
|
if(c->attr != attr)
|
||||||
|
freeattr(c->attr);
|
||||||
|
c->attr = addattrs(copyattr(attr), k->attr);
|
||||||
|
if((pw = strfindattr(k->privattr, "!password")) == nil){
|
||||||
|
werrstr("key has no password (cannot happen?)");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
npw = strlen(pw);
|
||||||
|
|
||||||
|
switch(astype){
|
||||||
|
case AuthApop:
|
||||||
|
ds = md5((uchar*)chal, nchal, nil, nil);
|
||||||
|
md5((uchar*)pw, npw, resp, ds);
|
||||||
|
break;
|
||||||
|
case AuthCram:
|
||||||
|
hmac_md5((uchar*)chal, nchal, (uchar*)pw, npw, resp, nil);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C->S: APOP user hex-response\n */
|
||||||
|
if(ntry == 1)
|
||||||
|
c->state = "write user";
|
||||||
|
else{
|
||||||
|
sprint(c->statebuf, "write user (auth attempt #%d)", ntry);
|
||||||
|
c->state = c->statebuf;
|
||||||
|
}
|
||||||
|
if(convprint(c, "%s", strfindattr(k->attr, "user")) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
c->state = "write response";
|
||||||
|
if(convprint(c, "%.*H", sizeof resp, resp) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
c->state = "read result";
|
||||||
|
if(convreadm(c, &res) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if(strcmp(res, "ok") == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(strncmp(res, "bad ", 4) != 0){
|
||||||
|
werrstr("bad result: %s", res);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->state = "replace key";
|
||||||
|
if((k = keyreplace(c, k, "%s", res+4)) == nil){
|
||||||
|
c->state = "auth failed";
|
||||||
|
werrstr("%s", res+4);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
free(res);
|
||||||
|
res = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
werrstr("succeeded");
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
keyclose(k);
|
||||||
|
free(chal);
|
||||||
|
if(c->attr != attr)
|
||||||
|
freeattr(attr);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* shared with auth dialing routines */
|
||||||
|
typedef struct ServerState ServerState;
|
||||||
|
struct ServerState
|
||||||
|
{
|
||||||
|
int asfd;
|
||||||
|
Key *k;
|
||||||
|
Ticketreq tr;
|
||||||
|
Ticket t;
|
||||||
|
char *dom;
|
||||||
|
char *hostid;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
APOPCHALLEN = 128,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int apopchal(ServerState*, int, char[APOPCHALLEN]);
|
||||||
|
static int apopresp(ServerState*, char*, char*);
|
||||||
|
|
||||||
|
static int
|
||||||
|
apopserver(Conv *c)
|
||||||
|
{
|
||||||
|
char chal[APOPCHALLEN], *user, *resp;
|
||||||
|
ServerState s;
|
||||||
|
int astype, ret;
|
||||||
|
Attr *a;
|
||||||
|
|
||||||
|
ret = -1;
|
||||||
|
user = nil;
|
||||||
|
resp = nil;
|
||||||
|
memset(&s, 0, sizeof s);
|
||||||
|
s.asfd = -1;
|
||||||
|
|
||||||
|
if(c->proto == &apop)
|
||||||
|
astype = AuthApop;
|
||||||
|
else if(c->proto == &cram)
|
||||||
|
astype = AuthCram;
|
||||||
|
else{
|
||||||
|
werrstr("bad proto");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->state = "find key";
|
||||||
|
if((s.k = plan9authkey(c->attr)) == nil)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
a = copyattr(s.k->attr);
|
||||||
|
a = delattr(a, "proto");
|
||||||
|
c->attr = addattrs(c->attr, a);
|
||||||
|
freeattr(a);
|
||||||
|
|
||||||
|
c->state = "authdial";
|
||||||
|
s.hostid = strfindattr(s.k->attr, "user");
|
||||||
|
s.dom = strfindattr(s.k->attr, "dom");
|
||||||
|
if((s.asfd = xioauthdial(nil, s.dom)) < 0){
|
||||||
|
werrstr("authdial %s: %r", s.dom);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->state = "authchal";
|
||||||
|
if(apopchal(&s, astype, chal) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
c->state = "write challenge";
|
||||||
|
if(convprint(c, "%s", chal) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
for(;;){
|
||||||
|
c->state = "read user";
|
||||||
|
if(convreadm(c, &user) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
c->state = "read response";
|
||||||
|
if(convreadm(c, &resp) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
c->state = "authwrite";
|
||||||
|
switch(apopresp(&s, user, resp)){
|
||||||
|
case -1:
|
||||||
|
goto out;
|
||||||
|
case 0:
|
||||||
|
c->state = "write status";
|
||||||
|
if(convprint(c, "bad authentication failed") < 0)
|
||||||
|
goto out;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
c->state = "write status";
|
||||||
|
if(convprint(c, "ok") < 0)
|
||||||
|
goto out;
|
||||||
|
goto ok;
|
||||||
|
}
|
||||||
|
free(user);
|
||||||
|
free(resp);
|
||||||
|
user = nil;
|
||||||
|
resp = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok:
|
||||||
|
ret = 0;
|
||||||
|
c->attr = addcap(c->attr, c->sysuser, &s.t);
|
||||||
|
|
||||||
|
out:
|
||||||
|
keyclose(s.k);
|
||||||
|
free(user);
|
||||||
|
free(resp);
|
||||||
|
// xioclose(s.asfd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
apopchal(ServerState *s, int astype, char chal[APOPCHALLEN])
|
||||||
|
{
|
||||||
|
char trbuf[TICKREQLEN];
|
||||||
|
Ticketreq tr;
|
||||||
|
|
||||||
|
memset(&tr, 0, sizeof tr);
|
||||||
|
|
||||||
|
tr.type = astype;
|
||||||
|
|
||||||
|
if(strlen(s->hostid) >= sizeof tr.hostid){
|
||||||
|
werrstr("hostid too long");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
strcpy(tr.hostid, s->hostid);
|
||||||
|
|
||||||
|
if(strlen(s->dom) >= sizeof tr.authdom){
|
||||||
|
werrstr("domain too long");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
strcpy(tr.authdom, s->dom);
|
||||||
|
|
||||||
|
convTR2M(&tr, trbuf);
|
||||||
|
if(xiowrite(s->asfd, trbuf, TICKREQLEN) != TICKREQLEN)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if(xioasrdresp(s->asfd, chal, APOPCHALLEN) <= 5)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
s->tr = tr;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
apopresp(ServerState *s, char *user, char *resp)
|
||||||
|
{
|
||||||
|
char tabuf[TICKETLEN+AUTHENTLEN];
|
||||||
|
char trbuf[TICKREQLEN];
|
||||||
|
int len;
|
||||||
|
Authenticator a;
|
||||||
|
Ticket t;
|
||||||
|
Ticketreq tr;
|
||||||
|
|
||||||
|
tr = s->tr;
|
||||||
|
if(memrandom(tr.chal, CHALLEN) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if(strlen(user) >= sizeof tr.uid){
|
||||||
|
werrstr("uid too long");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
strcpy(tr.uid, user);
|
||||||
|
|
||||||
|
convTR2M(&tr, trbuf);
|
||||||
|
if(xiowrite(s->asfd, trbuf, TICKREQLEN) != TICKREQLEN)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
len = strlen(resp);
|
||||||
|
if(xiowrite(s->asfd, resp, len) != len)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if(xioasrdresp(s->asfd, tabuf, TICKETLEN+AUTHENTLEN) != TICKETLEN+AUTHENTLEN)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
convM2T(tabuf, &t, s->k->priv);
|
||||||
|
if(t.num != AuthTs
|
||||||
|
|| memcmp(t.chal, tr.chal, sizeof tr.chal) != 0){
|
||||||
|
werrstr("key mismatch with auth server");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
convM2A(tabuf+TICKETLEN, &a, t.key);
|
||||||
|
if(a.num != AuthAc
|
||||||
|
|| memcmp(a.chal, tr.chal, sizeof a.chal) != 0
|
||||||
|
|| a.id != 0){
|
||||||
|
werrstr("key2 mismatch with auth server");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->t = t;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Role
|
||||||
|
apoproles[] =
|
||||||
|
{
|
||||||
|
"client", apopclient,
|
||||||
|
"server", apopserver,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
Proto apop = {
|
||||||
|
.name= "apop",
|
||||||
|
.roles= apoproles,
|
||||||
|
.checkkey= apopcheck,
|
||||||
|
.keyprompt= "user? !password?",
|
||||||
|
};
|
||||||
|
|
||||||
|
Proto cram = {
|
||||||
|
.name= "cram",
|
||||||
|
.roles= apoproles,
|
||||||
|
.checkkey= apopcheck,
|
||||||
|
.keyprompt= "user? !password?",
|
||||||
|
};
|
||||||
228
src/cmd/factotum/attr.c
Normal file
228
src/cmd/factotum/attr.c
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
#include "std.h"
|
||||||
|
#include "dat.h"
|
||||||
|
|
||||||
|
Attr*
|
||||||
|
addattr(Attr *a, char *fmt, ...)
|
||||||
|
{
|
||||||
|
char buf[1024];
|
||||||
|
va_list arg;
|
||||||
|
Attr *b;
|
||||||
|
|
||||||
|
va_start(arg, fmt);
|
||||||
|
vseprint(buf, buf+sizeof buf, fmt, arg);
|
||||||
|
va_end(arg);
|
||||||
|
b = _parseattr(buf);
|
||||||
|
a = addattrs(a, b);
|
||||||
|
setmalloctag(a, getcallerpc(&a));
|
||||||
|
_freeattr(b);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* add attributes in list b to list a. If any attributes are in
|
||||||
|
* both lists, replace those in a by those in b.
|
||||||
|
*/
|
||||||
|
Attr*
|
||||||
|
addattrs(Attr *a, Attr *b)
|
||||||
|
{
|
||||||
|
int found;
|
||||||
|
Attr **l, *aa;
|
||||||
|
|
||||||
|
for(; b; b=b->next){
|
||||||
|
switch(b->type){
|
||||||
|
case AttrNameval:
|
||||||
|
for(l=&a; *l; ){
|
||||||
|
if(strcmp((*l)->name, b->name) != 0){
|
||||||
|
l=&(*l)->next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
aa = *l;
|
||||||
|
*l = aa->next;
|
||||||
|
aa->next = nil;
|
||||||
|
freeattr(aa);
|
||||||
|
}
|
||||||
|
*l = mkattr(AttrNameval, b->name, b->val, nil);
|
||||||
|
break;
|
||||||
|
case AttrQuery:
|
||||||
|
found = 0;
|
||||||
|
for(l=&a; *l; l=&(*l)->next)
|
||||||
|
if((*l)->type==AttrNameval && strcmp((*l)->name, b->name) == 0)
|
||||||
|
found++;
|
||||||
|
if(!found)
|
||||||
|
*l = mkattr(AttrQuery, b->name, b->val, nil);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
setmalloctaghere(void *v)
|
||||||
|
{
|
||||||
|
setmalloctag(v, getcallerpc(&v));
|
||||||
|
}
|
||||||
|
|
||||||
|
Attr*
|
||||||
|
sortattr(Attr *a)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
Attr *anext, *a0, *a1, **l;
|
||||||
|
|
||||||
|
if(a == nil || a->next == nil)
|
||||||
|
return a;
|
||||||
|
|
||||||
|
/* cut list in halves */
|
||||||
|
a0 = nil;
|
||||||
|
a1 = nil;
|
||||||
|
i = 0;
|
||||||
|
for(; a; a=anext){
|
||||||
|
anext = a->next;
|
||||||
|
if(i++%2){
|
||||||
|
a->next = a0;
|
||||||
|
a0 = a;
|
||||||
|
}else{
|
||||||
|
a->next = a1;
|
||||||
|
a1 = a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sort */
|
||||||
|
a0 = sortattr(a0);
|
||||||
|
a1 = sortattr(a1);
|
||||||
|
|
||||||
|
/* merge */
|
||||||
|
l = &a;
|
||||||
|
while(a0 || a1){
|
||||||
|
if(a1==nil){
|
||||||
|
anext = a0;
|
||||||
|
a0 = a0->next;
|
||||||
|
}else if(a0==nil){
|
||||||
|
anext = a1;
|
||||||
|
a1 = a1->next;
|
||||||
|
}else if(strcmp(a0->name, a1->name) < 0){
|
||||||
|
anext = a0;
|
||||||
|
a0 = a0->next;
|
||||||
|
}else{
|
||||||
|
anext = a1;
|
||||||
|
a1 = a1->next;
|
||||||
|
}
|
||||||
|
*l = anext;
|
||||||
|
l = &(*l)->next;
|
||||||
|
}
|
||||||
|
*l = nil;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
attrnamefmt(Fmt *fmt)
|
||||||
|
{
|
||||||
|
char *b, buf[1024], *ebuf;
|
||||||
|
Attr *a;
|
||||||
|
|
||||||
|
ebuf = buf+sizeof buf;
|
||||||
|
b = buf;
|
||||||
|
strcpy(buf, " ");
|
||||||
|
for(a=va_arg(fmt->args, Attr*); a; a=a->next){
|
||||||
|
if(a->name == nil)
|
||||||
|
continue;
|
||||||
|
b = seprint(b, ebuf, " %q?", a->name);
|
||||||
|
}
|
||||||
|
return fmtstrcpy(fmt, buf+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hasqueries(Attr *a)
|
||||||
|
{
|
||||||
|
for(; a; a=a->next)
|
||||||
|
if(a->type == AttrQuery)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *ignored[] = {
|
||||||
|
"role",
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
ignoreattr(char *s)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i=0; i<nelem(ignored); i++)
|
||||||
|
if(strcmp(ignored[i], s)==0)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hasname(Attr *a0, Attr *a1, char *name)
|
||||||
|
{
|
||||||
|
return _findattr(a0, name) || _findattr(a1, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hasnameval(Attr *a0, Attr *a1, char *name, char *val)
|
||||||
|
{
|
||||||
|
Attr *a;
|
||||||
|
|
||||||
|
for(a=_findattr(a0, name); a; a=_findattr(a->next, name))
|
||||||
|
if(strcmp(a->val, val) == 0)
|
||||||
|
return 1;
|
||||||
|
for(a=_findattr(a1, name); a; a=_findattr(a->next, name))
|
||||||
|
if(strcmp(a->val, val) == 0)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
matchattr(Attr *pat, Attr *a0, Attr *a1)
|
||||||
|
{
|
||||||
|
int type;
|
||||||
|
|
||||||
|
for(; pat; pat=pat->next){
|
||||||
|
type = pat->type;
|
||||||
|
if(ignoreattr(pat->name))
|
||||||
|
type = AttrDefault;
|
||||||
|
switch(type){
|
||||||
|
case AttrQuery: /* name=something be present */
|
||||||
|
if(!hasname(a0, a1, pat->name))
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
case AttrNameval: /* name=val must be present */
|
||||||
|
if(!hasnameval(a0, a1, pat->name, pat->val))
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
case AttrDefault: /* name=val must be present if name=anything is present */
|
||||||
|
if(hasname(a0, a1, pat->name) && !hasnameval(a0, a1, pat->name, pat->val))
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Attr*
|
||||||
|
parseattrfmtv(char *fmt, va_list arg)
|
||||||
|
{
|
||||||
|
char *s;
|
||||||
|
Attr *a;
|
||||||
|
|
||||||
|
s = vsmprint(fmt, arg);
|
||||||
|
if(s == nil)
|
||||||
|
sysfatal("vsmprint: out of memory");
|
||||||
|
a = parseattr(s);
|
||||||
|
free(s);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
Attr*
|
||||||
|
parseattrfmt(char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list arg;
|
||||||
|
Attr *a;
|
||||||
|
|
||||||
|
va_start(arg, fmt);
|
||||||
|
a = parseattrfmtv(fmt, arg);
|
||||||
|
va_end(arg);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
424
src/cmd/factotum/chap.c
Normal file
424
src/cmd/factotum/chap.c
Normal file
@ -0,0 +1,424 @@
|
|||||||
|
/*
|
||||||
|
* CHAP, MSCHAP
|
||||||
|
*
|
||||||
|
* The client does not authenticate the server, hence no CAI
|
||||||
|
*
|
||||||
|
* Protocol:
|
||||||
|
*
|
||||||
|
* S -> C: random 8-byte challenge
|
||||||
|
* C -> S: user in UTF-8
|
||||||
|
* C -> S: Chapreply or MSchapreply structure
|
||||||
|
* S -> C: ok or 'bad why'
|
||||||
|
*
|
||||||
|
* The chap protocol requires the client to give it id=%d, the id of
|
||||||
|
* the PPP message containing the challenge, which is used
|
||||||
|
* as part of the response. Because the client protocol is message-id
|
||||||
|
* specific, there is no point in looping to try multiple keys.
|
||||||
|
*
|
||||||
|
* The MS chap protocol actually uses two different hashes, an
|
||||||
|
* older insecure one called the LM (Lan Manager) hash, and a newer
|
||||||
|
* more secure one called the NT hash. By default we send back only
|
||||||
|
* the NT hash, because the LM hash can help an eavesdropper run
|
||||||
|
* a brute force attack. If the key has an lm attribute, then we send only the
|
||||||
|
* LM hash.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "std.h"
|
||||||
|
#include "dat.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ChapChallen = 8,
|
||||||
|
|
||||||
|
MShashlen = 16,
|
||||||
|
MSchallen = 8,
|
||||||
|
MSresplen = 24,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
chapcheck(Key *k)
|
||||||
|
{
|
||||||
|
if(!strfindattr(k->attr, "user") || !strfindattr(k->privattr, "!password")){
|
||||||
|
werrstr("need user and !password attributes");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nthash(uchar hash[MShashlen], char *passwd)
|
||||||
|
{
|
||||||
|
uchar buf[512];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i=0; *passwd && i<sizeof(buf); passwd++) {
|
||||||
|
buf[i++] = *passwd;
|
||||||
|
buf[i++] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(hash, 0, 16);
|
||||||
|
|
||||||
|
md4(buf, i, hash, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
desencrypt(uchar data[8], uchar key[7])
|
||||||
|
{
|
||||||
|
ulong ekey[32];
|
||||||
|
|
||||||
|
key_setup(key, ekey);
|
||||||
|
block_cipher(ekey, data, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lmhash(uchar hash[MShashlen], char *passwd)
|
||||||
|
{
|
||||||
|
uchar buf[14];
|
||||||
|
char *stdtext = "KGS!@#$%";
|
||||||
|
int i;
|
||||||
|
|
||||||
|
strncpy((char*)buf, passwd, sizeof(buf));
|
||||||
|
for(i=0; i<sizeof(buf); i++)
|
||||||
|
if(buf[i] >= 'a' && buf[i] <= 'z')
|
||||||
|
buf[i] += 'A' - 'a';
|
||||||
|
|
||||||
|
memset(hash, 0, 16);
|
||||||
|
memcpy(hash, stdtext, 8);
|
||||||
|
memcpy(hash+8, stdtext, 8);
|
||||||
|
|
||||||
|
desencrypt(hash, buf);
|
||||||
|
desencrypt(hash+8, buf+7);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mschalresp(uchar resp[MSresplen], uchar hash[MShashlen], uchar chal[MSchallen])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uchar buf[21];
|
||||||
|
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
memcpy(buf, hash, MShashlen);
|
||||||
|
|
||||||
|
for(i=0; i<3; i++) {
|
||||||
|
memmove(resp+i*MSchallen, chal, MSchallen);
|
||||||
|
desencrypt(resp+i*MSchallen, buf+i*7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
chapclient(Conv *c)
|
||||||
|
{
|
||||||
|
int id, astype, nchal, npw, ret;
|
||||||
|
uchar *chal;
|
||||||
|
char *s, *pw, *user, *res;
|
||||||
|
Attr *attr;
|
||||||
|
Key *k;
|
||||||
|
Chapreply cr;
|
||||||
|
MSchapreply mscr;
|
||||||
|
DigestState *ds;
|
||||||
|
|
||||||
|
ret = -1;
|
||||||
|
chal = nil;
|
||||||
|
k = nil;
|
||||||
|
attr = c->attr;
|
||||||
|
|
||||||
|
if(c->proto == &chap){
|
||||||
|
astype = AuthChap;
|
||||||
|
s = strfindattr(attr, "id");
|
||||||
|
if(s == nil || *s == 0){
|
||||||
|
werrstr("need id=n attr in start message");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
id = strtol(s, &s, 10);
|
||||||
|
if(*s != 0 || id < 0 || id >= 256){
|
||||||
|
werrstr("bad id=n attr in start message");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
cr.id = id;
|
||||||
|
}else if(c->proto == &mschap)
|
||||||
|
astype = AuthMSchap;
|
||||||
|
else{
|
||||||
|
werrstr("bad proto");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->state = "find key";
|
||||||
|
k = keyfetch(c, "%A %s", attr, c->proto->keyprompt);
|
||||||
|
if(k == nil)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
c->attr = addattrs(copyattr(attr), k->attr);
|
||||||
|
|
||||||
|
c->state = "read challenge";
|
||||||
|
if((nchal = convreadm(c, (char**)&chal)) < 0)
|
||||||
|
goto out;
|
||||||
|
if(astype == AuthMSchap && nchal != MSchallen)
|
||||||
|
c->state = "write user";
|
||||||
|
if((user = strfindattr(k->attr, "user")) == nil){
|
||||||
|
werrstr("key has no user (cannot happen?)");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if(convprint(c, "%s", user) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
c->state = "write response";
|
||||||
|
if((pw = strfindattr(k->privattr, "!password")) == nil){
|
||||||
|
werrstr("key has no password (cannot happen?)");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
npw = strlen(pw);
|
||||||
|
|
||||||
|
if(astype == AuthChap){
|
||||||
|
ds = md5(&cr.id, 1, 0, 0);
|
||||||
|
md5((uchar*)pw, npw, 0, ds);
|
||||||
|
md5(chal, nchal, (uchar*)cr.resp, ds);
|
||||||
|
if(convwrite(c, &cr, sizeof cr) < 0)
|
||||||
|
goto out;
|
||||||
|
}else{
|
||||||
|
uchar hash[MShashlen];
|
||||||
|
|
||||||
|
memset(&mscr, 0, sizeof mscr);
|
||||||
|
if(strfindattr(k->attr, "lm")){
|
||||||
|
lmhash(hash, pw);
|
||||||
|
mschalresp((uchar*)mscr.LMresp, hash, chal);
|
||||||
|
}else{
|
||||||
|
nthash(hash, pw);
|
||||||
|
mschalresp((uchar*)mscr.NTresp, hash, chal);
|
||||||
|
}
|
||||||
|
if(convwrite(c, &mscr, sizeof mscr) < 0)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->state = "read result";
|
||||||
|
if(convreadm(c, &res) < 0)
|
||||||
|
goto out;
|
||||||
|
if(strcmp(res, "ok") == 0){
|
||||||
|
ret = 0;
|
||||||
|
werrstr("succeeded");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if(strncmp(res, "bad ", 4) != 0){
|
||||||
|
werrstr("bad result: %s", res);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->state = "replace key";
|
||||||
|
keyevict(c, k, "%s", res+4);
|
||||||
|
werrstr("%s", res+4);
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(res);
|
||||||
|
keyclose(k);
|
||||||
|
free(chal);
|
||||||
|
if(c->attr != attr)
|
||||||
|
freeattr(attr);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* shared with auth dialing routines */
|
||||||
|
typedef struct ServerState ServerState;
|
||||||
|
struct ServerState
|
||||||
|
{
|
||||||
|
int asfd;
|
||||||
|
Key *k;
|
||||||
|
Ticketreq tr;
|
||||||
|
Ticket t;
|
||||||
|
char *dom;
|
||||||
|
char *hostid;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int chapchal(ServerState*, int, char[ChapChallen]);
|
||||||
|
static int chapresp(ServerState*, char*, char*);
|
||||||
|
|
||||||
|
static int
|
||||||
|
chapserver(Conv *c)
|
||||||
|
{
|
||||||
|
char chal[ChapChallen], *user, *resp;
|
||||||
|
ServerState s;
|
||||||
|
int astype, ret;
|
||||||
|
Attr *a;
|
||||||
|
|
||||||
|
ret = -1;
|
||||||
|
user = nil;
|
||||||
|
resp = nil;
|
||||||
|
memset(&s, 0, sizeof s);
|
||||||
|
s.asfd = -1;
|
||||||
|
|
||||||
|
if(c->proto == &chap)
|
||||||
|
astype = AuthChap;
|
||||||
|
else if(c->proto == &mschap)
|
||||||
|
astype = AuthMSchap;
|
||||||
|
else{
|
||||||
|
werrstr("bad proto");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->state = "find key";
|
||||||
|
if((s.k = plan9authkey(c->attr)) == nil)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
a = copyattr(s.k->attr);
|
||||||
|
a = delattr(a, "proto");
|
||||||
|
c->attr = addattrs(c->attr, a);
|
||||||
|
freeattr(a);
|
||||||
|
|
||||||
|
c->state = "authdial";
|
||||||
|
s.hostid = strfindattr(s.k->attr, "user");
|
||||||
|
s.dom = strfindattr(s.k->attr, "dom");
|
||||||
|
if((s.asfd = xioauthdial(nil, s.dom)) < 0){
|
||||||
|
werrstr("authdial %s: %r", s.dom);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->state = "authchal";
|
||||||
|
if(chapchal(&s, astype, chal) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
c->state = "write challenge";
|
||||||
|
if(convprint(c, "%s", chal) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
c->state = "read user";
|
||||||
|
if(convreadm(c, &user) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
c->state = "read response";
|
||||||
|
if(convreadm(c, &resp) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
c->state = "authwrite";
|
||||||
|
switch(chapresp(&s, user, resp)){
|
||||||
|
default:
|
||||||
|
fprint(2, "factotum: bad result from chapresp\n");
|
||||||
|
goto out;
|
||||||
|
case -1:
|
||||||
|
goto out;
|
||||||
|
case 0:
|
||||||
|
c->state = "write status";
|
||||||
|
if(convprint(c, "bad authentication failed") < 0)
|
||||||
|
goto out;
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
c->state = "write status";
|
||||||
|
if(convprint(c, "ok") < 0)
|
||||||
|
goto out;
|
||||||
|
goto ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok:
|
||||||
|
ret = 0;
|
||||||
|
c->attr = addcap(c->attr, c->sysuser, &s.t);
|
||||||
|
|
||||||
|
out:
|
||||||
|
keyclose(s.k);
|
||||||
|
free(user);
|
||||||
|
free(resp);
|
||||||
|
// xioclose(s.asfd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
chapchal(ServerState *s, int astype, char chal[ChapChallen])
|
||||||
|
{
|
||||||
|
char trbuf[TICKREQLEN];
|
||||||
|
Ticketreq tr;
|
||||||
|
|
||||||
|
memset(&tr, 0, sizeof tr);
|
||||||
|
|
||||||
|
tr.type = astype;
|
||||||
|
|
||||||
|
if(strlen(s->hostid) >= sizeof tr.hostid){
|
||||||
|
werrstr("hostid too long");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
strcpy(tr.hostid, s->hostid);
|
||||||
|
|
||||||
|
if(strlen(s->dom) >= sizeof tr.authdom){
|
||||||
|
werrstr("domain too long");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
strcpy(tr.authdom, s->dom);
|
||||||
|
|
||||||
|
convTR2M(&tr, trbuf);
|
||||||
|
if(xiowrite(s->asfd, trbuf, TICKREQLEN) != TICKREQLEN)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if(xioasrdresp(s->asfd, chal, ChapChallen) <= 5)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
s->tr = tr;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
chapresp(ServerState *s, char *user, char *resp)
|
||||||
|
{
|
||||||
|
char tabuf[TICKETLEN+AUTHENTLEN];
|
||||||
|
char trbuf[TICKREQLEN];
|
||||||
|
int len;
|
||||||
|
Authenticator a;
|
||||||
|
Ticket t;
|
||||||
|
Ticketreq tr;
|
||||||
|
|
||||||
|
tr = s->tr;
|
||||||
|
if(memrandom(tr.chal, CHALLEN) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if(strlen(user) >= sizeof tr.uid){
|
||||||
|
werrstr("uid too long");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
strcpy(tr.uid, user);
|
||||||
|
|
||||||
|
convTR2M(&tr, trbuf);
|
||||||
|
if(xiowrite(s->asfd, trbuf, TICKREQLEN) != TICKREQLEN)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
len = strlen(resp);
|
||||||
|
if(xiowrite(s->asfd, resp, len) != len)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if(xioasrdresp(s->asfd, tabuf, TICKETLEN+AUTHENTLEN) != TICKETLEN+AUTHENTLEN)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
convM2T(tabuf, &t, s->k->priv);
|
||||||
|
if(t.num != AuthTs
|
||||||
|
|| memcmp(t.chal, tr.chal, sizeof tr.chal) != 0){
|
||||||
|
werrstr("key mismatch with auth server");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
convM2A(tabuf+TICKETLEN, &a, t.key);
|
||||||
|
if(a.num != AuthAc
|
||||||
|
|| memcmp(a.chal, tr.chal, sizeof a.chal) != 0
|
||||||
|
|| a.id != 0){
|
||||||
|
werrstr("key2 mismatch with auth server");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->t = t;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Role
|
||||||
|
chaproles[] =
|
||||||
|
{
|
||||||
|
"client", chapclient,
|
||||||
|
"server", chapserver,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
Proto chap = {
|
||||||
|
.name= "chap",
|
||||||
|
.roles= chaproles,
|
||||||
|
.checkkey= chapcheck,
|
||||||
|
.keyprompt= "user? !password?",
|
||||||
|
};
|
||||||
|
|
||||||
|
Proto mschap = {
|
||||||
|
.name= "mschap",
|
||||||
|
.roles= chaproles,
|
||||||
|
.checkkey= chapcheck,
|
||||||
|
.keyprompt= "user? !password?",
|
||||||
|
};
|
||||||
|
|
||||||
139
src/cmd/factotum/confirm.c
Normal file
139
src/cmd/factotum/confirm.c
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
#include "std.h"
|
||||||
|
#include "dat.h"
|
||||||
|
|
||||||
|
Logbuf confbuf;
|
||||||
|
|
||||||
|
void
|
||||||
|
confirmread(Req *r)
|
||||||
|
{
|
||||||
|
lbread(&confbuf, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
confirmflush(Req *r)
|
||||||
|
{
|
||||||
|
lbflush(&confbuf, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
confirmwrite(char *s)
|
||||||
|
{
|
||||||
|
char *t, *ans;
|
||||||
|
int allow;
|
||||||
|
ulong tag;
|
||||||
|
Attr *a;
|
||||||
|
Conv *c;
|
||||||
|
|
||||||
|
a = _parseattr(s);
|
||||||
|
if(a == nil){
|
||||||
|
werrstr("bad attr");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if((t = _strfindattr(a, "tag")) == nil){
|
||||||
|
werrstr("no tag");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
tag = strtoul(t, 0, 0);
|
||||||
|
if((ans = _strfindattr(a, "answer")) == nil){
|
||||||
|
werrstr("no answer");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(strcmp(ans, "yes") == 0)
|
||||||
|
allow = 1;
|
||||||
|
else if(strcmp(ans, "no") == 0)
|
||||||
|
allow = 0;
|
||||||
|
else{
|
||||||
|
werrstr("bad answer");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
for(c=conv; c; c=c->next){
|
||||||
|
if(tag == c->tag){
|
||||||
|
nbsendul(c->keywait, allow);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(c == nil){
|
||||||
|
werrstr("tag not found");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
confirmkey(Conv *c, Key *k)
|
||||||
|
{
|
||||||
|
if(*confirminuse == 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
lbappend(&confbuf, "confirm tag=%lud %A %N", c->tag, k->attr, k->privattr);
|
||||||
|
c->state = "keyconfirm";
|
||||||
|
return recvul(c->keywait);
|
||||||
|
}
|
||||||
|
|
||||||
|
Logbuf needkeybuf;
|
||||||
|
|
||||||
|
void
|
||||||
|
needkeyread(Req *r)
|
||||||
|
{
|
||||||
|
lbread(&needkeybuf, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
needkeyflush(Req *r)
|
||||||
|
{
|
||||||
|
lbflush(&needkeybuf, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
needkeywrite(char *s)
|
||||||
|
{
|
||||||
|
char *t;
|
||||||
|
ulong tag;
|
||||||
|
Attr *a;
|
||||||
|
Conv *c;
|
||||||
|
|
||||||
|
a = _parseattr(s);
|
||||||
|
if(a == nil){
|
||||||
|
werrstr("empty write");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if((t = _strfindattr(a, "tag")) == nil){
|
||||||
|
werrstr("no tag");
|
||||||
|
freeattr(a);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
tag = strtoul(t, 0, 0);
|
||||||
|
for(c=conv; c; c=c->next)
|
||||||
|
if(c->tag == tag){
|
||||||
|
nbsendul(c->keywait, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(c == nil){
|
||||||
|
werrstr("tag not found");
|
||||||
|
freeattr(a);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
freeattr(a);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
needkey(Conv *c, Attr *a)
|
||||||
|
{
|
||||||
|
if(c == nil || *needkeyinuse == 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
lbappend(&needkeybuf, "needkey tag=%lud %A", c->tag, a);
|
||||||
|
return nbrecvul(c->keywait);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
badkey(Conv *c, Key *k, char *msg, Attr *a)
|
||||||
|
{
|
||||||
|
if(c == nil || *needkeyinuse == 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
lbappend(&needkeybuf, "badkey tag=%lud %A %N\n%s\n%A",
|
||||||
|
c->tag, k->attr, k->privattr, msg, a);
|
||||||
|
return nbrecvul(c->keywait);
|
||||||
|
}
|
||||||
254
src/cmd/factotum/conv.c
Normal file
254
src/cmd/factotum/conv.c
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
#include "std.h"
|
||||||
|
#include "dat.h"
|
||||||
|
|
||||||
|
Conv *conv;
|
||||||
|
|
||||||
|
ulong taggen = 1;
|
||||||
|
|
||||||
|
Conv*
|
||||||
|
convalloc(char *sysuser)
|
||||||
|
{
|
||||||
|
Conv *c;
|
||||||
|
|
||||||
|
c = mallocz(sizeof(Conv), 1);
|
||||||
|
if(c == nil)
|
||||||
|
return nil;
|
||||||
|
c->ref = 1;
|
||||||
|
c->tag = taggen++;
|
||||||
|
c->next = conv;
|
||||||
|
c->sysuser = estrdup(sysuser);
|
||||||
|
c->state = "nascent";
|
||||||
|
c->rpcwait = chancreate(sizeof(void*), 0);
|
||||||
|
c->keywait = chancreate(sizeof(void*), 0);
|
||||||
|
strcpy(c->err, "protocol has not started");
|
||||||
|
conv = c;
|
||||||
|
convreset(c);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
convreset(Conv *c)
|
||||||
|
{
|
||||||
|
if(c->ref != 1){
|
||||||
|
c->hangup = 1;
|
||||||
|
nbsendp(c->rpcwait, 0);
|
||||||
|
while(c->ref > 1)
|
||||||
|
yield();
|
||||||
|
c->hangup = 0;
|
||||||
|
}
|
||||||
|
c->state = "nascent";
|
||||||
|
c->err[0] = '\0';
|
||||||
|
freeattr(c->attr);
|
||||||
|
c->attr = nil;
|
||||||
|
c->proto = nil;
|
||||||
|
c->rpc.op = 0;
|
||||||
|
c->active = 0;
|
||||||
|
c->done = 0;
|
||||||
|
c->hangup = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
convhangup(Conv *c)
|
||||||
|
{
|
||||||
|
c->hangup = 1;
|
||||||
|
c->rpc.op = 0;
|
||||||
|
(*c->kickreply)(c);
|
||||||
|
nbsendp(c->rpcwait, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
convclose(Conv *c)
|
||||||
|
{
|
||||||
|
Conv *p;
|
||||||
|
|
||||||
|
if(c == nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(--c->ref > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(c == conv){
|
||||||
|
conv = c->next;
|
||||||
|
goto free;
|
||||||
|
}
|
||||||
|
for(p=conv; p && p->next!=c; p=p->next)
|
||||||
|
;
|
||||||
|
if(p == nil){
|
||||||
|
print("cannot find conv in list\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
p->next = c->next;
|
||||||
|
|
||||||
|
free:
|
||||||
|
c->next = nil;
|
||||||
|
free(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Rpc*
|
||||||
|
convgetrpc(Conv *c, int want)
|
||||||
|
{
|
||||||
|
for(;;){
|
||||||
|
if(c->hangup){
|
||||||
|
werrstr("hangup");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
if(c->rpc.op == RpcUnknown){
|
||||||
|
recvp(c->rpcwait);
|
||||||
|
if(c->hangup){
|
||||||
|
werrstr("hangup");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
if(c->rpc.op == RpcUnknown)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(want < 0 || c->rpc.op == want)
|
||||||
|
return &c->rpc;
|
||||||
|
rpcrespond(c, "phase in state '%s' want '%s'", c->state, rpcname[want]);
|
||||||
|
}
|
||||||
|
return nil; /* not reached */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read until the done function tells us that's enough */
|
||||||
|
int
|
||||||
|
convreadfn(Conv *c, int (*done)(void*, int), char **ps)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
Rpc *r;
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
for(;;){
|
||||||
|
r = convgetrpc(c, RpcWrite);
|
||||||
|
if(r == nil)
|
||||||
|
return -1;
|
||||||
|
n = (*done)(r->data, r->count);
|
||||||
|
if(n == r->count)
|
||||||
|
break;
|
||||||
|
rpcrespond(c, "toosmall %d", n);
|
||||||
|
}
|
||||||
|
|
||||||
|
s = emalloc(r->count+1);
|
||||||
|
memmove(s, r->data, r->count);
|
||||||
|
s[r->count] = 0;
|
||||||
|
*ps = s;
|
||||||
|
rpcrespond(c, "ok");
|
||||||
|
return r->count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* read until we get a non-zero write. assumes remote side
|
||||||
|
* knows something about the protocol (is not auth_proxy).
|
||||||
|
* the remote side typically won't bother with the zero-length
|
||||||
|
* write to find out the length -- the loop is there only so the
|
||||||
|
* test program can call auth_proxy on both sides of a pipe
|
||||||
|
* to play a conversation.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
convreadm(Conv *c, char **ps)
|
||||||
|
{
|
||||||
|
char *s;
|
||||||
|
Rpc *r;
|
||||||
|
|
||||||
|
for(;;){
|
||||||
|
r = convgetrpc(c, RpcWrite);
|
||||||
|
if(r == nil)
|
||||||
|
return -1;
|
||||||
|
if(r->count > 0)
|
||||||
|
break;
|
||||||
|
rpcrespond(c, "toosmall %d", AuthRpcMax);
|
||||||
|
}
|
||||||
|
s = emalloc(r->count+1);
|
||||||
|
memmove(s, r->data, r->count);
|
||||||
|
s[r->count] = 0;
|
||||||
|
*ps = s;
|
||||||
|
rpcrespond(c, "ok");
|
||||||
|
return r->count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read exactly count bytes */
|
||||||
|
int
|
||||||
|
convread(Conv *c, void *data, int count)
|
||||||
|
{
|
||||||
|
Rpc *r;
|
||||||
|
|
||||||
|
for(;;){
|
||||||
|
r = convgetrpc(c, RpcWrite);
|
||||||
|
if(r == nil)
|
||||||
|
return -1;
|
||||||
|
if(r->count == count)
|
||||||
|
break;
|
||||||
|
if(r->count < count)
|
||||||
|
rpcrespond(c, "toosmall %d", count);
|
||||||
|
else
|
||||||
|
rpcrespond(c, "error too much data; want %d got %d", count, r->count);
|
||||||
|
}
|
||||||
|
memmove(data, r->data, count);
|
||||||
|
rpcrespond(c, "ok");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write exactly count bytes */
|
||||||
|
int
|
||||||
|
convwrite(Conv *c, void *data, int count)
|
||||||
|
{
|
||||||
|
Rpc *r;
|
||||||
|
|
||||||
|
for(;;){
|
||||||
|
r = convgetrpc(c, RpcRead);
|
||||||
|
if(r == nil)
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rpcrespondn(c, "ok", data, count);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* print to the conversation */
|
||||||
|
int
|
||||||
|
convprint(Conv *c, char *fmt, ...)
|
||||||
|
{
|
||||||
|
char *s;
|
||||||
|
va_list arg;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
va_start(arg, fmt);
|
||||||
|
s = vsmprint(fmt, arg);
|
||||||
|
va_end(arg);
|
||||||
|
if(s == nil)
|
||||||
|
return -1;
|
||||||
|
ret = convwrite(c, s, strlen(s));
|
||||||
|
free(s);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ask for a key */
|
||||||
|
int
|
||||||
|
convneedkey(Conv *c, Attr *a)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Piggyback key requests in the usual RPC channel.
|
||||||
|
* Wait for the next RPC and then send a key request
|
||||||
|
* in response. The keys get added out-of-band (via the
|
||||||
|
* ctl file), so assume the key has been added when the
|
||||||
|
* next request comes in.
|
||||||
|
*/
|
||||||
|
if(convgetrpc(c, -1) == nil)
|
||||||
|
return -1;
|
||||||
|
rpcrespond(c, "needkey %A", a);
|
||||||
|
if(convgetrpc(c, -1) == nil)
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ask for a replacement for a bad key*/
|
||||||
|
int
|
||||||
|
convbadkey(Conv *c, Key *k, char *msg, Attr *a)
|
||||||
|
{
|
||||||
|
if(convgetrpc(c, -1) == nil)
|
||||||
|
return -1;
|
||||||
|
rpcrespond(c, "badkey %A %N\n%s\n%A",
|
||||||
|
k->attr, k->privattr, msg, a);
|
||||||
|
if(convgetrpc(c, -1) == nil)
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
1117
src/cmd/factotum/cpu.c
Normal file
1117
src/cmd/factotum/cpu.c
Normal file
File diff suppressed because it is too large
Load Diff
158
src/cmd/factotum/ctl.c
Normal file
158
src/cmd/factotum/ctl.c
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
#include "std.h"
|
||||||
|
#include "dat.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* key attr=val... - add a key
|
||||||
|
* the attr=val pairs are protocol-specific.
|
||||||
|
* for example, both of these are valid:
|
||||||
|
* key p9sk1 gre cs.bell-labs.com mysecret
|
||||||
|
* key p9sk1 gre cs.bell-labs.com 11223344556677 fmt=des7hex
|
||||||
|
* delkey ... - delete a key
|
||||||
|
* if given, the attr=val pairs are used to narrow the search
|
||||||
|
* [maybe should require a password?]
|
||||||
|
*
|
||||||
|
* debug - toggle debugging
|
||||||
|
*/
|
||||||
|
|
||||||
|
static char *msg[] = {
|
||||||
|
"key",
|
||||||
|
"delkey",
|
||||||
|
"debug",
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
classify(char *s)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i=0; i<nelem(msg); i++)
|
||||||
|
if(strcmp(msg[i], s) == 0)
|
||||||
|
return i;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ctlwrite(char *a)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
int i, nmatch, ret;
|
||||||
|
Attr *attr, **l, **lpriv, **lprotos, *pa, *priv, *protos;
|
||||||
|
Key *k;
|
||||||
|
Proto *proto;
|
||||||
|
|
||||||
|
if(a[0] == '#' || a[0] == '\0')
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* it would be nice to emit a warning of some sort here.
|
||||||
|
* we ignore all but the first line of the write. this helps
|
||||||
|
* both with things like "echo delkey >/mnt/factotum/ctl"
|
||||||
|
* and writes that (incorrectly) contain multiple key lines.
|
||||||
|
*/
|
||||||
|
if(p = strchr(a, '\n')){
|
||||||
|
if(p[1] != '\0'){
|
||||||
|
werrstr("multiline write not allowed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*p = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if((p = strchr(a, ' ')) == nil)
|
||||||
|
p = "";
|
||||||
|
else
|
||||||
|
*p++ = '\0';
|
||||||
|
switch(classify(a)){
|
||||||
|
default:
|
||||||
|
werrstr("unknown verb");
|
||||||
|
return -1;
|
||||||
|
case 0: /* key */
|
||||||
|
attr = parseattr(p);
|
||||||
|
/* separate out proto= attributes */
|
||||||
|
lprotos = &protos;
|
||||||
|
for(l=&attr; (*l); ){
|
||||||
|
if(strcmp((*l)->name, "proto") == 0){
|
||||||
|
*lprotos = *l;
|
||||||
|
lprotos = &(*l)->next;
|
||||||
|
*l = (*l)->next;
|
||||||
|
}else
|
||||||
|
l = &(*l)->next;
|
||||||
|
}
|
||||||
|
*lprotos = nil;
|
||||||
|
if(protos == nil){
|
||||||
|
werrstr("key without protos");
|
||||||
|
freeattr(attr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* separate out private attributes */
|
||||||
|
lpriv = &priv;
|
||||||
|
for(l=&attr; (*l); ){
|
||||||
|
if((*l)->name[0] == '!'){
|
||||||
|
*lpriv = *l;
|
||||||
|
lpriv = &(*l)->next;
|
||||||
|
*l = (*l)->next;
|
||||||
|
}else
|
||||||
|
l = &(*l)->next;
|
||||||
|
}
|
||||||
|
*lpriv = nil;
|
||||||
|
|
||||||
|
/* add keys */
|
||||||
|
ret = 0;
|
||||||
|
for(pa=protos; pa; pa=pa->next){
|
||||||
|
if((proto = protolookup(pa->val)) == nil){
|
||||||
|
werrstr("unknown proto %s", pa->val);
|
||||||
|
ret = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(proto->checkkey == nil){
|
||||||
|
werrstr("proto %s does not accept keys", proto->name);
|
||||||
|
ret = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
k = emalloc(sizeof(Key));
|
||||||
|
k->attr = mkattr(AttrNameval, "proto", proto->name, copyattr(attr));
|
||||||
|
k->privattr = copyattr(priv);
|
||||||
|
k->ref = 1;
|
||||||
|
k->proto = proto;
|
||||||
|
if((*proto->checkkey)(k) < 0){
|
||||||
|
ret = -1;
|
||||||
|
keyclose(k);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
keyadd(k);
|
||||||
|
keyclose(k);
|
||||||
|
}
|
||||||
|
freeattr(attr);
|
||||||
|
freeattr(priv);
|
||||||
|
freeattr(protos);
|
||||||
|
return ret;
|
||||||
|
case 1: /* delkey */
|
||||||
|
nmatch = 0;
|
||||||
|
attr = parseattr(p);
|
||||||
|
for(pa=attr; pa; pa=pa->next){
|
||||||
|
if(pa->type != AttrQuery && pa->name[0]=='!'){
|
||||||
|
werrstr("only !private? patterns are allowed for private fields");
|
||||||
|
freeattr(attr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(i=0; i<ring.nkey; ){
|
||||||
|
if(matchattr(attr, ring.key[i]->attr, ring.key[i]->privattr)){
|
||||||
|
nmatch++;
|
||||||
|
keyclose(ring.key[i]);
|
||||||
|
ring.nkey--;
|
||||||
|
memmove(&ring.key[i], &ring.key[i+1], (ring.nkey-i)*sizeof(ring.key[0]));
|
||||||
|
}else
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
freeattr(attr);
|
||||||
|
if(nmatch == 0){
|
||||||
|
werrstr("found no keys to delete");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
case 2: /* debug */
|
||||||
|
debug ^= 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
224
src/cmd/factotum/dat.h
Normal file
224
src/cmd/factotum/dat.h
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
enum
|
||||||
|
{
|
||||||
|
MaxRpc = 2048, /* max size of any protocol message */
|
||||||
|
|
||||||
|
/* keep in sync with rpc.c:/rpcname */
|
||||||
|
RpcUnknown = 0, /* Rpc.op */
|
||||||
|
RpcAuthinfo,
|
||||||
|
RpcAttr,
|
||||||
|
RpcRead,
|
||||||
|
RpcStart,
|
||||||
|
RpcWrite,
|
||||||
|
|
||||||
|
/* thread stack size */
|
||||||
|
STACK = 8192,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct Conv Conv;
|
||||||
|
typedef struct Key Key;
|
||||||
|
typedef struct Logbuf Logbuf;
|
||||||
|
typedef struct Proto Proto;
|
||||||
|
typedef struct Ring Ring;
|
||||||
|
typedef struct Role Role;
|
||||||
|
typedef struct Rpc Rpc;
|
||||||
|
|
||||||
|
struct Rpc
|
||||||
|
{
|
||||||
|
int op;
|
||||||
|
void *data;
|
||||||
|
int count;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Conv
|
||||||
|
{
|
||||||
|
int ref; /* ref count */
|
||||||
|
int hangup; /* flag: please hang up */
|
||||||
|
int active; /* flag: there is an active thread */
|
||||||
|
int done; /* flag: conversation finished successfully */
|
||||||
|
ulong tag; /* identifying tag */
|
||||||
|
Conv *next; /* in linked list */
|
||||||
|
char *sysuser; /* system name for user speaking to us */
|
||||||
|
char *state; /* for debugging */
|
||||||
|
char statebuf[128]; /* for formatted states */
|
||||||
|
char err[ERRMAX]; /* last error */
|
||||||
|
|
||||||
|
Attr *attr; /* current attributes */
|
||||||
|
Proto *proto; /* protocol */
|
||||||
|
|
||||||
|
Channel *rpcwait; /* wait here for an rpc */
|
||||||
|
Rpc rpc; /* current rpc. op==RpcUnknown means none */
|
||||||
|
char rpcbuf[MaxRpc]; /* buffer for rpc */
|
||||||
|
char reply[MaxRpc]; /* buffer for response */
|
||||||
|
int nreply; /* count of response */
|
||||||
|
void (*kickreply)(Conv*); /* call to send response */
|
||||||
|
Req *req; /* 9P call to read response */
|
||||||
|
|
||||||
|
Channel *keywait; /* wait here for key confirmation */
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Key
|
||||||
|
{
|
||||||
|
int ref; /* ref count */
|
||||||
|
ulong tag; /* identifying tag: sequence number */
|
||||||
|
Attr *attr; /* public attributes */
|
||||||
|
Attr *privattr; /* private attributes, like !password */
|
||||||
|
Proto *proto; /* protocol owner of key */
|
||||||
|
void *priv; /* protocol-specific storage */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Logbuf
|
||||||
|
{
|
||||||
|
Req *wait;
|
||||||
|
Req **waitlast;
|
||||||
|
int rp;
|
||||||
|
int wp;
|
||||||
|
char *msg[128];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Ring
|
||||||
|
{
|
||||||
|
Key **key;
|
||||||
|
int nkey;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Proto
|
||||||
|
{
|
||||||
|
char *name; /* name of protocol */
|
||||||
|
Role *roles; /* list of roles and service functions */
|
||||||
|
char *keyprompt; /* required attributes for key proto=name */
|
||||||
|
int (*checkkey)(Key*); /* initialize k->priv or reject key */
|
||||||
|
void (*closekey)(Key*); /* free k->priv */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Role
|
||||||
|
{
|
||||||
|
char *name; /* name of role */
|
||||||
|
int (*fn)(Conv*); /* service function */
|
||||||
|
};
|
||||||
|
|
||||||
|
extern char *authaddr; /* plan9.c */
|
||||||
|
extern int *confirminuse; /* fs.c */
|
||||||
|
extern Conv* conv; /* conv.c */
|
||||||
|
extern int debug; /* main.c */
|
||||||
|
extern char *factname; /* main.c */
|
||||||
|
extern Srv fs; /* fs.c */
|
||||||
|
extern int *needkeyinuse; /* fs.c */
|
||||||
|
extern char *owner; /* main.c */
|
||||||
|
extern Proto *prototab[]; /* main.c */
|
||||||
|
extern Ring ring; /* key.c */
|
||||||
|
extern char *rpcname[]; /* rpc.c */
|
||||||
|
|
||||||
|
extern char Easproto[]; /* err.c */
|
||||||
|
|
||||||
|
extern Proto apop; /* apop.c */
|
||||||
|
extern Proto chap; /* chap.c */
|
||||||
|
extern Proto cram; /* cram.c */
|
||||||
|
extern Proto mschap; /* mschap.c */
|
||||||
|
extern Proto p9any; /* p9any.c */
|
||||||
|
extern Proto p9sk1; /* p9sk1.c */
|
||||||
|
extern Proto p9sk2; /* p9sk2.c */
|
||||||
|
|
||||||
|
/* provided by lib9p */
|
||||||
|
#define emalloc emalloc9p
|
||||||
|
#define erealloc erealloc9p
|
||||||
|
#define estrdup estrdup9p
|
||||||
|
|
||||||
|
/* hidden in libauth */
|
||||||
|
#define attrfmt _attrfmt
|
||||||
|
#define copyattr _copyattr
|
||||||
|
#define delattr _delattr
|
||||||
|
#define findattr _findattr
|
||||||
|
#define freeattr _freeattr
|
||||||
|
#define mkattr _mkattr
|
||||||
|
#define parseattr _parseattr
|
||||||
|
#define strfindattr _strfindattr
|
||||||
|
|
||||||
|
extern Attr* addattr(Attr*, char*, ...);
|
||||||
|
/* #pragma varargck argpos addattr 2 */
|
||||||
|
extern Attr* addattrs(Attr*, Attr*);
|
||||||
|
extern Attr* sortattr(Attr*);
|
||||||
|
extern int attrnamefmt(Fmt*);
|
||||||
|
/* #pragma varargck type "N" Attr* */
|
||||||
|
extern int matchattr(Attr*, Attr*, Attr*);
|
||||||
|
extern Attr* parseattrfmt(char*, ...);
|
||||||
|
/* #pragma varargck argpos parseattrfmt 1 */
|
||||||
|
extern Attr* parseattrfmtv(char*, va_list);
|
||||||
|
|
||||||
|
extern void confirmflush(Req*);
|
||||||
|
extern void confirmread(Req*);
|
||||||
|
extern int confirmwrite(char*);
|
||||||
|
extern int needkey(Conv*, Attr*);
|
||||||
|
extern int badkey(Conv*, Key*, char*, Attr*);
|
||||||
|
extern int confirmkey(Conv*, Key*);
|
||||||
|
|
||||||
|
extern Conv* convalloc(char*);
|
||||||
|
extern void convclose(Conv*);
|
||||||
|
extern void convhangup(Conv*);
|
||||||
|
extern int convneedkey(Conv*, Attr*);
|
||||||
|
extern int convbadkey(Conv*, Key*, char*, Attr*);
|
||||||
|
extern int convread(Conv*, void*, int);
|
||||||
|
extern int convreadm(Conv*, char**);
|
||||||
|
extern int convprint(Conv*, char*, ...);
|
||||||
|
/* #pragma varargck argpos convprint 2 */
|
||||||
|
extern int convreadfn(Conv*, int(*)(void*, int), char**);
|
||||||
|
extern void convreset(Conv*);
|
||||||
|
extern int convwrite(Conv*, void*, int);
|
||||||
|
|
||||||
|
extern int ctlwrite(char*);
|
||||||
|
|
||||||
|
extern char* estrappend(char*, char*, ...);
|
||||||
|
/* #pragma varargck argpos estrappend 2 */
|
||||||
|
extern int hexparse(char*, uchar*, int);
|
||||||
|
|
||||||
|
extern void keyadd(Key*);
|
||||||
|
extern Key* keylookup(char*, ...);
|
||||||
|
/* #pragma varargck argpos keylookup 1 */
|
||||||
|
extern Key* keyfetch(Conv*, char*, ...);
|
||||||
|
/* #pragma varargck argpos keyfetch 2 */
|
||||||
|
extern void keyclose(Key*);
|
||||||
|
extern void keyevict(Conv*, Key*, char*, ...);
|
||||||
|
/* #pragma varargck argpos keyevict 3 */
|
||||||
|
extern Key* keyreplace(Conv*, Key*, char*, ...);
|
||||||
|
/* #pragma varargck argpos keyreplace 3 */
|
||||||
|
|
||||||
|
extern void lbkick(Logbuf*);
|
||||||
|
extern void lbappend(Logbuf*, char*, ...);
|
||||||
|
extern void lbvappend(Logbuf*, char*, va_list);
|
||||||
|
/* #pragma varargck argpos lbappend 2 */
|
||||||
|
extern void lbread(Logbuf*, Req*);
|
||||||
|
extern void lbflush(Logbuf*, Req*);
|
||||||
|
extern void flog(char*, ...);
|
||||||
|
/* #pragma varargck argpos flog 1 */
|
||||||
|
|
||||||
|
extern void logflush(Req*);
|
||||||
|
extern void logread(Req*);
|
||||||
|
extern void logwrite(Req*);
|
||||||
|
|
||||||
|
extern void needkeyread(Req*);
|
||||||
|
extern void needkeyflush(Req*);
|
||||||
|
extern int needkeywrite(char*);
|
||||||
|
extern int needkeyqueue(void);
|
||||||
|
|
||||||
|
extern Attr* addcap(Attr*, char*, Ticket*);
|
||||||
|
extern Key* plan9authkey(Attr*);
|
||||||
|
extern int _authdial(char*, char*);
|
||||||
|
|
||||||
|
extern int memrandom(void*, int);
|
||||||
|
|
||||||
|
extern Proto* protolookup(char*);
|
||||||
|
|
||||||
|
extern char* readcons(char *prompt, char *def, int raw);
|
||||||
|
|
||||||
|
extern int rpcwrite(Conv*, void*, int);
|
||||||
|
extern void rpcrespond(Conv*, char*, ...);
|
||||||
|
/* #pragma varargck argpos rpcrespond 2 */
|
||||||
|
extern void rpcrespondn(Conv*, char*, void*, int);
|
||||||
|
extern void rpcexec(Conv*);
|
||||||
|
|
||||||
|
extern int xioauthdial(char*, char*);
|
||||||
|
extern void xioclose(int);
|
||||||
|
extern int xiodial(char*, char*, char*, int*);
|
||||||
|
extern int xiowrite(int, void*, int);
|
||||||
|
extern int xioasrdresp(int, void*, int);
|
||||||
|
extern int xioasgetticket(int, char*, char*);
|
||||||
1686
src/cmd/factotum/fs.acid
Normal file
1686
src/cmd/factotum/fs.acid
Normal file
File diff suppressed because it is too large
Load Diff
524
src/cmd/factotum/fs.c
Normal file
524
src/cmd/factotum/fs.c
Normal file
@ -0,0 +1,524 @@
|
|||||||
|
#include "std.h"
|
||||||
|
#include "dat.h"
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
Qroot,
|
||||||
|
Qfactotum,
|
||||||
|
Qrpc,
|
||||||
|
Qkeylist,
|
||||||
|
Qprotolist,
|
||||||
|
Qconfirm,
|
||||||
|
Qlog,
|
||||||
|
Qctl,
|
||||||
|
Qneedkey,
|
||||||
|
Qconv,
|
||||||
|
};
|
||||||
|
|
||||||
|
Qid
|
||||||
|
mkqid(int type, int path)
|
||||||
|
{
|
||||||
|
Qid q;
|
||||||
|
|
||||||
|
q.type = type;
|
||||||
|
q.path = path;
|
||||||
|
q.vers = 0;
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
int qidpath;
|
||||||
|
ulong perm;
|
||||||
|
} dirtab[] = {
|
||||||
|
/* positions of confirm and needkey known below */
|
||||||
|
"confirm", Qconfirm, 0600|DMEXCL,
|
||||||
|
"needkey", Qneedkey, 0600|DMEXCL,
|
||||||
|
"ctl", Qctl, 0600,
|
||||||
|
"rpc", Qrpc, 0666,
|
||||||
|
"proto", Qprotolist, 0444,
|
||||||
|
"log", Qlog, 0600|DMEXCL,
|
||||||
|
"conv", Qconv, 0400,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
fillstat(Dir *dir, char *name, int type, int path, ulong perm)
|
||||||
|
{
|
||||||
|
dir->name = estrdup(name);
|
||||||
|
dir->uid = estrdup(owner);
|
||||||
|
dir->gid = estrdup(owner);
|
||||||
|
dir->mode = perm;
|
||||||
|
dir->length = 0;
|
||||||
|
dir->qid = mkqid(type, path);
|
||||||
|
dir->atime = time(0);
|
||||||
|
dir->mtime = time(0);
|
||||||
|
dir->muid = estrdup("");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
rootdirgen(int n, Dir *dir, void *v)
|
||||||
|
{
|
||||||
|
USED(v);
|
||||||
|
|
||||||
|
if(n > 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
fillstat(dir, factname, QTDIR, Qfactotum, DMDIR|0555);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
fsdirgen(int n, Dir *dir, void *v)
|
||||||
|
{
|
||||||
|
USED(v);
|
||||||
|
|
||||||
|
if(n >= nelem(dirtab))
|
||||||
|
return -1;
|
||||||
|
fillstat(dir, dirtab[n].name, 0, dirtab[n].qidpath, dirtab[n].perm);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char*
|
||||||
|
fswalk1(Fid *fid, char *name, Qid *qid)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
switch((int)fid->qid.path){
|
||||||
|
default:
|
||||||
|
return "fswalk1: cannot happen";
|
||||||
|
case Qroot:
|
||||||
|
if(strcmp(name, factname) == 0){
|
||||||
|
*qid = mkqid(QTDIR, Qfactotum);
|
||||||
|
fid->qid = *qid;
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
if(strcmp(name, "..") == 0){
|
||||||
|
*qid = fid->qid;
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
return "not found";
|
||||||
|
case Qfactotum:
|
||||||
|
for(i=0; i<nelem(dirtab); i++)
|
||||||
|
if(strcmp(name, dirtab[i].name) == 0){
|
||||||
|
*qid = mkqid(0, dirtab[i].qidpath);
|
||||||
|
fid->qid = *qid;
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
if(strcmp(name, "..") == 0){
|
||||||
|
*qid = mkqid(QTDIR, Qroot);
|
||||||
|
fid->qid = *qid;
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
return "not found";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fsstat(Req *r)
|
||||||
|
{
|
||||||
|
int i, path;
|
||||||
|
|
||||||
|
path = r->fid->qid.path;
|
||||||
|
switch(path){
|
||||||
|
case Qroot:
|
||||||
|
fillstat(&r->d, "/", QTDIR, Qroot, 0555|DMDIR);
|
||||||
|
break;
|
||||||
|
case Qfactotum:
|
||||||
|
fillstat(&r->d, "factotum", QTDIR, Qfactotum, 0555|DMDIR);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
for(i=0; i<nelem(dirtab); i++)
|
||||||
|
if(dirtab[i].qidpath == path){
|
||||||
|
fillstat(&r->d, dirtab[i].name, 0, dirtab[i].qidpath, dirtab[i].perm);
|
||||||
|
goto Break2;
|
||||||
|
}
|
||||||
|
respond(r, "file not found");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Break2:
|
||||||
|
respond(r, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
readlist(int off, int (*gen)(int, char*, uint), Req *r)
|
||||||
|
{
|
||||||
|
char *a, *ea;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
a = r->ofcall.data;
|
||||||
|
ea = a+r->ifcall.count;
|
||||||
|
for(;;){
|
||||||
|
n = (*gen)(off, a, ea-a);
|
||||||
|
if(n == 0){
|
||||||
|
r->ofcall.count = a - (char*)r->ofcall.data;
|
||||||
|
return off;
|
||||||
|
}
|
||||||
|
a += n;
|
||||||
|
off++;
|
||||||
|
}
|
||||||
|
return -1; /* not reached */
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
keylist(int i, char *a, uint nn)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
char buf[512];
|
||||||
|
Key *k;
|
||||||
|
|
||||||
|
if(i >= ring.nkey)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
k = ring.key[i];
|
||||||
|
k->attr = sortattr(k->attr);
|
||||||
|
n = snprint(buf, sizeof buf, "key %A %N\n", k->attr, k->privattr);
|
||||||
|
if(n >= sizeof(buf)-5)
|
||||||
|
strcpy(buf+sizeof(buf)-5, "...\n");
|
||||||
|
n = strlen(buf);
|
||||||
|
if(n > nn)
|
||||||
|
return 0;
|
||||||
|
memmove(a, buf, n);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
protolist(int i, char *a, uint n)
|
||||||
|
{
|
||||||
|
if(prototab[i] == nil)
|
||||||
|
return 0;
|
||||||
|
if(strlen(prototab[i]->name)+1 > n)
|
||||||
|
return 0;
|
||||||
|
n = strlen(prototab[i]->name)+1;
|
||||||
|
memmove(a, prototab[i]->name, n-1);
|
||||||
|
a[n-1] = '\n';
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* BUG this is O(n^2) to fill in the list */
|
||||||
|
static int
|
||||||
|
convlist(int i, char *a, uint nn)
|
||||||
|
{
|
||||||
|
Conv *c;
|
||||||
|
char buf[512];
|
||||||
|
int n;
|
||||||
|
|
||||||
|
for(c=conv; c && i-- > 0; c=c->next)
|
||||||
|
;
|
||||||
|
|
||||||
|
if(c == nil)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(c->state)
|
||||||
|
n = snprint(buf, sizeof buf, "conv state=%q %A\n", c->state, c->attr);
|
||||||
|
else
|
||||||
|
n = snprint(buf, sizeof buf, "conv state=closed err=%q\n", c->err);
|
||||||
|
|
||||||
|
if(n >= sizeof(buf)-5)
|
||||||
|
strcpy(buf+sizeof(buf)-5, "...\n");
|
||||||
|
n = strlen(buf);
|
||||||
|
if(n > nn)
|
||||||
|
return 0;
|
||||||
|
memmove(a, buf, n);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fskickreply(Conv *c)
|
||||||
|
{
|
||||||
|
Req *r;
|
||||||
|
|
||||||
|
if(c->hangup){
|
||||||
|
if(c->req){
|
||||||
|
respond(c->req, "hangup");
|
||||||
|
c->req = nil;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!c->req || !c->nreply)
|
||||||
|
return;
|
||||||
|
|
||||||
|
r = c->req;
|
||||||
|
r->ofcall.count = c->nreply;
|
||||||
|
r->ofcall.data = c->reply;
|
||||||
|
if(r->ofcall.count > r->ifcall.count)
|
||||||
|
r->ofcall.count = r->ifcall.count;
|
||||||
|
respond(r, nil);
|
||||||
|
c->req = nil;
|
||||||
|
c->nreply = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some of the file system work happens in the fs proc, but
|
||||||
|
* fsopen, fsread, fswrite, fsdestroyfid, and fsflush happen in
|
||||||
|
* the main proc so that they can access the various shared
|
||||||
|
* data structures without worrying about locking.
|
||||||
|
*/
|
||||||
|
static int inuse[nelem(dirtab)];
|
||||||
|
int *confirminuse = &inuse[0];
|
||||||
|
int *needkeyinuse = &inuse[1];
|
||||||
|
static void
|
||||||
|
fsopen(Req *r)
|
||||||
|
{
|
||||||
|
int i, *inusep, perm;
|
||||||
|
static int need[4] = { 4, 2, 6, 1 };
|
||||||
|
Conv *c;
|
||||||
|
|
||||||
|
inusep = nil;
|
||||||
|
perm = 5; /* directory */
|
||||||
|
for(i=0; i<nelem(dirtab); i++)
|
||||||
|
if(dirtab[i].qidpath == r->fid->qid.path){
|
||||||
|
if(dirtab[i].perm & DMEXCL)
|
||||||
|
inusep = &inuse[i];
|
||||||
|
if(strcmp(r->fid->uid, owner) == 0)
|
||||||
|
perm = dirtab[i].perm>>6;
|
||||||
|
else
|
||||||
|
perm = dirtab[i].perm;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((r->ifcall.mode&~(OMASK|OTRUNC))
|
||||||
|
|| (need[r->ifcall.mode&3] & ~perm)){
|
||||||
|
respond(r, "permission denied");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(inusep){
|
||||||
|
if(*inusep){
|
||||||
|
respond(r, "file in use");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*inusep = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(r->fid->qid.path == Qrpc){
|
||||||
|
if((c = convalloc(r->fid->uid)) == nil){
|
||||||
|
char e[ERRMAX];
|
||||||
|
|
||||||
|
rerrstr(e, sizeof e);
|
||||||
|
respond(r, e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
c->kickreply = fskickreply;
|
||||||
|
r->fid->aux = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
respond(r, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fsread(Req *r)
|
||||||
|
{
|
||||||
|
Conv *c;
|
||||||
|
|
||||||
|
switch((int)r->fid->qid.path){
|
||||||
|
default:
|
||||||
|
respond(r, "fsread: cannot happen");
|
||||||
|
break;
|
||||||
|
case Qroot:
|
||||||
|
dirread9p(r, rootdirgen, nil);
|
||||||
|
respond(r, nil);
|
||||||
|
break;
|
||||||
|
case Qfactotum:
|
||||||
|
dirread9p(r, fsdirgen, nil);
|
||||||
|
respond(r, nil);
|
||||||
|
break;
|
||||||
|
case Qrpc:
|
||||||
|
c = r->fid->aux;
|
||||||
|
if(c->rpc.op == RpcUnknown){
|
||||||
|
respond(r, "no rpc pending");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(c->req){
|
||||||
|
respond(r, "read already pending");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
c->req = r;
|
||||||
|
if(c->nreply)
|
||||||
|
(*c->kickreply)(c);
|
||||||
|
else
|
||||||
|
rpcexec(c);
|
||||||
|
break;
|
||||||
|
case Qconfirm:
|
||||||
|
confirmread(r);
|
||||||
|
break;
|
||||||
|
case Qlog:
|
||||||
|
logread(r);
|
||||||
|
break;
|
||||||
|
case Qctl:
|
||||||
|
r->fid->aux = (void*)readlist((int)r->fid->aux, keylist, r);
|
||||||
|
respond(r, nil);
|
||||||
|
break;
|
||||||
|
case Qneedkey:
|
||||||
|
needkeyread(r);
|
||||||
|
break;
|
||||||
|
case Qprotolist:
|
||||||
|
r->fid->aux = (void*)readlist((int)r->fid->aux, protolist, r);
|
||||||
|
respond(r, nil);
|
||||||
|
break;
|
||||||
|
case Qconv:
|
||||||
|
r->fid->aux = (void*)readlist((int)r->fid->aux, convlist, r);
|
||||||
|
respond(r, nil);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fswrite(Req *r)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
char err[ERRMAX], *s;
|
||||||
|
int (*strfn)(char*);
|
||||||
|
|
||||||
|
switch((int)r->fid->qid.path){
|
||||||
|
default:
|
||||||
|
respond(r, "fswrite: cannot happen");
|
||||||
|
break;
|
||||||
|
case Qrpc:
|
||||||
|
if(rpcwrite(r->fid->aux, r->ifcall.data, r->ifcall.count) < 0){
|
||||||
|
rerrstr(err, sizeof err);
|
||||||
|
respond(r, err);
|
||||||
|
}else{
|
||||||
|
r->ofcall.count = r->ifcall.count;
|
||||||
|
respond(r, nil);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Qneedkey:
|
||||||
|
strfn = needkeywrite;
|
||||||
|
goto string;
|
||||||
|
case Qctl:
|
||||||
|
strfn = ctlwrite;
|
||||||
|
goto string;
|
||||||
|
case Qconfirm:
|
||||||
|
strfn = confirmwrite;
|
||||||
|
string:
|
||||||
|
s = emalloc(r->ifcall.count+1);
|
||||||
|
memmove(s, r->ifcall.data, r->ifcall.count);
|
||||||
|
s[r->ifcall.count] = '\0';
|
||||||
|
ret = (*strfn)(s);
|
||||||
|
free(s);
|
||||||
|
if(ret < 0){
|
||||||
|
rerrstr(err, sizeof err);
|
||||||
|
respond(r, err);
|
||||||
|
}else{
|
||||||
|
r->ofcall.count = r->ifcall.count;
|
||||||
|
respond(r, nil);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fsflush(Req *r)
|
||||||
|
{
|
||||||
|
confirmflush(r);
|
||||||
|
logflush(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fsdestroyfid(Fid *fid)
|
||||||
|
{
|
||||||
|
if(fid->qid.path == Qrpc){
|
||||||
|
convhangup(fid->aux);
|
||||||
|
convclose(fid->aux);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Channel *creq;
|
||||||
|
static Channel *cfid, *cfidr;
|
||||||
|
|
||||||
|
static void
|
||||||
|
fsreqthread(void *v)
|
||||||
|
{
|
||||||
|
Req *r;
|
||||||
|
|
||||||
|
USED(v);
|
||||||
|
|
||||||
|
creq = chancreate(sizeof(Req*), 0);
|
||||||
|
|
||||||
|
while((r = recvp(creq)) != nil){
|
||||||
|
switch(r->ifcall.type){
|
||||||
|
default:
|
||||||
|
respond(r, "bug in fsreqthread");
|
||||||
|
break;
|
||||||
|
case Topen:
|
||||||
|
fsopen(r);
|
||||||
|
break;
|
||||||
|
case Tread:
|
||||||
|
fsread(r);
|
||||||
|
break;
|
||||||
|
case Twrite:
|
||||||
|
fswrite(r);
|
||||||
|
break;
|
||||||
|
case Tflush:
|
||||||
|
fsflush(r);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fsclunkthread(void *v)
|
||||||
|
{
|
||||||
|
Fid *f;
|
||||||
|
|
||||||
|
USED(v);
|
||||||
|
cfid = chancreate(sizeof(Fid*), 0);
|
||||||
|
cfidr = chancreate(sizeof(Fid*), 0);
|
||||||
|
|
||||||
|
while((f = recvp(cfid)) != nil){
|
||||||
|
fsdestroyfid(f);
|
||||||
|
sendp(cfidr, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fsproc(void *v)
|
||||||
|
{
|
||||||
|
USED(v);
|
||||||
|
|
||||||
|
threadcreate(fsreqthread, nil, STACK);
|
||||||
|
threadcreate(fsclunkthread, nil, STACK);
|
||||||
|
threadexits(nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fsattach(Req *r)
|
||||||
|
{
|
||||||
|
static int first = 1;
|
||||||
|
|
||||||
|
if(first){
|
||||||
|
proccreate(fsproc, nil, STACK);
|
||||||
|
first = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
r->fid->qid = mkqid(QTDIR, Qroot);
|
||||||
|
r->ofcall.qid = r->fid->qid;
|
||||||
|
respond(r, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fssend(Req *r)
|
||||||
|
{
|
||||||
|
sendp(creq, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fssendclunk(Fid *f)
|
||||||
|
{
|
||||||
|
sendp(cfid, f);
|
||||||
|
recvp(cfidr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Srv fs = {
|
||||||
|
.attach= fsattach,
|
||||||
|
.walk1= fswalk1,
|
||||||
|
.open= fssend,
|
||||||
|
.read= fssend,
|
||||||
|
.write= fssend,
|
||||||
|
.stat= fsstat,
|
||||||
|
.flush= fssend,
|
||||||
|
.destroyfid= fssendclunk,
|
||||||
|
};
|
||||||
|
|
||||||
3
src/cmd/factotum/guide
Executable file
3
src/cmd/factotum/guide
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
kill 8.out|rc
|
||||||
|
unmount /srv/factotum /mnt
|
||||||
|
8.out
|
||||||
6
src/cmd/factotum/guide2
Normal file
6
src/cmd/factotum/guide2
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
kill 8.out|rc
|
||||||
|
unmount /mnt/factotum
|
||||||
|
8.out -m /mnt/factotum
|
||||||
|
cat /mnt/factotum/log &
|
||||||
|
unmount /factotum
|
||||||
|
bind 8.out /factotum
|
||||||
190
src/cmd/factotum/key.c
Normal file
190
src/cmd/factotum/key.c
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
#include "std.h"
|
||||||
|
#include "dat.h"
|
||||||
|
|
||||||
|
Ring ring;
|
||||||
|
|
||||||
|
Key*
|
||||||
|
keylookup(char *fmt, ...)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
Attr *a;
|
||||||
|
Key *k;
|
||||||
|
va_list arg;
|
||||||
|
|
||||||
|
va_start(arg, fmt);
|
||||||
|
a = parseattrfmtv(fmt, arg);
|
||||||
|
va_end(arg);
|
||||||
|
|
||||||
|
for(i=0; i<ring.nkey; i++){
|
||||||
|
k = ring.key[i];
|
||||||
|
if(matchattr(a, k->attr, k->privattr)){
|
||||||
|
k->ref++;
|
||||||
|
freeattr(a);
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
freeattr(a);
|
||||||
|
werrstr("no key found");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
Key*
|
||||||
|
keyfetch(Conv *c, char *fmt, ...)
|
||||||
|
{
|
||||||
|
int i, tag;
|
||||||
|
Attr *a;
|
||||||
|
Key *k;
|
||||||
|
va_list arg;
|
||||||
|
|
||||||
|
va_start(arg, fmt);
|
||||||
|
a = parseattrfmtv(fmt, arg);
|
||||||
|
va_end(arg);
|
||||||
|
|
||||||
|
tag = 0;
|
||||||
|
|
||||||
|
for(i=0; i<ring.nkey; i++){
|
||||||
|
k = ring.key[i];
|
||||||
|
if(tag < k->tag)
|
||||||
|
tag = k->tag;
|
||||||
|
if(matchattr(a, k->attr, k->privattr)){
|
||||||
|
k->ref++;
|
||||||
|
if(strfindattr(k->attr, "confirm") && confirmkey(c, k) != 1){
|
||||||
|
k->ref--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
freeattr(a);
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(needkey(c, a) < 0)
|
||||||
|
convneedkey(c, a);
|
||||||
|
|
||||||
|
for(i=0; i<ring.nkey; i++){
|
||||||
|
k = ring.key[i];
|
||||||
|
if(k->tag <= tag)
|
||||||
|
continue;
|
||||||
|
if(matchattr(a, k->attr, k->privattr)){
|
||||||
|
k->ref++;
|
||||||
|
if(strfindattr(k->attr, "confirm") && confirmkey(c, k) != 1){
|
||||||
|
k->ref--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
freeattr(a);
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
freeattr(a);
|
||||||
|
werrstr("no key found");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int taggen;
|
||||||
|
|
||||||
|
void
|
||||||
|
keyadd(Key *k)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
k->ref++;
|
||||||
|
k->tag = ++taggen;
|
||||||
|
for(i=0; i<ring.nkey; i++){
|
||||||
|
if(matchattr(k->attr, ring.key[i]->attr, nil)
|
||||||
|
&& matchattr(ring.key[i]->attr, k->attr, nil)){
|
||||||
|
keyclose(ring.key[i]);
|
||||||
|
ring.key[i] = k;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ring.key = erealloc(ring.key, (ring.nkey+1)*sizeof(ring.key[0]));
|
||||||
|
ring.key[ring.nkey++] = k;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
keyclose(Key *k)
|
||||||
|
{
|
||||||
|
if(k == nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(--k->ref > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(k->proto->closekey)
|
||||||
|
(*k->proto->closekey)(k);
|
||||||
|
|
||||||
|
freeattr(k->attr);
|
||||||
|
freeattr(k->privattr);
|
||||||
|
free(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
Key*
|
||||||
|
keyreplace(Conv *c, Key *k, char *fmt, ...)
|
||||||
|
{
|
||||||
|
Key *kk;
|
||||||
|
char *msg;
|
||||||
|
Attr *a, *b, *bp;
|
||||||
|
va_list arg;
|
||||||
|
|
||||||
|
va_start(arg, fmt);
|
||||||
|
msg = vsmprint(fmt, arg);
|
||||||
|
if(msg == nil)
|
||||||
|
sysfatal("out of memory");
|
||||||
|
va_end(arg);
|
||||||
|
|
||||||
|
/* replace prompted values with prompts */
|
||||||
|
a = copyattr(k->attr);
|
||||||
|
bp = parseattr(k->proto->keyprompt);
|
||||||
|
for(b=bp; b; b=b->next){
|
||||||
|
a = delattr(a, b->name);
|
||||||
|
a = addattr(a, "%q?", b->name);
|
||||||
|
}
|
||||||
|
freeattr(bp);
|
||||||
|
|
||||||
|
if(badkey(c, k, msg, a) < 0)
|
||||||
|
convbadkey(c, k, msg, a);
|
||||||
|
kk = keylookup("%A", a);
|
||||||
|
freeattr(a);
|
||||||
|
keyclose(k);
|
||||||
|
if(kk == k){
|
||||||
|
keyclose(kk);
|
||||||
|
werrstr("%s", msg);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strfindattr(kk->attr, "confirm")){
|
||||||
|
if(confirmkey(c, kk) != 1){
|
||||||
|
werrstr("key use not confirmed");
|
||||||
|
keyclose(kk);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return kk;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
keyevict(Conv *c, Key *k, char *fmt, ...)
|
||||||
|
{
|
||||||
|
char *msg;
|
||||||
|
Attr *a, *b, *bp;
|
||||||
|
va_list arg;
|
||||||
|
|
||||||
|
va_start(arg, fmt);
|
||||||
|
msg = vsmprint(fmt, arg);
|
||||||
|
if(msg == nil)
|
||||||
|
sysfatal("out of memory");
|
||||||
|
va_end(arg);
|
||||||
|
|
||||||
|
/* replace prompted values with prompts */
|
||||||
|
a = copyattr(k->attr);
|
||||||
|
bp = parseattr(k->proto->keyprompt);
|
||||||
|
for(b=bp; b; b=b->next){
|
||||||
|
a = delattr(a, b->name);
|
||||||
|
a = addattr(a, "%q?", b->name);
|
||||||
|
}
|
||||||
|
freeattr(bp);
|
||||||
|
|
||||||
|
if(badkey(c, k, msg, nil) < 0)
|
||||||
|
convbadkey(c, k, msg, nil);
|
||||||
|
keyclose(k);
|
||||||
|
}
|
||||||
121
src/cmd/factotum/log.c
Normal file
121
src/cmd/factotum/log.c
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
#include "std.h"
|
||||||
|
#include "dat.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
lbkick(Logbuf *lb)
|
||||||
|
{
|
||||||
|
char *s;
|
||||||
|
int n;
|
||||||
|
Req *r;
|
||||||
|
|
||||||
|
while(lb->wait && lb->rp != lb->wp){
|
||||||
|
r = lb->wait;
|
||||||
|
lb->wait = r->aux;
|
||||||
|
if(lb->wait == nil)
|
||||||
|
lb->waitlast = &lb->wait;
|
||||||
|
r->aux = nil;
|
||||||
|
if(r->ifcall.count < 5){
|
||||||
|
respond(r, "factotum: read request count too short");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
s = lb->msg[lb->rp];
|
||||||
|
lb->msg[lb->rp] = nil;
|
||||||
|
if(++lb->rp == nelem(lb->msg))
|
||||||
|
lb->rp = 0;
|
||||||
|
n = r->ifcall.count;
|
||||||
|
if(n < strlen(s)+1+1){
|
||||||
|
memmove(r->ofcall.data, s, n-5);
|
||||||
|
n -= 5;
|
||||||
|
r->ofcall.data[n] = '\0';
|
||||||
|
/* look for first byte of UTF-8 sequence by skipping continuation bytes */
|
||||||
|
while(n>0 && (r->ofcall.data[--n]&0xC0)==0x80)
|
||||||
|
;
|
||||||
|
strcpy(r->ofcall.data+n, "...\n");
|
||||||
|
}else{
|
||||||
|
strcpy(r->ofcall.data, s);
|
||||||
|
strcat(r->ofcall.data, "\n");
|
||||||
|
}
|
||||||
|
r->ofcall.count = strlen(r->ofcall.data);
|
||||||
|
free(s);
|
||||||
|
respond(r, nil);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lbread(Logbuf *lb, Req *r)
|
||||||
|
{
|
||||||
|
if(lb->waitlast == nil)
|
||||||
|
lb->waitlast = &lb->wait;
|
||||||
|
*(lb->waitlast) = r;
|
||||||
|
lb->waitlast = (Req**)&r->aux;
|
||||||
|
r->aux = nil;
|
||||||
|
lbkick(lb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lbflush(Logbuf *lb, Req *r)
|
||||||
|
{
|
||||||
|
Req **l;
|
||||||
|
|
||||||
|
for(l=&lb->wait; *l; l=(Req**)&(*l)->aux){
|
||||||
|
if(*l == r){
|
||||||
|
*l = r->aux;
|
||||||
|
r->aux = nil;
|
||||||
|
if(*l == nil)
|
||||||
|
lb->waitlast = l;
|
||||||
|
closereq(r);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lbappend(Logbuf *lb, char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list arg;
|
||||||
|
|
||||||
|
va_start(arg, fmt);
|
||||||
|
lbvappend(lb, fmt, arg);
|
||||||
|
va_end(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lbvappend(Logbuf *lb, char *fmt, va_list arg)
|
||||||
|
{
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
s = smprint(fmt, arg);
|
||||||
|
if(s == nil)
|
||||||
|
sysfatal("out of memory");
|
||||||
|
if(lb->msg[lb->wp])
|
||||||
|
free(lb->msg[lb->wp]);
|
||||||
|
lb->msg[lb->wp] = s;
|
||||||
|
if(++lb->wp == nelem(lb->msg))
|
||||||
|
lb->wp = 0;
|
||||||
|
lbkick(lb);
|
||||||
|
}
|
||||||
|
|
||||||
|
Logbuf logbuf;
|
||||||
|
|
||||||
|
void
|
||||||
|
logread(Req *r)
|
||||||
|
{
|
||||||
|
lbread(&logbuf, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
logflush(Req *r)
|
||||||
|
{
|
||||||
|
lbflush(&logbuf, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
flog(char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list arg;
|
||||||
|
|
||||||
|
va_start(arg, fmt);
|
||||||
|
lbvappend(&logbuf, fmt, arg);
|
||||||
|
va_end(arg);
|
||||||
|
}
|
||||||
|
|
||||||
163
src/cmd/factotum/main.c
Normal file
163
src/cmd/factotum/main.c
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
#include "std.h"
|
||||||
|
#include "dat.h"
|
||||||
|
|
||||||
|
int debug;
|
||||||
|
char *factname = "factotum";
|
||||||
|
char *service = nil;
|
||||||
|
char *owner;
|
||||||
|
char *authaddr;
|
||||||
|
void gflag(char*);
|
||||||
|
|
||||||
|
void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
fprint(2, "usage: factotum [-Dd] [-a authaddr] [-m mtpt]\n");
|
||||||
|
fprint(2, " or factotum -g keypattern\n");
|
||||||
|
fprint(2, " or factotum -g 'badkeyattr\nmsg\nkeypattern'");
|
||||||
|
exits("usage");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
threadmain(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
char *mtpt;
|
||||||
|
|
||||||
|
mtpt = "/mnt";
|
||||||
|
owner = getuser();
|
||||||
|
quotefmtinstall();
|
||||||
|
fmtinstall('A', attrfmt);
|
||||||
|
fmtinstall('H', encodefmt);
|
||||||
|
fmtinstall('N', attrnamefmt);
|
||||||
|
|
||||||
|
if(argc == 3 && strcmp(argv[1], "-g") == 0){
|
||||||
|
gflag(argv[2]);
|
||||||
|
exits(nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
ARGBEGIN{
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
case 'D':
|
||||||
|
chatty9p++;
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
authaddr = EARGF(usage());
|
||||||
|
break;
|
||||||
|
case 'g':
|
||||||
|
usage();
|
||||||
|
case 'm':
|
||||||
|
mtpt = EARGF(usage());
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
service = EARGF(usage());
|
||||||
|
break;
|
||||||
|
}ARGEND
|
||||||
|
|
||||||
|
if(argc != 0)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
threadpostmountsrv(&fs, service, mtpt, MBEFORE);
|
||||||
|
threadexits(nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* prompt user for a key. don't care about memory leaks, runs standalone
|
||||||
|
*/
|
||||||
|
static Attr*
|
||||||
|
promptforkey(int fd, char *params)
|
||||||
|
{
|
||||||
|
char *v;
|
||||||
|
Attr *a, *attr;
|
||||||
|
char *def;
|
||||||
|
|
||||||
|
attr = _parseattr(params);
|
||||||
|
fprint(fd, "!adding key:");
|
||||||
|
for(a=attr; a; a=a->next)
|
||||||
|
if(a->type != AttrQuery && a->name[0] != '!')
|
||||||
|
fprint(fd, " %q=%q", a->name, a->val);
|
||||||
|
fprint(fd, "\n");
|
||||||
|
|
||||||
|
for(a=attr; a; a=a->next){
|
||||||
|
v = a->name;
|
||||||
|
if(a->type != AttrQuery || v[0]=='!')
|
||||||
|
continue;
|
||||||
|
def = nil;
|
||||||
|
if(strcmp(v, "user") == 0)
|
||||||
|
def = getuser();
|
||||||
|
a->val = readcons(v, def, 0);
|
||||||
|
if(a->val == nil)
|
||||||
|
sysfatal("user terminated key input");
|
||||||
|
a->type = AttrNameval;
|
||||||
|
}
|
||||||
|
for(a=attr; a; a=a->next){
|
||||||
|
v = a->name;
|
||||||
|
if(a->type != AttrQuery || v[0]!='!')
|
||||||
|
continue;
|
||||||
|
def = nil;
|
||||||
|
if(strcmp(v+1, "user") == 0)
|
||||||
|
def = getuser();
|
||||||
|
a->val = readcons(v+1, def, 1);
|
||||||
|
if(a->val == nil)
|
||||||
|
sysfatal("user terminated key input");
|
||||||
|
a->type = AttrNameval;
|
||||||
|
}
|
||||||
|
fprint(fd, "!\n");
|
||||||
|
close(fd);
|
||||||
|
return attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* send a key to the mounted factotum
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
sendkey(Attr *attr)
|
||||||
|
{
|
||||||
|
int fd, rv;
|
||||||
|
char buf[1024];
|
||||||
|
|
||||||
|
fd = open("/mnt/factotum/ctl", ORDWR);
|
||||||
|
if(fd < 0)
|
||||||
|
sysfatal("opening /mnt/factotum/ctl: %r");
|
||||||
|
rv = fprint(fd, "key %A\n", attr);
|
||||||
|
read(fd, buf, sizeof buf);
|
||||||
|
close(fd);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
askuser(int fd, char *params)
|
||||||
|
{
|
||||||
|
Attr *attr;
|
||||||
|
|
||||||
|
attr = promptforkey(fd, params);
|
||||||
|
if(attr == nil)
|
||||||
|
sysfatal("no key supplied");
|
||||||
|
if(sendkey(attr) < 0)
|
||||||
|
sysfatal("sending key to factotum: %r");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gflag(char *s)
|
||||||
|
{
|
||||||
|
char *f[4];
|
||||||
|
int nf;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if((fd = open("/dev/cons", ORDWR)) < 0)
|
||||||
|
sysfatal("open /dev/cons: %r");
|
||||||
|
|
||||||
|
nf = getfields(s, f, nelem(f), 0, "\n");
|
||||||
|
if(nf == 1){ /* needkey or old badkey */
|
||||||
|
fprint(fd, "\n");
|
||||||
|
askuser(fd, s);
|
||||||
|
exits(nil);
|
||||||
|
}
|
||||||
|
if(nf == 3){ /* new badkey */
|
||||||
|
fprint(fd, "\n");
|
||||||
|
fprint(fd, "!replace: %s\n", f[0]);
|
||||||
|
fprint(fd, "!because: %s\n", f[1]);
|
||||||
|
askuser(fd, f[2]);
|
||||||
|
exits(nil);
|
||||||
|
}
|
||||||
|
usage();
|
||||||
|
}
|
||||||
34
src/cmd/factotum/mkfile
Normal file
34
src/cmd/factotum/mkfile
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
PLAN9=../../..
|
||||||
|
<$PLAN9/src/mkhdr
|
||||||
|
|
||||||
|
TARG=factotum
|
||||||
|
PROTO=\
|
||||||
|
apop.$O\
|
||||||
|
chap.$O\
|
||||||
|
p9any.$O\
|
||||||
|
p9sk1.$O\
|
||||||
|
|
||||||
|
OFILES=\
|
||||||
|
$PROTO\
|
||||||
|
attr.$O\
|
||||||
|
confirm.$O\
|
||||||
|
conv.$O\
|
||||||
|
ctl.$O\
|
||||||
|
fs.$O\
|
||||||
|
key.$O\
|
||||||
|
log.$O\
|
||||||
|
main.$O\
|
||||||
|
plan9.$O\
|
||||||
|
proto.$O\
|
||||||
|
rpc.$O\
|
||||||
|
util.$O\
|
||||||
|
xio.$O\
|
||||||
|
|
||||||
|
HFILES=dat.h
|
||||||
|
|
||||||
|
SHORTLIB=auth authsrv sec mp 9p thread 9
|
||||||
|
<$PLAN9/src/mkone
|
||||||
|
|
||||||
|
$O.test: test.$O
|
||||||
|
$LD -o $target $prereq
|
||||||
|
|
||||||
266
src/cmd/factotum/p9any.c
Normal file
266
src/cmd/factotum/p9any.c
Normal file
@ -0,0 +1,266 @@
|
|||||||
|
#include "std.h"
|
||||||
|
#include "dat.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* p9any - protocol negotiator
|
||||||
|
*
|
||||||
|
* Protocol:
|
||||||
|
* S->C: v.2 proto@dom proto@dom proto@dom... NUL
|
||||||
|
* C->S: proto dom NUL
|
||||||
|
* [negotiated proto continues]
|
||||||
|
*/
|
||||||
|
|
||||||
|
static Proto* okproto[] =
|
||||||
|
{
|
||||||
|
&p9sk1,
|
||||||
|
nil,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
rolecall(Role *r, char *name, Conv *c)
|
||||||
|
{
|
||||||
|
for(; r->name; r++)
|
||||||
|
if(strcmp(r->name, name) == 0)
|
||||||
|
return (*r->fn)(c);
|
||||||
|
werrstr("unknown role");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hasnul(void *v, int n)
|
||||||
|
{
|
||||||
|
char *c;
|
||||||
|
|
||||||
|
c = v;
|
||||||
|
if(n > 0 && c[n-1] == '\0')
|
||||||
|
return n;
|
||||||
|
else
|
||||||
|
return n+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
p9anyserver(Conv *c)
|
||||||
|
{
|
||||||
|
char *s, *dom;
|
||||||
|
int i, j, n, m, ret;
|
||||||
|
char *tok[3];
|
||||||
|
Attr *attr;
|
||||||
|
Key *k;
|
||||||
|
|
||||||
|
ret = -1;
|
||||||
|
s = estrdup("v.2");
|
||||||
|
n = 0;
|
||||||
|
attr = delattr(copyattr(c->attr), "proto");
|
||||||
|
|
||||||
|
for(i=0; i<ring.nkey; i++){
|
||||||
|
k = ring.key[i];
|
||||||
|
for(j=0; okproto[j]; j++)
|
||||||
|
if(k->proto == okproto[j]
|
||||||
|
&& (dom = strfindattr(k->attr, "dom")) != nil
|
||||||
|
&& matchattr(attr, k->attr, k->privattr)){
|
||||||
|
s = estrappend(s, " %s@%s", k->proto->name, dom);
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(n == 0){
|
||||||
|
werrstr("no valid keys");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->state = "write offer";
|
||||||
|
if(convwrite(c, s, strlen(s)+1) < 0)
|
||||||
|
goto out;
|
||||||
|
free(s);
|
||||||
|
s = nil;
|
||||||
|
|
||||||
|
c->state = "read choice";
|
||||||
|
if(convreadfn(c, hasnul, &s) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
m = tokenize(s, tok, nelem(tok));
|
||||||
|
if(m != 2){
|
||||||
|
werrstr("bad protocol message");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i=0; okproto[i]; i++)
|
||||||
|
if(strcmp(okproto[i]->name, tok[0]) == 0)
|
||||||
|
break;
|
||||||
|
if(!okproto[i]){
|
||||||
|
werrstr("bad chosen protocol %q", tok[0]);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->state = "write ok";
|
||||||
|
if(convwrite(c, "OK\0", 3) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
c->state = "start choice";
|
||||||
|
attr = addattr(attr, "proto=%q dom=%q", tok[0], tok[1]);
|
||||||
|
free(c->attr);
|
||||||
|
c->attr = attr;
|
||||||
|
attr = nil;
|
||||||
|
c->proto = okproto[i];
|
||||||
|
|
||||||
|
if(rolecall(c->proto->roles, "server", c) < 0){
|
||||||
|
werrstr("%s: %r", tok[0]);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(s);
|
||||||
|
freeattr(attr);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
p9anyclient(Conv *c)
|
||||||
|
{
|
||||||
|
char *s, **f, *tok[20], ok[3], *q, *user, *dom;
|
||||||
|
int i, n, ret, version;
|
||||||
|
Key *k;
|
||||||
|
Attr *attr;
|
||||||
|
Proto *p;
|
||||||
|
|
||||||
|
ret = -1;
|
||||||
|
s = nil;
|
||||||
|
k = nil;
|
||||||
|
|
||||||
|
user = strfindattr(c->attr, "user");
|
||||||
|
dom = strfindattr(c->attr, "dom");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if the user is the factotum owner, any key will do.
|
||||||
|
* if not, then if we have a speakfor key,
|
||||||
|
* we will only vouch for the user's local identity.
|
||||||
|
*
|
||||||
|
* this logic is duplicated in p9sk1.c
|
||||||
|
*/
|
||||||
|
attr = delattr(copyattr(c->attr), "role");
|
||||||
|
attr = delattr(attr, "proto");
|
||||||
|
if(strcmp(c->sysuser, owner) == 0)
|
||||||
|
attr = addattr(attr, "role=client");
|
||||||
|
else if(user==nil || strcmp(c->sysuser, user)==0){
|
||||||
|
attr = delattr(attr, "user");
|
||||||
|
attr = addattr(attr, "role=speakfor");
|
||||||
|
}else{
|
||||||
|
werrstr("will not authenticate for %q as %q", c->sysuser, user);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->state = "read offer";
|
||||||
|
if(convreadfn(c, hasnul, &s) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
c->state = "look for keys";
|
||||||
|
n = tokenize(s, tok, nelem(tok));
|
||||||
|
f = tok;
|
||||||
|
version = 1;
|
||||||
|
if(n > 0 && memcmp(f[0], "v.", 2) == 0){
|
||||||
|
version = atoi(f[0]+2);
|
||||||
|
if(version != 2){
|
||||||
|
werrstr("unknown p9any version: %s", f[0]);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
f++;
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* look for keys that don't need confirmation */
|
||||||
|
for(i=0; i<n; i++){
|
||||||
|
if((q = strchr(f[i], '@')) == nil)
|
||||||
|
continue;
|
||||||
|
if(dom && strcmp(q+1, dom) != 0)
|
||||||
|
continue;
|
||||||
|
*q++ = '\0';
|
||||||
|
if((k = keylookup("%A proto=%q dom=%q", attr, f[i], q))
|
||||||
|
&& strfindattr(k->attr, "confirm") == nil)
|
||||||
|
goto found;
|
||||||
|
*--q = '@';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* look for any keys at all */
|
||||||
|
for(i=0; i<n; i++){
|
||||||
|
if((q = strchr(f[i], '@')) == nil)
|
||||||
|
continue;
|
||||||
|
if(dom && strcmp(q+1, dom) != 0)
|
||||||
|
continue;
|
||||||
|
*q++ = '\0';
|
||||||
|
if(k = keyfetch(c, "%A proto=%q dom=%q", attr, f[i], q))
|
||||||
|
goto found;
|
||||||
|
*--q = '@';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ask for new keys */
|
||||||
|
c->state = "ask for keys";
|
||||||
|
for(i=0; i<n; i++){
|
||||||
|
if((q = strchr(f[i], '@')) == nil)
|
||||||
|
continue;
|
||||||
|
if(dom && strcmp(q+1, dom) != 0)
|
||||||
|
continue;
|
||||||
|
*q++ = '\0';
|
||||||
|
p = protolookup(f[i]);
|
||||||
|
if(p == nil || p->keyprompt == nil){
|
||||||
|
*--q = '@';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(k = keyfetch(c, "%A proto=%q dom=%q %s", attr, f[i], q, p->keyprompt))
|
||||||
|
goto found;
|
||||||
|
*--q = '@';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* nothing worked */
|
||||||
|
werrstr("unable to find common key");
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
found:
|
||||||
|
/* f[i] is the chosen protocol, q the chosen domain */
|
||||||
|
attr = addattr(attr, "proto=%q dom=%q", f[i], q);
|
||||||
|
c->state = "write choice";
|
||||||
|
/* have a key: go for it */
|
||||||
|
if(convprint(c, "%q %q", f[i], q) < 0
|
||||||
|
|| convwrite(c, "\0", 1) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if(version == 2){
|
||||||
|
c->state = "read ok";
|
||||||
|
if(convread(c, ok, 3) < 0 || memcmp(ok, "OK\0", 3) != 0)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->state = "start choice";
|
||||||
|
c->proto = protolookup(f[i]);
|
||||||
|
freeattr(c->attr);
|
||||||
|
c->attr = attr;
|
||||||
|
attr = nil;
|
||||||
|
|
||||||
|
if(rolecall(c->proto->roles, "client", c) < 0){
|
||||||
|
werrstr("%s: %r", c->proto->name);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
keyclose(k);
|
||||||
|
freeattr(attr);
|
||||||
|
free(s);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Role
|
||||||
|
p9anyroles[] =
|
||||||
|
{
|
||||||
|
"client", p9anyclient,
|
||||||
|
"server", p9anyserver,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
Proto p9any = {
|
||||||
|
.name= "p9any",
|
||||||
|
.roles= p9anyroles,
|
||||||
|
};
|
||||||
|
|
||||||
545
src/cmd/factotum/p9cr.c
Normal file
545
src/cmd/factotum/p9cr.c
Normal file
@ -0,0 +1,545 @@
|
|||||||
|
/*
|
||||||
|
* p9cr, vnc - one-sided challenge/response authentication
|
||||||
|
*
|
||||||
|
* Protocol:
|
||||||
|
*
|
||||||
|
* C -> S: user
|
||||||
|
* S -> C: challenge
|
||||||
|
* C -> S: response
|
||||||
|
* S -> C: ok or bad
|
||||||
|
*
|
||||||
|
* Note that this is the protocol between factotum and the local
|
||||||
|
* program, not between the two factotums. The information
|
||||||
|
* exchanged here is wrapped in other protocols by the local
|
||||||
|
* programs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "std.h"
|
||||||
|
#include "dat.h"
|
||||||
|
|
||||||
|
static int
|
||||||
|
p9crcheck(Key *k)
|
||||||
|
{
|
||||||
|
if(!strfindattr(k->attr, "user") || !strfindattr(k->privattr, "!password")){
|
||||||
|
werrstr("need user and !password attributes");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
p9crclient(Conv *c)
|
||||||
|
{
|
||||||
|
char *chal, *pw, *res, *user;
|
||||||
|
int astype, nchal, npw, ntry, ret;
|
||||||
|
uchar resp[MD5dlen];
|
||||||
|
Attr *attr;
|
||||||
|
DigestState *ds;
|
||||||
|
Key *k;
|
||||||
|
|
||||||
|
chal = nil;
|
||||||
|
k = nil;
|
||||||
|
res = nil;
|
||||||
|
ret = -1;
|
||||||
|
attr = c->attr;
|
||||||
|
|
||||||
|
if(c->proto == &p9cr){
|
||||||
|
astype = AuthChal;
|
||||||
|
challen = NETCHLEN;
|
||||||
|
}else if(c->proto == &vnc){
|
||||||
|
astype = AuthVnc;
|
||||||
|
challen = MAXCHAL;
|
||||||
|
}else{
|
||||||
|
werrstr("bad proto");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->state = "find key";
|
||||||
|
k = keyfetch(c, "%A %s", attr, c->proto->keyprompt);
|
||||||
|
if(k == nil)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
for(ntry=1;; ntry++){
|
||||||
|
if(c->attr != attr)
|
||||||
|
freeattr(c->attr);
|
||||||
|
c->attr = addattrs(copyattr(attr), k->attr);
|
||||||
|
if((pw = strfindattr(k->privattr, "!password")) == nil){
|
||||||
|
werrstr("key has no !password (cannot happen)");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
npw = strlen(pw);
|
||||||
|
|
||||||
|
if((user = strfindattr(k->attr, "user")) == nil){
|
||||||
|
werrstr("key has no user (cannot happen)");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(convprint(c, "%s", user) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if(convreadm(c, &chal) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if((nresp = (*response)(chal, resp)) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if(convwrite(c, resp, nresp) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if(convreadm(c, &res) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if(strcmp(res, "ok") == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if((k = keyreplace(c, k, "%s", res)) == nil){
|
||||||
|
c->state = "auth failed";
|
||||||
|
werrstr("%s", res);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
werrstr("succeeded");
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
keyclose(k);
|
||||||
|
free(chal);
|
||||||
|
if(c->attr != attr)
|
||||||
|
freeattr(attr);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
p9crserver(Conv *c)
|
||||||
|
{
|
||||||
|
char chal[APOPCHALLEN], *user, *resp;
|
||||||
|
ServerState s;
|
||||||
|
int astype, ret;
|
||||||
|
Attr *a;
|
||||||
|
|
||||||
|
ret = -1;
|
||||||
|
user = nil;
|
||||||
|
resp = nil;
|
||||||
|
memset(&s, 0, sizeof s);
|
||||||
|
s.asfd = -1;
|
||||||
|
|
||||||
|
if(c->proto == &apop)
|
||||||
|
astype = AuthApop;
|
||||||
|
else if(c->proto == &cram)
|
||||||
|
astype = AuthCram;
|
||||||
|
else{
|
||||||
|
werrstr("bad proto");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->state = "find key";
|
||||||
|
if((s.k = plan9authkey(c->attr)) == nil)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
a = copyattr(s.k->attr);
|
||||||
|
a = delattr(a, "proto");
|
||||||
|
c->attr = addattrs(c->attr, a);
|
||||||
|
freeattr(a);
|
||||||
|
|
||||||
|
c->state = "authdial";
|
||||||
|
s.hostid = strfindattr(s.k->attr, "user");
|
||||||
|
s.dom = strfindattr(s.k->attr, "dom");
|
||||||
|
if((s.asfd = xioauthdial(nil, s.dom)) < 0){
|
||||||
|
werrstr("authdial %s: %r", s.dom);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->state = "authchal";
|
||||||
|
if(p9crchal(&s, astype, chal) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
c->state = "write challenge";
|
||||||
|
if(convprint(c, "%s", chal) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
for(;;){
|
||||||
|
c->state = "read user";
|
||||||
|
if(convreadm(c, &user) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
c->state = "read response";
|
||||||
|
if(convreadm(c, &resp) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
c->state = "authwrite";
|
||||||
|
switch(apopresp(&s, user, resp)){
|
||||||
|
case -1:
|
||||||
|
goto out;
|
||||||
|
case 0:
|
||||||
|
c->state = "write status";
|
||||||
|
if(convprint(c, "bad authentication failed") < 0)
|
||||||
|
goto out;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
c->state = "write status";
|
||||||
|
if(convprint(c, "ok") < 0)
|
||||||
|
goto out;
|
||||||
|
goto ok;
|
||||||
|
}
|
||||||
|
free(user);
|
||||||
|
free(resp);
|
||||||
|
user = nil;
|
||||||
|
resp = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok:
|
||||||
|
ret = 0;
|
||||||
|
c->attr = addcap(c->attr, c->sysuser, &s.t);
|
||||||
|
|
||||||
|
out:
|
||||||
|
keyclose(s.k);
|
||||||
|
free(user);
|
||||||
|
free(resp);
|
||||||
|
// xioclose(s.asfd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
MAXCHAL = 64,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct State State;
|
||||||
|
struct State
|
||||||
|
{
|
||||||
|
Key *key;
|
||||||
|
int astype;
|
||||||
|
int asfd;
|
||||||
|
Ticket t;
|
||||||
|
Ticketreq tr;
|
||||||
|
char chal[MAXCHAL];
|
||||||
|
int challen;
|
||||||
|
char resp[MAXCHAL];
|
||||||
|
int resplen;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CNeedChal,
|
||||||
|
CHaveResp,
|
||||||
|
|
||||||
|
SHaveChal,
|
||||||
|
SNeedResp,
|
||||||
|
|
||||||
|
Maxphase,
|
||||||
|
};
|
||||||
|
|
||||||
|
static char *phasenames[Maxphase] =
|
||||||
|
{
|
||||||
|
[CNeedChal] "CNeedChal",
|
||||||
|
[CHaveResp] "CHaveResp",
|
||||||
|
|
||||||
|
[SHaveChal] "SHaveChal",
|
||||||
|
[SNeedResp] "SNeedResp",
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
p9crclose(Fsstate *fss)
|
||||||
|
{
|
||||||
|
State *s;
|
||||||
|
|
||||||
|
s = fss->ps;
|
||||||
|
if(s->asfd >= 0){
|
||||||
|
close(s->asfd);
|
||||||
|
s->asfd = -1;
|
||||||
|
}
|
||||||
|
free(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getchal(State*, Fsstate*);
|
||||||
|
|
||||||
|
static int
|
||||||
|
p9crinit(Proto *p, Fsstate *fss)
|
||||||
|
{
|
||||||
|
int iscli, ret;
|
||||||
|
char *user;
|
||||||
|
State *s;
|
||||||
|
Attr *attr;
|
||||||
|
|
||||||
|
if((iscli = isclient(_str_findattr(fss->attr, "role"))) < 0)
|
||||||
|
return failure(fss, nil);
|
||||||
|
|
||||||
|
s = emalloc(sizeof(*s));
|
||||||
|
s->asfd = -1;
|
||||||
|
if(p == &p9cr){
|
||||||
|
s->astype = AuthChal;
|
||||||
|
s->challen = NETCHLEN;
|
||||||
|
}else if(p == &vnc){
|
||||||
|
s->astype = AuthVNC;
|
||||||
|
s->challen = Maxchal;
|
||||||
|
}else
|
||||||
|
abort();
|
||||||
|
|
||||||
|
if(iscli){
|
||||||
|
fss->phase = CNeedChal;
|
||||||
|
if(p == &p9cr)
|
||||||
|
attr = setattr(_copyattr(fss->attr), "proto=p9sk1");
|
||||||
|
else
|
||||||
|
attr = nil;
|
||||||
|
ret = findkey(&s->key, fss, Kuser, 0, attr ? attr : fss->attr,
|
||||||
|
"role=client %s", p->keyprompt);
|
||||||
|
_freeattr(attr);
|
||||||
|
if(ret != RpcOk){
|
||||||
|
free(s);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
fss->ps = s;
|
||||||
|
}else{
|
||||||
|
if((ret = findp9authkey(&s->key, fss)) != RpcOk){
|
||||||
|
free(s);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if((user = _str_findattr(fss->attr, "user")) == nil){
|
||||||
|
free(s);
|
||||||
|
return failure(fss, "no user name specified in start msg");
|
||||||
|
}
|
||||||
|
if(strlen(user) >= sizeof s->tr.uid){
|
||||||
|
free(s);
|
||||||
|
return failure(fss, "user name too long");
|
||||||
|
}
|
||||||
|
fss->ps = s;
|
||||||
|
strcpy(s->tr.uid, user);
|
||||||
|
ret = getchal(s, fss);
|
||||||
|
if(ret != RpcOk){
|
||||||
|
p9crclose(fss); /* frees s */
|
||||||
|
fss->ps = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fss->phasename = phasenames;
|
||||||
|
fss->maxphase = Maxphase;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
p9crread(Fsstate *fss, void *va, uint *n)
|
||||||
|
{
|
||||||
|
int m;
|
||||||
|
State *s;
|
||||||
|
|
||||||
|
s = fss->ps;
|
||||||
|
switch(fss->phase){
|
||||||
|
default:
|
||||||
|
return phaseerror(fss, "read");
|
||||||
|
|
||||||
|
case CHaveResp:
|
||||||
|
if(s->resplen < *n)
|
||||||
|
*n = s->resplen;
|
||||||
|
memmove(va, s->resp, *n);
|
||||||
|
fss->phase = Established;
|
||||||
|
return RpcOk;
|
||||||
|
|
||||||
|
case SHaveChal:
|
||||||
|
if(s->astype == AuthChal)
|
||||||
|
m = strlen(s->chal); /* ascii string */
|
||||||
|
else
|
||||||
|
m = s->challen; /* fixed length binary */
|
||||||
|
if(m > *n)
|
||||||
|
return toosmall(fss, m);
|
||||||
|
*n = m;
|
||||||
|
memmove(va, s->chal, m);
|
||||||
|
fss->phase = SNeedResp;
|
||||||
|
return RpcOk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
p9response(Fsstate *fss, State *s)
|
||||||
|
{
|
||||||
|
char key[DESKEYLEN];
|
||||||
|
uchar buf[8];
|
||||||
|
ulong chal;
|
||||||
|
char *pw;
|
||||||
|
|
||||||
|
pw = _str_findattr(s->key->privattr, "!password");
|
||||||
|
if(pw == nil)
|
||||||
|
return failure(fss, "vncresponse cannot happen");
|
||||||
|
passtokey(key, pw);
|
||||||
|
memset(buf, 0, 8);
|
||||||
|
sprint((char*)buf, "%d", atoi(s->chal));
|
||||||
|
if(encrypt(key, buf, 8) < 0)
|
||||||
|
return failure(fss, "can't encrypt response");
|
||||||
|
chal = (buf[0]<<24)+(buf[1]<<16)+(buf[2]<<8)+buf[3];
|
||||||
|
s->resplen = snprint(s->resp, sizeof s->resp, "%.8lux", chal);
|
||||||
|
return RpcOk;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uchar tab[256];
|
||||||
|
|
||||||
|
/* VNC reverses the bits of each byte before using as a des key */
|
||||||
|
static void
|
||||||
|
mktab(void)
|
||||||
|
{
|
||||||
|
int i, j, k;
|
||||||
|
static int once;
|
||||||
|
|
||||||
|
if(once)
|
||||||
|
return;
|
||||||
|
once = 1;
|
||||||
|
|
||||||
|
for(i=0; i<256; i++) {
|
||||||
|
j=i;
|
||||||
|
tab[i] = 0;
|
||||||
|
for(k=0; k<8; k++) {
|
||||||
|
tab[i] = (tab[i]<<1) | (j&1);
|
||||||
|
j >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
vncaddkey(Key *k)
|
||||||
|
{
|
||||||
|
uchar *p;
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
k->priv = emalloc(8+1);
|
||||||
|
if(s = _str_findattr(k->privattr, "!password")){
|
||||||
|
mktab();
|
||||||
|
memset(k->priv, 0, 8+1);
|
||||||
|
strncpy((char*)k->priv, s, 8);
|
||||||
|
for(p=k->priv; *p; p++)
|
||||||
|
*p = tab[*p];
|
||||||
|
}else{
|
||||||
|
werrstr("no key data");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return replacekey(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
vncclosekey(Key *k)
|
||||||
|
{
|
||||||
|
free(k->priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
vncresponse(Fsstate*, State *s)
|
||||||
|
{
|
||||||
|
DESstate des;
|
||||||
|
|
||||||
|
memmove(s->resp, s->chal, sizeof s->chal);
|
||||||
|
setupDESstate(&des, s->key->priv, nil);
|
||||||
|
desECBencrypt((uchar*)s->resp, s->challen, &des);
|
||||||
|
s->resplen = s->challen;
|
||||||
|
return RpcOk;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
p9crwrite(Fsstate *fss, void *va, uint n)
|
||||||
|
{
|
||||||
|
char tbuf[TICKETLEN+AUTHENTLEN];
|
||||||
|
State *s;
|
||||||
|
char *data = va;
|
||||||
|
Authenticator a;
|
||||||
|
char resp[Maxchal];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
s = fss->ps;
|
||||||
|
switch(fss->phase){
|
||||||
|
default:
|
||||||
|
return phaseerror(fss, "write");
|
||||||
|
|
||||||
|
case CNeedChal:
|
||||||
|
if(n >= sizeof(s->chal))
|
||||||
|
return failure(fss, Ebadarg);
|
||||||
|
memset(s->chal, 0, sizeof s->chal);
|
||||||
|
memmove(s->chal, data, n);
|
||||||
|
s->challen = n;
|
||||||
|
|
||||||
|
if(s->astype == AuthChal)
|
||||||
|
ret = p9response(fss, s);
|
||||||
|
else
|
||||||
|
ret = vncresponse(fss, s);
|
||||||
|
if(ret != RpcOk)
|
||||||
|
return ret;
|
||||||
|
fss->phase = CHaveResp;
|
||||||
|
return RpcOk;
|
||||||
|
|
||||||
|
case SNeedResp:
|
||||||
|
/* send response to auth server and get ticket */
|
||||||
|
if(n > sizeof(resp))
|
||||||
|
return failure(fss, Ebadarg);
|
||||||
|
memset(resp, 0, sizeof resp);
|
||||||
|
memmove(resp, data, n);
|
||||||
|
if(write(s->asfd, resp, s->challen) != s->challen)
|
||||||
|
return failure(fss, Easproto);
|
||||||
|
|
||||||
|
/* get ticket plus authenticator from auth server */
|
||||||
|
if(_asrdresp(s->asfd, tbuf, TICKETLEN+AUTHENTLEN) < 0)
|
||||||
|
return failure(fss, nil);
|
||||||
|
|
||||||
|
/* check ticket */
|
||||||
|
convM2T(tbuf, &s->t, s->key->priv);
|
||||||
|
if(s->t.num != AuthTs
|
||||||
|
|| memcmp(s->t.chal, s->tr.chal, sizeof(s->t.chal)) != 0)
|
||||||
|
return failure(fss, Easproto);
|
||||||
|
convM2A(tbuf+TICKETLEN, &a, s->t.key);
|
||||||
|
if(a.num != AuthAc
|
||||||
|
|| memcmp(a.chal, s->tr.chal, sizeof(a.chal)) != 0
|
||||||
|
|| a.id != 0)
|
||||||
|
return failure(fss, Easproto);
|
||||||
|
|
||||||
|
fss->haveai = 1;
|
||||||
|
fss->ai.cuid = s->t.cuid;
|
||||||
|
fss->ai.suid = s->t.suid;
|
||||||
|
fss->ai.nsecret = 0;
|
||||||
|
fss->ai.secret = nil;
|
||||||
|
fss->phase = Established;
|
||||||
|
return RpcOk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
getchal(State *s, Fsstate *fss)
|
||||||
|
{
|
||||||
|
char trbuf[TICKREQLEN];
|
||||||
|
int n;
|
||||||
|
|
||||||
|
safecpy(s->tr.hostid, _str_findattr(s->key->attr, "user"), sizeof(s->tr.hostid));
|
||||||
|
safecpy(s->tr.authdom, _str_findattr(s->key->attr, "dom"), sizeof(s->tr.authdom));
|
||||||
|
s->tr.type = s->astype;
|
||||||
|
convTR2M(&s->tr, trbuf);
|
||||||
|
|
||||||
|
/* get challenge from auth server */
|
||||||
|
s->asfd = _authdial(nil, _str_findattr(s->key->attr, "dom"));
|
||||||
|
if(s->asfd < 0)
|
||||||
|
return failure(fss, Easproto);
|
||||||
|
if(write(s->asfd, trbuf, TICKREQLEN) != TICKREQLEN)
|
||||||
|
return failure(fss, Easproto);
|
||||||
|
n = _asrdresp(s->asfd, s->chal, s->challen);
|
||||||
|
if(n <= 0){
|
||||||
|
if(n == 0)
|
||||||
|
werrstr("_asrdresp short read");
|
||||||
|
return failure(fss, nil);
|
||||||
|
}
|
||||||
|
s->challen = n;
|
||||||
|
fss->phase = SHaveChal;
|
||||||
|
return RpcOk;
|
||||||
|
}
|
||||||
|
|
||||||
|
Proto p9cr =
|
||||||
|
{
|
||||||
|
.name= "p9cr",
|
||||||
|
.init= p9crinit,
|
||||||
|
.write= p9crwrite,
|
||||||
|
.read= p9crread,
|
||||||
|
.close= p9crclose,
|
||||||
|
.keyprompt= "user? !password?",
|
||||||
|
};
|
||||||
|
|
||||||
|
Proto vnc =
|
||||||
|
{
|
||||||
|
.name= "vnc",
|
||||||
|
.init= p9crinit,
|
||||||
|
.write= p9crwrite,
|
||||||
|
.read= p9crread,
|
||||||
|
.close= p9crclose,
|
||||||
|
.keyprompt= "!password?",
|
||||||
|
.addkey= vncaddkey,
|
||||||
|
};
|
||||||
352
src/cmd/factotum/p9sk1.c
Normal file
352
src/cmd/factotum/p9sk1.c
Normal file
@ -0,0 +1,352 @@
|
|||||||
|
/*
|
||||||
|
* p9sk1, p9sk2 - Plan 9 secret (private) key authentication.
|
||||||
|
* p9sk2 is an incomplete flawed variant of p9sk1.
|
||||||
|
*
|
||||||
|
* Client protocol:
|
||||||
|
* write challenge[challen] (p9sk1 only)
|
||||||
|
* read tickreq[tickreqlen]
|
||||||
|
* write ticket[ticketlen]
|
||||||
|
* read authenticator[authentlen]
|
||||||
|
*
|
||||||
|
* Server protocol:
|
||||||
|
* read challenge[challen] (p9sk1 only)
|
||||||
|
* write tickreq[tickreqlen]
|
||||||
|
* read ticket[ticketlen]
|
||||||
|
* write authenticator[authentlen]
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "std.h"
|
||||||
|
#include "dat.h"
|
||||||
|
|
||||||
|
static int gettickets(Ticketreq*, char*, Key*);
|
||||||
|
|
||||||
|
#define max(a, b) ((a) > (b) ? (a) : (b))
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
MAXAUTH = max(TICKREQLEN, TICKETLEN+max(TICKETLEN, AUTHENTLEN))
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
p9skclient(Conv *c)
|
||||||
|
{
|
||||||
|
char *user;
|
||||||
|
char cchal[CHALLEN];
|
||||||
|
uchar secret[8];
|
||||||
|
char buf[MAXAUTH];
|
||||||
|
int speakfor, ret;
|
||||||
|
Attr *a;
|
||||||
|
Authenticator au;
|
||||||
|
Key *k;
|
||||||
|
Ticket t;
|
||||||
|
Ticketreq tr;
|
||||||
|
|
||||||
|
ret = -1;
|
||||||
|
a = nil;
|
||||||
|
k = nil;
|
||||||
|
|
||||||
|
/* p9sk1: send client challenge */
|
||||||
|
if(c->proto == &p9sk1){
|
||||||
|
c->state = "write challenge";
|
||||||
|
memrandom(cchal, CHALLEN);
|
||||||
|
if(convwrite(c, cchal, CHALLEN) < 0)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read ticket request */
|
||||||
|
c->state = "read tickreq";
|
||||||
|
if(convread(c, buf, TICKREQLEN) < 0)
|
||||||
|
goto out;
|
||||||
|
convM2TR(buf, &tr);
|
||||||
|
|
||||||
|
/* p9sk2: use server challenge as client challenge */
|
||||||
|
if(c->proto == &p9sk2)
|
||||||
|
memmove(cchal, tr.chal, CHALLEN);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* find a key.
|
||||||
|
*
|
||||||
|
* if the user is the factotum owner, any key will do.
|
||||||
|
* if not, then if we have a speakfor key,
|
||||||
|
* we will only vouch for the user's local identity.
|
||||||
|
*
|
||||||
|
* this logic is duplicated in p9any.c
|
||||||
|
*/
|
||||||
|
user = strfindattr(c->attr, "user");
|
||||||
|
a = delattr(copyattr(c->attr), "role");
|
||||||
|
a = addattr(a, "proto=p9sk1");
|
||||||
|
|
||||||
|
if(strcmp(c->sysuser, owner) == 0){
|
||||||
|
speakfor = 0;
|
||||||
|
a = addattr(a, "proto=p9sk1 user? dom=%q", tr.authdom);
|
||||||
|
}else if(user==nil || strcmp(c->sysuser, user)==0){
|
||||||
|
speakfor = 1;
|
||||||
|
a = delattr(a, "user");
|
||||||
|
a = addattr(a, "proto=p9sk1 user? dom=%q role=speakfor", tr.authdom);
|
||||||
|
}else{
|
||||||
|
werrstr("will not authenticate for %q as %q", c->sysuser, user);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(;;){
|
||||||
|
c->state = "find key";
|
||||||
|
k = keyfetch(c, "%A", a);
|
||||||
|
if(k == nil)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* relay ticket request to auth server, get tickets */
|
||||||
|
strcpy(tr.hostid, strfindattr(k->attr, "user"));
|
||||||
|
if(speakfor)
|
||||||
|
strcpy(tr.uid, c->sysuser);
|
||||||
|
else
|
||||||
|
strcpy(tr.uid, tr.hostid);
|
||||||
|
|
||||||
|
c->state = "get tickets";
|
||||||
|
if(gettickets(&tr, buf, k) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
convM2T(buf, &t, k->priv);
|
||||||
|
if(t.num == AuthTc)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* we don't agree with the auth server about the key; try again */
|
||||||
|
c->state = "replace key";
|
||||||
|
if((k = keyreplace(c, k, "key mismatch with auth server")) == nil){
|
||||||
|
werrstr("key mismatch with auth server");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* send second ticket and authenticator to server */
|
||||||
|
c->state = "write ticket+auth";
|
||||||
|
memmove(buf, buf+TICKETLEN, TICKETLEN);
|
||||||
|
au.num = AuthAc;
|
||||||
|
memmove(au.chal, tr.chal, CHALLEN);
|
||||||
|
au.id = 0;
|
||||||
|
convA2M(&au, buf+TICKETLEN, t.key);
|
||||||
|
if(convwrite(c, buf, TICKETLEN+AUTHENTLEN) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* read authenticator from server */
|
||||||
|
c->state = "read auth";
|
||||||
|
if(convread(c, buf, AUTHENTLEN) < 0)
|
||||||
|
goto out;
|
||||||
|
convM2A(buf, &au, t.key);
|
||||||
|
if(au.num != AuthAs || memcmp(au.chal, cchal, CHALLEN) != 0 || au.id != 0){
|
||||||
|
werrstr("server lies through his teeth");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* success */
|
||||||
|
c->attr = addcap(c->attr, c->sysuser, &t);
|
||||||
|
des56to64((uchar*)t.key, secret);
|
||||||
|
c->attr = addattr(c->attr, "secret=%.8H", secret);
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
freeattr(a);
|
||||||
|
keyclose(k);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
p9skserver(Conv *c)
|
||||||
|
{
|
||||||
|
char cchal[CHALLEN], buf[MAXAUTH];
|
||||||
|
uchar secret[8];
|
||||||
|
int ret;
|
||||||
|
Attr *a;
|
||||||
|
Authenticator au;
|
||||||
|
Key *k;
|
||||||
|
Ticketreq tr;
|
||||||
|
Ticket t;
|
||||||
|
|
||||||
|
ret = -1;
|
||||||
|
|
||||||
|
a = addattr(copyattr(c->attr), "user? dom?");
|
||||||
|
a = addattr(a, "user? dom? proto=p9sk1");
|
||||||
|
if((k = keyfetch(c, "%A", a)) == nil)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* p9sk1: read client challenge */
|
||||||
|
if(c->proto == &p9sk1){
|
||||||
|
if(convread(c, cchal, CHALLEN) < 0)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* send ticket request */
|
||||||
|
memset(&tr, 0, sizeof tr);
|
||||||
|
tr.type = AuthTreq;
|
||||||
|
strcpy(tr.authid, strfindattr(k->attr, "user"));
|
||||||
|
strcpy(tr.authdom, strfindattr(k->attr, "dom"));
|
||||||
|
memrandom(tr.chal, sizeof tr.chal);
|
||||||
|
convTR2M(&tr, buf);
|
||||||
|
if(convwrite(c, buf, TICKREQLEN) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* p9sk2: use server challenge as client challenge */
|
||||||
|
if(c->proto == &p9sk2)
|
||||||
|
memmove(cchal, tr.chal, sizeof tr.chal);
|
||||||
|
|
||||||
|
/* read ticket+authenticator */
|
||||||
|
if(convread(c, buf, TICKETLEN+AUTHENTLEN) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
convM2T(buf, &t, k->priv);
|
||||||
|
if(t.num != AuthTs || memcmp(t.chal, tr.chal, CHALLEN) != 0){
|
||||||
|
/* BUG badkey */
|
||||||
|
werrstr("key mismatch with auth server");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
convM2A(buf+TICKETLEN, &au, t.key);
|
||||||
|
if(au.num != AuthAc || memcmp(au.chal, tr.chal, CHALLEN) != 0 || au.id != 0){
|
||||||
|
werrstr("client lies through his teeth");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* send authenticator */
|
||||||
|
au.num = AuthAs;
|
||||||
|
memmove(au.chal, cchal, CHALLEN);
|
||||||
|
convA2M(&au, buf, t.key);
|
||||||
|
if(convwrite(c, buf, AUTHENTLEN) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* success */
|
||||||
|
c->attr = addcap(c->attr, c->sysuser, &t);
|
||||||
|
des56to64((uchar*)t.key, secret);
|
||||||
|
c->attr = addattr(c->attr, "secret=%.8H", secret);
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
freeattr(a);
|
||||||
|
keyclose(k);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_asgetticket(int fd, char *trbuf, char *tbuf)
|
||||||
|
{
|
||||||
|
if(write(fd, trbuf, TICKREQLEN) < 0){
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return _asrdresp(fd, tbuf, 2*TICKETLEN);
|
||||||
|
}
|
||||||
|
static int
|
||||||
|
getastickets(Ticketreq *tr, char *buf)
|
||||||
|
{
|
||||||
|
int asfd;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if((asfd = xioauthdial(nil, tr->authdom)) < 0)
|
||||||
|
return -1;
|
||||||
|
convTR2M(tr, buf);
|
||||||
|
ret = xioasgetticket(asfd, buf, buf);
|
||||||
|
xioclose(asfd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mktickets(Ticketreq *tr, char *buf, Key *k)
|
||||||
|
{
|
||||||
|
Ticket t;
|
||||||
|
|
||||||
|
if(strcmp(tr->authid, tr->hostid) != 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
memset(&t, 0, sizeof t);
|
||||||
|
memmove(t.chal, tr->chal, CHALLEN);
|
||||||
|
strcpy(t.cuid, tr->uid);
|
||||||
|
strcpy(t.suid, tr->uid);
|
||||||
|
memrandom(t.key, DESKEYLEN);
|
||||||
|
t.num = AuthTc;
|
||||||
|
convT2M(&t, buf, k->priv);
|
||||||
|
t.num = AuthTs;
|
||||||
|
convT2M(&t, buf+TICKETLEN, k->priv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
gettickets(Ticketreq *tr, char *buf, Key *k)
|
||||||
|
{
|
||||||
|
if(getastickets(tr, buf) == 0)
|
||||||
|
return 0;
|
||||||
|
if(mktickets(tr, buf, k) == 0)
|
||||||
|
return 0;
|
||||||
|
werrstr("gettickets: %r");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
p9sk1check(Key *k)
|
||||||
|
{
|
||||||
|
char *user, *dom, *pass;
|
||||||
|
Ticketreq tr;
|
||||||
|
|
||||||
|
user = strfindattr(k->attr, "user");
|
||||||
|
dom = strfindattr(k->attr, "dom");
|
||||||
|
if(user==nil || dom==nil){
|
||||||
|
werrstr("need user and dom attributes");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(strlen(user) >= sizeof tr.authid){
|
||||||
|
werrstr("user name too long");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(strlen(dom) >= sizeof tr.authdom){
|
||||||
|
werrstr("auth dom name too long");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
k->priv = emalloc(DESKEYLEN);
|
||||||
|
if(pass = strfindattr(k->privattr, "!password"))
|
||||||
|
passtokey(k->priv, pass);
|
||||||
|
else if(pass = strfindattr(k->privattr, "!hex")){
|
||||||
|
if(hexparse(pass, k->priv, 7) < 0){
|
||||||
|
werrstr("malformed !hex key data");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
werrstr("need !password or !hex attribute");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
p9sk1close(Key *k)
|
||||||
|
{
|
||||||
|
free(k->priv);
|
||||||
|
k->priv = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Role
|
||||||
|
p9sk1roles[] =
|
||||||
|
{
|
||||||
|
"client", p9skclient,
|
||||||
|
"server", p9skserver,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
static Role
|
||||||
|
p9sk2roles[] =
|
||||||
|
{
|
||||||
|
"client", p9skclient,
|
||||||
|
"server", p9skserver,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
Proto p9sk1 = {
|
||||||
|
.name= "p9sk1",
|
||||||
|
.roles= p9sk1roles,
|
||||||
|
.checkkey= p9sk1check,
|
||||||
|
.closekey= p9sk1close,
|
||||||
|
.keyprompt= "user? dom? !password?",
|
||||||
|
};
|
||||||
|
|
||||||
|
Proto p9sk2 = {
|
||||||
|
.name= "p9sk2",
|
||||||
|
.roles= p9sk2roles,
|
||||||
|
};
|
||||||
|
|
||||||
100
src/cmd/factotum/pass.c
Normal file
100
src/cmd/factotum/pass.c
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* This is just a repository for a password.
|
||||||
|
* We don't want to encourage this, there's
|
||||||
|
* no server side.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dat.h"
|
||||||
|
|
||||||
|
typedef struct State State;
|
||||||
|
struct State
|
||||||
|
{
|
||||||
|
Key *key;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
HavePass,
|
||||||
|
Maxphase,
|
||||||
|
};
|
||||||
|
|
||||||
|
static char *phasenames[Maxphase] =
|
||||||
|
{
|
||||||
|
[HavePass] "HavePass",
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
passinit(Proto *p, Fsstate *fss)
|
||||||
|
{
|
||||||
|
int ask;
|
||||||
|
Key *k;
|
||||||
|
State *s;
|
||||||
|
|
||||||
|
k = findkey(fss, Kuser, &ask, 0, fss->attr, "%s", p->keyprompt);
|
||||||
|
if(k == nil){
|
||||||
|
if(ask)
|
||||||
|
return RpcNeedkey;
|
||||||
|
return failure(fss, nil);
|
||||||
|
}
|
||||||
|
setattrs(fss->attr, k->attr);
|
||||||
|
s = emalloc(sizeof(*s));
|
||||||
|
s->key = k;
|
||||||
|
fss->ps = s;
|
||||||
|
return RpcOk;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
passclose(Fsstate *fss)
|
||||||
|
{
|
||||||
|
State *s;
|
||||||
|
|
||||||
|
s = fss->ps;
|
||||||
|
if(s->key)
|
||||||
|
closekey(s->key);
|
||||||
|
free(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
passread(Fsstate *fss, void *va, uint *n)
|
||||||
|
{
|
||||||
|
int m;
|
||||||
|
char buf[500];
|
||||||
|
char *pass, *user;
|
||||||
|
State *s;
|
||||||
|
|
||||||
|
s = fss->ps;
|
||||||
|
switch(fss->phase){
|
||||||
|
default:
|
||||||
|
return phaseerror(fss, "read");
|
||||||
|
|
||||||
|
case HavePass:
|
||||||
|
user = strfindattr(s->key->attr, "user");
|
||||||
|
pass = strfindattr(s->key->privattr, "!password");
|
||||||
|
if(user==nil || pass==nil)
|
||||||
|
return failure(fss, "passread cannot happen");
|
||||||
|
snprint(buf, sizeof buf, "%q %q", user, pass);
|
||||||
|
m = strlen(buf);
|
||||||
|
if(m > *n)
|
||||||
|
return toosmall(fss, m);
|
||||||
|
*n = m;
|
||||||
|
memmove(va, buf, m);
|
||||||
|
return RpcOk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
passwrite(Fsstate *fss, void*, uint)
|
||||||
|
{
|
||||||
|
return phaseerror(fss, "write");
|
||||||
|
}
|
||||||
|
|
||||||
|
Proto pass =
|
||||||
|
{
|
||||||
|
.name= "pass",
|
||||||
|
.init= passinit,
|
||||||
|
.write= passwrite,
|
||||||
|
.read= passread,
|
||||||
|
.close= passclose,
|
||||||
|
.addkey= replacekey,
|
||||||
|
.keyprompt= "user? !password?",
|
||||||
|
};
|
||||||
189
src/cmd/factotum/plan9.c
Normal file
189
src/cmd/factotum/plan9.c
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
#include "std.h"
|
||||||
|
#include "dat.h"
|
||||||
|
#include <bio.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
memrandom(void *p, int n)
|
||||||
|
{
|
||||||
|
uchar *cp;
|
||||||
|
|
||||||
|
for(cp = (uchar*)p; n > 0; n--)
|
||||||
|
*cp++ = fastrand();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* create a change uid capability
|
||||||
|
*/
|
||||||
|
static int caphashfd;
|
||||||
|
|
||||||
|
static char*
|
||||||
|
mkcap(char *from, char *to)
|
||||||
|
{
|
||||||
|
uchar rand[20];
|
||||||
|
char *cap;
|
||||||
|
char *key;
|
||||||
|
int nfrom, nto;
|
||||||
|
uchar hash[SHA1dlen];
|
||||||
|
|
||||||
|
if(caphashfd < 0)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
/* create the capability */
|
||||||
|
nto = strlen(to);
|
||||||
|
nfrom = strlen(from);
|
||||||
|
cap = emalloc(nfrom+1+nto+1+sizeof(rand)*3+1);
|
||||||
|
sprint(cap, "%s@%s", from, to);
|
||||||
|
memrandom(rand, sizeof(rand));
|
||||||
|
key = cap+nfrom+1+nto+1;
|
||||||
|
enc64(key, sizeof(rand)*3, rand, sizeof(rand));
|
||||||
|
|
||||||
|
/* hash the capability */
|
||||||
|
hmac_sha1((uchar*)cap, strlen(cap), (uchar*)key, strlen(key), hash, nil);
|
||||||
|
|
||||||
|
/* give the kernel the hash */
|
||||||
|
key[-1] = '@';
|
||||||
|
if(write(caphashfd, hash, SHA1dlen) < 0){
|
||||||
|
free(cap);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cap;
|
||||||
|
}
|
||||||
|
|
||||||
|
Attr*
|
||||||
|
addcap(Attr *a, char *from, Ticket *t)
|
||||||
|
{
|
||||||
|
char *cap;
|
||||||
|
|
||||||
|
cap = mkcap(from, t->suid);
|
||||||
|
return addattr(a, "cuid=%q suid=%q cap=%q", t->cuid, t->suid, cap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* bind in the default network and cs */
|
||||||
|
static int
|
||||||
|
bindnetcs(void)
|
||||||
|
{
|
||||||
|
int srvfd;
|
||||||
|
|
||||||
|
if(access("/net/tcp", AEXIST) < 0)
|
||||||
|
bind("#I", "/net", MBEFORE);
|
||||||
|
|
||||||
|
if(access("/net/cs", AEXIST) < 0){
|
||||||
|
if((srvfd = open("#s/cs", ORDWR)) >= 0){
|
||||||
|
/* mount closes srvfd on success */
|
||||||
|
if(mount(srvfd, -1, "/net", MBEFORE, "") >= 0)
|
||||||
|
return 0;
|
||||||
|
close(srvfd);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_authdial(char *net, char *authdom)
|
||||||
|
{
|
||||||
|
int vanilla;
|
||||||
|
|
||||||
|
vanilla = net==nil || strcmp(net, "/net")==0;
|
||||||
|
|
||||||
|
if(!vanilla || bindnetcs()>=0)
|
||||||
|
return authdial(net, authdom);
|
||||||
|
|
||||||
|
/* use the auth sever passed to us as an arg */
|
||||||
|
if(authaddr == nil)
|
||||||
|
return -1;
|
||||||
|
return dial(netmkaddr(authaddr, "tcp", "567"), 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Key*
|
||||||
|
plan9authkey(Attr *a)
|
||||||
|
{
|
||||||
|
char *dom;
|
||||||
|
Key *k;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The only important part of a is dom.
|
||||||
|
* We don't care, for example, about user name.
|
||||||
|
*/
|
||||||
|
dom = strfindattr(a, "dom");
|
||||||
|
if(dom)
|
||||||
|
k = keylookup("proto=p9sk1 role=server user? dom=%q", dom);
|
||||||
|
else
|
||||||
|
k = keylookup("proto=p9sk1 role=server user? dom?");
|
||||||
|
if(k == nil)
|
||||||
|
werrstr("could not find plan 9 auth key dom %q", dom);
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* prompt for a string with a possible default response
|
||||||
|
*/
|
||||||
|
char*
|
||||||
|
readcons(char *prompt, char *def, int raw)
|
||||||
|
{
|
||||||
|
int fdin, fdout, ctl, n;
|
||||||
|
char line[10];
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
fdin = open("/dev/cons", OREAD);
|
||||||
|
if(fdin < 0)
|
||||||
|
fdin = 0;
|
||||||
|
fdout = open("/dev/cons", OWRITE);
|
||||||
|
if(fdout < 0)
|
||||||
|
fdout = 1;
|
||||||
|
if(def != nil)
|
||||||
|
fprint(fdout, "%s[%s]: ", prompt, def);
|
||||||
|
else
|
||||||
|
fprint(fdout, "%s: ", prompt);
|
||||||
|
if(raw){
|
||||||
|
ctl = open("/dev/consctl", OWRITE);
|
||||||
|
if(ctl >= 0)
|
||||||
|
write(ctl, "rawon", 5);
|
||||||
|
} else
|
||||||
|
ctl = -1;
|
||||||
|
s = estrdup("");
|
||||||
|
for(;;){
|
||||||
|
n = read(fdin, line, 1);
|
||||||
|
if(n == 0){
|
||||||
|
Error:
|
||||||
|
close(fdin);
|
||||||
|
close(fdout);
|
||||||
|
if(ctl >= 0)
|
||||||
|
close(ctl);
|
||||||
|
free(s);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
if(n < 0)
|
||||||
|
goto Error;
|
||||||
|
if(line[0] == 0x7f)
|
||||||
|
goto Error;
|
||||||
|
if(n == 0 || line[0] == '\n' || line[0] == '\r'){
|
||||||
|
if(raw){
|
||||||
|
write(ctl, "rawoff", 6);
|
||||||
|
write(fdout, "\n", 1);
|
||||||
|
}
|
||||||
|
close(ctl);
|
||||||
|
close(fdin);
|
||||||
|
close(fdout);
|
||||||
|
if(*s == 0 && def != nil)
|
||||||
|
s = estrappend(s, "%s", def);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
if(line[0] == '\b'){
|
||||||
|
if(strlen(s) > 0)
|
||||||
|
s[strlen(s)-1] = 0;
|
||||||
|
} else if(line[0] == 0x15) { /* ^U: line kill */
|
||||||
|
if(def != nil)
|
||||||
|
fprint(fdout, "\n%s[%s]: ", prompt, def);
|
||||||
|
else
|
||||||
|
fprint(fdout, "\n%s: ", prompt);
|
||||||
|
|
||||||
|
s[0] = 0;
|
||||||
|
} else {
|
||||||
|
s = estrappend(s, "%c", line[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil; /* not reached */
|
||||||
|
}
|
||||||
0
src/cmd/factotum/privattr
Normal file
0
src/cmd/factotum/privattr
Normal file
22
src/cmd/factotum/proto.c
Normal file
22
src/cmd/factotum/proto.c
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#include "std.h"
|
||||||
|
#include "dat.h"
|
||||||
|
|
||||||
|
Proto *prototab[] = {
|
||||||
|
&apop,
|
||||||
|
&cram,
|
||||||
|
&p9any,
|
||||||
|
&p9sk1,
|
||||||
|
&p9sk2,
|
||||||
|
nil,
|
||||||
|
};
|
||||||
|
|
||||||
|
Proto*
|
||||||
|
protolookup(char *name)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i=0; prototab[i]; i++)
|
||||||
|
if(strcmp(prototab[i]->name, name) == 0)
|
||||||
|
return prototab[i];
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
315
src/cmd/factotum/rpc.c
Normal file
315
src/cmd/factotum/rpc.c
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
#include "std.h"
|
||||||
|
#include "dat.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Factotum RPC
|
||||||
|
*
|
||||||
|
* Must be paired write/read cycles on /mnt/factotum/rpc.
|
||||||
|
* The format of a request is verb, single space, data.
|
||||||
|
* Data format is verb-dependent; in particular, it can be binary.
|
||||||
|
* The format of a response is the same. The write only sets up
|
||||||
|
* the RPC. The read tries to execute it. If the /mnt/factotum/key
|
||||||
|
* file is open, we ask for new keys using that instead of returning
|
||||||
|
* an error in the RPC. This means the read blocks.
|
||||||
|
* Textual arguments are parsed with tokenize, so rc-style quoting
|
||||||
|
* rules apply.
|
||||||
|
*
|
||||||
|
* Only authentication protocol messages go here. Configuration
|
||||||
|
* is still via ctl (below).
|
||||||
|
*
|
||||||
|
* Request RPCs are:
|
||||||
|
* start attrs - initializes protocol for authentication, can fail.
|
||||||
|
* returns "ok read" or "ok write" on success.
|
||||||
|
* read - execute protocol read
|
||||||
|
* write - execute protocol write
|
||||||
|
* authinfo - if the protocol is finished, return the AI if any
|
||||||
|
* attr - return protocol information
|
||||||
|
* Return values are:
|
||||||
|
* error message - an error happened.
|
||||||
|
* ok [data] - success, possible data is request dependent.
|
||||||
|
* needkey attrs - request aborted, get me this key and try again
|
||||||
|
* badkey attrs - request aborted, this key might be bad
|
||||||
|
* done [haveai] - authentication is done [haveai: you can get an ai with authinfo]
|
||||||
|
*/
|
||||||
|
|
||||||
|
char *rpcname[] =
|
||||||
|
{
|
||||||
|
"unknown",
|
||||||
|
"authinfo",
|
||||||
|
"attr",
|
||||||
|
"read",
|
||||||
|
"start",
|
||||||
|
"write",
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
classify(char *s)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i=1; i<nelem(rpcname); i++)
|
||||||
|
if(strcmp(s, rpcname[i]) == 0)
|
||||||
|
return i;
|
||||||
|
return RpcUnknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
rpcwrite(Conv *c, void *data, int count)
|
||||||
|
{
|
||||||
|
int op;
|
||||||
|
uchar *p;
|
||||||
|
|
||||||
|
if(count >= MaxRpc){
|
||||||
|
werrstr("rpc too large");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cancel any current rpc */
|
||||||
|
c->rpc.op = RpcUnknown;
|
||||||
|
c->nreply = 0;
|
||||||
|
|
||||||
|
/* parse new rpc */
|
||||||
|
memmove(c->rpcbuf, data, count);
|
||||||
|
c->rpcbuf[count] = 0;
|
||||||
|
if(p = (uchar*)strchr((char*)c->rpcbuf, ' ')){
|
||||||
|
*p++ = '\0';
|
||||||
|
c->rpc.data = p;
|
||||||
|
c->rpc.count = count - (p - (uchar*)c->rpcbuf);
|
||||||
|
}else{
|
||||||
|
c->rpc.data = "";
|
||||||
|
c->rpc.count = 0;
|
||||||
|
}
|
||||||
|
op = classify(c->rpcbuf);
|
||||||
|
if(op == RpcUnknown){
|
||||||
|
werrstr("bad rpc verb: %s", c->rpcbuf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->rpc.op = op;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
convthread(void *v)
|
||||||
|
{
|
||||||
|
Conv *c;
|
||||||
|
Attr *a;
|
||||||
|
char *role, *proto;
|
||||||
|
Proto *p;
|
||||||
|
Role *r;
|
||||||
|
|
||||||
|
c = v;
|
||||||
|
a = parseattr(c->rpc.data);
|
||||||
|
if(a == nil){
|
||||||
|
werrstr("empty attr");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
c->attr = a;
|
||||||
|
proto = strfindattr(a, "proto");
|
||||||
|
role = strfindattr(a, "role");
|
||||||
|
|
||||||
|
if(proto == nil){
|
||||||
|
werrstr("no proto in attrs");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if(role == nil){
|
||||||
|
werrstr("no role in attrs");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = protolookup(proto);
|
||||||
|
if(p == nil){
|
||||||
|
werrstr("unknown proto %s", proto);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->proto = p;
|
||||||
|
for(r=p->roles; r->name; r++){
|
||||||
|
if(strcmp(r->name, role) != 0)
|
||||||
|
continue;
|
||||||
|
rpcrespond(c, "ok");
|
||||||
|
c->active = 1;
|
||||||
|
if((*r->fn)(c) == 0){
|
||||||
|
c->done = 1;
|
||||||
|
werrstr("protocol finished");
|
||||||
|
}else
|
||||||
|
werrstr("%s %s %s: %r", p->name, r->name, c->state);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
werrstr("unknown role");
|
||||||
|
|
||||||
|
out:
|
||||||
|
c->active = 0;
|
||||||
|
c->state = 0;
|
||||||
|
rerrstr(c->err, sizeof c->err);
|
||||||
|
rpcrespond(c, "error %r");
|
||||||
|
convclose(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uchar* convAI2M(uchar *p, int n, char *cuid, char *suid, char *cap, char *hex);
|
||||||
|
|
||||||
|
void
|
||||||
|
rpcexec(Conv *c)
|
||||||
|
{
|
||||||
|
uchar *p;
|
||||||
|
|
||||||
|
switch(c->rpc.op){
|
||||||
|
case RpcRead:
|
||||||
|
if(c->rpc.count > 0){
|
||||||
|
rpcrespond(c, "error read takes no parameters");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* fall through */
|
||||||
|
default:
|
||||||
|
if(!c->active){
|
||||||
|
if(c->done)
|
||||||
|
rpcrespond(c, "done");
|
||||||
|
else
|
||||||
|
rpcrespond(c, "error %s", c->err);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
nbsendp(c->rpcwait, 0);
|
||||||
|
break;
|
||||||
|
case RpcUnknown:
|
||||||
|
break;
|
||||||
|
case RpcAuthinfo:
|
||||||
|
/* deprecated */
|
||||||
|
if(c->active)
|
||||||
|
rpcrespond(c, "error conversation still active");
|
||||||
|
else if(!c->done)
|
||||||
|
rpcrespond(c, "error conversation not successful");
|
||||||
|
else{
|
||||||
|
/* make up an auth info using the attr */
|
||||||
|
p = convAI2M((uchar*)c->reply+3, sizeof c->reply-3,
|
||||||
|
strfindattr(c->attr, "cuid"),
|
||||||
|
strfindattr(c->attr, "suid"),
|
||||||
|
strfindattr(c->attr, "cap"),
|
||||||
|
strfindattr(c->attr, "secret"));
|
||||||
|
if(p == nil)
|
||||||
|
rpcrespond(c, "error %r");
|
||||||
|
else
|
||||||
|
rpcrespondn(c, "ok", c->reply+3, p-(uchar*)(c->reply+3));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RpcAttr:
|
||||||
|
rpcrespond(c, "ok %A", c->attr);
|
||||||
|
break;
|
||||||
|
case RpcStart:
|
||||||
|
convreset(c);
|
||||||
|
c->ref++;
|
||||||
|
threadcreate(convthread, c, STACK);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rpcrespond(Conv *c, char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list arg;
|
||||||
|
|
||||||
|
if(c->hangup)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(fmt == nil)
|
||||||
|
fmt = "";
|
||||||
|
|
||||||
|
va_start(arg, fmt);
|
||||||
|
c->nreply = vsnprint(c->reply, sizeof c->reply, fmt, arg);
|
||||||
|
va_end(arg);
|
||||||
|
(*c->kickreply)(c);
|
||||||
|
c->rpc.op = RpcUnknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rpcrespondn(Conv *c, char *verb, void *data, int count)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
if(c->hangup)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(strlen(verb)+1+count > sizeof c->reply){
|
||||||
|
print("RPC response too large; caller %#lux", getcallerpc(&c));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(c->reply, verb);
|
||||||
|
p = c->reply + strlen(c->reply);
|
||||||
|
*p++ = ' ';
|
||||||
|
memmove(p, data, count);
|
||||||
|
c->nreply = count + (p - c->reply);
|
||||||
|
(*c->kickreply)(c);
|
||||||
|
c->rpc.op = RpcUnknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* deprecated */
|
||||||
|
static uchar*
|
||||||
|
pstring(uchar *p, uchar *e, char *s)
|
||||||
|
{
|
||||||
|
uint n;
|
||||||
|
|
||||||
|
if(p == nil)
|
||||||
|
return nil;
|
||||||
|
if(s == nil)
|
||||||
|
s = "";
|
||||||
|
n = strlen(s);
|
||||||
|
if(p+n+BIT16SZ >= e)
|
||||||
|
return nil;
|
||||||
|
PBIT16(p, n);
|
||||||
|
p += BIT16SZ;
|
||||||
|
memmove(p, s, n);
|
||||||
|
p += n;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uchar*
|
||||||
|
pcarray(uchar *p, uchar *e, uchar *s, uint n)
|
||||||
|
{
|
||||||
|
if(p == nil)
|
||||||
|
return nil;
|
||||||
|
if(s == nil){
|
||||||
|
if(n > 0)
|
||||||
|
sysfatal("pcarray");
|
||||||
|
s = (uchar*)"";
|
||||||
|
}
|
||||||
|
if(p+n+BIT16SZ >= e)
|
||||||
|
return nil;
|
||||||
|
PBIT16(p, n);
|
||||||
|
p += BIT16SZ;
|
||||||
|
memmove(p, s, n);
|
||||||
|
p += n;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uchar*
|
||||||
|
convAI2M(uchar *p, int n, char *cuid, char *suid, char *cap, char *hex)
|
||||||
|
{
|
||||||
|
uchar *e = p+n;
|
||||||
|
uchar *secret;
|
||||||
|
int nsecret;
|
||||||
|
|
||||||
|
if(cuid == nil)
|
||||||
|
cuid = "";
|
||||||
|
if(suid == nil)
|
||||||
|
suid = "";
|
||||||
|
if(cap == nil)
|
||||||
|
cap = "";
|
||||||
|
if(hex == nil)
|
||||||
|
hex = "";
|
||||||
|
nsecret = strlen(hex)/2;
|
||||||
|
secret = emalloc(nsecret);
|
||||||
|
if(hexparse(hex, secret, nsecret) < 0){
|
||||||
|
werrstr("hexparse %s failed", hex); /* can't happen */
|
||||||
|
free(secret);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
p = pstring(p, e, cuid);
|
||||||
|
p = pstring(p, e, suid);
|
||||||
|
p = pstring(p, e, cap);
|
||||||
|
p = pcarray(p, e, secret, nsecret);
|
||||||
|
free(secret);
|
||||||
|
if(p == nil)
|
||||||
|
werrstr("authinfo too big");
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
135
src/cmd/factotum/ssh.c
Normal file
135
src/cmd/factotum/ssh.c
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
#include "dat.h"
|
||||||
|
#include <mp.h>
|
||||||
|
#include <libsec.h>
|
||||||
|
|
||||||
|
typedef struct Sshrsastate Sshrsastate;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CReadpub,
|
||||||
|
CWritechal,
|
||||||
|
CReadresp,
|
||||||
|
};
|
||||||
|
struct State
|
||||||
|
{
|
||||||
|
RSApriv *priv;
|
||||||
|
Key *k;
|
||||||
|
mpint *resp;
|
||||||
|
int phase;
|
||||||
|
};
|
||||||
|
|
||||||
|
static RSApriv*
|
||||||
|
readrsapriv(char *s)
|
||||||
|
{
|
||||||
|
RSApriv *priv;
|
||||||
|
|
||||||
|
priv = rsaprivalloc();
|
||||||
|
|
||||||
|
strtoul(s, &s, 10);
|
||||||
|
if((priv->pub.ek=strtomp(s, &s, 16, nil)) == nil)
|
||||||
|
goto Error;
|
||||||
|
if((priv->dk=strtomp(s, &s, 16, nil)) == nil)
|
||||||
|
goto Error;
|
||||||
|
if((priv->pub.n=strtomp(s, &s, 16, nil)) == nil)
|
||||||
|
goto Error;
|
||||||
|
if((priv->p=strtomp(s, &s, 16, nil)) == nil)
|
||||||
|
goto Error;
|
||||||
|
if((priv->q=strtomp(s, &s, 16, nil)) == nil)
|
||||||
|
goto Error;
|
||||||
|
if((priv->kp=strtomp(s, &s, 16, nil)) == nil)
|
||||||
|
goto Error;
|
||||||
|
if((priv->kq=strtomp(s, &s, 16, nil)) == nil)
|
||||||
|
goto Error;
|
||||||
|
if((priv->c2=strtomp(s, &s, 16, nil)) == nil)
|
||||||
|
goto Error;
|
||||||
|
|
||||||
|
return priv;
|
||||||
|
|
||||||
|
Error:
|
||||||
|
rsaprivfree(priv);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
sshinit(Fsstate *fss,
|
||||||
|
sshrsaopen(Key *k, char*, int client)
|
||||||
|
{
|
||||||
|
Sshrsastate *s;
|
||||||
|
|
||||||
|
fmtinstall('B', mpconv);
|
||||||
|
assert(client);
|
||||||
|
s = emalloc(sizeof *s);
|
||||||
|
s->priv = readrsapriv(s_to_c(k->data));
|
||||||
|
s->k = k;
|
||||||
|
if(s->priv == nil){
|
||||||
|
agentlog("error parsing ssh key %s", k->file);
|
||||||
|
free(s);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
sshrsaread(void *va, void *buf, int n)
|
||||||
|
{
|
||||||
|
Sshrsastate *s;
|
||||||
|
|
||||||
|
s = va;
|
||||||
|
switch(s->phase){
|
||||||
|
case Readpub:
|
||||||
|
s->phase = Done;
|
||||||
|
return snprint(buf, n, "%B", s->priv->pub.n);
|
||||||
|
case Readresp:
|
||||||
|
s->phase = Done;
|
||||||
|
return snprint(buf, n, "%B", s->resp);
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
sshrsawrite(void *va, void *vbuf, int n)
|
||||||
|
{
|
||||||
|
mpint *m;
|
||||||
|
char *buf;
|
||||||
|
Sshrsastate *s;
|
||||||
|
|
||||||
|
s = va;
|
||||||
|
if((s->k->flags&Fconfirmuse) && confirm("ssh use") < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
buf = emalloc(n+1);
|
||||||
|
memmove(buf, vbuf, n);
|
||||||
|
buf[n] = '\0';
|
||||||
|
m = strtomp(buf, nil, 16, nil);
|
||||||
|
free(buf);
|
||||||
|
if(m == nil){
|
||||||
|
werrstr("bad bignum");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
agentlog("ssh use");
|
||||||
|
m = rsadecrypt(s->priv, m, m);
|
||||||
|
s->resp = m;
|
||||||
|
s->phase = Readresp;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
sshrsaclose(void *v)
|
||||||
|
{
|
||||||
|
Sshrsastate *s;
|
||||||
|
|
||||||
|
s = v;
|
||||||
|
rsaprivfree(s->priv);
|
||||||
|
mpfree(s->resp);
|
||||||
|
free(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
Proto sshrsa = {
|
||||||
|
.name= "ssh-rsa",
|
||||||
|
.perm= 0666,
|
||||||
|
.open= sshrsaopen,
|
||||||
|
.read= sshrsaread,
|
||||||
|
.write= sshrsawrite,
|
||||||
|
.close= sshrsaclose,
|
||||||
|
};
|
||||||
172
src/cmd/factotum/sshrsa.c
Normal file
172
src/cmd/factotum/sshrsa.c
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
/*
|
||||||
|
* SSH RSA authentication.
|
||||||
|
*
|
||||||
|
* Client protocol:
|
||||||
|
* read public key
|
||||||
|
* if you don't like it, read another, repeat
|
||||||
|
* write challenge
|
||||||
|
* read response
|
||||||
|
* all numbers are hexadecimal biginits parsable with strtomp.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dat.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CHavePub,
|
||||||
|
CHaveResp,
|
||||||
|
|
||||||
|
Maxphase,
|
||||||
|
};
|
||||||
|
|
||||||
|
static char *phasenames[] = {
|
||||||
|
[CHavePub] "CHavePub",
|
||||||
|
[CHaveResp] "CHaveResp",
|
||||||
|
};
|
||||||
|
|
||||||
|
struct State
|
||||||
|
{
|
||||||
|
RSApriv *priv;
|
||||||
|
mpint *resp;
|
||||||
|
int off;
|
||||||
|
Key *key;
|
||||||
|
};
|
||||||
|
|
||||||
|
static RSApriv*
|
||||||
|
readrsapriv(Key *k)
|
||||||
|
{
|
||||||
|
char *a;
|
||||||
|
RSApriv *priv;
|
||||||
|
|
||||||
|
priv = rsaprivalloc();
|
||||||
|
|
||||||
|
if((a=strfindattr(k->attr, "ek"))==nil || (priv->pub.ek=strtomp(a, nil, 16, nil))==nil)
|
||||||
|
goto Error;
|
||||||
|
if((a=strfindattr(k->attr, "n"))==nil || (priv->pub.n=strtomp(a, nil, 16, nil))==nil)
|
||||||
|
goto Error;
|
||||||
|
if((a=strfindattr(k->privattr, "!p"))==nil || (priv->p=strtomp(a, nil, 16, nil))==nil)
|
||||||
|
goto Error;
|
||||||
|
if((a=strfindattr(k->privattr, "!q"))==nil || (priv->q=strtomp(a, nil, 16, nil))==nil)
|
||||||
|
goto Error;
|
||||||
|
if((a=strfindattr(k->privattr, "!kp"))==nil || (priv->kp=strtomp(a, nil, 16, nil))==nil)
|
||||||
|
goto Error;
|
||||||
|
if((a=strfindattr(k->privattr, "!kq"))==nil || (priv->kq=strtomp(a, nil, 16, nil))==nil)
|
||||||
|
goto Error;
|
||||||
|
if((a=strfindattr(k->privattr, "!c2"))==nil || (priv->c2=strtomp(a, nil, 16, nil))==nil)
|
||||||
|
goto Error;
|
||||||
|
if((a=strfindattr(k->privattr, "!dk"))==nil || (priv->dk=strtomp(a, nil, 16, nil))==nil)
|
||||||
|
goto Error;
|
||||||
|
return priv;
|
||||||
|
|
||||||
|
Error:
|
||||||
|
rsaprivfree(priv);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sshrsainit(Proto*, Fsstate *fss)
|
||||||
|
{
|
||||||
|
int iscli;
|
||||||
|
State *s;
|
||||||
|
|
||||||
|
if((iscli = isclient(strfindattr(fss->attr, "role"))) < 0)
|
||||||
|
return failure(fss, nil);
|
||||||
|
if(iscli==0)
|
||||||
|
return failure(fss, "sshrsa server unimplemented");
|
||||||
|
|
||||||
|
s = emalloc(sizeof *s);
|
||||||
|
fss->phasename = phasenames;
|
||||||
|
fss->maxphase = Maxphase;
|
||||||
|
fss->phase = CHavePub;
|
||||||
|
fss->ps = s;
|
||||||
|
return RpcOk;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sshrsaread(Fsstate *fss, void *va, uint *n)
|
||||||
|
{
|
||||||
|
RSApriv *priv;
|
||||||
|
State *s;
|
||||||
|
|
||||||
|
s = fss->ps;
|
||||||
|
switch(fss->phase){
|
||||||
|
default:
|
||||||
|
return phaseerror(fss, "read");
|
||||||
|
case CHavePub:
|
||||||
|
if(s->key){
|
||||||
|
closekey(s->key);
|
||||||
|
s->key = nil;
|
||||||
|
}
|
||||||
|
if((s->key = findkey(fss, Kuser, nil, s->off, fss->attr, nil)) == nil)
|
||||||
|
return failure(fss, nil);
|
||||||
|
s->off++;
|
||||||
|
priv = s->key->priv;
|
||||||
|
*n = snprint(va, *n, "%B", priv->pub.n);
|
||||||
|
return RpcOk;
|
||||||
|
case CHaveResp:
|
||||||
|
*n = snprint(va, *n, "%B", s->resp);
|
||||||
|
fss->phase = Established;
|
||||||
|
return RpcOk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sshrsawrite(Fsstate *fss, void *va, uint)
|
||||||
|
{
|
||||||
|
mpint *m;
|
||||||
|
State *s;
|
||||||
|
|
||||||
|
s = fss->ps;
|
||||||
|
switch(fss->phase){
|
||||||
|
default:
|
||||||
|
return phaseerror(fss, "write");
|
||||||
|
case CHavePub:
|
||||||
|
if(s->key == nil)
|
||||||
|
return failure(fss, "no current key");
|
||||||
|
m = strtomp(va, nil, 16, nil);
|
||||||
|
m = rsadecrypt(s->key->priv, m, m);
|
||||||
|
s->resp = m;
|
||||||
|
fss->phase = CHaveResp;
|
||||||
|
return RpcOk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sshrsaclose(Fsstate *fss)
|
||||||
|
{
|
||||||
|
State *s;
|
||||||
|
|
||||||
|
s = fss->ps;
|
||||||
|
if(s->key)
|
||||||
|
closekey(s->key);
|
||||||
|
if(s->resp)
|
||||||
|
mpfree(s->resp);
|
||||||
|
free(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sshrsaaddkey(Key *k)
|
||||||
|
{
|
||||||
|
fmtinstall('B', mpconv);
|
||||||
|
|
||||||
|
if((k->priv = readrsapriv(k)) == nil){
|
||||||
|
werrstr("malformed key data");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return replacekey(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sshrsaclosekey(Key *k)
|
||||||
|
{
|
||||||
|
rsaprivfree(k->priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
Proto sshrsa = {
|
||||||
|
.name= "sshrsa",
|
||||||
|
.init= sshrsainit,
|
||||||
|
.write= sshrsawrite,
|
||||||
|
.read= sshrsaread,
|
||||||
|
.close= sshrsaclose,
|
||||||
|
.addkey= sshrsaaddkey,
|
||||||
|
.closekey= sshrsaclosekey,
|
||||||
|
};
|
||||||
10
src/cmd/factotum/std.h
Normal file
10
src/cmd/factotum/std.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <auth.h>
|
||||||
|
#include <authsrv.h>
|
||||||
|
#include <mp.h>
|
||||||
|
#include <libsec.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <fcall.h>
|
||||||
|
#include <9p.h>
|
||||||
|
|
||||||
121
src/cmd/factotum/test.c
Normal file
121
src/cmd/factotum/test.c
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <auth.h>
|
||||||
|
|
||||||
|
typedef struct Test Test;
|
||||||
|
|
||||||
|
struct Test
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
int (*server)(Test*, AuthRpc*, int);
|
||||||
|
int (*client)(Test*, int);
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
ai2status(AuthInfo *ai)
|
||||||
|
{
|
||||||
|
if(ai == nil)
|
||||||
|
return -1;
|
||||||
|
auth_freeAI(ai);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
proxyserver(Test *t, AuthRpc *rpc, int fd)
|
||||||
|
{
|
||||||
|
char buf[1024];
|
||||||
|
|
||||||
|
sprint(buf, "proto=%q role=server", t->name);
|
||||||
|
return ai2status(fauth_proxy(fd, rpc, nil, buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
proxyclient(Test *t, int fd)
|
||||||
|
{
|
||||||
|
return ai2status(auth_proxy(fd, auth_getkey, "proto=%q role=client", t->name));
|
||||||
|
}
|
||||||
|
|
||||||
|
Test test[] =
|
||||||
|
{
|
||||||
|
"apop", proxyserver, proxyclient,
|
||||||
|
"cram", proxyserver, proxyclient,
|
||||||
|
"p9sk1", proxyserver, proxyclient,
|
||||||
|
"p9sk2", proxyserver, proxyclient,
|
||||||
|
"p9any", proxyserver, proxyclient,
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
fprint(2, "usage: test [name]...\n");
|
||||||
|
exits("usage");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
runtest(AuthRpc *srpc, Test *t)
|
||||||
|
{
|
||||||
|
int p[2], bad;
|
||||||
|
Waitmsg *w;
|
||||||
|
|
||||||
|
if(pipe(p) < 0)
|
||||||
|
sysfatal("pipe: %r");
|
||||||
|
|
||||||
|
print("%s...", t->name);
|
||||||
|
|
||||||
|
switch(fork()){
|
||||||
|
case -1:
|
||||||
|
sysfatal("fork: %r");
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
close(p[0]);
|
||||||
|
if((*t->server)(t, srpc, p[1]) < 0){
|
||||||
|
print("\n\tserver: %r");
|
||||||
|
_exits("oops");
|
||||||
|
}
|
||||||
|
close(p[1]);
|
||||||
|
_exits(nil);
|
||||||
|
default:
|
||||||
|
close(p[1]);
|
||||||
|
if((*t->client)(t, p[0]) < 0){
|
||||||
|
print("\n\tclient: %r");
|
||||||
|
bad = 1;
|
||||||
|
}
|
||||||
|
close(p[0]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
w = wait();
|
||||||
|
if(w->msg[0])
|
||||||
|
bad = 1;
|
||||||
|
print("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
int afd;
|
||||||
|
AuthRpc *srpc;
|
||||||
|
|
||||||
|
ARGBEGIN{
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
}ARGEND
|
||||||
|
|
||||||
|
quotefmtinstall();
|
||||||
|
afd = open("/n/kremvax/factotum/rpc", ORDWR);
|
||||||
|
if(afd < 0)
|
||||||
|
sysfatal("open /n/kremvax/factotum/rpc: %r");
|
||||||
|
srpc = auth_allocrpc(afd);
|
||||||
|
if(srpc == nil)
|
||||||
|
sysfatal("auth_allocrpc: %r");
|
||||||
|
|
||||||
|
if(argc == 0)
|
||||||
|
for(i=0; i<nelem(test); i++)
|
||||||
|
runtest(srpc, &test[i]);
|
||||||
|
else
|
||||||
|
for(i=0; i<argc; i++)
|
||||||
|
for(j=0; j<nelem(test); j++)
|
||||||
|
if(strcmp(argv[i], test[j].name) == 0)
|
||||||
|
runtest(srpc, &test[j]);
|
||||||
|
exits(nil);
|
||||||
|
}
|
||||||
11
src/cmd/factotum/testsetup
Executable file
11
src/cmd/factotum/testsetup
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/rc
|
||||||
|
|
||||||
|
slay 8.out|rc
|
||||||
|
8.out $* -s fact.s -m /n/kremvax
|
||||||
|
8.out $* -s fact.c
|
||||||
|
ramfs -m /n/sid >[2]/dev/null
|
||||||
|
auth/aescbc -d < /usr/rsc/lib/factotum.aes >/n/sid/all
|
||||||
|
read -m /n/sid/all >/n/kremvax/factotum/ctl
|
||||||
|
read -m /n/sid/all >/mnt/factotum/ctl
|
||||||
|
unmount /n/sid
|
||||||
|
|
||||||
52
src/cmd/factotum/util.c
Normal file
52
src/cmd/factotum/util.c
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#include "std.h"
|
||||||
|
#include "dat.h"
|
||||||
|
|
||||||
|
static int
|
||||||
|
unhex(char c)
|
||||||
|
{
|
||||||
|
if('0' <= c && c <= '9')
|
||||||
|
return c-'0';
|
||||||
|
if('a' <= c && c <= 'f')
|
||||||
|
return c-'a'+10;
|
||||||
|
if('A' <= c && c <= 'F')
|
||||||
|
return c-'A'+10;
|
||||||
|
abort();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hexparse(char *hex, uchar *dat, int ndat)
|
||||||
|
{
|
||||||
|
int i, n;
|
||||||
|
|
||||||
|
n = strlen(hex);
|
||||||
|
if(n%2)
|
||||||
|
return -1;
|
||||||
|
n /= 2;
|
||||||
|
if(n > ndat)
|
||||||
|
return -1;
|
||||||
|
if(hex[strspn(hex, "0123456789abcdefABCDEF")] != '\0')
|
||||||
|
return -1;
|
||||||
|
for(i=0; i<n; i++)
|
||||||
|
dat[i] = (unhex(hex[2*i])<<4)|unhex(hex[2*i+1]);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
char*
|
||||||
|
estrappend(char *s, char *fmt, ...)
|
||||||
|
{
|
||||||
|
char *t;
|
||||||
|
va_list arg;
|
||||||
|
|
||||||
|
va_start(arg, fmt);
|
||||||
|
t = vsmprint(fmt, arg);
|
||||||
|
if(t == nil)
|
||||||
|
sysfatal("out of memory");
|
||||||
|
va_end(arg);
|
||||||
|
s = erealloc(s, strlen(s)+strlen(t)+1);
|
||||||
|
strcat(s, t);
|
||||||
|
free(t);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
15
src/cmd/factotum/x.c
Normal file
15
src/cmd/factotum/x.c
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <auth.h>
|
||||||
|
|
||||||
|
void
|
||||||
|
f(void*)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
f(auth_challenge);
|
||||||
|
f(auth_response);
|
||||||
|
}
|
||||||
165
src/cmd/factotum/xio.c
Normal file
165
src/cmd/factotum/xio.c
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
#include "std.h"
|
||||||
|
#include "dat.h"
|
||||||
|
|
||||||
|
static Ioproc *cache[5];
|
||||||
|
static int ncache;
|
||||||
|
|
||||||
|
static Ioproc*
|
||||||
|
xioproc(void)
|
||||||
|
{
|
||||||
|
Ioproc *c;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i=0; i<ncache; i++){
|
||||||
|
if(c = cache[i]){
|
||||||
|
cache[i] = nil;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ioproc();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
closexioproc(Ioproc *io)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i=0; i<ncache; i++)
|
||||||
|
if(cache[i] == nil){
|
||||||
|
cache[i] = io;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
closeioproc(io);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xiodial(char *ds, char *local, char *dir, int *cfdp)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
Ioproc *io;
|
||||||
|
|
||||||
|
if((io = xioproc()) == nil)
|
||||||
|
return -1;
|
||||||
|
fd = iodial(io, ds, local, dir, cfdp);
|
||||||
|
closexioproc(io);
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xioclose(int fd)
|
||||||
|
{
|
||||||
|
Ioproc *io;
|
||||||
|
|
||||||
|
if((io = xioproc()) == nil){
|
||||||
|
close(fd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ioclose(io, fd);
|
||||||
|
closexioproc(io);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xiowrite(int fd, void *v, int n)
|
||||||
|
{
|
||||||
|
int m;
|
||||||
|
Ioproc *io;
|
||||||
|
|
||||||
|
if((io = xioproc()) == nil)
|
||||||
|
return -1;
|
||||||
|
m = iowrite(io, fd, v, n);
|
||||||
|
closexioproc(io);
|
||||||
|
if(m != n)
|
||||||
|
return -1;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long
|
||||||
|
_ioauthdial(va_list *arg)
|
||||||
|
{
|
||||||
|
char *net;
|
||||||
|
char *dom;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
net = va_arg(*arg, char*);
|
||||||
|
dom = va_arg(*arg, char*);
|
||||||
|
fd = _authdial(net, dom);
|
||||||
|
if(fd < 0)
|
||||||
|
fprint(2, "authdial: %r");
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xioauthdial(char *net, char *dom)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
Ioproc *io;
|
||||||
|
|
||||||
|
if((io = xioproc()) == nil)
|
||||||
|
return -1;
|
||||||
|
fd = iocall(io, _ioauthdial, net, dom);
|
||||||
|
closexioproc(io);
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long
|
||||||
|
_ioasrdresp(va_list *arg)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
void *a;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
fd = va_arg(*arg, int);
|
||||||
|
a = va_arg(*arg, void*);
|
||||||
|
n = va_arg(*arg, int);
|
||||||
|
|
||||||
|
return _asrdresp(fd, a, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xioasrdresp(int fd, void *a, int n)
|
||||||
|
{
|
||||||
|
Ioproc *io;
|
||||||
|
|
||||||
|
if((io = xioproc()) == nil)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
n = iocall(io, _ioasrdresp, fd, a, n);
|
||||||
|
closexioproc(io);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long
|
||||||
|
_ioasgetticket(va_list *arg)
|
||||||
|
{
|
||||||
|
int asfd;
|
||||||
|
char *trbuf;
|
||||||
|
char *tbuf;
|
||||||
|
|
||||||
|
asfd = va_arg(*arg, int);
|
||||||
|
trbuf = va_arg(*arg, char*);
|
||||||
|
tbuf = va_arg(*arg, char*);
|
||||||
|
|
||||||
|
return _asgetticket(asfd, trbuf, tbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xioasgetticket(int fd, char *trbuf, char *tbuf)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
Ioproc *io;
|
||||||
|
|
||||||
|
if((io = xioproc()) == nil)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
n = iocall(io, _ioasgetticket, fd, trbuf, tbuf);
|
||||||
|
closexioproc(io);
|
||||||
|
if(n != 2*TICKETLEN)
|
||||||
|
n = -1;
|
||||||
|
else
|
||||||
|
n = 0;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
@ -7,7 +7,7 @@ SHORTLIB=sec fs mux regexp9 thread bio 9
|
|||||||
|
|
||||||
<$PLAN9/src/mkmany
|
<$PLAN9/src/mkmany
|
||||||
|
|
||||||
BUGGERED='CVS|faces|factotum|oplumb|plumb2|mk|vac|9term|upas|venti|htmlfmt'
|
BUGGERED='CVS|9term|faces|factotum|htmlfmt|mk|rio|upas|vac|venti'
|
||||||
DIRS=`ls -l |sed -n 's/^d.* //p' |egrep -v "^($BUGGERED)$"`
|
DIRS=`ls -l |sed -n 's/^d.* //p' |egrep -v "^($BUGGERED)$"`
|
||||||
|
|
||||||
<$PLAN9/src/mkdirs
|
<$PLAN9/src/mkdirs
|
||||||
|
|||||||
@ -54,6 +54,8 @@ threadmain(int argc, char *argv[])
|
|||||||
error("can't initialize $user or $home: %r");
|
error("can't initialize $user or $home: %r");
|
||||||
if(plumbfile == nil){
|
if(plumbfile == nil){
|
||||||
sprint(buf, "%s/lib/plumbing", home);
|
sprint(buf, "%s/lib/plumbing", home);
|
||||||
|
if(access(buf, 0) < 0)
|
||||||
|
sprint(buf, "#9/plumb/initial.plumbing");
|
||||||
plumbfile = estrdup(buf);
|
plumbfile = estrdup(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -81,7 +81,7 @@ void Vinit(void){
|
|||||||
for(s=*env;*s && *s!='(' && *s!='=';s++);
|
for(s=*env;*s && *s!='(' && *s!='=';s++);
|
||||||
switch(*s){
|
switch(*s){
|
||||||
case '\0':
|
case '\0':
|
||||||
pfmt(err, "environment %q?\n", *env);
|
pfmt(err, "rc: odd environment %q?\n", *env);
|
||||||
break;
|
break;
|
||||||
case '=':
|
case '=':
|
||||||
*s='\0';
|
*s='\0';
|
||||||
|
|||||||
@ -26,6 +26,9 @@
|
|||||||
#include "x.tab.h"
|
#include "x.tab.h"
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#undef pipe /* so that /dev/fd works */
|
||||||
|
|
||||||
typedef struct tree tree;
|
typedef struct tree tree;
|
||||||
typedef struct word word;
|
typedef struct word word;
|
||||||
typedef struct io io;
|
typedef struct io io;
|
||||||
|
|||||||
@ -10,6 +10,12 @@
|
|||||||
#include <cursor.h>
|
#include <cursor.h>
|
||||||
#include <keyboard.h>
|
#include <keyboard.h>
|
||||||
#include <frame.h>
|
#include <frame.h>
|
||||||
|
#define Tversion Tversion9p
|
||||||
|
#define Twrite Twrite9p
|
||||||
|
#include <fcall.h>
|
||||||
|
#undef Tversion
|
||||||
|
#undef Twrite
|
||||||
|
#include <fs.h>
|
||||||
#include <plumb.h>
|
#include <plumb.h>
|
||||||
#include "flayer.h"
|
#include "flayer.h"
|
||||||
#include "samterm.h"
|
#include "samterm.h"
|
||||||
@ -212,27 +218,22 @@ plumbformat(Plumbmsg *m, int i)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
plumbproc(void *argv)
|
plumbproc(void *arg)
|
||||||
{
|
{
|
||||||
Channel *c;
|
Fid *fid;
|
||||||
int i, *fdp;
|
int i;
|
||||||
void **arg;
|
|
||||||
Plumbmsg *m;
|
Plumbmsg *m;
|
||||||
|
|
||||||
arg = argv;
|
fid = arg;
|
||||||
c = arg[0];
|
|
||||||
fdp = arg[1];
|
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
threadfdnoblock(*fdp);
|
|
||||||
for(;;){
|
for(;;){
|
||||||
m = threadplumbrecv(*fdp);
|
m = plumbrecvfid(fid);
|
||||||
if(m == nil){
|
if(m == nil){
|
||||||
fprint(2, "samterm: plumb read error: %r\n");
|
fprint(2, "samterm: plumb read error: %r\n");
|
||||||
threadexits("plumb"); /* not a fatal error */
|
threadexits("plumb"); /* not a fatal error */
|
||||||
}
|
}
|
||||||
if(plumbformat(m, i)){
|
if(plumbformat(m, i)){
|
||||||
send(c, &i);
|
send(plumbc, &i);
|
||||||
i = 1-i; /* toggle */
|
i = 1-i; /* toggle */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -241,21 +242,18 @@ plumbproc(void *argv)
|
|||||||
int
|
int
|
||||||
plumbstart(void)
|
plumbstart(void)
|
||||||
{
|
{
|
||||||
static int fd;
|
Fid *fid;
|
||||||
static void *arg[2];
|
|
||||||
|
|
||||||
plumbfd = plumbopen("send", OWRITE|OCEXEC); /* not open is ok */
|
plumbfd = plumbopen("send", OWRITE|OCEXEC); /* not open is ok */
|
||||||
fd = plumbopen("edit", OREAD|OCEXEC);
|
fid = plumbopenfid("edit", OREAD|OCEXEC);
|
||||||
if(fd < 0)
|
if(fid == nil)
|
||||||
return -1;
|
return -1;
|
||||||
plumbc = chancreate(sizeof(int), 0);
|
plumbc = chancreate(sizeof(int), 0);
|
||||||
if(plumbc == nil){
|
if(plumbc == nil){
|
||||||
close(fd);
|
fsclose(fid);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
arg[0] = plumbc;
|
threadcreate(plumbproc, fid, STACK);
|
||||||
arg[1] = &fd;
|
|
||||||
threadcreate(plumbproc, arg, STACK);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
|
#include <sys/stat.h>
|
||||||
#include "stdinc.h"
|
#include "stdinc.h"
|
||||||
#include "vac.h"
|
#include "vac.h"
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
|
int mainstacksize = 128*1024;
|
||||||
|
|
||||||
typedef struct Sink Sink;
|
typedef struct Sink Sink;
|
||||||
typedef struct MetaSink MetaSink;
|
typedef struct MetaSink MetaSink;
|
||||||
typedef struct DirSink DirSink;
|
typedef struct DirSink DirSink;
|
||||||
@ -170,6 +173,9 @@ threadmain(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
}ARGEND;
|
}ARGEND;
|
||||||
|
|
||||||
|
if(argc == 0)
|
||||||
|
usage();
|
||||||
|
|
||||||
if(bsize < 512)
|
if(bsize < 512)
|
||||||
bsize = 512;
|
bsize = 512;
|
||||||
if(bsize > VtMaxLumpSize)
|
if(bsize > VtMaxLumpSize)
|
||||||
@ -215,8 +221,6 @@ vacwrite(VtConn *z, uchar score[VtScoreSize], int type, uchar *buf, int n)
|
|||||||
sha1(buf, n, score, nil);
|
sha1(buf, n, score, nil);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
sha1(buf, n, score, nil);
|
|
||||||
fprint(2, "write %V %d\n", score, type);
|
|
||||||
return vtwrite(z, score, type, buf, n);
|
return vtwrite(z, score, type, buf, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -377,6 +381,18 @@ isexcluded(char *name)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
islink(char *name)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
if(lstat(name, &st) < 0)
|
||||||
|
return 0;
|
||||||
|
if((st.st_mode&S_IFMT) == S_IFLNK)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
vacfile(DirSink *dsink, char *lname, char *sname, VacFile *vf)
|
vacfile(DirSink *dsink, char *lname, char *sname, VacFile *vf)
|
||||||
{
|
{
|
||||||
@ -393,6 +409,9 @@ vacfile(DirSink *dsink, char *lname, char *sname, VacFile *vf)
|
|||||||
if(merge && vacmerge(dsink, lname, sname) >= 0)
|
if(merge && vacmerge(dsink, lname, sname) >= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if(islink(sname))
|
||||||
|
return;
|
||||||
|
|
||||||
fd = open(sname, OREAD);
|
fd = open(sname, OREAD);
|
||||||
if(fd < 0) {
|
if(fd < 0) {
|
||||||
warn("could not open file: %s: %r", lname);
|
warn("could not open file: %s: %r", lname);
|
||||||
@ -820,10 +839,8 @@ sinkclose(Sink *k)
|
|||||||
if(k->pbuf[n] > k->buf + kd->psize*n)
|
if(k->pbuf[n] > k->buf + kd->psize*n)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
fprint(2, "type %d -> ", kd->type);
|
|
||||||
base = kd->type&~VtTypeDepthMask;
|
base = kd->type&~VtTypeDepthMask;
|
||||||
kd->type = base + sizetodepth(kd->size, kd->psize, kd->dsize);
|
kd->type = base + sizetodepth(kd->size, kd->psize, kd->dsize);
|
||||||
fprint(2, "%d ", kd->type);
|
|
||||||
|
|
||||||
/* skip full part of tree */
|
/* skip full part of tree */
|
||||||
for(i=0; i<n && k->pbuf[i] == k->buf + kd->psize*i; i++)
|
for(i=0; i<n && k->pbuf[i] == k->buf + kd->psize*i; i++)
|
||||||
@ -831,7 +848,6 @@ fprint(2, "%d ", kd->type);
|
|||||||
|
|
||||||
/* is the tree completely full */
|
/* is the tree completely full */
|
||||||
if(i == n && k->pbuf[n] == k->buf + kd->psize*n + VtScoreSize) {
|
if(i == n && k->pbuf[n] == k->buf + kd->psize*n + VtScoreSize) {
|
||||||
fprint(2, "full\n");
|
|
||||||
memmove(kd->score, k->pbuf[n] - VtScoreSize, VtScoreSize);
|
memmove(kd->score, k->pbuf[n] - VtScoreSize, VtScoreSize);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -846,7 +862,6 @@ fprint(2, "full\n");
|
|||||||
k->pbuf[i+1] += VtScoreSize;
|
k->pbuf[i+1] += VtScoreSize;
|
||||||
}
|
}
|
||||||
memmove(kd->score, k->pbuf[i] - VtScoreSize, VtScoreSize);
|
memmove(kd->score, k->pbuf[i] - VtScoreSize, VtScoreSize);
|
||||||
fprint(2, "%V\n", kd->score);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -881,7 +896,6 @@ dirsinkwrite(DirSink *k, VtEntry *dir)
|
|||||||
sinkwrite(k->sink, k->buf, k->p - k->buf);
|
sinkwrite(k->sink, k->buf, k->p - k->buf);
|
||||||
k->p = k->buf;
|
k->p = k->buf;
|
||||||
}
|
}
|
||||||
fprint(2, "write entry %V %d\n", dir->score, dir->type);
|
|
||||||
vtentrypack(dir, k->p, 0);
|
vtentrypack(dir, k->p, 0);
|
||||||
k->nentry++;
|
k->nentry++;
|
||||||
k->p += VtEntrySize;
|
k->p += VtEntrySize;
|
||||||
|
|||||||
@ -22,6 +22,5 @@ p9putenv(char *s, char *v)
|
|||||||
if(t == nil)
|
if(t == nil)
|
||||||
return -1;
|
return -1;
|
||||||
putenv(t);
|
putenv(t);
|
||||||
free(t);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -107,6 +107,8 @@ LIB9OFILES=\
|
|||||||
getuser.$O\
|
getuser.$O\
|
||||||
getwd.$O\
|
getwd.$O\
|
||||||
jmp.$O\
|
jmp.$O\
|
||||||
|
lrand.$O\
|
||||||
|
lnrand.$O\
|
||||||
lock.$O\
|
lock.$O\
|
||||||
main.$O\
|
main.$O\
|
||||||
malloc.$O\
|
malloc.$O\
|
||||||
@ -119,6 +121,7 @@ LIB9OFILES=\
|
|||||||
nrand.$O\
|
nrand.$O\
|
||||||
nulldir.$O\
|
nulldir.$O\
|
||||||
open.$O\
|
open.$O\
|
||||||
|
opentemp.$O\
|
||||||
pipe.$O\
|
pipe.$O\
|
||||||
post9p.$O\
|
post9p.$O\
|
||||||
postnote.$O\
|
postnote.$O\
|
||||||
|
|||||||
@ -3,6 +3,11 @@
|
|||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We use socketpair to get a two-way pipe.
|
||||||
|
* The pipe still doesn't preserve message boundaries.
|
||||||
|
* Worse, it cannot be reopened via /dev/fd/NNN on Linux.
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
p9pipe(int fd[2])
|
p9pipe(int fd[2])
|
||||||
{
|
{
|
||||||
|
|||||||
77
src/lib9p/_post.c
Normal file
77
src/lib9p/_post.c
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <fcall.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <9p.h>
|
||||||
|
#include <auth.h>
|
||||||
|
#include "post.h"
|
||||||
|
|
||||||
|
Postcrud*
|
||||||
|
_post1(Srv *s, char *name, char *mtpt, int flag)
|
||||||
|
{
|
||||||
|
Postcrud *p;
|
||||||
|
|
||||||
|
p = emalloc9p(sizeof *p);
|
||||||
|
if(!s->nopipe){
|
||||||
|
if(pipe(p->fd) < 0)
|
||||||
|
sysfatal("pipe: %r");
|
||||||
|
s->infd = s->outfd = p->fd[1];
|
||||||
|
s->srvfd = p->fd[0];
|
||||||
|
}
|
||||||
|
if(name)
|
||||||
|
if(postfd(name, s->srvfd) < 0)
|
||||||
|
sysfatal("postfd %s: %r", name);
|
||||||
|
p->s = s;
|
||||||
|
p->mtpt = mtpt;
|
||||||
|
p->flag = flag;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_post2(void *v)
|
||||||
|
{
|
||||||
|
Srv *s;
|
||||||
|
|
||||||
|
s = v;
|
||||||
|
rfork(RFNOTEG);
|
||||||
|
if(!s->leavefdsopen){
|
||||||
|
rendezvous((ulong)s, 0);
|
||||||
|
close(s->srvfd);
|
||||||
|
}
|
||||||
|
srv(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_post3(Postcrud *p)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Normally the server is posting as the last thing it does
|
||||||
|
* before exiting, so the correct thing to do is drop into
|
||||||
|
* a different fd space and close the 9P server half of the
|
||||||
|
* pipe before trying to mount the kernel half. This way,
|
||||||
|
* if the file server dies, we don't have a ref to the 9P server
|
||||||
|
* half of the pipe. Then killing the other procs will drop
|
||||||
|
* all the refs on the 9P server half, and the mount will fail.
|
||||||
|
* Otherwise the mount hangs forever.
|
||||||
|
*
|
||||||
|
* Libthread in general and acme win in particular make
|
||||||
|
* it hard to make this fd bookkeeping work out properly,
|
||||||
|
* so leaveinfdopen is a flag that win sets to opt out of this
|
||||||
|
* safety net.
|
||||||
|
*/
|
||||||
|
if(!p->s->leavefdsopen){
|
||||||
|
rfork(RFFDG);
|
||||||
|
rendezvous((ulong)p->s, 0);
|
||||||
|
close(p->s->infd);
|
||||||
|
if(p->s->infd != p->s->outfd)
|
||||||
|
close(p->s->outfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(p->mtpt){
|
||||||
|
if(amount(p->s->srvfd, p->mtpt, p->flag, "") == -1)
|
||||||
|
sysfatal("mount %s: %r", p->mtpt);
|
||||||
|
}else
|
||||||
|
close(p->s->srvfd);
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
|
||||||
40
src/lib9p/dirread.c
Normal file
40
src/lib9p/dirread.c
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <auth.h>
|
||||||
|
#include <fcall.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <9p.h>
|
||||||
|
|
||||||
|
void
|
||||||
|
dirread9p(Req *r, Dirgen *gen, void *aux)
|
||||||
|
{
|
||||||
|
int start;
|
||||||
|
uchar *p, *ep;
|
||||||
|
uint rv;
|
||||||
|
Dir d;
|
||||||
|
|
||||||
|
if(r->ifcall.offset == 0)
|
||||||
|
start = 0;
|
||||||
|
else
|
||||||
|
start = r->fid->dirindex;
|
||||||
|
|
||||||
|
p = (uchar*)r->ofcall.data;
|
||||||
|
ep = p+r->ifcall.count;
|
||||||
|
|
||||||
|
while(p < ep){
|
||||||
|
memset(&d, 0, sizeof d);
|
||||||
|
if((*gen)(start, &d, aux) < 0)
|
||||||
|
break;
|
||||||
|
rv = convD2M(&d, p, ep-p);
|
||||||
|
free(d.name);
|
||||||
|
free(d.muid);
|
||||||
|
free(d.uid);
|
||||||
|
free(d.gid);
|
||||||
|
if(rv <= BIT16SZ)
|
||||||
|
break;
|
||||||
|
p += rv;
|
||||||
|
start++;
|
||||||
|
}
|
||||||
|
r->fid->dirindex = start;
|
||||||
|
r->ofcall.count = p - (uchar*)r->ofcall.data;
|
||||||
|
}
|
||||||
81
src/lib9p/fid.c
Normal file
81
src/lib9p/fid.c
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <auth.h>
|
||||||
|
#include <fcall.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include "9p.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
incfidref(void *v)
|
||||||
|
{
|
||||||
|
Fid *f;
|
||||||
|
|
||||||
|
f = v;
|
||||||
|
if(f)
|
||||||
|
incref(&f->ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
Fidpool*
|
||||||
|
allocfidpool(void (*destroy)(Fid*))
|
||||||
|
{
|
||||||
|
Fidpool *f;
|
||||||
|
|
||||||
|
f = emalloc9p(sizeof *f);
|
||||||
|
f->map = allocmap(incfidref);
|
||||||
|
f->destroy = destroy;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
freefidpool(Fidpool *p)
|
||||||
|
{
|
||||||
|
freemap(p->map, (void(*)(void*))p->destroy);
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
Fid*
|
||||||
|
allocfid(Fidpool *pool, ulong fid)
|
||||||
|
{
|
||||||
|
Fid *f;
|
||||||
|
|
||||||
|
f = emalloc9p(sizeof *f);
|
||||||
|
f->fid = fid;
|
||||||
|
f->omode = -1;
|
||||||
|
f->pool = pool;
|
||||||
|
|
||||||
|
incfidref(f);
|
||||||
|
incfidref(f);
|
||||||
|
if(caninsertkey(pool->map, fid, f) == 0){
|
||||||
|
closefid(f);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
Fid*
|
||||||
|
lookupfid(Fidpool *pool, ulong fid)
|
||||||
|
{
|
||||||
|
return lookupkey(pool->map, fid);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
closefid(Fid *f)
|
||||||
|
{
|
||||||
|
if(decref(&f->ref) == 0) {
|
||||||
|
if(f->rdir)
|
||||||
|
closedirfile(f->rdir);
|
||||||
|
if(f->pool->destroy)
|
||||||
|
f->pool->destroy(f);
|
||||||
|
if(f->file)
|
||||||
|
closefile(f->file);
|
||||||
|
free(f->uid);
|
||||||
|
free(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Fid*
|
||||||
|
removefid(Fidpool *pool, ulong fid)
|
||||||
|
{
|
||||||
|
return deletekey(pool->map, fid);
|
||||||
|
}
|
||||||
372
src/lib9p/file.c
Normal file
372
src/lib9p/file.c
Normal file
@ -0,0 +1,372 @@
|
|||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <auth.h>
|
||||||
|
#include <fcall.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <9p.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* To avoid deadlock, the following rules must be followed.
|
||||||
|
* Always lock child then parent, never parent then child.
|
||||||
|
* If holding the free file lock, do not lock any Files.
|
||||||
|
*/
|
||||||
|
struct Filelist {
|
||||||
|
File *f;
|
||||||
|
Filelist *link;
|
||||||
|
};
|
||||||
|
|
||||||
|
static QLock filelk;
|
||||||
|
static File *freefilelist;
|
||||||
|
|
||||||
|
static File*
|
||||||
|
allocfile(void)
|
||||||
|
{
|
||||||
|
int i, a;
|
||||||
|
File *f;
|
||||||
|
enum { N = 16 };
|
||||||
|
|
||||||
|
qlock(&filelk);
|
||||||
|
if(freefilelist == nil){
|
||||||
|
f = emalloc9p(N*sizeof(*f));
|
||||||
|
for(i=0; i<N-1; i++)
|
||||||
|
f[i].aux = &f[i+1];
|
||||||
|
f[N-1].aux = nil;
|
||||||
|
f[0].allocd = 1;
|
||||||
|
freefilelist = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
f = freefilelist;
|
||||||
|
freefilelist = f->aux;
|
||||||
|
qunlock(&filelk);
|
||||||
|
|
||||||
|
a = f->allocd;
|
||||||
|
memset(f, 0, sizeof *f);
|
||||||
|
f->allocd = a;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
freefile(File *f)
|
||||||
|
{
|
||||||
|
Filelist *fl, *flnext;
|
||||||
|
|
||||||
|
for(fl=f->filelist; fl; fl=flnext){
|
||||||
|
flnext = fl->link;
|
||||||
|
assert(fl->f == nil);
|
||||||
|
free(fl);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(f->dir.name);
|
||||||
|
free(f->dir.uid);
|
||||||
|
free(f->dir.gid);
|
||||||
|
free(f->dir.muid);
|
||||||
|
qlock(&filelk);
|
||||||
|
assert(f->ref.ref == 0);
|
||||||
|
f->aux = freefilelist;
|
||||||
|
freefilelist = f;
|
||||||
|
qunlock(&filelk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
closefile(File *f)
|
||||||
|
{
|
||||||
|
if(decref(&f->ref) == 0){
|
||||||
|
f->tree->destroy(f);
|
||||||
|
freefile(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nop(File *f)
|
||||||
|
{
|
||||||
|
USED(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
removefile(File *f)
|
||||||
|
{
|
||||||
|
File *fp;
|
||||||
|
Filelist *fl;
|
||||||
|
|
||||||
|
fp = f->parent;
|
||||||
|
if(fp == nil){
|
||||||
|
werrstr("no parent");
|
||||||
|
closefile(f);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fp == f){
|
||||||
|
werrstr("cannot remove root");
|
||||||
|
closefile(f);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlock(&fp->rwlock);
|
||||||
|
wlock(&f->rwlock);
|
||||||
|
if(f->nchild != 0){
|
||||||
|
werrstr("has children");
|
||||||
|
wunlock(&f->rwlock);
|
||||||
|
wunlock(&fp->rwlock);
|
||||||
|
closefile(f);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(f->parent != fp){
|
||||||
|
werrstr("parent changed underfoot");
|
||||||
|
wunlock(&f->rwlock);
|
||||||
|
wunlock(&fp->rwlock);
|
||||||
|
closefile(f);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(fl=fp->filelist; fl; fl=fl->link)
|
||||||
|
if(fl->f == f)
|
||||||
|
break;
|
||||||
|
assert(fl != nil && fl->f == f);
|
||||||
|
|
||||||
|
fl->f = nil;
|
||||||
|
fp->nchild--;
|
||||||
|
f->parent = nil;
|
||||||
|
wunlock(&fp->rwlock);
|
||||||
|
wunlock(&f->rwlock);
|
||||||
|
|
||||||
|
closefile(fp); /* reference from child */
|
||||||
|
closefile(f); /* reference from tree */
|
||||||
|
closefile(f);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
File*
|
||||||
|
createfile(File *fp, char *name, char *uid, ulong perm, void *aux)
|
||||||
|
{
|
||||||
|
File *f;
|
||||||
|
Filelist *fl, *freel;
|
||||||
|
Tree *t;
|
||||||
|
|
||||||
|
if((fp->dir.qid.type&QTDIR) == 0){
|
||||||
|
werrstr("create in non-directory");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
freel = nil;
|
||||||
|
wlock(&fp->rwlock);
|
||||||
|
for(fl=fp->filelist; fl; fl=fl->link){
|
||||||
|
if(fl->f == nil)
|
||||||
|
freel = fl;
|
||||||
|
else if(strcmp(fl->f->dir.name, name) == 0){
|
||||||
|
wunlock(&fp->rwlock);
|
||||||
|
werrstr("file already exists");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(freel == nil){
|
||||||
|
freel = emalloc9p(sizeof *freel);
|
||||||
|
freel->link = fp->filelist;
|
||||||
|
fp->filelist = freel;
|
||||||
|
}
|
||||||
|
|
||||||
|
f = allocfile();
|
||||||
|
f->dir.name = estrdup9p(name);
|
||||||
|
f->dir.uid = estrdup9p(uid ? uid : fp->dir.uid);
|
||||||
|
f->dir.gid = estrdup9p(fp->dir.gid);
|
||||||
|
f->dir.muid = estrdup9p(uid ? uid : "unknown");
|
||||||
|
f->aux = aux;
|
||||||
|
f->dir.mode = perm;
|
||||||
|
|
||||||
|
t = fp->tree;
|
||||||
|
lock(&t->genlock);
|
||||||
|
f->dir.qid.path = t->qidgen++;
|
||||||
|
unlock(&t->genlock);
|
||||||
|
if(perm & DMDIR)
|
||||||
|
f->dir.qid.type |= QTDIR;
|
||||||
|
if(perm & DMAPPEND)
|
||||||
|
f->dir.qid.type |= QTAPPEND;
|
||||||
|
if(perm & DMEXCL)
|
||||||
|
f->dir.qid.type |= QTEXCL;
|
||||||
|
|
||||||
|
f->dir.mode = perm;
|
||||||
|
f->dir.atime = f->dir.mtime = time(0);
|
||||||
|
f->dir.length = 0;
|
||||||
|
f->parent = fp;
|
||||||
|
incref(&fp->ref);
|
||||||
|
f->tree = fp->tree;
|
||||||
|
|
||||||
|
incref(&f->ref); /* being returned */
|
||||||
|
incref(&f->ref); /* for the tree */
|
||||||
|
freel->f = f;
|
||||||
|
fp->nchild++;
|
||||||
|
wunlock(&fp->rwlock);
|
||||||
|
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
static File*
|
||||||
|
walkfile1(File *dir, char *elem)
|
||||||
|
{
|
||||||
|
File *fp;
|
||||||
|
Filelist *fl;
|
||||||
|
|
||||||
|
rlock(&dir->rwlock);
|
||||||
|
if(strcmp(elem, "..") == 0){
|
||||||
|
fp = dir->parent;
|
||||||
|
incref(&fp->ref);
|
||||||
|
runlock(&dir->rwlock);
|
||||||
|
closefile(dir);
|
||||||
|
return fp;
|
||||||
|
}
|
||||||
|
|
||||||
|
fp = nil;
|
||||||
|
for(fl=dir->filelist; fl; fl=fl->link)
|
||||||
|
if(fl->f && strcmp(fl->f->dir.name, elem)==0){
|
||||||
|
fp = fl->f;
|
||||||
|
incref(&fp->ref);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
runlock(&dir->rwlock);
|
||||||
|
closefile(dir);
|
||||||
|
return fp;
|
||||||
|
}
|
||||||
|
|
||||||
|
File*
|
||||||
|
walkfile(File *f, char *path)
|
||||||
|
{
|
||||||
|
char *os, *s, *nexts;
|
||||||
|
File *nf;
|
||||||
|
|
||||||
|
if(strchr(path, '/') == nil)
|
||||||
|
return walkfile1(f, path); /* avoid malloc */
|
||||||
|
|
||||||
|
os = s = estrdup9p(path);
|
||||||
|
incref(&f->ref);
|
||||||
|
for(; *s; s=nexts){
|
||||||
|
if(nexts = strchr(s, '/'))
|
||||||
|
*nexts++ = '\0';
|
||||||
|
else
|
||||||
|
nexts = s+strlen(s);
|
||||||
|
nf = walkfile1(f, s);
|
||||||
|
decref(&f->ref);
|
||||||
|
f = nf;
|
||||||
|
if(f == nil)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
free(os);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tree*
|
||||||
|
alloctree(char *uid, char *gid, ulong mode, void (*destroy)(File*))
|
||||||
|
{
|
||||||
|
char *muid;
|
||||||
|
Tree *t;
|
||||||
|
File *f;
|
||||||
|
|
||||||
|
t = emalloc9p(sizeof *t);
|
||||||
|
f = allocfile();
|
||||||
|
f->dir.name = estrdup9p("/");
|
||||||
|
if(uid == nil){
|
||||||
|
if(uid = getuser())
|
||||||
|
uid = estrdup9p(uid);
|
||||||
|
}
|
||||||
|
if(uid == nil)
|
||||||
|
uid = estrdup9p("none");
|
||||||
|
else
|
||||||
|
uid = estrdup9p(uid);
|
||||||
|
|
||||||
|
if(gid == nil)
|
||||||
|
gid = estrdup9p(uid);
|
||||||
|
else
|
||||||
|
gid = estrdup9p(gid);
|
||||||
|
|
||||||
|
muid = estrdup9p(uid);
|
||||||
|
|
||||||
|
f->dir.qid = (Qid){0, 0, QTDIR};
|
||||||
|
f->dir.length = 0;
|
||||||
|
f->dir.atime = f->dir.mtime = time(0);
|
||||||
|
f->dir.mode = DMDIR | mode;
|
||||||
|
f->tree = t;
|
||||||
|
f->parent = f;
|
||||||
|
f->dir.uid = uid;
|
||||||
|
f->dir.gid = gid;
|
||||||
|
f->dir.muid = muid;
|
||||||
|
|
||||||
|
incref(&f->ref);
|
||||||
|
t->root = f;
|
||||||
|
t->qidgen = 0;
|
||||||
|
t->dirqidgen = 1;
|
||||||
|
if(destroy == nil)
|
||||||
|
destroy = nop;
|
||||||
|
t->destroy = destroy;
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_freefiles(File *f)
|
||||||
|
{
|
||||||
|
Filelist *fl, *flnext;
|
||||||
|
|
||||||
|
for(fl=f->filelist; fl; fl=flnext){
|
||||||
|
flnext = fl->link;
|
||||||
|
_freefiles(fl->f);
|
||||||
|
free(fl);
|
||||||
|
}
|
||||||
|
|
||||||
|
f->tree->destroy(f);
|
||||||
|
freefile(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
freetree(Tree *t)
|
||||||
|
{
|
||||||
|
_freefiles(t->root);
|
||||||
|
free(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Readdir {
|
||||||
|
Filelist *fl;
|
||||||
|
};
|
||||||
|
|
||||||
|
Readdir*
|
||||||
|
opendirfile(File *dir)
|
||||||
|
{
|
||||||
|
Readdir *r;
|
||||||
|
|
||||||
|
rlock(&dir->rwlock);
|
||||||
|
if((dir->dir.mode & DMDIR)==0){
|
||||||
|
runlock(&dir->rwlock);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
r = emalloc9p(sizeof(*r));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This reference won't go away while we're using it
|
||||||
|
* since we are dir->rdir.
|
||||||
|
*/
|
||||||
|
r->fl = dir->filelist;
|
||||||
|
runlock(&dir->rwlock);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
long
|
||||||
|
readdirfile(Readdir *r, uchar *buf, long n)
|
||||||
|
{
|
||||||
|
long x, m;
|
||||||
|
Filelist *fl;
|
||||||
|
|
||||||
|
for(fl=r->fl, m=0; fl && m+2<=n; fl=fl->link, m+=x){
|
||||||
|
if(fl->f == nil)
|
||||||
|
x = 0;
|
||||||
|
else if((x=convD2M(&fl->f->dir, buf+m, n-m)) <= BIT16SZ)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
r->fl = fl;
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
closedirfile(Readdir *r)
|
||||||
|
{
|
||||||
|
free(r);
|
||||||
|
}
|
||||||
29
src/lib9p/ftest.c
Normal file
29
src/lib9p/ftest.c
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <auth.h>
|
||||||
|
#include <fcall.h>
|
||||||
|
#include "9p.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
Tree *t;
|
||||||
|
File *hello, *goodbye, *world;
|
||||||
|
|
||||||
|
t = mktree();
|
||||||
|
|
||||||
|
hello = fcreate(t->root, "hello", CHDIR|0777);
|
||||||
|
assert(hello != nil);
|
||||||
|
|
||||||
|
goodbye = fcreate(t->root, "goodbye", CHDIR|0777);
|
||||||
|
assert(goodbye != nil);
|
||||||
|
|
||||||
|
world = fcreate(hello, "world", 0666);
|
||||||
|
assert(world != nil);
|
||||||
|
world = fcreate(goodbye, "world", 0666);
|
||||||
|
assert(world != nil);
|
||||||
|
fdump(t->root, 0);
|
||||||
|
|
||||||
|
fremove(world);
|
||||||
|
fdump(t->root, 0);
|
||||||
|
}
|
||||||
166
src/lib9p/intmap.c
Normal file
166
src/lib9p/intmap.c
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <auth.h>
|
||||||
|
#include <fcall.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <9p.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
NHASH = 128
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct Intlist Intlist;
|
||||||
|
struct Intlist
|
||||||
|
{
|
||||||
|
ulong id;
|
||||||
|
void* aux;
|
||||||
|
Intlist* link;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Intmap
|
||||||
|
{
|
||||||
|
RWLock rwlock;
|
||||||
|
Intlist* hash[NHASH];
|
||||||
|
void (*inc)(void*);
|
||||||
|
};
|
||||||
|
|
||||||
|
static ulong
|
||||||
|
hashid(ulong id)
|
||||||
|
{
|
||||||
|
return id%NHASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nop(void *v)
|
||||||
|
{
|
||||||
|
USED(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
Intmap*
|
||||||
|
allocmap(void (*inc)(void*))
|
||||||
|
{
|
||||||
|
Intmap *m;
|
||||||
|
|
||||||
|
m = emalloc9p(sizeof(*m));
|
||||||
|
if(inc == nil)
|
||||||
|
inc = nop;
|
||||||
|
m->inc = inc;
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
freemap(Intmap *map, void (*destroy)(void*))
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
Intlist *p, *nlink;
|
||||||
|
|
||||||
|
if(destroy == nil)
|
||||||
|
destroy = nop;
|
||||||
|
for(i=0; i<NHASH; i++){
|
||||||
|
for(p=map->hash[i]; p; p=nlink){
|
||||||
|
nlink = p->link;
|
||||||
|
destroy(p->aux);
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Intlist**
|
||||||
|
llookup(Intmap *map, ulong id)
|
||||||
|
{
|
||||||
|
Intlist **lf;
|
||||||
|
|
||||||
|
for(lf=&map->hash[hashid(id)]; *lf; lf=&(*lf)->link)
|
||||||
|
if((*lf)->id == id)
|
||||||
|
break;
|
||||||
|
return lf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The RWlock is used as expected except that we allow
|
||||||
|
* inc() to be called while holding it. This is because we're
|
||||||
|
* locking changes to the tree structure, not to the references.
|
||||||
|
* Inc() is expected to have its own locking.
|
||||||
|
*/
|
||||||
|
void*
|
||||||
|
lookupkey(Intmap *map, ulong id)
|
||||||
|
{
|
||||||
|
Intlist *f;
|
||||||
|
void *v;
|
||||||
|
|
||||||
|
rlock(&map->rwlock);
|
||||||
|
if(f = *llookup(map, id)){
|
||||||
|
v = f->aux;
|
||||||
|
map->inc(v);
|
||||||
|
}else
|
||||||
|
v = nil;
|
||||||
|
runlock(&map->rwlock);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
insertkey(Intmap *map, ulong id, void *v)
|
||||||
|
{
|
||||||
|
Intlist *f;
|
||||||
|
void *ov;
|
||||||
|
ulong h;
|
||||||
|
|
||||||
|
wlock(&map->rwlock);
|
||||||
|
if(f = *llookup(map, id)){
|
||||||
|
/* no decrement for ov because we're returning it */
|
||||||
|
ov = f->aux;
|
||||||
|
f->aux = v;
|
||||||
|
}else{
|
||||||
|
f = emalloc9p(sizeof(*f));
|
||||||
|
f->id = id;
|
||||||
|
f->aux = v;
|
||||||
|
h = hashid(id);
|
||||||
|
f->link = map->hash[h];
|
||||||
|
map->hash[h] = f;
|
||||||
|
ov = nil;
|
||||||
|
}
|
||||||
|
wunlock(&map->rwlock);
|
||||||
|
return ov;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
caninsertkey(Intmap *map, ulong id, void *v)
|
||||||
|
{
|
||||||
|
Intlist *f;
|
||||||
|
int rv;
|
||||||
|
ulong h;
|
||||||
|
|
||||||
|
wlock(&map->rwlock);
|
||||||
|
if(*llookup(map, id))
|
||||||
|
rv = 0;
|
||||||
|
else{
|
||||||
|
f = emalloc9p(sizeof *f);
|
||||||
|
f->id = id;
|
||||||
|
f->aux = v;
|
||||||
|
h = hashid(id);
|
||||||
|
f->link = map->hash[h];
|
||||||
|
map->hash[h] = f;
|
||||||
|
rv = 1;
|
||||||
|
}
|
||||||
|
wunlock(&map->rwlock);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
deletekey(Intmap *map, ulong id)
|
||||||
|
{
|
||||||
|
Intlist **lf, *f;
|
||||||
|
void *ov;
|
||||||
|
|
||||||
|
wlock(&map->rwlock);
|
||||||
|
if(f = *(lf = llookup(map, id))){
|
||||||
|
ov = f->aux;
|
||||||
|
*lf = f->link;
|
||||||
|
free(f);
|
||||||
|
}else
|
||||||
|
ov = nil;
|
||||||
|
wunlock(&map->rwlock);
|
||||||
|
return ov;
|
||||||
|
}
|
||||||
49
src/lib9p/mem.c
Normal file
49
src/lib9p/mem.c
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <auth.h>
|
||||||
|
#include <fcall.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include "9p.h"
|
||||||
|
|
||||||
|
void*
|
||||||
|
emalloc9p(ulong sz)
|
||||||
|
{
|
||||||
|
void *v;
|
||||||
|
|
||||||
|
if((v = malloc(sz)) == nil) {
|
||||||
|
fprint(2, "out of memory allocating %lud\n", sz);
|
||||||
|
exits("mem");
|
||||||
|
}
|
||||||
|
memset(v, 0, sz);
|
||||||
|
setmalloctag(v, getcallerpc(&sz));
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
erealloc9p(void *v, ulong sz)
|
||||||
|
{
|
||||||
|
void *nv;
|
||||||
|
|
||||||
|
if((nv = realloc(v, sz)) == nil) {
|
||||||
|
fprint(2, "out of memory allocating %lud\n", sz);
|
||||||
|
exits("mem");
|
||||||
|
}
|
||||||
|
if(v == nil)
|
||||||
|
setmalloctag(nv, getcallerpc(&v));
|
||||||
|
setrealloctag(nv, getcallerpc(&v));
|
||||||
|
return nv;
|
||||||
|
}
|
||||||
|
|
||||||
|
char*
|
||||||
|
estrdup9p(char *s)
|
||||||
|
{
|
||||||
|
char *t;
|
||||||
|
|
||||||
|
if((t = strdup(s)) == nil) {
|
||||||
|
fprint(2, "out of memory in strdup(%.10s)\n", s);
|
||||||
|
exits("mem");
|
||||||
|
}
|
||||||
|
setmalloctag(t, getcallerpc(&s));
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
20
src/lib9p/mkfile
Normal file
20
src/lib9p/mkfile
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
PLAN9=../..
|
||||||
|
<$PLAN9/src/mkhdr
|
||||||
|
|
||||||
|
LIB=lib9p.a
|
||||||
|
OFILES=\
|
||||||
|
_post.$O\
|
||||||
|
dirread.$O\
|
||||||
|
fid.$O\
|
||||||
|
file.$O\
|
||||||
|
intmap.$O\
|
||||||
|
mem.$O\
|
||||||
|
req.$O\
|
||||||
|
parse.$O\
|
||||||
|
post.$O\
|
||||||
|
srv.$O\
|
||||||
|
tpost.$O\
|
||||||
|
uid.$O\
|
||||||
|
util.$O\
|
||||||
|
|
||||||
|
<$PLAN9/src/mksyslib
|
||||||
115
src/lib9p/parse.c
Normal file
115
src/lib9p/parse.c
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <fcall.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <9p.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generous estimate of number of fields, including terminal nil pointer
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
ncmdfield(char *p, int n)
|
||||||
|
{
|
||||||
|
int white, nwhite;
|
||||||
|
char *ep;
|
||||||
|
int nf;
|
||||||
|
|
||||||
|
if(p == nil)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
nf = 0;
|
||||||
|
ep = p+n;
|
||||||
|
white = 1; /* first text will start field */
|
||||||
|
while(p < ep){
|
||||||
|
nwhite = (strchr(" \t\r\n", *p++ & 0xFF) != 0); /* UTF is irrelevant */
|
||||||
|
if(white && !nwhite) /* beginning of field */
|
||||||
|
nf++;
|
||||||
|
white = nwhite;
|
||||||
|
}
|
||||||
|
return nf+1; /* +1 for nil */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* parse a command written to a device
|
||||||
|
*/
|
||||||
|
Cmdbuf*
|
||||||
|
parsecmd(char *p, int n)
|
||||||
|
{
|
||||||
|
Cmdbuf *cb;
|
||||||
|
int nf;
|
||||||
|
char *sp;
|
||||||
|
|
||||||
|
nf = ncmdfield(p, n);
|
||||||
|
|
||||||
|
/* allocate Cmdbuf plus string pointers plus copy of string including \0 */
|
||||||
|
sp = emalloc9p(sizeof(*cb) + nf * sizeof(char*) + n + 1);
|
||||||
|
cb = (Cmdbuf*)sp;
|
||||||
|
cb->f = (char**)(&cb[1]);
|
||||||
|
cb->buf = (char*)(&cb->f[nf]);
|
||||||
|
|
||||||
|
memmove(cb->buf, p, n);
|
||||||
|
|
||||||
|
/* dump new line and null terminate */
|
||||||
|
if(n > 0 && cb->buf[n-1] == '\n')
|
||||||
|
n--;
|
||||||
|
cb->buf[n] = '\0';
|
||||||
|
|
||||||
|
cb->nf = tokenize(cb->buf, cb->f, nf-1);
|
||||||
|
cb->f[cb->nf] = nil;
|
||||||
|
|
||||||
|
return cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reconstruct original message, for error diagnostic
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
respondcmderror(Req *r, Cmdbuf *cb, char *fmt, ...)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
va_list arg;
|
||||||
|
char *p, *e;
|
||||||
|
char err[ERRMAX];
|
||||||
|
|
||||||
|
e = err+ERRMAX-10;
|
||||||
|
va_start(arg, fmt);
|
||||||
|
p = vseprint(err, e, fmt, arg);
|
||||||
|
va_end(arg);
|
||||||
|
p = seprint(p, e, ": \"");
|
||||||
|
for(i=0; i<cb->nf; i++){
|
||||||
|
if(i > 0)
|
||||||
|
p = seprint(p, e, " ");
|
||||||
|
p = seprint(p, e, "%q", cb->f[i]);
|
||||||
|
}
|
||||||
|
strcpy(p, "\"");
|
||||||
|
respond(r, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look up entry in table
|
||||||
|
*/
|
||||||
|
Cmdtab*
|
||||||
|
lookupcmd(Cmdbuf *cb, Cmdtab *ctab, int nctab)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
Cmdtab *ct;
|
||||||
|
|
||||||
|
if(cb->nf == 0){
|
||||||
|
werrstr("empty control message");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(ct = ctab, i=0; i<nctab; i++, ct++){
|
||||||
|
if(strcmp(ct->cmd, "*") !=0) /* wildcard always matches */
|
||||||
|
if(strcmp(ct->cmd, cb->f[0]) != 0)
|
||||||
|
continue;
|
||||||
|
if(ct->narg != 0 && ct->narg != cb->nf){
|
||||||
|
werrstr("bad # args to command");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
return ct;
|
||||||
|
}
|
||||||
|
|
||||||
|
werrstr("unknown control message");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
24
src/lib9p/post.c
Normal file
24
src/lib9p/post.c
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <fcall.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <9p.h>
|
||||||
|
#include "post.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
postmountsrv(Srv *s, char *name, char *mtpt, int flag)
|
||||||
|
{
|
||||||
|
Postcrud *p;
|
||||||
|
|
||||||
|
p = _post1(s, name, mtpt, flag);
|
||||||
|
switch(rfork(RFPROC|RFNOTEG|RFNAMEG|RFMEM)){
|
||||||
|
case -1:
|
||||||
|
sysfatal("rfork: %r");
|
||||||
|
case 0:
|
||||||
|
_post2(s);
|
||||||
|
exits(nil);
|
||||||
|
default:
|
||||||
|
_post3(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
13
src/lib9p/post.h
Normal file
13
src/lib9p/post.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
typedef struct Postcrud Postcrud;
|
||||||
|
struct Postcrud
|
||||||
|
{
|
||||||
|
int fd[2];
|
||||||
|
Srv *s;
|
||||||
|
char *name;
|
||||||
|
char *mtpt;
|
||||||
|
int flag;
|
||||||
|
};
|
||||||
|
|
||||||
|
Postcrud *_post1(Srv*, char*, char*, int);
|
||||||
|
void _post2(void*);
|
||||||
|
void _post3(Postcrud*);
|
||||||
163
src/lib9p/ramfs.c
Normal file
163
src/lib9p/ramfs.c
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <auth.h>
|
||||||
|
#include <fcall.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <9p.h>
|
||||||
|
|
||||||
|
static char Ebad[] = "something bad happened";
|
||||||
|
static char Enomem[] = "no memory";
|
||||||
|
|
||||||
|
typedef struct Ramfile Ramfile;
|
||||||
|
struct Ramfile {
|
||||||
|
char *data;
|
||||||
|
int ndata;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
fsread(Req *r)
|
||||||
|
{
|
||||||
|
Ramfile *rf;
|
||||||
|
vlong offset;
|
||||||
|
long count;
|
||||||
|
|
||||||
|
rf = r->fid->file->aux;
|
||||||
|
offset = r->ifcall.offset;
|
||||||
|
count = r->ifcall.count;
|
||||||
|
|
||||||
|
//print("read %ld %lld\n", *count, offset);
|
||||||
|
if(offset >= rf->ndata){
|
||||||
|
r->ofcall.count = 0;
|
||||||
|
respond(r, nil);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(offset+count >= rf->ndata)
|
||||||
|
count = rf->ndata - offset;
|
||||||
|
|
||||||
|
memmove(r->ofcall.data, rf->data+offset, count);
|
||||||
|
r->ofcall.count = count;
|
||||||
|
respond(r, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fswrite(Req *r)
|
||||||
|
{
|
||||||
|
void *v;
|
||||||
|
Ramfile *rf;
|
||||||
|
vlong offset;
|
||||||
|
long count;
|
||||||
|
|
||||||
|
rf = r->fid->file->aux;
|
||||||
|
offset = r->ifcall.offset;
|
||||||
|
count = r->ifcall.count;
|
||||||
|
|
||||||
|
if(offset+count >= rf->ndata){
|
||||||
|
v = realloc(rf->data, offset+count);
|
||||||
|
if(v == nil){
|
||||||
|
respond(r, Enomem);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rf->data = v;
|
||||||
|
rf->ndata = offset+count;
|
||||||
|
r->fid->file->length = rf->ndata;
|
||||||
|
}
|
||||||
|
memmove(rf->data+offset, r->ifcall.data, count);
|
||||||
|
r->ofcall.count = count;
|
||||||
|
respond(r, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fscreate(Req *r)
|
||||||
|
{
|
||||||
|
Ramfile *rf;
|
||||||
|
File *f;
|
||||||
|
|
||||||
|
if(f = createfile(r->fid->file, r->ifcall.name, r->fid->uid, r->ifcall.perm, nil)){
|
||||||
|
rf = emalloc9p(sizeof *rf);
|
||||||
|
f->aux = rf;
|
||||||
|
r->fid->file = f;
|
||||||
|
r->ofcall.qid = f->qid;
|
||||||
|
respond(r, nil);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
respond(r, Ebad);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fsopen(Req *r)
|
||||||
|
{
|
||||||
|
Ramfile *rf;
|
||||||
|
|
||||||
|
rf = r->fid->file->aux;
|
||||||
|
|
||||||
|
if(rf && (r->ifcall.mode&OTRUNC)){
|
||||||
|
rf->ndata = 0;
|
||||||
|
r->fid->file->length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
respond(r, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fsdestroyfile(File *f)
|
||||||
|
{
|
||||||
|
Ramfile *rf;
|
||||||
|
|
||||||
|
//fprint(2, "clunk\n");
|
||||||
|
rf = f->aux;
|
||||||
|
if(rf){
|
||||||
|
free(rf->data);
|
||||||
|
free(rf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Srv fs = {
|
||||||
|
.open= fsopen,
|
||||||
|
.read= fsread,
|
||||||
|
.write= fswrite,
|
||||||
|
.create= fscreate,
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
fprint(2, "usage: ramfs [-D] [-s srvname] [-m mtpt]\n");
|
||||||
|
exits("usage");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
char *srvname = nil;
|
||||||
|
char *mtpt = nil;
|
||||||
|
Qid q;
|
||||||
|
|
||||||
|
fs.tree = alloctree(nil, nil, DMDIR|0777, fsdestroyfile);
|
||||||
|
q = fs.tree->root->qid;
|
||||||
|
|
||||||
|
ARGBEGIN{
|
||||||
|
case 'D':
|
||||||
|
chatty9p++;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
srvname = EARGF(usage());
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
mtpt = EARGF(usage());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
}ARGEND;
|
||||||
|
|
||||||
|
if(argc)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
if(chatty9p)
|
||||||
|
fprint(2, "ramsrv.nopipe %d srvname %s mtpt %s\n", fs.nopipe, srvname, mtpt);
|
||||||
|
if(srvname == nil && mtpt == nil)
|
||||||
|
sysfatal("you should at least specify a -s or -m option");
|
||||||
|
|
||||||
|
postmountsrv(&fs, srvname, mtpt, MREPL|MCREATE);
|
||||||
|
exits(0);
|
||||||
|
}
|
||||||
112
src/lib9p/req.c
Normal file
112
src/lib9p/req.c
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <auth.h>
|
||||||
|
#include <fcall.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <9p.h>
|
||||||
|
|
||||||
|
static void
|
||||||
|
increqref(void *v)
|
||||||
|
{
|
||||||
|
Req *r;
|
||||||
|
|
||||||
|
r = v;
|
||||||
|
if(r){
|
||||||
|
if(chatty9p > 1)
|
||||||
|
fprint(2, "increfreq %p %ld\n", r, r->ref.ref);
|
||||||
|
incref(&r->ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Reqpool*
|
||||||
|
allocreqpool(void (*destroy)(Req*))
|
||||||
|
{
|
||||||
|
Reqpool *f;
|
||||||
|
|
||||||
|
f = emalloc9p(sizeof *f);
|
||||||
|
f->map = allocmap(increqref);
|
||||||
|
f->destroy = destroy;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
freereqpool(Reqpool *p)
|
||||||
|
{
|
||||||
|
freemap(p->map, (void(*)(void*))p->destroy);
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
Req*
|
||||||
|
allocreq(Reqpool *pool, ulong tag)
|
||||||
|
{
|
||||||
|
Req *r;
|
||||||
|
|
||||||
|
r = emalloc9p(sizeof *r);
|
||||||
|
r->tag = tag;
|
||||||
|
r->pool = pool;
|
||||||
|
|
||||||
|
increqref(r);
|
||||||
|
increqref(r);
|
||||||
|
if(caninsertkey(pool->map, tag, r) == 0){
|
||||||
|
closereq(r);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
Req*
|
||||||
|
lookupreq(Reqpool *pool, ulong tag)
|
||||||
|
{
|
||||||
|
if(chatty9p > 1)
|
||||||
|
fprint(2, "lookupreq %lud\n", tag);
|
||||||
|
return lookupkey(pool->map, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
closereq(Req *r)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(r == nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(chatty9p > 1)
|
||||||
|
fprint(2, "closereq %p %ld\n", r, r->ref.ref);
|
||||||
|
|
||||||
|
if(decref(&r->ref) == 0){
|
||||||
|
if(r->fid)
|
||||||
|
closefid(r->fid);
|
||||||
|
if(r->newfid)
|
||||||
|
closefid(r->newfid);
|
||||||
|
if(r->afid)
|
||||||
|
closefid(r->afid);
|
||||||
|
if(r->oldreq)
|
||||||
|
closereq(r->oldreq);
|
||||||
|
for(i=0; i<r->nflush; i++)
|
||||||
|
respond(r->flush[i], nil);
|
||||||
|
free(r->flush);
|
||||||
|
switch(r->ifcall.type){
|
||||||
|
case Tstat:
|
||||||
|
free(r->ofcall.stat);
|
||||||
|
free(r->d.name);
|
||||||
|
free(r->d.uid);
|
||||||
|
free(r->d.gid);
|
||||||
|
free(r->d.muid);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(r->pool->destroy)
|
||||||
|
r->pool->destroy(r);
|
||||||
|
free(r->buf);
|
||||||
|
free(r->rbuf);
|
||||||
|
free(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Req*
|
||||||
|
removereq(Reqpool *pool, ulong tag)
|
||||||
|
{
|
||||||
|
if(chatty9p > 1)
|
||||||
|
fprint(2, "removereq %lud\n", tag);
|
||||||
|
return deletekey(pool->map, tag);
|
||||||
|
}
|
||||||
837
src/lib9p/srv.c
Normal file
837
src/lib9p/srv.c
Normal file
@ -0,0 +1,837 @@
|
|||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <auth.h>
|
||||||
|
#include <fcall.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <9p.h>
|
||||||
|
|
||||||
|
// static char Ebadattach[] = "unknown specifier in attach";
|
||||||
|
static char Ebadoffset[] = "bad offset";
|
||||||
|
// static char Ebadcount[] = "bad count";
|
||||||
|
static char Ebotch[] = "9P protocol botch";
|
||||||
|
static char Ecreatenondir[] = "create in non-directory";
|
||||||
|
static char Edupfid[] = "duplicate fid";
|
||||||
|
static char Eduptag[] = "duplicate tag";
|
||||||
|
static char Eisdir[] = "is a directory";
|
||||||
|
static char Enocreate[] = "create prohibited";
|
||||||
|
// static char Enomem[] = "out of memory";
|
||||||
|
static char Enoremove[] = "remove prohibited";
|
||||||
|
static char Enostat[] = "stat prohibited";
|
||||||
|
static char Enotfound[] = "file not found";
|
||||||
|
// static char Enowrite[] = "write prohibited";
|
||||||
|
static char Enowstat[] = "wstat prohibited";
|
||||||
|
static char Eperm[] = "permission denied";
|
||||||
|
static char Eunknownfid[] = "unknown fid";
|
||||||
|
static char Ebaddir[] = "bad directory in wstat";
|
||||||
|
static char Ewalknodir[] = "walk in non-directory";
|
||||||
|
|
||||||
|
static void
|
||||||
|
setfcallerror(Fcall *f, char *err)
|
||||||
|
{
|
||||||
|
f->ename = err;
|
||||||
|
f->type = Rerror;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
changemsize(Srv *srv, int msize)
|
||||||
|
{
|
||||||
|
if(srv->rbuf && srv->wbuf && srv->msize == msize)
|
||||||
|
return;
|
||||||
|
qlock(&srv->rlock);
|
||||||
|
qlock(&srv->wlock);
|
||||||
|
srv->msize = msize;
|
||||||
|
free(srv->rbuf);
|
||||||
|
free(srv->wbuf);
|
||||||
|
srv->rbuf = emalloc9p(msize);
|
||||||
|
srv->wbuf = emalloc9p(msize);
|
||||||
|
qunlock(&srv->rlock);
|
||||||
|
qunlock(&srv->wlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Req*
|
||||||
|
getreq(Srv *s)
|
||||||
|
{
|
||||||
|
long n;
|
||||||
|
uchar *buf;
|
||||||
|
Fcall f;
|
||||||
|
Req *r;
|
||||||
|
|
||||||
|
qlock(&s->rlock);
|
||||||
|
if((n = read9pmsg(s->infd, s->rbuf, s->msize)) <= 0){
|
||||||
|
qunlock(&s->rlock);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = emalloc9p(n);
|
||||||
|
memmove(buf, s->rbuf, n);
|
||||||
|
qunlock(&s->rlock);
|
||||||
|
|
||||||
|
if(convM2S(buf, n, &f) != n){
|
||||||
|
free(buf);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((r=allocreq(s->rpool, f.tag)) == nil){ /* duplicate tag: cons up a fake Req */
|
||||||
|
r = emalloc9p(sizeof *r);
|
||||||
|
incref(&r->ref);
|
||||||
|
r->tag = f.tag;
|
||||||
|
r->ifcall = f;
|
||||||
|
r->error = Eduptag;
|
||||||
|
r->buf = buf;
|
||||||
|
r->responded = 0;
|
||||||
|
r->type = 0;
|
||||||
|
r->srv = s;
|
||||||
|
r->pool = nil;
|
||||||
|
if(chatty9p)
|
||||||
|
fprint(2, "<-%d- %F: dup tag\n", s->infd, &f);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
r->srv = s;
|
||||||
|
r->responded = 0;
|
||||||
|
r->buf = buf;
|
||||||
|
r->ifcall = f;
|
||||||
|
memset(&r->ofcall, 0, sizeof r->ofcall);
|
||||||
|
r->type = r->ifcall.type;
|
||||||
|
|
||||||
|
if(chatty9p)
|
||||||
|
if(r->error)
|
||||||
|
fprint(2, "<-%d- %F: %s\n", s->infd, &r->ifcall, r->error);
|
||||||
|
else
|
||||||
|
fprint(2, "<-%d- %F\n", s->infd, &r->ifcall);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
filewalk(Req *r)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
File *f;
|
||||||
|
|
||||||
|
f = r->fid->file;
|
||||||
|
assert(f != nil);
|
||||||
|
|
||||||
|
incref(&f->ref);
|
||||||
|
for(i=0; i<r->ifcall.nwname; i++)
|
||||||
|
if(f = walkfile(f, r->ifcall.wname[i]))
|
||||||
|
r->ofcall.wqid[i] = f->dir.qid;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
|
||||||
|
r->ofcall.nwqid = i;
|
||||||
|
if(f){
|
||||||
|
r->newfid->file = f;
|
||||||
|
r->newfid->qid = r->newfid->file->dir.qid;
|
||||||
|
}
|
||||||
|
respond(r, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
walkandclone(Req *r, char *(*walk1)(Fid*, char*, void*), char *(*clone)(Fid*, Fid*, void*), void *arg)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char *e;
|
||||||
|
|
||||||
|
if(r->fid == r->newfid && r->ifcall.nwname > 1){
|
||||||
|
respond(r, "lib9p: unused documented feature not implemented");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(r->fid != r->newfid){
|
||||||
|
r->newfid->qid = r->fid->qid;
|
||||||
|
if(clone && (e = clone(r->fid, r->newfid, arg))){
|
||||||
|
respond(r, e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
e = nil;
|
||||||
|
for(i=0; i<r->ifcall.nwname; i++){
|
||||||
|
if(e = walk1(r->newfid, r->ifcall.wname[i], arg))
|
||||||
|
break;
|
||||||
|
r->ofcall.wqid[i] = r->newfid->qid;
|
||||||
|
}
|
||||||
|
|
||||||
|
r->ofcall.nwqid = i;
|
||||||
|
if(e && i==0)
|
||||||
|
respond(r, e);
|
||||||
|
else
|
||||||
|
respond(r, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sversion(Srv *srv, Req *r)
|
||||||
|
{
|
||||||
|
USED(srv);
|
||||||
|
|
||||||
|
if(strncmp(r->ifcall.version, "9P", 2) != 0){
|
||||||
|
r->ofcall.version = "unknown";
|
||||||
|
respond(r, nil);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
r->ofcall.version = "9P2000";
|
||||||
|
r->ofcall.msize = r->ifcall.msize;
|
||||||
|
respond(r, nil);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
rversion(Req *r, char *error)
|
||||||
|
{
|
||||||
|
assert(error == nil);
|
||||||
|
changemsize(r->srv, r->ofcall.msize);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sauth(Srv *srv, Req *r)
|
||||||
|
{
|
||||||
|
char e[ERRMAX];
|
||||||
|
|
||||||
|
if((r->afid = allocfid(srv->fpool, r->ifcall.afid)) == nil){
|
||||||
|
respond(r, Edupfid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(srv->auth)
|
||||||
|
srv->auth(r);
|
||||||
|
else{
|
||||||
|
snprint(e, sizeof e, "%s: authentication not required", argv0);
|
||||||
|
respond(r, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
rauth(Req *r, char *error)
|
||||||
|
{
|
||||||
|
if(error && r->afid)
|
||||||
|
closefid(removefid(r->srv->fpool, r->afid->fid));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sattach(Srv *srv, Req *r)
|
||||||
|
{
|
||||||
|
if((r->fid = allocfid(srv->fpool, r->ifcall.fid)) == nil){
|
||||||
|
respond(r, Edupfid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
r->afid = nil;
|
||||||
|
if(r->ifcall.afid != NOFID && (r->afid = lookupfid(srv->fpool, r->ifcall.afid)) == nil){
|
||||||
|
respond(r, Eunknownfid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
r->fid->uid = estrdup9p(r->ifcall.uname);
|
||||||
|
if(srv->tree){
|
||||||
|
r->fid->file = srv->tree->root;
|
||||||
|
/* BUG? incref(r->fid->file) ??? */
|
||||||
|
r->ofcall.qid = r->fid->file->dir.qid;
|
||||||
|
r->fid->qid = r->ofcall.qid;
|
||||||
|
}
|
||||||
|
if(srv->attach)
|
||||||
|
srv->attach(r);
|
||||||
|
else
|
||||||
|
respond(r, nil);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
rattach(Req *r, char *error)
|
||||||
|
{
|
||||||
|
if(error && r->fid)
|
||||||
|
closefid(removefid(r->srv->fpool, r->fid->fid));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sflush(Srv *srv, Req *r)
|
||||||
|
{
|
||||||
|
r->oldreq = lookupreq(srv->rpool, r->ifcall.oldtag);
|
||||||
|
if(r->oldreq == nil || r->oldreq == r)
|
||||||
|
respond(r, nil);
|
||||||
|
else if(srv->flush)
|
||||||
|
srv->flush(r);
|
||||||
|
else
|
||||||
|
respond(r, nil);
|
||||||
|
}
|
||||||
|
static int
|
||||||
|
rflush(Req *r, char *error)
|
||||||
|
{
|
||||||
|
Req *or;
|
||||||
|
|
||||||
|
assert(error == nil);
|
||||||
|
or = r->oldreq;
|
||||||
|
if(or){
|
||||||
|
qlock(&or->lk);
|
||||||
|
if(or->responded == 0){
|
||||||
|
or->flush = erealloc9p(or->flush, (or->nflush+1)*sizeof(or->flush[0]));
|
||||||
|
or->flush[or->nflush++] = r;
|
||||||
|
qunlock(&or->lk);
|
||||||
|
return -1; /* delay response until or is responded */
|
||||||
|
}
|
||||||
|
qunlock(&or->lk);
|
||||||
|
closereq(or);
|
||||||
|
}
|
||||||
|
r->oldreq = nil;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char*
|
||||||
|
oldwalk1(Fid *fid, char *name, void *arg)
|
||||||
|
{
|
||||||
|
char *e;
|
||||||
|
Qid qid;
|
||||||
|
Srv *srv;
|
||||||
|
|
||||||
|
srv = arg;
|
||||||
|
e = srv->walk1(fid, name, &qid);
|
||||||
|
if(e)
|
||||||
|
return e;
|
||||||
|
fid->qid = qid;
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char*
|
||||||
|
oldclone(Fid *fid, Fid *newfid, void *arg)
|
||||||
|
{
|
||||||
|
Srv *srv;
|
||||||
|
|
||||||
|
srv = arg;
|
||||||
|
if(srv->clone == nil)
|
||||||
|
return nil;
|
||||||
|
return srv->clone(fid, newfid);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
swalk(Srv *srv, Req *r)
|
||||||
|
{
|
||||||
|
if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
|
||||||
|
respond(r, Eunknownfid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(r->fid->omode != -1){
|
||||||
|
respond(r, "cannot clone open fid");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(r->ifcall.nwname && !(r->fid->qid.type&QTDIR)){
|
||||||
|
respond(r, Ewalknodir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(r->ifcall.fid != r->ifcall.newfid){
|
||||||
|
if((r->newfid = allocfid(srv->fpool, r->ifcall.newfid)) == nil){
|
||||||
|
respond(r, Edupfid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
r->newfid->uid = estrdup9p(r->fid->uid);
|
||||||
|
}else{
|
||||||
|
incref(&r->fid->ref);
|
||||||
|
r->newfid = r->fid;
|
||||||
|
}
|
||||||
|
if(r->fid->file){
|
||||||
|
filewalk(r);
|
||||||
|
}else if(srv->walk1)
|
||||||
|
walkandclone(r, oldwalk1, oldclone, srv);
|
||||||
|
else if(srv->walk)
|
||||||
|
srv->walk(r);
|
||||||
|
else
|
||||||
|
sysfatal("no walk function, no file trees");
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
rwalk(Req *r, char *error)
|
||||||
|
{
|
||||||
|
if(error || r->ofcall.nwqid < r->ifcall.nwname){
|
||||||
|
if(r->ifcall.fid != r->ifcall.newfid && r->newfid)
|
||||||
|
closefid(removefid(r->srv->fpool, r->newfid->fid));
|
||||||
|
if (r->ofcall.nwqid==0){
|
||||||
|
if(error==nil && r->ifcall.nwname!=0)
|
||||||
|
r->error = Enotfound;
|
||||||
|
}else
|
||||||
|
r->error = nil; // No error on partial walks
|
||||||
|
}else{
|
||||||
|
if(r->ofcall.nwqid == 0){
|
||||||
|
/* Just a clone */
|
||||||
|
r->newfid->qid = r->fid->qid;
|
||||||
|
}else{
|
||||||
|
/* if file trees are in use, filewalk took care of the rest */
|
||||||
|
r->newfid->qid = r->ofcall.wqid[r->ofcall.nwqid-1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sopen(Srv *srv, Req *r)
|
||||||
|
{
|
||||||
|
int p;
|
||||||
|
|
||||||
|
if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
|
||||||
|
respond(r, Eunknownfid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(r->fid->omode != -1){
|
||||||
|
respond(r, Ebotch);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if((r->fid->qid.type&QTDIR) && (r->ifcall.mode&~ORCLOSE) != OREAD){
|
||||||
|
respond(r, Eisdir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
r->ofcall.qid = r->fid->qid;
|
||||||
|
switch(r->ifcall.mode&3){
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
case OREAD:
|
||||||
|
p = AREAD;
|
||||||
|
break;
|
||||||
|
case OWRITE:
|
||||||
|
p = AWRITE;
|
||||||
|
break;
|
||||||
|
case ORDWR:
|
||||||
|
p = AREAD|AWRITE;
|
||||||
|
break;
|
||||||
|
case OEXEC:
|
||||||
|
p = AEXEC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(r->ifcall.mode&OTRUNC)
|
||||||
|
p |= AWRITE;
|
||||||
|
if((r->fid->qid.type&QTDIR) && p!=AREAD){
|
||||||
|
respond(r, Eperm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(r->fid->file){
|
||||||
|
if(!hasperm(r->fid->file, r->fid->uid, p)){
|
||||||
|
respond(r, Eperm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* BUG RACE */
|
||||||
|
if((r->ifcall.mode&ORCLOSE)
|
||||||
|
&& !hasperm(r->fid->file->parent, r->fid->uid, AWRITE)){
|
||||||
|
respond(r, Eperm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
r->ofcall.qid = r->fid->file->dir.qid;
|
||||||
|
if((r->ofcall.qid.type&QTDIR)
|
||||||
|
&& (r->fid->rdir = opendirfile(r->fid->file)) == nil){
|
||||||
|
respond(r, "opendirfile failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(srv->open)
|
||||||
|
srv->open(r);
|
||||||
|
else
|
||||||
|
respond(r, nil);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
ropen(Req *r, char *error)
|
||||||
|
{
|
||||||
|
char errbuf[ERRMAX];
|
||||||
|
if(error)
|
||||||
|
return;
|
||||||
|
if(chatty9p){
|
||||||
|
snprint(errbuf, sizeof errbuf, "fid mode is 0x%ux\n", r->ifcall.mode);
|
||||||
|
write(2, errbuf, strlen(errbuf));
|
||||||
|
}
|
||||||
|
r->fid->omode = r->ifcall.mode;
|
||||||
|
r->fid->qid = r->ofcall.qid;
|
||||||
|
if(r->ofcall.qid.type&QTDIR)
|
||||||
|
r->fid->diroffset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
screate(Srv *srv, Req *r)
|
||||||
|
{
|
||||||
|
if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil)
|
||||||
|
respond(r, Eunknownfid);
|
||||||
|
else if(r->fid->omode != -1)
|
||||||
|
respond(r, Ebotch);
|
||||||
|
else if(!(r->fid->qid.type&QTDIR))
|
||||||
|
respond(r, Ecreatenondir);
|
||||||
|
else if(r->fid->file && !hasperm(r->fid->file, r->fid->uid, AWRITE))
|
||||||
|
respond(r, Eperm);
|
||||||
|
else if(srv->create)
|
||||||
|
srv->create(r);
|
||||||
|
else
|
||||||
|
respond(r, Enocreate);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
rcreate(Req *r, char *error)
|
||||||
|
{
|
||||||
|
if(error)
|
||||||
|
return;
|
||||||
|
r->fid->omode = r->ifcall.mode;
|
||||||
|
r->fid->qid = r->ofcall.qid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sread(Srv *srv, Req *r)
|
||||||
|
{
|
||||||
|
int o;
|
||||||
|
|
||||||
|
if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
|
||||||
|
respond(r, Eunknownfid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(r->ifcall.count < 0){
|
||||||
|
respond(r, Ebotch);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(r->ifcall.offset < 0
|
||||||
|
|| ((r->fid->qid.type&QTDIR) && r->ifcall.offset != 0 && r->ifcall.offset != r->fid->diroffset)){
|
||||||
|
respond(r, Ebadoffset);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(r->ifcall.count > srv->msize - IOHDRSZ)
|
||||||
|
r->ifcall.count = srv->msize - IOHDRSZ;
|
||||||
|
r->rbuf = emalloc9p(r->ifcall.count);
|
||||||
|
r->ofcall.data = r->rbuf;
|
||||||
|
o = r->fid->omode & 3;
|
||||||
|
if(o != OREAD && o != ORDWR && o != OEXEC){
|
||||||
|
respond(r, Ebotch);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if((r->fid->qid.type&QTDIR) && r->fid->file){
|
||||||
|
r->ofcall.count = readdirfile(r->fid->rdir, r->rbuf, r->ifcall.count);
|
||||||
|
respond(r, nil);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(srv->read)
|
||||||
|
srv->read(r);
|
||||||
|
else
|
||||||
|
respond(r, "no srv->read");
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
rread(Req *r, char *error)
|
||||||
|
{
|
||||||
|
if(error==nil && (r->fid->qid.type&QTDIR))
|
||||||
|
r->fid->diroffset += r->ofcall.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
swrite(Srv *srv, Req *r)
|
||||||
|
{
|
||||||
|
int o;
|
||||||
|
char e[ERRMAX];
|
||||||
|
|
||||||
|
if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
|
||||||
|
respond(r, Eunknownfid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(r->ifcall.count < 0){
|
||||||
|
respond(r, Ebotch);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(r->ifcall.offset < 0){
|
||||||
|
respond(r, Ebotch);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(r->ifcall.count > srv->msize - IOHDRSZ)
|
||||||
|
r->ifcall.count = srv->msize - IOHDRSZ;
|
||||||
|
o = r->fid->omode & 3;
|
||||||
|
if(o != OWRITE && o != ORDWR){
|
||||||
|
snprint(e, sizeof e, "write on fid with open mode 0x%ux", r->fid->omode);
|
||||||
|
respond(r, e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(srv->write)
|
||||||
|
srv->write(r);
|
||||||
|
else
|
||||||
|
respond(r, "no srv->write");
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
rwrite(Req *r, char *error)
|
||||||
|
{
|
||||||
|
if(error)
|
||||||
|
return;
|
||||||
|
if(r->fid->file)
|
||||||
|
r->fid->file->dir.qid.vers++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sclunk(Srv *srv, Req *r)
|
||||||
|
{
|
||||||
|
if((r->fid = removefid(srv->fpool, r->ifcall.fid)) == nil)
|
||||||
|
respond(r, Eunknownfid);
|
||||||
|
else
|
||||||
|
respond(r, nil);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
rclunk(Req *r, char *msg)
|
||||||
|
{
|
||||||
|
USED(r);
|
||||||
|
USED(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sremove(Srv *srv, Req *r)
|
||||||
|
{
|
||||||
|
if((r->fid = removefid(srv->fpool, r->ifcall.fid)) == nil){
|
||||||
|
respond(r, Eunknownfid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* BUG RACE */
|
||||||
|
if(r->fid->file && !hasperm(r->fid->file->parent, r->fid->uid, AWRITE)){
|
||||||
|
respond(r, Eperm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(srv->remove)
|
||||||
|
srv->remove(r);
|
||||||
|
else
|
||||||
|
respond(r, r->fid->file ? nil : Enoremove);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
rremove(Req *r, char *error, char *errbuf)
|
||||||
|
{
|
||||||
|
if(error)
|
||||||
|
return;
|
||||||
|
if(r->fid->file){
|
||||||
|
if(removefile(r->fid->file) < 0){
|
||||||
|
snprint(errbuf, ERRMAX, "remove %s: %r",
|
||||||
|
r->fid->file->dir.name);
|
||||||
|
r->error = errbuf;
|
||||||
|
}
|
||||||
|
r->fid->file = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sstat(Srv *srv, Req *r)
|
||||||
|
{
|
||||||
|
if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
|
||||||
|
respond(r, Eunknownfid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(r->fid->file){
|
||||||
|
r->d = r->fid->file->dir;
|
||||||
|
if(r->d.name)
|
||||||
|
r->d.name = estrdup9p(r->d.name);
|
||||||
|
if(r->d.uid)
|
||||||
|
r->d.uid = estrdup9p(r->d.uid);
|
||||||
|
if(r->d.gid)
|
||||||
|
r->d.gid = estrdup9p(r->d.gid);
|
||||||
|
if(r->d.muid)
|
||||||
|
r->d.muid = estrdup9p(r->d.muid);
|
||||||
|
}
|
||||||
|
if(srv->stat)
|
||||||
|
srv->stat(r);
|
||||||
|
else if(r->fid->file)
|
||||||
|
respond(r, nil);
|
||||||
|
else
|
||||||
|
respond(r, Enostat);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
rstat(Req *r, char *error)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
uchar *statbuf;
|
||||||
|
uchar tmp[BIT16SZ];
|
||||||
|
|
||||||
|
if(error)
|
||||||
|
return;
|
||||||
|
if(convD2M(&r->d, tmp, BIT16SZ) != BIT16SZ){
|
||||||
|
r->error = "convD2M(_,_,BIT16SZ) did not return BIT16SZ";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
n = GBIT16(tmp)+BIT16SZ;
|
||||||
|
statbuf = emalloc9p(n);
|
||||||
|
if(statbuf == nil){
|
||||||
|
r->error = "out of memory";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
r->ofcall.nstat = convD2M(&r->d, statbuf, n);
|
||||||
|
r->ofcall.stat = statbuf; /* freed in closereq */
|
||||||
|
if(r->ofcall.nstat <= BIT16SZ){
|
||||||
|
r->error = "convD2M fails";
|
||||||
|
free(statbuf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
swstat(Srv *srv, Req *r)
|
||||||
|
{
|
||||||
|
if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
|
||||||
|
respond(r, Eunknownfid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(srv->wstat == nil){
|
||||||
|
respond(r, Enowstat);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(convM2D(r->ifcall.stat, r->ifcall.nstat, &r->d, (char*)r->ifcall.stat) != r->ifcall.nstat){
|
||||||
|
respond(r, Ebaddir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if((ushort)~r->d.type){
|
||||||
|
respond(r, "wstat -- attempt to change type");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if((uint)~r->d.dev){
|
||||||
|
respond(r, "wstat -- attempt to change dev");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if((uchar)~r->d.qid.type || (ulong)~r->d.qid.vers || (uvlong)~r->d.qid.path){
|
||||||
|
respond(r, "wstat -- attempt to change qid");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(r->d.muid && r->d.muid[0]){
|
||||||
|
respond(r, "wstat -- attempt to change muid");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if((ulong)~r->d.mode && ((r->d.mode&DMDIR)>>24) != (r->fid->qid.type&QTDIR)){
|
||||||
|
respond(r, "wstat -- attempt to change DMDIR bit");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
srv->wstat(r);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
rwstat(Req *r, char *msg)
|
||||||
|
{
|
||||||
|
USED(r);
|
||||||
|
USED(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
srv(Srv *srv)
|
||||||
|
{
|
||||||
|
Req *r;
|
||||||
|
|
||||||
|
fmtinstall('D', dirfmt);
|
||||||
|
fmtinstall('F', fcallfmt);
|
||||||
|
|
||||||
|
if(srv->fpool == nil)
|
||||||
|
srv->fpool = allocfidpool(srv->destroyfid);
|
||||||
|
if(srv->rpool == nil)
|
||||||
|
srv->rpool = allocreqpool(srv->destroyreq);
|
||||||
|
if(srv->msize == 0)
|
||||||
|
srv->msize = 8192+IOHDRSZ;
|
||||||
|
|
||||||
|
changemsize(srv, srv->msize);
|
||||||
|
|
||||||
|
srv->fpool->srv = srv;
|
||||||
|
srv->rpool->srv = srv;
|
||||||
|
|
||||||
|
while(r = getreq(srv)){
|
||||||
|
if(r->error){
|
||||||
|
respond(r, r->error);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch(r->ifcall.type){
|
||||||
|
default:
|
||||||
|
respond(r, "unknown message");
|
||||||
|
break;
|
||||||
|
case Tversion: sversion(srv, r); break;
|
||||||
|
case Tauth: sauth(srv, r); break;
|
||||||
|
case Tattach: sattach(srv, r); break;
|
||||||
|
case Tflush: sflush(srv, r); break;
|
||||||
|
case Twalk: swalk(srv, r); break;
|
||||||
|
case Topen: sopen(srv, r); break;
|
||||||
|
case Tcreate: screate(srv, r); break;
|
||||||
|
case Tread: sread(srv, r); break;
|
||||||
|
case Twrite: swrite(srv, r); break;
|
||||||
|
case Tclunk: sclunk(srv, r); break;
|
||||||
|
case Tremove: sremove(srv, r); break;
|
||||||
|
case Tstat: sstat(srv, r); break;
|
||||||
|
case Twstat: swstat(srv, r); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(srv->end)
|
||||||
|
srv->end(srv);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
respond(Req *r, char *error)
|
||||||
|
{
|
||||||
|
int i, m, n;
|
||||||
|
char errbuf[ERRMAX];
|
||||||
|
Srv *srv;
|
||||||
|
|
||||||
|
srv = r->srv;
|
||||||
|
assert(srv != nil);
|
||||||
|
|
||||||
|
assert(r->responded == 0);
|
||||||
|
r->error = error;
|
||||||
|
|
||||||
|
switch(r->ifcall.type){
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
/*
|
||||||
|
* Flush is special. If the handler says so, we return
|
||||||
|
* without further processing. Respond will be called
|
||||||
|
* again once it is safe.
|
||||||
|
*/
|
||||||
|
case Tflush:
|
||||||
|
if(rflush(r, error)<0)
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
case Tversion: rversion(r, error); break;
|
||||||
|
case Tauth: rauth(r, error); break;
|
||||||
|
case Tattach: rattach(r, error); break;
|
||||||
|
case Twalk: rwalk(r, error); break;
|
||||||
|
case Topen: ropen(r, error); break;
|
||||||
|
case Tcreate: rcreate(r, error); break;
|
||||||
|
case Tread: rread(r, error); break;
|
||||||
|
case Twrite: rwrite(r, error); break;
|
||||||
|
case Tclunk: rclunk(r, error); break;
|
||||||
|
case Tremove: rremove(r, error, errbuf); break;
|
||||||
|
case Tstat: rstat(r, error); break;
|
||||||
|
case Twstat: rwstat(r, error); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
r->ofcall.tag = r->ifcall.tag;
|
||||||
|
r->ofcall.type = r->ifcall.type+1;
|
||||||
|
if(r->error)
|
||||||
|
setfcallerror(&r->ofcall, r->error);
|
||||||
|
|
||||||
|
if(chatty9p)
|
||||||
|
fprint(2, "-%d-> %F\n", srv->outfd, &r->ofcall);
|
||||||
|
|
||||||
|
qlock(&srv->wlock);
|
||||||
|
n = convS2M(&r->ofcall, srv->wbuf, srv->msize);
|
||||||
|
if(n <= 0){
|
||||||
|
fprint(2, "n = %d %F\n", n, &r->ofcall);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
assert(n > 2);
|
||||||
|
if(r->pool) /* not a fake */
|
||||||
|
closereq(removereq(r->pool, r->ifcall.tag));
|
||||||
|
m = write(srv->outfd, srv->wbuf, n);
|
||||||
|
if(m != n)
|
||||||
|
sysfatal("lib9p srv: write %d returned %d on fd %d: %r", n, m, srv->outfd);
|
||||||
|
qunlock(&srv->wlock);
|
||||||
|
|
||||||
|
qlock(&r->lk); /* no one will add flushes now */
|
||||||
|
r->responded = 1;
|
||||||
|
qunlock(&r->lk);
|
||||||
|
|
||||||
|
for(i=0; i<r->nflush; i++)
|
||||||
|
respond(r->flush[i], nil);
|
||||||
|
free(r->flush);
|
||||||
|
|
||||||
|
if(r->pool)
|
||||||
|
closereq(r);
|
||||||
|
else
|
||||||
|
free(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
postfd(char *name, int pfd)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
char buf[80];
|
||||||
|
|
||||||
|
snprint(buf, sizeof buf, "/srv/%s", name);
|
||||||
|
if(chatty9p)
|
||||||
|
fprint(2, "postfd %s\n", buf);
|
||||||
|
fd = create(buf, OWRITE|ORCLOSE|OCEXEC, 0600);
|
||||||
|
if(fd < 0){
|
||||||
|
if(chatty9p)
|
||||||
|
fprint(2, "create fails: %r\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(fprint(fd, "%d", pfd) < 0){
|
||||||
|
if(chatty9p)
|
||||||
|
fprint(2, "write fails: %r\n");
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(chatty9p)
|
||||||
|
fprint(2, "postfd successful\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
18
src/lib9p/tpost.c
Normal file
18
src/lib9p/tpost.c
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <fcall.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <9p.h>
|
||||||
|
#include "post.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
threadpostmountsrv(Srv *s, char *name, char *mtpt, int flag)
|
||||||
|
{
|
||||||
|
Postcrud *p;
|
||||||
|
|
||||||
|
p = _post1(s, name, mtpt, flag);
|
||||||
|
if(procrfork(_post2, s, 32*1024, RFNAMEG|RFNOTEG) < 0)
|
||||||
|
sysfatal("procrfork: %r");
|
||||||
|
_post3(p);
|
||||||
|
}
|
||||||
|
|
||||||
34
src/lib9p/uid.c
Normal file
34
src/lib9p/uid.c
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <auth.h>
|
||||||
|
#include <fcall.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <9p.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* simplistic permission checking. assume that
|
||||||
|
* each user is the leader of her own group.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
hasperm(File *f, char *uid, int p)
|
||||||
|
{
|
||||||
|
int m;
|
||||||
|
|
||||||
|
m = f->dir.mode & 7; /* other */
|
||||||
|
if((p & m) == p)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if(strcmp(f->dir.uid, uid) == 0) {
|
||||||
|
m |= (f->dir.mode>>6) & 7;
|
||||||
|
if((p & m) == p)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strcmp(f->dir.gid, uid) == 0) {
|
||||||
|
m |= (f->dir.mode>>3) & 7;
|
||||||
|
if((p & m) == p)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
25
src/lib9p/util.c
Normal file
25
src/lib9p/util.c
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <auth.h>
|
||||||
|
#include <fcall.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include "9p.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
readbuf(Req *r, void *s, long n)
|
||||||
|
{
|
||||||
|
r->ofcall.count = r->ifcall.count;
|
||||||
|
if(r->ifcall.offset >= n){
|
||||||
|
r->ofcall.count = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(r->ifcall.offset+r->ofcall.count > n)
|
||||||
|
r->ofcall.count = n - r->ifcall.offset;
|
||||||
|
memmove(r->ofcall.data, (char*)s+r->ifcall.offset, r->ofcall.count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
readstr(Req *r, char *s)
|
||||||
|
{
|
||||||
|
readbuf(r, s, strlen(s));
|
||||||
|
}
|
||||||
@ -259,7 +259,7 @@ _fssend(Mux *mux, void *pkt)
|
|||||||
Fsys *fs;
|
Fsys *fs;
|
||||||
|
|
||||||
fs = mux->aux;
|
fs = mux->aux;
|
||||||
return write(fs->fd, pkt, GBIT32((uchar*)pkt));
|
return threadwrite(fs->fd, pkt, GBIT32((uchar*)pkt));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void*
|
static void*
|
||||||
|
|||||||
@ -52,3 +52,21 @@ fsread(Fid *fid, void *buf, long n)
|
|||||||
{
|
{
|
||||||
return fspread(fid, buf, n, -1);
|
return fspread(fid, buf, n, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long
|
||||||
|
fsreadn(Fid *fid, void *buf, long n)
|
||||||
|
{
|
||||||
|
long tot, nn;
|
||||||
|
|
||||||
|
for(tot=0; tot<n; tot+=nn){
|
||||||
|
nn = fsread(fid, (char*)buf+tot, n-tot);
|
||||||
|
if(nn <= 0){
|
||||||
|
if(tot == 0)
|
||||||
|
return nn;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tot;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -15,11 +15,15 @@ hgethead(HConnect *c, int many)
|
|||||||
int n;
|
int n;
|
||||||
|
|
||||||
hin = &c->hin;
|
hin = &c->hin;
|
||||||
|
fprint(2, "hgethead top %p - %p\n", hin->pos, hin->stop);
|
||||||
for(;;){
|
for(;;){
|
||||||
s = (char*)hin->pos;
|
s = (char*)hin->pos;
|
||||||
pp = s;
|
pp = s;
|
||||||
|
fprint(2, "hgethead %p - %p\n", pp, hin->stop);
|
||||||
while(p = memchr(pp, '\n', (char*)hin->stop - pp)){
|
while(p = memchr(pp, '\n', (char*)hin->stop - pp)){
|
||||||
if(!many || p == pp || p == pp + 1 && *pp == '\r'){
|
fprint(2, "hgethead %p - %p newline at %p %d\n", pp, hin->stop, p, *pp);
|
||||||
|
if(!many || p == pp || (p == pp + 1 && *pp == '\r')){
|
||||||
|
fprint(2, "breaking\n");
|
||||||
pp = p + 1;
|
pp = p + 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -32,6 +36,7 @@ hgethead(HConnect *c, int many)
|
|||||||
memmove(c->hstop, s, n);
|
memmove(c->hstop, s, n);
|
||||||
c->hstop += n;
|
c->hstop += n;
|
||||||
*c->hstop = '\0';
|
*c->hstop = '\0';
|
||||||
|
fprint(2, "p %p\n", p);
|
||||||
if(p != nil)
|
if(p != nil)
|
||||||
return 1;
|
return 1;
|
||||||
if(hreadbuf(hin, hin->pos) == nil || hin->state == Hend)
|
if(hreadbuf(hin, hin->pos) == nil || hin->state == Hend)
|
||||||
|
|||||||
@ -157,10 +157,15 @@ hreadbuf(Hio *h, void *vsave)
|
|||||||
memmove(h->start + cpy, hh->pos, in);
|
memmove(h->start + cpy, hh->pos, in);
|
||||||
hh->pos += in;
|
hh->pos += in;
|
||||||
}
|
}
|
||||||
}else if(in && (in = read(h->fd, h->start + cpy, in)) < 0){
|
}else if(in){
|
||||||
h->state = Herr;
|
fprint(2, "read %d from %d\n", in, h->fd);
|
||||||
h->pos = h->stop;
|
if((in = read(h->fd, h->start + cpy, in)) < 0){
|
||||||
return nil;
|
fprint(2, "got error: %r\n");
|
||||||
|
h->state = Herr;
|
||||||
|
h->pos = h->stop;
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
fprint(2, "got %d\n", in);
|
||||||
}
|
}
|
||||||
if(in == 0)
|
if(in == 0)
|
||||||
h->state = Hend;
|
h->state = Hend;
|
||||||
|
|||||||
@ -3,16 +3,17 @@ PLAN9=../..
|
|||||||
|
|
||||||
LIB=libip.a
|
LIB=libip.a
|
||||||
OFILES=\
|
OFILES=\
|
||||||
|
bo.$O\
|
||||||
|
classmask.$O\
|
||||||
eipfmt.$O\
|
eipfmt.$O\
|
||||||
parseip.$O\
|
ipaux.$O\
|
||||||
parseether.$O\
|
|
||||||
myetheraddr.$O\
|
myetheraddr.$O\
|
||||||
myipaddr.$O\
|
myipaddr.$O\
|
||||||
classmask.$O\
|
parseether.$O\
|
||||||
bo.$O\
|
parseip.$O\
|
||||||
readipifc.$O\
|
|
||||||
ipaux.$O\
|
|
||||||
ptclbsum.$O\
|
ptclbsum.$O\
|
||||||
|
readipifc.$O\
|
||||||
|
udp.$O\
|
||||||
|
|
||||||
HFILES=\
|
HFILES=\
|
||||||
ip.h
|
ip.h
|
||||||
|
|||||||
@ -13,8 +13,6 @@ static Fid *pfid;
|
|||||||
int
|
int
|
||||||
plumbopen(char *name, int omode)
|
plumbopen(char *name, int omode)
|
||||||
{
|
{
|
||||||
int fd;
|
|
||||||
|
|
||||||
if(fsplumb == nil)
|
if(fsplumb == nil)
|
||||||
fsplumb = nsmount("plumb", "");
|
fsplumb = nsmount("plumb", "");
|
||||||
if(fsplumb == nil)
|
if(fsplumb == nil)
|
||||||
@ -47,26 +45,42 @@ plumbopen(char *name, int omode)
|
|||||||
return pfd;
|
return pfd;
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = fsopenfd(fsplumb, name, omode);
|
return fsopenfd(fsplumb, name, omode);
|
||||||
return fd;
|
}
|
||||||
|
|
||||||
|
Fid*
|
||||||
|
plumbopenfid(char *name, int mode)
|
||||||
|
{
|
||||||
|
if(fsplumb == nil)
|
||||||
|
fsplumb = nsmount("plumb", "");
|
||||||
|
if(fsplumb == nil)
|
||||||
|
return nil;
|
||||||
|
return fsopen(fsplumb, name, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
plumbsendtofid(Fid *fid, Plumbmsg *m)
|
||||||
|
{
|
||||||
|
char *buf;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
buf = plumbpack(m, &n);
|
||||||
|
if(buf == nil)
|
||||||
|
return -1;
|
||||||
|
n = fswrite(fid, buf, n);
|
||||||
|
fprint(2, "fswrite %d\n", n);
|
||||||
|
free(buf);
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
plumbsend(int fd, Plumbmsg *m)
|
plumbsend(int fd, Plumbmsg *m)
|
||||||
{
|
{
|
||||||
char *buf;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
if(fd != pfd){
|
if(fd != pfd){
|
||||||
werrstr("fd is not the plumber");
|
werrstr("fd is not the plumber");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
buf = plumbpack(m, &n);
|
return plumbsendtofid(pfid, m);
|
||||||
if(buf == nil)
|
|
||||||
return -1;
|
|
||||||
n = fswrite(pfid, buf, n);
|
|
||||||
free(buf);
|
|
||||||
return n;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -427,3 +441,31 @@ plumbrecv(int fd)
|
|||||||
free(buf);
|
free(buf);
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Plumbmsg*
|
||||||
|
plumbrecvfid(Fid *fid)
|
||||||
|
{
|
||||||
|
char *buf;
|
||||||
|
Plumbmsg *m;
|
||||||
|
int n, more;
|
||||||
|
|
||||||
|
buf = malloc(8192);
|
||||||
|
if(buf == nil)
|
||||||
|
return nil;
|
||||||
|
n = fsread(fid, buf, 8192);
|
||||||
|
m = nil;
|
||||||
|
if(n > 0){
|
||||||
|
m = plumbunpackpartial(buf, n, &more);
|
||||||
|
if(m==nil && more>0){
|
||||||
|
/* we now know how many more bytes to read for complete message */
|
||||||
|
buf = realloc(buf, n+more);
|
||||||
|
if(buf == nil)
|
||||||
|
return nil;
|
||||||
|
if(fsreadn(fid, buf+n, more) == more)
|
||||||
|
m = plumbunpackpartial(buf, n+more, nil);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(buf);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -31,3 +31,4 @@ threadplumbrecv(int fd)
|
|||||||
free(buf);
|
free(buf);
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -43,7 +43,7 @@ static const u32 Td3[256];
|
|||||||
static const u8 Te4[256];
|
static const u8 Te4[256];
|
||||||
|
|
||||||
static int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits);
|
static int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits);
|
||||||
// static int rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits);
|
static int rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits);
|
||||||
static int rijndaelKeySetup(u32 erk[/*4*(Nr + 1)*/], u32 drk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits);
|
static int rijndaelKeySetup(u32 erk[/*4*(Nr + 1)*/], u32 drk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits);
|
||||||
static void rijndaelEncrypt(const u32int rk[], int Nr, const uchar pt[16], uchar ct[16]);
|
static void rijndaelEncrypt(const u32int rk[], int Nr, const uchar pt[16], uchar ct[16]);
|
||||||
static void rijndaelDecrypt(const u32int rk[], int Nr, const uchar ct[16], uchar pt[16]);
|
static void rijndaelDecrypt(const u32int rk[], int Nr, const uchar ct[16], uchar pt[16]);
|
||||||
@ -950,7 +950,6 @@ static int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
/**
|
/**
|
||||||
* Expand the cipher key into the decryption key schedule.
|
* Expand the cipher key into the decryption key schedule.
|
||||||
*
|
*
|
||||||
@ -995,7 +994,6 @@ static int rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int
|
|||||||
}
|
}
|
||||||
return Nr;
|
return Nr;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16], u8 ct[16]) {
|
static void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16], u8 ct[16]) {
|
||||||
u32 s0, s1, s2, s3, t0, t1, t2, t3;
|
u32 s0, s1, s2, s3, t0, t1, t2, t3;
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
#include "os.h"
|
#include "os.h"
|
||||||
|
#include <mp.h>
|
||||||
#include <libsec.h>
|
#include <libsec.h>
|
||||||
|
|
||||||
typedef struct State{
|
typedef struct State{
|
||||||
|
|||||||
@ -5,14 +5,55 @@ LIB=libsec.a
|
|||||||
|
|
||||||
OFILES=\
|
OFILES=\
|
||||||
aes.$O\
|
aes.$O\
|
||||||
|
blowfish.$O\
|
||||||
|
decodepem.$O\
|
||||||
des.$O\
|
des.$O\
|
||||||
|
des3CBC.$O\
|
||||||
|
des3ECB.$O\
|
||||||
|
desCBC.$O\
|
||||||
|
desECB.$O\
|
||||||
desmodes.$O\
|
desmodes.$O\
|
||||||
|
dsaalloc.$O\
|
||||||
|
dsagen.$O\
|
||||||
|
dsaprimes.$O\
|
||||||
|
dsaprivtopub.$O\
|
||||||
|
dsasign.$O\
|
||||||
|
dsaverify.$O\
|
||||||
|
egalloc.$O\
|
||||||
|
egdecrypt.$O\
|
||||||
|
egencrypt.$O\
|
||||||
|
eggen.$O\
|
||||||
|
egprivtopub.$O\
|
||||||
|
egsign.$O\
|
||||||
|
egverify.$O\
|
||||||
fastrand.$O\
|
fastrand.$O\
|
||||||
|
genprime.$O\
|
||||||
genrandom.$O\
|
genrandom.$O\
|
||||||
|
gensafeprime.$O\
|
||||||
|
genstrongprime.$O\
|
||||||
|
hmac.$O\
|
||||||
|
md4.$O\
|
||||||
md5.$O\
|
md5.$O\
|
||||||
md5block.$O\
|
md5block.$O\
|
||||||
|
md5pickle.$O\
|
||||||
|
nfastrand.$O\
|
||||||
|
prng.$O\
|
||||||
|
probably_prime.$O\
|
||||||
|
rc4.$O\
|
||||||
|
readcert.$O\
|
||||||
|
rsaalloc.$O\
|
||||||
|
rsadecrypt.$O\
|
||||||
|
rsaencrypt.$O\
|
||||||
|
rsafill.$O\
|
||||||
|
rsagen.$O\
|
||||||
|
rsaprivtopub.$O\
|
||||||
sha1.$O\
|
sha1.$O\
|
||||||
sha1block.$O\
|
sha1block.$O\
|
||||||
|
sha1pickle.$O\
|
||||||
|
smallprimetest.$O\
|
||||||
|
thumb.$O\
|
||||||
|
tlshand.$O\
|
||||||
|
x509.$O\
|
||||||
|
|
||||||
HFILES=$PLAN9/include/libsec.h
|
HFILES=$PLAN9/include/libsec.h
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
#include <u.h>
|
#include "os.h"
|
||||||
#include <libc.h>
|
|
||||||
#include <libsec.h>
|
#include <libsec.h>
|
||||||
|
|
||||||
static void encode(uchar*, u32int*, ulong);
|
static void encode(uchar*, u32int*, ulong);
|
||||||
@ -11,8 +10,6 @@ extern void _sha1block(uchar*, ulong, u32int*);
|
|||||||
* the last call. There must be room in the input buffer
|
* the last call. There must be room in the input buffer
|
||||||
* to pad.
|
* to pad.
|
||||||
*/
|
*/
|
||||||
ulong lastlen;
|
|
||||||
|
|
||||||
SHA1state*
|
SHA1state*
|
||||||
sha1(uchar *p, ulong len, uchar *digest, SHA1state *s)
|
sha1(uchar *p, ulong len, uchar *digest, SHA1state *s)
|
||||||
{
|
{
|
||||||
@ -21,15 +18,12 @@ sha1(uchar *p, ulong len, uchar *digest, SHA1state *s)
|
|||||||
int i;
|
int i;
|
||||||
uchar *e;
|
uchar *e;
|
||||||
|
|
||||||
lastlen = len;
|
|
||||||
if(s == nil){
|
if(s == nil){
|
||||||
s = malloc(sizeof(*s));
|
s = malloc(sizeof(*s));
|
||||||
if(s == nil)
|
if(s == nil)
|
||||||
return nil;
|
return nil;
|
||||||
memset(s, 0, sizeof(*s));
|
memset(s, 0, sizeof(*s));
|
||||||
s->malloced = 1;
|
s->malloced = 1;
|
||||||
assert(!s->seeded);
|
|
||||||
assert(!s->blen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(s->seeded == 0){
|
if(s->seeded == 0){
|
||||||
@ -42,11 +36,8 @@ lastlen = len;
|
|||||||
s->seeded = 1;
|
s->seeded = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(len < 100000);
|
|
||||||
|
|
||||||
/* fill out the partial 64 byte block from previous calls */
|
/* fill out the partial 64 byte block from previous calls */
|
||||||
if(s->blen){
|
if(s->blen){
|
||||||
assert(s);
|
|
||||||
i = 64 - s->blen;
|
i = 64 - s->blen;
|
||||||
if(len < i)
|
if(len < i)
|
||||||
i = len;
|
i = len;
|
||||||
@ -61,11 +52,9 @@ assert(s);
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(len < 1000000);
|
|
||||||
/* do 64 byte blocks */
|
/* do 64 byte blocks */
|
||||||
i = len & ~0x3f;
|
i = len & ~0x3f;
|
||||||
if(i){
|
if(i){
|
||||||
assert(i < 1000000);
|
|
||||||
_sha1block(p, i, s->state);
|
_sha1block(p, i, s->state);
|
||||||
s->len += i;
|
s->len += i;
|
||||||
len -= i;
|
len -= i;
|
||||||
|
|||||||
@ -1,10 +1,4 @@
|
|||||||
#include <u.h>
|
#include "os.h"
|
||||||
#include <libc.h>
|
|
||||||
|
|
||||||
uchar* lastsbp;
|
|
||||||
ulong lastsblen;
|
|
||||||
u32int* lastsbs;
|
|
||||||
Lock slock;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
_sha1block(uchar *p, ulong len, u32int *s)
|
_sha1block(uchar *p, ulong len, u32int *s)
|
||||||
@ -14,11 +8,6 @@ _sha1block(uchar *p, ulong len, u32int *s)
|
|||||||
u32int *wp, *wend;
|
u32int *wp, *wend;
|
||||||
u32int w[80];
|
u32int w[80];
|
||||||
|
|
||||||
lock(&slock);
|
|
||||||
lastsbp=p;
|
|
||||||
lastsblen=len;
|
|
||||||
lastsbs=s;
|
|
||||||
|
|
||||||
/* at this point, we have a multiple of 64 bytes */
|
/* at this point, we have a multiple of 64 bytes */
|
||||||
for(end = p+len; p < end;){
|
for(end = p+len; p < end;){
|
||||||
a = s[0];
|
a = s[0];
|
||||||
@ -195,5 +184,4 @@ lastsbs=s;
|
|||||||
s[3] += d;
|
s[3] += d;
|
||||||
s[4] += e;
|
s[4] += e;
|
||||||
}
|
}
|
||||||
unlock(&slock);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,6 +45,7 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
signal(SIGTERM, _threaddie);
|
signal(SIGTERM, _threaddie);
|
||||||
signal(SIGCHLD, _nop);
|
signal(SIGCHLD, _nop);
|
||||||
|
signal(SIGALRM, _nop);
|
||||||
// signal(SIGINFO, _threadstatus);
|
// signal(SIGINFO, _threadstatus);
|
||||||
// rfork(RFREND);
|
// rfork(RFREND);
|
||||||
|
|
||||||
|
|||||||
@ -55,11 +55,13 @@ listenproc(void *v)
|
|||||||
|
|
||||||
srv = v;
|
srv = v;
|
||||||
for(;;){
|
for(;;){
|
||||||
|
fprint(2, "listen for venti\n");
|
||||||
ctl = listen(srv->adir, dir);
|
ctl = listen(srv->adir, dir);
|
||||||
if(ctl < 0){
|
if(ctl < 0){
|
||||||
srv->dead = 1;
|
srv->dead = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
fprint(2, "got one\n");
|
||||||
sc = vtmallocz(sizeof(VtSconn));
|
sc = vtmallocz(sizeof(VtSconn));
|
||||||
sc->ctl = ctl;
|
sc->ctl = ctl;
|
||||||
sc->srv = srv;
|
sc->srv = srv;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<mkhdr
|
<mkhdr
|
||||||
|
|
||||||
BUGGERED="String|html|httpd|ip|venti"
|
BUGGERED='9p|html|httpd|ip|venti'
|
||||||
LIBDIRS=`ls -ld lib* | sed -n 's/^d.* //p' |egrep -v "^lib($BUGGERED)$"`
|
LIBDIRS=`ls -ld lib* | sed -n 's/^d.* //p' |egrep -v "^lib($BUGGERED)$"`
|
||||||
|
|
||||||
DIRS=\
|
DIRS=\
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user