12bef681aSDavid du Colombier /*
22bef681aSDavid du Colombier * keyfs
32bef681aSDavid du Colombier */
4219b2ee8SDavid du Colombier #include <u.h>
5219b2ee8SDavid du Colombier #include <libc.h>
62bef681aSDavid du Colombier #include <ctype.h>
79a747e4fSDavid du Colombier #include <authsrv.h>
8219b2ee8SDavid du Colombier #include <fcall.h>
9219b2ee8SDavid du Colombier #include <bio.h>
107dd7cddfSDavid du Colombier #include <mp.h>
117dd7cddfSDavid du Colombier #include <libsec.h>
129a747e4fSDavid du Colombier #include "authcmdlib.h"
13219b2ee8SDavid du Colombier
142bef681aSDavid du Colombier #pragma varargck type "W" char*
152bef681aSDavid du Colombier
167dd7cddfSDavid du Colombier char authkey[8];
17219b2ee8SDavid du Colombier
18219b2ee8SDavid du Colombier typedef struct Fid Fid;
19219b2ee8SDavid du Colombier typedef struct User User;
20219b2ee8SDavid du Colombier
21219b2ee8SDavid du Colombier enum {
22219b2ee8SDavid du Colombier Qroot,
23219b2ee8SDavid du Colombier Quser,
24219b2ee8SDavid du Colombier Qkey,
257dd7cddfSDavid du Colombier Qsecret,
26219b2ee8SDavid du Colombier Qlog,
27219b2ee8SDavid du Colombier Qstatus,
28219b2ee8SDavid du Colombier Qexpire,
29219b2ee8SDavid du Colombier Qwarnings,
30219b2ee8SDavid du Colombier Qmax,
31219b2ee8SDavid du Colombier
32219b2ee8SDavid du Colombier Nuser = 512,
332bef681aSDavid du Colombier MAXBAD = 10, /* max # of bad attempts before disabling the account */
342bef681aSDavid du Colombier /* file must be randomly addressible, so names have fixed length */
352bef681aSDavid du Colombier Namelen = ANAMELEN,
36219b2ee8SDavid du Colombier };
37219b2ee8SDavid du Colombier
38219b2ee8SDavid du Colombier enum {
39219b2ee8SDavid du Colombier Sok,
40219b2ee8SDavid du Colombier Sdisabled,
41219b2ee8SDavid du Colombier Smax,
42219b2ee8SDavid du Colombier };
43219b2ee8SDavid du Colombier
44219b2ee8SDavid du Colombier struct Fid {
45219b2ee8SDavid du Colombier int fid;
46219b2ee8SDavid du Colombier ulong qtype;
47219b2ee8SDavid du Colombier User *user;
48219b2ee8SDavid du Colombier int busy;
49219b2ee8SDavid du Colombier Fid *next;
50219b2ee8SDavid du Colombier };
51219b2ee8SDavid du Colombier
52219b2ee8SDavid du Colombier struct User {
539a747e4fSDavid du Colombier char *name;
54219b2ee8SDavid du Colombier char key[DESKEYLEN];
557dd7cddfSDavid du Colombier char secret[SECRETLEN];
56219b2ee8SDavid du Colombier ulong expire; /* 0 == never */
57219b2ee8SDavid du Colombier uchar status;
582bef681aSDavid du Colombier ulong bad; /* # of consecutive bad authentication attempts */
59219b2ee8SDavid du Colombier int ref;
60219b2ee8SDavid du Colombier char removed;
61219b2ee8SDavid du Colombier uchar warnings;
620dac3555SDavid du Colombier long purgatory; /* time purgatory ends */
63219b2ee8SDavid du Colombier ulong uniq;
64219b2ee8SDavid du Colombier User *link;
65219b2ee8SDavid du Colombier };
66219b2ee8SDavid du Colombier
67219b2ee8SDavid du Colombier char *qinfo[Qmax] = {
68219b2ee8SDavid du Colombier [Qroot] "keys",
69219b2ee8SDavid du Colombier [Quser] ".",
70219b2ee8SDavid du Colombier [Qkey] "key",
717dd7cddfSDavid du Colombier [Qsecret] "secret",
72219b2ee8SDavid du Colombier [Qlog] "log",
73219b2ee8SDavid du Colombier [Qexpire] "expire",
74219b2ee8SDavid du Colombier [Qstatus] "status",
75219b2ee8SDavid du Colombier [Qwarnings] "warnings",
76219b2ee8SDavid du Colombier };
77219b2ee8SDavid du Colombier
78219b2ee8SDavid du Colombier char *status[Smax] = {
79219b2ee8SDavid du Colombier [Sok] "ok",
80219b2ee8SDavid du Colombier [Sdisabled] "disabled",
81219b2ee8SDavid du Colombier };
82219b2ee8SDavid du Colombier
83219b2ee8SDavid du Colombier Fid *fids;
84219b2ee8SDavid du Colombier User *users[Nuser];
85219b2ee8SDavid du Colombier char *userkeys;
86219b2ee8SDavid du Colombier int nuser;
87219b2ee8SDavid du Colombier ulong uniq = 1;
88219b2ee8SDavid du Colombier Fcall rhdr,
89219b2ee8SDavid du Colombier thdr;
90219b2ee8SDavid du Colombier int usepass;
91219b2ee8SDavid du Colombier char *warnarg;
929a747e4fSDavid du Colombier uchar mdata[8192 + IOHDRSZ];
939a747e4fSDavid du Colombier int messagesize = sizeof mdata;
94219b2ee8SDavid du Colombier
95219b2ee8SDavid du Colombier int readusers(void);
96219b2ee8SDavid du Colombier ulong hash(char*);
97219b2ee8SDavid du Colombier Fid *findfid(int);
98219b2ee8SDavid du Colombier User *finduser(char*);
99219b2ee8SDavid du Colombier User *installuser(char*);
100219b2ee8SDavid du Colombier int removeuser(User*);
101219b2ee8SDavid du Colombier void insertuser(User*);
102219b2ee8SDavid du Colombier void writeusers(void);
103219b2ee8SDavid du Colombier void io(int, int);
104219b2ee8SDavid du Colombier void *emalloc(ulong);
105219b2ee8SDavid du Colombier Qid mkqid(User*, ulong);
1069a747e4fSDavid du Colombier int dostat(User*, ulong, void*, int);
107219b2ee8SDavid du Colombier int newkeys(void);
108219b2ee8SDavid du Colombier void warning(void);
1095864cca7SDavid du Colombier int weirdfmt(Fmt *f);
110219b2ee8SDavid du Colombier
1119a747e4fSDavid du Colombier char *Auth(Fid*), *Attach(Fid*), *Version(Fid*),
1129a747e4fSDavid du Colombier *Flush(Fid*), *Walk(Fid*),
1139a747e4fSDavid du Colombier *Open(Fid*), *Create(Fid*),
114219b2ee8SDavid du Colombier *Read(Fid *), *Write(Fid*), *Clunk(Fid*),
115219b2ee8SDavid du Colombier *Remove(Fid *), *Stat(Fid*), *Wstat(Fid*);
116219b2ee8SDavid du Colombier char *(*fcalls[])(Fid*) = {
117219b2ee8SDavid du Colombier [Tattach] Attach,
1189a747e4fSDavid du Colombier [Tauth] Auth,
119219b2ee8SDavid du Colombier [Tclunk] Clunk,
120219b2ee8SDavid du Colombier [Tcreate] Create,
121219b2ee8SDavid du Colombier [Tflush] Flush,
122219b2ee8SDavid du Colombier [Topen] Open,
123219b2ee8SDavid du Colombier [Tread] Read,
124219b2ee8SDavid du Colombier [Tremove] Remove,
125219b2ee8SDavid du Colombier [Tstat] Stat,
1269a747e4fSDavid du Colombier [Tversion] Version,
127219b2ee8SDavid du Colombier [Twalk] Walk,
128219b2ee8SDavid du Colombier [Twrite] Write,
129219b2ee8SDavid du Colombier [Twstat] Wstat,
130219b2ee8SDavid du Colombier };
131219b2ee8SDavid du Colombier
1322bef681aSDavid du Colombier static void
usage(void)1332bef681aSDavid du Colombier usage(void)
1342bef681aSDavid du Colombier {
1352bef681aSDavid du Colombier fprint(2, "usage: %s [-p] [-m mtpt] [-w warn] [keyfile]\n", argv0);
1362bef681aSDavid du Colombier exits("usage");
1372bef681aSDavid du Colombier }
1382bef681aSDavid du Colombier
139219b2ee8SDavid du Colombier void
main(int argc,char * argv[])140219b2ee8SDavid du Colombier main(int argc, char *argv[])
141219b2ee8SDavid du Colombier {
142219b2ee8SDavid du Colombier char *mntpt;
143219b2ee8SDavid du Colombier int p[2];
144219b2ee8SDavid du Colombier
1455864cca7SDavid du Colombier fmtinstall('W', weirdfmt);
146219b2ee8SDavid du Colombier mntpt = "/mnt/keys";
147219b2ee8SDavid du Colombier ARGBEGIN{
148219b2ee8SDavid du Colombier case 'm':
1492bef681aSDavid du Colombier mntpt = EARGF(usage());
150219b2ee8SDavid du Colombier break;
151219b2ee8SDavid du Colombier case 'p':
152219b2ee8SDavid du Colombier usepass = 1;
153219b2ee8SDavid du Colombier break;
1542bef681aSDavid du Colombier case 'w':
1552bef681aSDavid du Colombier warnarg = EARGF(usage());
1562bef681aSDavid du Colombier break;
1572bef681aSDavid du Colombier default:
1582bef681aSDavid du Colombier usage();
1592bef681aSDavid du Colombier break;
160219b2ee8SDavid du Colombier }ARGEND
161219b2ee8SDavid du Colombier argv0 = "keyfs";
162219b2ee8SDavid du Colombier
163219b2ee8SDavid du Colombier userkeys = "/adm/keys";
1642bef681aSDavid du Colombier if(argc > 1)
1652bef681aSDavid du Colombier usage();
1662bef681aSDavid du Colombier if(argc == 1)
167219b2ee8SDavid du Colombier userkeys = argv[0];
168219b2ee8SDavid du Colombier
169219b2ee8SDavid du Colombier if(pipe(p) < 0)
170219b2ee8SDavid du Colombier error("can't make pipe: %r");
171219b2ee8SDavid du Colombier
1726b8bc682SDavid du Colombier if(usepass) {
1736b8bc682SDavid du Colombier getpass(authkey, nil, 0, 0);
1746b8bc682SDavid du Colombier } else {
1756b8bc682SDavid du Colombier if(!getauthkey(authkey))
1762bef681aSDavid du Colombier print("keyfs: warning: can't read NVRAM\n");
1776b8bc682SDavid du Colombier }
1786b8bc682SDavid du Colombier
1797dd7cddfSDavid du Colombier switch(rfork(RFPROC|RFNAMEG|RFNOTEG|RFNOWAIT|RFENVG|RFFDG)){
180219b2ee8SDavid du Colombier case 0:
1817dd7cddfSDavid du Colombier close(p[0]);
182219b2ee8SDavid du Colombier io(p[1], p[1]);
183219b2ee8SDavid du Colombier exits(0);
184219b2ee8SDavid du Colombier case -1:
185219b2ee8SDavid du Colombier error("fork");
186219b2ee8SDavid du Colombier default:
1877dd7cddfSDavid du Colombier close(p[1]);
1889a747e4fSDavid du Colombier if(mount(p[0], -1, mntpt, MREPL|MCREATE, "") < 0)
189219b2ee8SDavid du Colombier error("can't mount: %r");
190219b2ee8SDavid du Colombier exits(0);
191219b2ee8SDavid du Colombier }
192219b2ee8SDavid du Colombier }
193219b2ee8SDavid du Colombier
194219b2ee8SDavid du Colombier char *
Flush(Fid * f)195219b2ee8SDavid du Colombier Flush(Fid *f)
196219b2ee8SDavid du Colombier {
197219b2ee8SDavid du Colombier USED(f);
198219b2ee8SDavid du Colombier return 0;
199219b2ee8SDavid du Colombier }
200219b2ee8SDavid du Colombier
201219b2ee8SDavid du Colombier char *
Auth(Fid *)2029a747e4fSDavid du Colombier Auth(Fid *)
203219b2ee8SDavid du Colombier {
2043ff48bf5SDavid du Colombier return "keyfs: authentication not required";
205219b2ee8SDavid du Colombier }
206219b2ee8SDavid du Colombier
207219b2ee8SDavid du Colombier char *
Attach(Fid * f)208219b2ee8SDavid du Colombier Attach(Fid *f)
209219b2ee8SDavid du Colombier {
210219b2ee8SDavid du Colombier if(f->busy)
211219b2ee8SDavid du Colombier Clunk(f);
212219b2ee8SDavid du Colombier f->user = 0;
213219b2ee8SDavid du Colombier f->qtype = Qroot;
214219b2ee8SDavid du Colombier f->busy = 1;
215219b2ee8SDavid du Colombier thdr.qid = mkqid(f->user, f->qtype);
216219b2ee8SDavid du Colombier return 0;
217219b2ee8SDavid du Colombier }
218219b2ee8SDavid du Colombier
219219b2ee8SDavid du Colombier char*
Version(Fid *)2209a747e4fSDavid du Colombier Version(Fid*)
221219b2ee8SDavid du Colombier {
2229a747e4fSDavid du Colombier Fid *f;
223219b2ee8SDavid du Colombier
2249a747e4fSDavid du Colombier for(f = fids; f; f = f->next)
2259a747e4fSDavid du Colombier if(f->busy)
2269a747e4fSDavid du Colombier Clunk(f);
2279a747e4fSDavid du Colombier if(rhdr.msize > sizeof mdata)
2289a747e4fSDavid du Colombier thdr.msize = sizeof mdata;
2299a747e4fSDavid du Colombier else
2309a747e4fSDavid du Colombier thdr.msize = rhdr.msize;
2319a747e4fSDavid du Colombier messagesize = thdr.msize;
2329a747e4fSDavid du Colombier if(strncmp(rhdr.version, "9P2000", 6) != 0)
2339a747e4fSDavid du Colombier return "bad 9P version";
2349a747e4fSDavid du Colombier thdr.version = "9P2000";
235219b2ee8SDavid du Colombier return 0;
236219b2ee8SDavid du Colombier }
237219b2ee8SDavid du Colombier
238219b2ee8SDavid du Colombier char *
Walk(Fid * f)239219b2ee8SDavid du Colombier Walk(Fid *f)
240219b2ee8SDavid du Colombier {
2419a747e4fSDavid du Colombier char *name, *err;
2429a747e4fSDavid du Colombier int i, j, max;
2439a747e4fSDavid du Colombier Fid *nf;
2449a747e4fSDavid du Colombier ulong qtype;
2459a747e4fSDavid du Colombier User *user;
246219b2ee8SDavid du Colombier
247219b2ee8SDavid du Colombier if(!f->busy)
2489a747e4fSDavid du Colombier return "walk of unused fid";
2499a747e4fSDavid du Colombier nf = nil;
2509a747e4fSDavid du Colombier qtype = f->qtype;
2519a747e4fSDavid du Colombier user = f->user;
2529a747e4fSDavid du Colombier if(rhdr.fid != rhdr.newfid){
2539a747e4fSDavid du Colombier nf = findfid(rhdr.newfid);
2549a747e4fSDavid du Colombier if(nf->busy)
2559a747e4fSDavid du Colombier return "fid in use";
2569a747e4fSDavid du Colombier f = nf; /* walk f */
2579a747e4fSDavid du Colombier }
2589a747e4fSDavid du Colombier
2599a747e4fSDavid du Colombier err = nil;
2609a747e4fSDavid du Colombier i = 0;
2619a747e4fSDavid du Colombier if(rhdr.nwname > 0){
2629a747e4fSDavid du Colombier for(; i<rhdr.nwname; i++){
2639a747e4fSDavid du Colombier if(i >= MAXWELEM){
2649a747e4fSDavid du Colombier err = "too many path name elements";
265219b2ee8SDavid du Colombier break;
2669a747e4fSDavid du Colombier }
2679a747e4fSDavid du Colombier name = rhdr.wname[i];
2689a747e4fSDavid du Colombier switch(qtype){
2699a747e4fSDavid du Colombier case Qroot:
2709a747e4fSDavid du Colombier if(strcmp(name, "..") == 0)
2719a747e4fSDavid du Colombier goto Accept;
2729a747e4fSDavid du Colombier user = finduser(name);
2739a747e4fSDavid du Colombier if(!user)
2749a747e4fSDavid du Colombier goto Out;
2759a747e4fSDavid du Colombier qtype = Quser;
2769a747e4fSDavid du Colombier
2779a747e4fSDavid du Colombier Accept:
2789a747e4fSDavid du Colombier thdr.wqid[i] = mkqid(user, qtype);
2799a747e4fSDavid du Colombier break;
2809a747e4fSDavid du Colombier
281219b2ee8SDavid du Colombier case Quser:
2826b8bc682SDavid du Colombier if(strcmp(name, "..") == 0) {
2836b8bc682SDavid du Colombier qtype = Qroot;
2846b8bc682SDavid du Colombier user = 0;
2856b8bc682SDavid du Colombier goto Accept;
2866b8bc682SDavid du Colombier }
287219b2ee8SDavid du Colombier max = Qmax;
2889a747e4fSDavid du Colombier for(j = Quser + 1; j < Qmax; j++)
2899a747e4fSDavid du Colombier if(strcmp(name, qinfo[j]) == 0){
2909a747e4fSDavid du Colombier qtype = j;
291219b2ee8SDavid du Colombier break;
292219b2ee8SDavid du Colombier }
2939a747e4fSDavid du Colombier if(j < max)
2949a747e4fSDavid du Colombier goto Accept;
2959a747e4fSDavid du Colombier goto Out;
2969a747e4fSDavid du Colombier
297219b2ee8SDavid du Colombier default:
2989a747e4fSDavid du Colombier err = "file is not a directory";
2999a747e4fSDavid du Colombier goto Out;
300219b2ee8SDavid du Colombier }
3019a747e4fSDavid du Colombier }
3029a747e4fSDavid du Colombier Out:
3039a747e4fSDavid du Colombier if(i < rhdr.nwname && err == nil)
3049a747e4fSDavid du Colombier err = "file not found";
3059a747e4fSDavid du Colombier }
3069a747e4fSDavid du Colombier
3079a747e4fSDavid du Colombier if(err != nil){
3089a747e4fSDavid du Colombier return err;
3099a747e4fSDavid du Colombier }
3109a747e4fSDavid du Colombier
3119a747e4fSDavid du Colombier /* if we cloned and then completed the walk, update new fid */
3129a747e4fSDavid du Colombier if(rhdr.fid != rhdr.newfid && i == rhdr.nwname){
3139a747e4fSDavid du Colombier nf->busy = 1;
3149a747e4fSDavid du Colombier nf->qtype = qtype;
3159a747e4fSDavid du Colombier if(nf->user = user)
3169a747e4fSDavid du Colombier nf->user->ref++;
3179a747e4fSDavid du Colombier }else if(nf == nil && rhdr.nwname > 0){ /* walk without clone (rare) */
3189a747e4fSDavid du Colombier Clunk(f);
3199a747e4fSDavid du Colombier f->busy = 1;
3209a747e4fSDavid du Colombier f->qtype = qtype;
3219a747e4fSDavid du Colombier if(f->user = user)
3229a747e4fSDavid du Colombier f->user->ref++;
3239a747e4fSDavid du Colombier }
3249a747e4fSDavid du Colombier
3259a747e4fSDavid du Colombier thdr.nwqid = i;
326219b2ee8SDavid du Colombier return 0;
327219b2ee8SDavid du Colombier }
328219b2ee8SDavid du Colombier
329219b2ee8SDavid du Colombier char *
Clunk(Fid * f)330219b2ee8SDavid du Colombier Clunk(Fid *f)
331219b2ee8SDavid du Colombier {
332219b2ee8SDavid du Colombier f->busy = 0;
3336b8bc682SDavid du Colombier if(f->user && --f->user->ref == 0 && f->user->removed) {
3346b8bc682SDavid du Colombier free(f->user->name);
335219b2ee8SDavid du Colombier free(f->user);
3366b8bc682SDavid du Colombier }
337219b2ee8SDavid du Colombier f->user = 0;
338219b2ee8SDavid du Colombier return 0;
339219b2ee8SDavid du Colombier }
340219b2ee8SDavid du Colombier
341219b2ee8SDavid du Colombier char *
Open(Fid * f)342219b2ee8SDavid du Colombier Open(Fid *f)
343219b2ee8SDavid du Colombier {
344219b2ee8SDavid du Colombier int mode;
345219b2ee8SDavid du Colombier
346219b2ee8SDavid du Colombier if(!f->busy)
3479a747e4fSDavid du Colombier return "open of unused fid";
348219b2ee8SDavid du Colombier mode = rhdr.mode;
349219b2ee8SDavid du Colombier if(f->qtype == Quser && (mode & (OWRITE|OTRUNC)))
350219b2ee8SDavid du Colombier return "user already exists";
351219b2ee8SDavid du Colombier thdr.qid = mkqid(f->user, f->qtype);
3529a747e4fSDavid du Colombier thdr.iounit = messagesize - IOHDRSZ;
353219b2ee8SDavid du Colombier return 0;
354219b2ee8SDavid du Colombier }
355219b2ee8SDavid du Colombier
356219b2ee8SDavid du Colombier char *
Create(Fid * f)357219b2ee8SDavid du Colombier Create(Fid *f)
358219b2ee8SDavid du Colombier {
359219b2ee8SDavid du Colombier char *name;
360219b2ee8SDavid du Colombier long perm;
361219b2ee8SDavid du Colombier
362219b2ee8SDavid du Colombier if(!f->busy)
3639a747e4fSDavid du Colombier return "create of unused fid";
364219b2ee8SDavid du Colombier name = rhdr.name;
365219b2ee8SDavid du Colombier if(f->user){
366219b2ee8SDavid du Colombier return "permission denied";
367219b2ee8SDavid du Colombier }else{
368219b2ee8SDavid du Colombier perm = rhdr.perm;
3699a747e4fSDavid du Colombier if(!(perm & DMDIR))
370219b2ee8SDavid du Colombier return "permission denied";
3719a747e4fSDavid du Colombier if(strcmp(name, "") == 0)
3729a747e4fSDavid du Colombier return "empty file name";
3739a747e4fSDavid du Colombier if(strlen(name) >= Namelen)
3749a747e4fSDavid du Colombier return "file name too long";
375219b2ee8SDavid du Colombier if(finduser(name))
376219b2ee8SDavid du Colombier return "user already exists";
377219b2ee8SDavid du Colombier f->user = installuser(name);
378219b2ee8SDavid du Colombier f->user->ref++;
379219b2ee8SDavid du Colombier f->qtype = Quser;
380219b2ee8SDavid du Colombier }
381219b2ee8SDavid du Colombier thdr.qid = mkqid(f->user, f->qtype);
3829a747e4fSDavid du Colombier thdr.iounit = messagesize - IOHDRSZ;
383219b2ee8SDavid du Colombier writeusers();
384219b2ee8SDavid du Colombier return 0;
385219b2ee8SDavid du Colombier }
386219b2ee8SDavid du Colombier
387219b2ee8SDavid du Colombier char *
Read(Fid * f)388219b2ee8SDavid du Colombier Read(Fid *f)
389219b2ee8SDavid du Colombier {
390219b2ee8SDavid du Colombier User *u;
391219b2ee8SDavid du Colombier char *data;
3929a747e4fSDavid du Colombier ulong off, n, m;
393219b2ee8SDavid du Colombier int i, j, max;
394219b2ee8SDavid du Colombier
395219b2ee8SDavid du Colombier if(!f->busy)
3969a747e4fSDavid du Colombier return "read of unused fid";
397219b2ee8SDavid du Colombier n = rhdr.count;
398219b2ee8SDavid du Colombier off = rhdr.offset;
399219b2ee8SDavid du Colombier thdr.count = 0;
400219b2ee8SDavid du Colombier data = thdr.data;
401219b2ee8SDavid du Colombier switch(f->qtype){
402219b2ee8SDavid du Colombier case Qroot:
403219b2ee8SDavid du Colombier j = 0;
404219b2ee8SDavid du Colombier for(i = 0; i < Nuser; i++)
4059a747e4fSDavid du Colombier for(u = users[i]; u; j += m, u = u->link){
4069a747e4fSDavid du Colombier m = dostat(u, Quser, data, n);
4079a747e4fSDavid du Colombier if(m <= BIT16SZ)
4089a747e4fSDavid du Colombier break;
409219b2ee8SDavid du Colombier if(j < off)
410219b2ee8SDavid du Colombier continue;
4119a747e4fSDavid du Colombier data += m;
4129a747e4fSDavid du Colombier n -= m;
413219b2ee8SDavid du Colombier }
414219b2ee8SDavid du Colombier thdr.count = data - thdr.data;
415219b2ee8SDavid du Colombier return 0;
416219b2ee8SDavid du Colombier case Quser:
417219b2ee8SDavid du Colombier max = Qmax;
418219b2ee8SDavid du Colombier max -= Quser + 1;
4199a747e4fSDavid du Colombier j = 0;
4209a747e4fSDavid du Colombier for(i = 0; i < max; j += m, i++){
4219a747e4fSDavid du Colombier m = dostat(f->user, i + Quser + 1, data, n);
4229a747e4fSDavid du Colombier if(m <= BIT16SZ)
423219b2ee8SDavid du Colombier break;
4249a747e4fSDavid du Colombier if(j < off)
4259a747e4fSDavid du Colombier continue;
4269a747e4fSDavid du Colombier data += m;
4279a747e4fSDavid du Colombier n -= m;
428219b2ee8SDavid du Colombier }
429219b2ee8SDavid du Colombier thdr.count = data - thdr.data;
430219b2ee8SDavid du Colombier return 0;
431219b2ee8SDavid du Colombier case Qkey:
432219b2ee8SDavid du Colombier if(f->user->status != Sok)
433219b2ee8SDavid du Colombier return "user disabled";
4340dac3555SDavid du Colombier if(f->user->purgatory > time(0))
4350dac3555SDavid du Colombier return "user in purgatory";
436219b2ee8SDavid du Colombier if(f->user->expire != 0 && f->user->expire < time(0))
437219b2ee8SDavid du Colombier return "user expired";
438219b2ee8SDavid du Colombier if(off != 0)
439219b2ee8SDavid du Colombier return 0;
440219b2ee8SDavid du Colombier if(n > DESKEYLEN)
441219b2ee8SDavid du Colombier n = DESKEYLEN;
442219b2ee8SDavid du Colombier memmove(thdr.data, f->user->key, n);
443219b2ee8SDavid du Colombier thdr.count = n;
444219b2ee8SDavid du Colombier return 0;
4457dd7cddfSDavid du Colombier case Qsecret:
4467dd7cddfSDavid du Colombier if(f->user->status != Sok)
4477dd7cddfSDavid du Colombier return "user disabled";
4480dac3555SDavid du Colombier if(f->user->purgatory > time(0))
4490dac3555SDavid du Colombier return "user in purgatory";
4507dd7cddfSDavid du Colombier if(f->user->expire != 0 && f->user->expire < time(0))
4517dd7cddfSDavid du Colombier return "user expired";
4527dd7cddfSDavid du Colombier if(off != 0)
4537dd7cddfSDavid du Colombier return 0;
4547dd7cddfSDavid du Colombier if(n > strlen(f->user->secret))
4557dd7cddfSDavid du Colombier n = strlen(f->user->secret);
4567dd7cddfSDavid du Colombier memmove(thdr.data, f->user->secret, n);
4577dd7cddfSDavid du Colombier thdr.count = n;
4587dd7cddfSDavid du Colombier return 0;
459219b2ee8SDavid du Colombier case Qstatus:
460219b2ee8SDavid du Colombier if(off != 0){
461219b2ee8SDavid du Colombier thdr.count = 0;
462219b2ee8SDavid du Colombier return 0;
463219b2ee8SDavid du Colombier }
464219b2ee8SDavid du Colombier if(f->user->status == Sok && f->user->expire && f->user->expire < time(0))
465219b2ee8SDavid du Colombier sprint(thdr.data, "expired\n");
466219b2ee8SDavid du Colombier else
467219b2ee8SDavid du Colombier sprint(thdr.data, "%s\n", status[f->user->status]);
468219b2ee8SDavid du Colombier thdr.count = strlen(thdr.data);
469219b2ee8SDavid du Colombier return 0;
470219b2ee8SDavid du Colombier case Qexpire:
471219b2ee8SDavid du Colombier if(off != 0){
472219b2ee8SDavid du Colombier thdr.count = 0;
473219b2ee8SDavid du Colombier return 0;
474219b2ee8SDavid du Colombier }
475219b2ee8SDavid du Colombier if(!f->user->expire)
476219b2ee8SDavid du Colombier strcpy(data, "never\n");
477219b2ee8SDavid du Colombier else
478219b2ee8SDavid du Colombier sprint(data, "%lud\n", f->user->expire);
479219b2ee8SDavid du Colombier if(n > strlen(data))
480219b2ee8SDavid du Colombier n = strlen(data);
481219b2ee8SDavid du Colombier thdr.count = n;
482219b2ee8SDavid du Colombier return 0;
483219b2ee8SDavid du Colombier case Qlog:
484219b2ee8SDavid du Colombier if(off != 0){
485219b2ee8SDavid du Colombier thdr.count = 0;
486219b2ee8SDavid du Colombier return 0;
487219b2ee8SDavid du Colombier }
48839734e7eSDavid du Colombier sprint(data, "%lud\n", f->user->bad);
489219b2ee8SDavid du Colombier if(n > strlen(data))
490219b2ee8SDavid du Colombier n = strlen(data);
491219b2ee8SDavid du Colombier thdr.count = n;
492219b2ee8SDavid du Colombier return 0;
493219b2ee8SDavid du Colombier case Qwarnings:
494219b2ee8SDavid du Colombier if(off != 0){
495219b2ee8SDavid du Colombier thdr.count = 0;
496219b2ee8SDavid du Colombier return 0;
497219b2ee8SDavid du Colombier }
4987dd7cddfSDavid du Colombier sprint(data, "%ud\n", f->user->warnings);
499219b2ee8SDavid du Colombier if(n > strlen(data))
500219b2ee8SDavid du Colombier n = strlen(data);
501219b2ee8SDavid du Colombier thdr.count = n;
502219b2ee8SDavid du Colombier return 0;
503219b2ee8SDavid du Colombier default:
5049a747e4fSDavid du Colombier return "permission denied: unknown qid";
505219b2ee8SDavid du Colombier }
506219b2ee8SDavid du Colombier }
507219b2ee8SDavid du Colombier
508219b2ee8SDavid du Colombier char *
Write(Fid * f)509219b2ee8SDavid du Colombier Write(Fid *f)
510219b2ee8SDavid du Colombier {
511219b2ee8SDavid du Colombier char *data, *p;
512219b2ee8SDavid du Colombier ulong n, expire;
513219b2ee8SDavid du Colombier int i;
514219b2ee8SDavid du Colombier
515219b2ee8SDavid du Colombier if(!f->busy)
516219b2ee8SDavid du Colombier return "permission denied";
517219b2ee8SDavid du Colombier n = rhdr.count;
518219b2ee8SDavid du Colombier data = rhdr.data;
519219b2ee8SDavid du Colombier switch(f->qtype){
520219b2ee8SDavid du Colombier case Qkey:
521219b2ee8SDavid du Colombier if(n != DESKEYLEN)
522219b2ee8SDavid du Colombier return "garbled write data";
523219b2ee8SDavid du Colombier memmove(f->user->key, data, DESKEYLEN);
524219b2ee8SDavid du Colombier thdr.count = DESKEYLEN;
525219b2ee8SDavid du Colombier break;
5267dd7cddfSDavid du Colombier case Qsecret:
5277dd7cddfSDavid du Colombier if(n >= SECRETLEN)
5287dd7cddfSDavid du Colombier return "garbled write data";
5297dd7cddfSDavid du Colombier memmove(f->user->secret, data, n);
5307dd7cddfSDavid du Colombier f->user->secret[n] = 0;
5317dd7cddfSDavid du Colombier thdr.count = n;
5327dd7cddfSDavid du Colombier break;
533219b2ee8SDavid du Colombier case Qstatus:
534219b2ee8SDavid du Colombier data[n] = '\0';
535219b2ee8SDavid du Colombier if(p = strchr(data, '\n'))
536219b2ee8SDavid du Colombier *p = '\0';
537219b2ee8SDavid du Colombier for(i = 0; i < Smax; i++)
538219b2ee8SDavid du Colombier if(strcmp(data, status[i]) == 0){
539219b2ee8SDavid du Colombier f->user->status = i;
540219b2ee8SDavid du Colombier break;
541219b2ee8SDavid du Colombier }
542219b2ee8SDavid du Colombier if(i == Smax)
543219b2ee8SDavid du Colombier return "unknown status";
544219b2ee8SDavid du Colombier f->user->bad = 0;
545219b2ee8SDavid du Colombier thdr.count = n;
546219b2ee8SDavid du Colombier break;
547219b2ee8SDavid du Colombier case Qexpire:
548219b2ee8SDavid du Colombier data[n] = '\0';
549219b2ee8SDavid du Colombier if(p = strchr(data, '\n'))
550219b2ee8SDavid du Colombier *p = '\0';
551219b2ee8SDavid du Colombier else
552219b2ee8SDavid du Colombier p = &data[n];
553219b2ee8SDavid du Colombier if(strcmp(data, "never") == 0)
554219b2ee8SDavid du Colombier expire = 0;
555219b2ee8SDavid du Colombier else{
556219b2ee8SDavid du Colombier expire = strtoul(data, &data, 10);
557219b2ee8SDavid du Colombier if(data != p)
558219b2ee8SDavid du Colombier return "bad expiration date";
559219b2ee8SDavid du Colombier }
560219b2ee8SDavid du Colombier f->user->expire = expire;
561219b2ee8SDavid du Colombier f->user->warnings = 0;
562219b2ee8SDavid du Colombier thdr.count = n;
563219b2ee8SDavid du Colombier break;
564219b2ee8SDavid du Colombier case Qlog:
565219b2ee8SDavid du Colombier data[n] = '\0';
566219b2ee8SDavid du Colombier if(strcmp(data, "good") == 0)
567219b2ee8SDavid du Colombier f->user->bad = 0;
568219b2ee8SDavid du Colombier else
569219b2ee8SDavid du Colombier f->user->bad++;
57039734e7eSDavid du Colombier if(f->user->bad && ((f->user->bad)%MAXBAD) == 0)
57139734e7eSDavid du Colombier f->user->purgatory = time(0) + f->user->bad;
572219b2ee8SDavid du Colombier return 0;
573219b2ee8SDavid du Colombier case Qwarnings:
574219b2ee8SDavid du Colombier data[n] = '\0';
575219b2ee8SDavid du Colombier f->user->warnings = strtoul(data, 0, 10);
576219b2ee8SDavid du Colombier thdr.count = n;
577219b2ee8SDavid du Colombier break;
578219b2ee8SDavid du Colombier case Qroot:
579219b2ee8SDavid du Colombier case Quser:
580219b2ee8SDavid du Colombier default:
581219b2ee8SDavid du Colombier return "permission denied";
582219b2ee8SDavid du Colombier }
583219b2ee8SDavid du Colombier writeusers();
584219b2ee8SDavid du Colombier return 0;
585219b2ee8SDavid du Colombier }
586219b2ee8SDavid du Colombier
587219b2ee8SDavid du Colombier char *
Remove(Fid * f)588219b2ee8SDavid du Colombier Remove(Fid *f)
589219b2ee8SDavid du Colombier {
590219b2ee8SDavid du Colombier if(!f->busy)
591219b2ee8SDavid du Colombier return "permission denied";
592219b2ee8SDavid du Colombier if(f->qtype == Qwarnings)
593219b2ee8SDavid du Colombier f->user->warnings = 0;
594219b2ee8SDavid du Colombier else if(f->qtype == Quser)
595219b2ee8SDavid du Colombier removeuser(f->user);
5966b8bc682SDavid du Colombier else {
5976b8bc682SDavid du Colombier Clunk(f);
598219b2ee8SDavid du Colombier return "permission denied";
5996b8bc682SDavid du Colombier }
600219b2ee8SDavid du Colombier Clunk(f);
601219b2ee8SDavid du Colombier writeusers();
602219b2ee8SDavid du Colombier return 0;
603219b2ee8SDavid du Colombier }
604219b2ee8SDavid du Colombier
605219b2ee8SDavid du Colombier char *
Stat(Fid * f)606219b2ee8SDavid du Colombier Stat(Fid *f)
607219b2ee8SDavid du Colombier {
6089a747e4fSDavid du Colombier static uchar statbuf[1024];
6099a747e4fSDavid du Colombier
610219b2ee8SDavid du Colombier if(!f->busy)
611219b2ee8SDavid du Colombier return "stat on unattached fid";
6129a747e4fSDavid du Colombier thdr.nstat = dostat(f->user, f->qtype, statbuf, sizeof statbuf);
6139a747e4fSDavid du Colombier if(thdr.nstat <= BIT16SZ)
6149a747e4fSDavid du Colombier return "stat buffer too small";
6159a747e4fSDavid du Colombier thdr.stat = statbuf;
616219b2ee8SDavid du Colombier return 0;
617219b2ee8SDavid du Colombier }
618219b2ee8SDavid du Colombier
619219b2ee8SDavid du Colombier char *
Wstat(Fid * f)620219b2ee8SDavid du Colombier Wstat(Fid *f)
621219b2ee8SDavid du Colombier {
622219b2ee8SDavid du Colombier Dir d;
6239a747e4fSDavid du Colombier int n;
6249a747e4fSDavid du Colombier char buf[1024];
625219b2ee8SDavid du Colombier
626219b2ee8SDavid du Colombier if(!f->busy || f->qtype != Quser)
627219b2ee8SDavid du Colombier return "permission denied";
6289a747e4fSDavid du Colombier if(rhdr.nstat > sizeof buf)
6299a747e4fSDavid du Colombier return "wstat buffer too big";
6309a747e4fSDavid du Colombier if(convM2D(rhdr.stat, rhdr.nstat, &d, buf) == 0)
631219b2ee8SDavid du Colombier return "bad stat buffer";
6329a747e4fSDavid du Colombier n = strlen(d.name);
6339a747e4fSDavid du Colombier if(n == 0 || n >= Namelen)
634219b2ee8SDavid du Colombier return "bad user name";
635219b2ee8SDavid du Colombier if(finduser(d.name))
636219b2ee8SDavid du Colombier return "user already exists";
637219b2ee8SDavid du Colombier if(!removeuser(f->user))
638219b2ee8SDavid du Colombier return "user previously removed";
6399a747e4fSDavid du Colombier free(f->user->name);
6409a747e4fSDavid du Colombier f->user->name = strdup(d.name);
6419a747e4fSDavid du Colombier if(f->user->name == nil)
6429a747e4fSDavid du Colombier error("wstat: malloc failed: %r");
643219b2ee8SDavid du Colombier insertuser(f->user);
644219b2ee8SDavid du Colombier writeusers();
645219b2ee8SDavid du Colombier return 0;
646219b2ee8SDavid du Colombier }
647219b2ee8SDavid du Colombier
648219b2ee8SDavid du Colombier Qid
mkqid(User * u,ulong qtype)649219b2ee8SDavid du Colombier mkqid(User *u, ulong qtype)
650219b2ee8SDavid du Colombier {
651219b2ee8SDavid du Colombier Qid q;
652219b2ee8SDavid du Colombier
653219b2ee8SDavid du Colombier q.vers = 0;
654219b2ee8SDavid du Colombier q.path = qtype;
655219b2ee8SDavid du Colombier if(u)
656219b2ee8SDavid du Colombier q.path |= u->uniq * 0x100;
657219b2ee8SDavid du Colombier if(qtype == Quser || qtype == Qroot)
6589a747e4fSDavid du Colombier q.type = QTDIR;
6599a747e4fSDavid du Colombier else
6609a747e4fSDavid du Colombier q.type = QTFILE;
661219b2ee8SDavid du Colombier return q;
662219b2ee8SDavid du Colombier }
663219b2ee8SDavid du Colombier
6649a747e4fSDavid du Colombier int
dostat(User * user,ulong qtype,void * p,int n)6659a747e4fSDavid du Colombier dostat(User *user, ulong qtype, void *p, int n)
666219b2ee8SDavid du Colombier {
667219b2ee8SDavid du Colombier Dir d;
668219b2ee8SDavid du Colombier
669219b2ee8SDavid du Colombier if(qtype == Quser)
6709a747e4fSDavid du Colombier d.name = user->name;
671219b2ee8SDavid du Colombier else
6729a747e4fSDavid du Colombier d.name = qinfo[qtype];
6739a747e4fSDavid du Colombier d.uid = d.gid = d.muid = "auth";
674219b2ee8SDavid du Colombier d.qid = mkqid(user, qtype);
6759a747e4fSDavid du Colombier if(d.qid.type & QTDIR)
6769a747e4fSDavid du Colombier d.mode = 0777|DMDIR;
677219b2ee8SDavid du Colombier else
678219b2ee8SDavid du Colombier d.mode = 0666;
679219b2ee8SDavid du Colombier d.atime = d.mtime = time(0);
6807dd7cddfSDavid du Colombier d.length = 0;
6819a747e4fSDavid du Colombier return convD2M(&d, p, n);
682219b2ee8SDavid du Colombier }
683219b2ee8SDavid du Colombier
684219b2ee8SDavid du Colombier int
passline(Biobuf * b,void * vbuf)685219b2ee8SDavid du Colombier passline(Biobuf *b, void *vbuf)
686219b2ee8SDavid du Colombier {
687219b2ee8SDavid du Colombier char *buf = vbuf;
688219b2ee8SDavid du Colombier
689219b2ee8SDavid du Colombier if(Bread(b, buf, KEYDBLEN) != KEYDBLEN)
690219b2ee8SDavid du Colombier return 0;
691219b2ee8SDavid du Colombier decrypt(authkey, buf, KEYDBLEN);
6929a747e4fSDavid du Colombier buf[Namelen-1] = '\0';
693219b2ee8SDavid du Colombier return 1;
694219b2ee8SDavid du Colombier }
695219b2ee8SDavid du Colombier
696219b2ee8SDavid du Colombier void
randombytes(uchar * p,int len)6977dd7cddfSDavid du Colombier randombytes(uchar *p, int len)
698219b2ee8SDavid du Colombier {
6997dd7cddfSDavid du Colombier int i, fd;
700219b2ee8SDavid du Colombier
7017dd7cddfSDavid du Colombier fd = open("/dev/random", OREAD);
7027dd7cddfSDavid du Colombier if(fd < 0){
703d854de59SDavid du Colombier fprint(2, "keyfs: can't open /dev/random, using rand()\n");
7047dd7cddfSDavid du Colombier srand(time(0));
7057dd7cddfSDavid du Colombier for(i = 0; i < len; i++)
7067dd7cddfSDavid du Colombier p[i] = rand();
707219b2ee8SDavid du Colombier return;
708219b2ee8SDavid du Colombier }
7097dd7cddfSDavid du Colombier read(fd, p, len);
7107dd7cddfSDavid du Colombier close(fd);
7117dd7cddfSDavid du Colombier }
7127dd7cddfSDavid du Colombier
7137dd7cddfSDavid du Colombier void
oldCBCencrypt(char * key7,uchar * p,int len)7147dd7cddfSDavid du Colombier oldCBCencrypt(char *key7, uchar *p, int len)
7157dd7cddfSDavid du Colombier {
7167dd7cddfSDavid du Colombier uchar ivec[8];
7177dd7cddfSDavid du Colombier uchar key[8];
7187dd7cddfSDavid du Colombier DESstate s;
7197dd7cddfSDavid du Colombier
7207dd7cddfSDavid du Colombier memset(ivec, 0, 8);
7217dd7cddfSDavid du Colombier des56to64((uchar*)key7, key);
7227dd7cddfSDavid du Colombier setupDESstate(&s, key, ivec);
7237dd7cddfSDavid du Colombier desCBCencrypt((uchar*)p, len, &s);
7247dd7cddfSDavid du Colombier }
7257dd7cddfSDavid du Colombier
7267dd7cddfSDavid du Colombier void
oldCBCdecrypt(char * key7,uchar * p,int len)7277dd7cddfSDavid du Colombier oldCBCdecrypt(char *key7, uchar *p, int len)
7287dd7cddfSDavid du Colombier {
7297dd7cddfSDavid du Colombier uchar ivec[8];
7307dd7cddfSDavid du Colombier uchar key[8];
7317dd7cddfSDavid du Colombier DESstate s;
7327dd7cddfSDavid du Colombier
7337dd7cddfSDavid du Colombier memset(ivec, 0, 8);
7347dd7cddfSDavid du Colombier des56to64((uchar*)key7, key);
7357dd7cddfSDavid du Colombier setupDESstate(&s, key, ivec);
7367dd7cddfSDavid du Colombier desCBCdecrypt((uchar*)p, len, &s);
7377dd7cddfSDavid du Colombier
7387dd7cddfSDavid du Colombier }
7397dd7cddfSDavid du Colombier
7407dd7cddfSDavid du Colombier void
writeusers(void)7417dd7cddfSDavid du Colombier writeusers(void)
7427dd7cddfSDavid du Colombier {
7437dd7cddfSDavid du Colombier int fd, i, nu;
7447dd7cddfSDavid du Colombier User *u;
7457dd7cddfSDavid du Colombier uchar *p, *buf;
7467dd7cddfSDavid du Colombier ulong expire;
7477dd7cddfSDavid du Colombier
7487dd7cddfSDavid du Colombier /* count users */
7497dd7cddfSDavid du Colombier nu = 0;
7507dd7cddfSDavid du Colombier for(i = 0; i < Nuser; i++)
7517dd7cddfSDavid du Colombier for(u = users[i]; u; u = u->link)
7527dd7cddfSDavid du Colombier nu++;
7537dd7cddfSDavid du Colombier
7547dd7cddfSDavid du Colombier /* pack into buffer */
7557dd7cddfSDavid du Colombier buf = malloc(KEYDBOFF + nu*KEYDBLEN);
7567dd7cddfSDavid du Colombier if(buf == 0){
7577dd7cddfSDavid du Colombier fprint(2, "keyfs: can't write keys file, out of memory\n");
7587dd7cddfSDavid du Colombier return;
7597dd7cddfSDavid du Colombier }
7607dd7cddfSDavid du Colombier p = buf;
7617dd7cddfSDavid du Colombier randombytes(p, KEYDBOFF);
7627dd7cddfSDavid du Colombier p += KEYDBOFF;
763219b2ee8SDavid du Colombier for(i = 0; i < Nuser; i++)
764219b2ee8SDavid du Colombier for(u = users[i]; u; u = u->link){
7659a747e4fSDavid du Colombier strncpy((char*)p, u->name, Namelen);
7669a747e4fSDavid du Colombier p += Namelen;
7677dd7cddfSDavid du Colombier memmove(p, u->key, DESKEYLEN);
7687dd7cddfSDavid du Colombier p += DESKEYLEN;
769219b2ee8SDavid du Colombier *p++ = u->status;
770219b2ee8SDavid du Colombier *p++ = u->warnings;
771219b2ee8SDavid du Colombier expire = u->expire;
772219b2ee8SDavid du Colombier *p++ = expire;
773219b2ee8SDavid du Colombier *p++ = expire >> 8;
774219b2ee8SDavid du Colombier *p++ = expire >> 16;
7757dd7cddfSDavid du Colombier *p++ = expire >> 24;
7767dd7cddfSDavid du Colombier memmove(p, u->secret, SECRETLEN);
7777dd7cddfSDavid du Colombier p += SECRETLEN;
778219b2ee8SDavid du Colombier }
7797dd7cddfSDavid du Colombier
7807dd7cddfSDavid du Colombier /* encrypt */
7817dd7cddfSDavid du Colombier oldCBCencrypt(authkey, buf, p - buf);
7827dd7cddfSDavid du Colombier
7837dd7cddfSDavid du Colombier /* write file */
7847dd7cddfSDavid du Colombier fd = create(userkeys, OWRITE, 0660);
7857dd7cddfSDavid du Colombier if(fd < 0){
7867dd7cddfSDavid du Colombier free(buf);
7877dd7cddfSDavid du Colombier fprint(2, "keyfs: can't write keys file\n");
7887dd7cddfSDavid du Colombier return;
7897dd7cddfSDavid du Colombier }
7907dd7cddfSDavid du Colombier if(write(fd, buf, p - buf) != (p - buf))
7917dd7cddfSDavid du Colombier fprint(2, "keyfs: can't write keys file\n");
7927dd7cddfSDavid du Colombier
7937dd7cddfSDavid du Colombier free(buf);
7947dd7cddfSDavid du Colombier close(fd);
795219b2ee8SDavid du Colombier }
796219b2ee8SDavid du Colombier
797219b2ee8SDavid du Colombier int
weirdfmt(Fmt * f)7985864cca7SDavid du Colombier weirdfmt(Fmt *f)
7992bef681aSDavid du Colombier {
800*f54edc78SDavid du Colombier char *s, *p, *ep, buf[ANAMELEN*4 + 1];
801*f54edc78SDavid du Colombier int i, n;
8022bef681aSDavid du Colombier Rune r;
8032bef681aSDavid du Colombier
8042bef681aSDavid du Colombier s = va_arg(f->args, char*);
805*f54edc78SDavid du Colombier p = buf;
806*f54edc78SDavid du Colombier ep = buf + sizeof buf;
8072bef681aSDavid du Colombier for(i = 0; i < ANAMELEN; i += n){
8082bef681aSDavid du Colombier n = chartorune(&r, s + i);
8092bef681aSDavid du Colombier if(r == Runeerror)
810*f54edc78SDavid du Colombier p = seprint(p, ep, "[%.2x]", buf[i]);
8112bef681aSDavid du Colombier else if(isascii(r) && iscntrl(r))
812*f54edc78SDavid du Colombier p = seprint(p, ep, "[%.2x]", r);
8132bef681aSDavid du Colombier else if(r == ' ' || r == '/')
814*f54edc78SDavid du Colombier p = seprint(p, ep, "[%c]", r);
8152bef681aSDavid du Colombier else
816*f54edc78SDavid du Colombier p = seprint(p, ep, "%C", r);
8172bef681aSDavid du Colombier }
8182bef681aSDavid du Colombier return fmtstrcpy(f, buf);
8192bef681aSDavid du Colombier }
8202bef681aSDavid du Colombier
8212bef681aSDavid du Colombier int
userok(char * user,int nu)8222bef681aSDavid du Colombier userok(char *user, int nu)
8232bef681aSDavid du Colombier {
8242bef681aSDavid du Colombier int i, n, rv;
8252bef681aSDavid du Colombier Rune r;
8262bef681aSDavid du Colombier char buf[ANAMELEN+1];
8272bef681aSDavid du Colombier
8282bef681aSDavid du Colombier memset(buf, 0, sizeof buf);
8292bef681aSDavid du Colombier memmove(buf, user, ANAMELEN);
8302bef681aSDavid du Colombier
8312bef681aSDavid du Colombier if(buf[ANAMELEN-1] != 0){
8322bef681aSDavid du Colombier fprint(2, "keyfs: %d: no termination: %W\n", nu, buf);
8332bef681aSDavid du Colombier return -1;
8342bef681aSDavid du Colombier }
8352bef681aSDavid du Colombier
8362bef681aSDavid du Colombier rv = 0;
8372bef681aSDavid du Colombier for(i = 0; buf[i]; i += n){
8382bef681aSDavid du Colombier n = chartorune(&r, buf+i);
8392bef681aSDavid du Colombier if(r == Runeerror){
8402bef681aSDavid du Colombier // fprint(2, "keyfs: name %W bad rune byte %d\n", buf, i);
8412bef681aSDavid du Colombier rv = -1;
8422bef681aSDavid du Colombier } else if(isascii(r) && iscntrl(r) || r == ' ' || r == '/'){
8432bef681aSDavid du Colombier // fprint(2, "keyfs: name %W bad char %C\n", buf, r);
8442bef681aSDavid du Colombier rv = -1;
8452bef681aSDavid du Colombier }
8462bef681aSDavid du Colombier }
8472bef681aSDavid du Colombier
8482bef681aSDavid du Colombier if(i == 0){
8492bef681aSDavid du Colombier fprint(2, "keyfs: %d: nil name\n", nu);
8502bef681aSDavid du Colombier return -1;
8512bef681aSDavid du Colombier }
8522bef681aSDavid du Colombier if(rv == -1)
8532bef681aSDavid du Colombier fprint(2, "keyfs: %d: bad syntax: %W\n", nu, buf);
8542bef681aSDavid du Colombier return rv;
8552bef681aSDavid du Colombier }
8562bef681aSDavid du Colombier
8572bef681aSDavid du Colombier int
readusers(void)858219b2ee8SDavid du Colombier readusers(void)
859219b2ee8SDavid du Colombier {
8607dd7cddfSDavid du Colombier int fd, i, n, nu;
8617dd7cddfSDavid du Colombier uchar *p, *buf, *ep;
862219b2ee8SDavid du Colombier User *u;
8639a747e4fSDavid du Colombier Dir *d;
864219b2ee8SDavid du Colombier
8657dd7cddfSDavid du Colombier /* read file into an array */
8667dd7cddfSDavid du Colombier fd = open(userkeys, OREAD);
8677dd7cddfSDavid du Colombier if(fd < 0)
8687dd7cddfSDavid du Colombier return 0;
8699a747e4fSDavid du Colombier d = dirfstat(fd);
8709a747e4fSDavid du Colombier if(d == nil){
8717dd7cddfSDavid du Colombier close(fd);
8727dd7cddfSDavid du Colombier return 0;
8737dd7cddfSDavid du Colombier }
8749a747e4fSDavid du Colombier buf = malloc(d->length);
8757dd7cddfSDavid du Colombier if(buf == 0){
8767dd7cddfSDavid du Colombier close(fd);
8779a747e4fSDavid du Colombier free(d);
8787dd7cddfSDavid du Colombier return 0;
8797dd7cddfSDavid du Colombier }
8809a747e4fSDavid du Colombier n = readn(fd, buf, d->length);
8817dd7cddfSDavid du Colombier close(fd);
8829a747e4fSDavid du Colombier free(d);
8839a747e4fSDavid du Colombier if(n != d->length){
8847dd7cddfSDavid du Colombier free(buf);
8857dd7cddfSDavid du Colombier return 0;
8867dd7cddfSDavid du Colombier }
8877dd7cddfSDavid du Colombier
8887dd7cddfSDavid du Colombier /* decrypt */
8897dd7cddfSDavid du Colombier n -= n % KEYDBLEN;
8907dd7cddfSDavid du Colombier oldCBCdecrypt(authkey, buf, n);
8917dd7cddfSDavid du Colombier
8927dd7cddfSDavid du Colombier /* unpack */
893219b2ee8SDavid du Colombier nu = 0;
8947dd7cddfSDavid du Colombier for(i = KEYDBOFF; i < n; i += KEYDBLEN){
8957dd7cddfSDavid du Colombier ep = buf + i;
8962bef681aSDavid du Colombier if(userok((char*)ep, i/KEYDBLEN) < 0)
8972bef681aSDavid du Colombier continue;
8987dd7cddfSDavid du Colombier u = finduser((char*)ep);
899219b2ee8SDavid du Colombier if(u == 0)
9007dd7cddfSDavid du Colombier u = installuser((char*)ep);
9019a747e4fSDavid du Colombier memmove(u->key, ep + Namelen, DESKEYLEN);
9029a747e4fSDavid du Colombier p = ep + Namelen + DESKEYLEN;
903219b2ee8SDavid du Colombier u->status = *p++;
904219b2ee8SDavid du Colombier u->warnings = *p++;
905219b2ee8SDavid du Colombier if(u->status >= Smax)
906219b2ee8SDavid du Colombier fprint(2, "keyfs: warning: bad status in key file\n");
907219b2ee8SDavid du Colombier u->expire = p[0] + (p[1]<<8) + (p[2]<<16) + (p[3]<<24);
9087dd7cddfSDavid du Colombier p += 4;
9097dd7cddfSDavid du Colombier memmove(u->secret, p, SECRETLEN);
9107dd7cddfSDavid du Colombier u->secret[SECRETLEN-1] = 0;
911219b2ee8SDavid du Colombier nu++;
912219b2ee8SDavid du Colombier }
9137dd7cddfSDavid du Colombier free(buf);
9147dd7cddfSDavid du Colombier
915219b2ee8SDavid du Colombier print("%d keys read\n", nu);
9167dd7cddfSDavid du Colombier return 1;
917219b2ee8SDavid du Colombier }
918219b2ee8SDavid du Colombier
919219b2ee8SDavid du Colombier User *
installuser(char * name)920219b2ee8SDavid du Colombier installuser(char *name)
921219b2ee8SDavid du Colombier {
922219b2ee8SDavid du Colombier User *u;
923219b2ee8SDavid du Colombier int h;
924219b2ee8SDavid du Colombier
925219b2ee8SDavid du Colombier h = hash(name);
926219b2ee8SDavid du Colombier u = emalloc(sizeof *u);
9279a747e4fSDavid du Colombier u->name = strdup(name);
9289a747e4fSDavid du Colombier if(u->name == nil)
9299a747e4fSDavid du Colombier error("malloc failed: %r");
930219b2ee8SDavid du Colombier u->removed = 0;
931219b2ee8SDavid du Colombier u->ref = 0;
9320dac3555SDavid du Colombier u->purgatory = 0;
933219b2ee8SDavid du Colombier u->expire = 0;
934219b2ee8SDavid du Colombier u->status = Sok;
935219b2ee8SDavid du Colombier u->bad = 0;
936219b2ee8SDavid du Colombier u->warnings = 0;
937219b2ee8SDavid du Colombier u->uniq = uniq++;
938219b2ee8SDavid du Colombier u->link = users[h];
939219b2ee8SDavid du Colombier users[h] = u;
940219b2ee8SDavid du Colombier return u;
941219b2ee8SDavid du Colombier }
942219b2ee8SDavid du Colombier
943219b2ee8SDavid du Colombier User *
finduser(char * name)944219b2ee8SDavid du Colombier finduser(char *name)
945219b2ee8SDavid du Colombier {
946219b2ee8SDavid du Colombier User *u;
947219b2ee8SDavid du Colombier
948219b2ee8SDavid du Colombier for(u = users[hash(name)]; u; u = u->link)
949219b2ee8SDavid du Colombier if(strcmp(name, u->name) == 0)
950219b2ee8SDavid du Colombier return u;
951219b2ee8SDavid du Colombier return 0;
952219b2ee8SDavid du Colombier }
953219b2ee8SDavid du Colombier
954219b2ee8SDavid du Colombier int
removeuser(User * user)955219b2ee8SDavid du Colombier removeuser(User *user)
956219b2ee8SDavid du Colombier {
957219b2ee8SDavid du Colombier User *u, **last;
958219b2ee8SDavid du Colombier char *name;
959219b2ee8SDavid du Colombier
960219b2ee8SDavid du Colombier user->removed = 1;
961219b2ee8SDavid du Colombier name = user->name;
962219b2ee8SDavid du Colombier last = &users[hash(name)];
963219b2ee8SDavid du Colombier for(u = *last; u; u = *last){
964219b2ee8SDavid du Colombier if(strcmp(name, u->name) == 0){
965219b2ee8SDavid du Colombier *last = u->link;
966219b2ee8SDavid du Colombier return 1;
967219b2ee8SDavid du Colombier }
968219b2ee8SDavid du Colombier last = &u->link;
969219b2ee8SDavid du Colombier }
970219b2ee8SDavid du Colombier return 0;
971219b2ee8SDavid du Colombier }
972219b2ee8SDavid du Colombier
973219b2ee8SDavid du Colombier void
insertuser(User * user)974219b2ee8SDavid du Colombier insertuser(User *user)
975219b2ee8SDavid du Colombier {
976219b2ee8SDavid du Colombier int h;
977219b2ee8SDavid du Colombier
978219b2ee8SDavid du Colombier user->removed = 0;
979219b2ee8SDavid du Colombier h = hash(user->name);
980219b2ee8SDavid du Colombier user->link = users[h];
981219b2ee8SDavid du Colombier users[h] = user;
982219b2ee8SDavid du Colombier }
983219b2ee8SDavid du Colombier
984219b2ee8SDavid du Colombier ulong
hash(char * s)985219b2ee8SDavid du Colombier hash(char *s)
986219b2ee8SDavid du Colombier {
987219b2ee8SDavid du Colombier ulong h;
988219b2ee8SDavid du Colombier
989219b2ee8SDavid du Colombier h = 0;
990219b2ee8SDavid du Colombier while(*s)
991219b2ee8SDavid du Colombier h = (h << 1) ^ *s++;
992219b2ee8SDavid du Colombier return h % Nuser;
993219b2ee8SDavid du Colombier }
994219b2ee8SDavid du Colombier
995219b2ee8SDavid du Colombier Fid *
findfid(int fid)996219b2ee8SDavid du Colombier findfid(int fid)
997219b2ee8SDavid du Colombier {
998219b2ee8SDavid du Colombier Fid *f, *ff;
999219b2ee8SDavid du Colombier
1000219b2ee8SDavid du Colombier ff = 0;
1001219b2ee8SDavid du Colombier for(f = fids; f; f = f->next)
1002219b2ee8SDavid du Colombier if(f->fid == fid)
1003219b2ee8SDavid du Colombier return f;
1004219b2ee8SDavid du Colombier else if(!ff && !f->busy)
1005219b2ee8SDavid du Colombier ff = f;
1006219b2ee8SDavid du Colombier if(ff){
1007219b2ee8SDavid du Colombier ff->fid = fid;
1008219b2ee8SDavid du Colombier return ff;
1009219b2ee8SDavid du Colombier }
1010219b2ee8SDavid du Colombier f = emalloc(sizeof *f);
1011219b2ee8SDavid du Colombier f->fid = fid;
1012219b2ee8SDavid du Colombier f->busy = 0;
1013219b2ee8SDavid du Colombier f->user = 0;
1014219b2ee8SDavid du Colombier f->next = fids;
1015219b2ee8SDavid du Colombier fids = f;
1016219b2ee8SDavid du Colombier return f;
1017219b2ee8SDavid du Colombier }
1018219b2ee8SDavid du Colombier
1019219b2ee8SDavid du Colombier void
io(int in,int out)1020219b2ee8SDavid du Colombier io(int in, int out)
1021219b2ee8SDavid du Colombier {
10229a747e4fSDavid du Colombier char *err;
1023219b2ee8SDavid du Colombier int n;
10247dd7cddfSDavid du Colombier long now, lastwarning;
10257dd7cddfSDavid du Colombier
10267dd7cddfSDavid du Colombier /* after restart, let the system settle for 5 mins before warning */
10277dd7cddfSDavid du Colombier lastwarning = time(0) - 24*60*60 + 5*60;
1028219b2ee8SDavid du Colombier
1029219b2ee8SDavid du Colombier for(;;){
10309a747e4fSDavid du Colombier n = read9pmsg(in, mdata, messagesize);
1031219b2ee8SDavid du Colombier if(n == 0)
1032219b2ee8SDavid du Colombier continue;
1033219b2ee8SDavid du Colombier if(n < 0)
1034219b2ee8SDavid du Colombier error("mount read %d", n);
10359a747e4fSDavid du Colombier if(convM2S(mdata, n, &rhdr) == 0)
1036219b2ee8SDavid du Colombier continue;
1037219b2ee8SDavid du Colombier
1038219b2ee8SDavid du Colombier if(newkeys())
1039219b2ee8SDavid du Colombier readusers();
1040219b2ee8SDavid du Colombier
10419a747e4fSDavid du Colombier thdr.data = (char*)mdata + IOHDRSZ;
1042219b2ee8SDavid du Colombier thdr.fid = rhdr.fid;
1043219b2ee8SDavid du Colombier if(!fcalls[rhdr.type])
1044219b2ee8SDavid du Colombier err = "fcall request";
1045219b2ee8SDavid du Colombier else
1046219b2ee8SDavid du Colombier err = (*fcalls[rhdr.type])(findfid(rhdr.fid));
1047219b2ee8SDavid du Colombier thdr.tag = rhdr.tag;
1048219b2ee8SDavid du Colombier thdr.type = rhdr.type+1;
1049219b2ee8SDavid du Colombier if(err){
1050219b2ee8SDavid du Colombier thdr.type = Rerror;
10519a747e4fSDavid du Colombier thdr.ename = err;
1052219b2ee8SDavid du Colombier }
10539a747e4fSDavid du Colombier n = convS2M(&thdr, mdata, messagesize);
1054219b2ee8SDavid du Colombier if(write(out, mdata, n) != n)
1055219b2ee8SDavid du Colombier error("mount write");
1056219b2ee8SDavid du Colombier
10577dd7cddfSDavid du Colombier now = time(0);
10587dd7cddfSDavid du Colombier if(warnarg && (now - lastwarning > 24*60*60)){
10592bef681aSDavid du Colombier syslog(0, "auth", "keyfs starting warnings: %lux %lux",
10602bef681aSDavid du Colombier now, lastwarning);
1061219b2ee8SDavid du Colombier warning();
10627dd7cddfSDavid du Colombier lastwarning = now;
1063219b2ee8SDavid du Colombier }
1064219b2ee8SDavid du Colombier }
1065219b2ee8SDavid du Colombier }
1066219b2ee8SDavid du Colombier
1067219b2ee8SDavid du Colombier int
newkeys(void)1068219b2ee8SDavid du Colombier newkeys(void)
1069219b2ee8SDavid du Colombier {
10709a747e4fSDavid du Colombier Dir *d;
1071219b2ee8SDavid du Colombier static long ftime;
1072219b2ee8SDavid du Colombier
10739a747e4fSDavid du Colombier d = dirstat(userkeys);
10749a747e4fSDavid du Colombier if(d == nil)
1075219b2ee8SDavid du Colombier return 0;
10769a747e4fSDavid du Colombier if(d->mtime > ftime){
10779a747e4fSDavid du Colombier ftime = d->mtime;
10789a747e4fSDavid du Colombier free(d);
1079219b2ee8SDavid du Colombier return 1;
1080219b2ee8SDavid du Colombier }
10819a747e4fSDavid du Colombier free(d);
1082219b2ee8SDavid du Colombier return 0;
1083219b2ee8SDavid du Colombier }
1084219b2ee8SDavid du Colombier
1085219b2ee8SDavid du Colombier void *
emalloc(ulong n)1086219b2ee8SDavid du Colombier emalloc(ulong n)
1087219b2ee8SDavid du Colombier {
1088219b2ee8SDavid du Colombier void *p;
1089219b2ee8SDavid du Colombier
1090219b2ee8SDavid du Colombier if(p = malloc(n))
1091219b2ee8SDavid du Colombier return p;
1092219b2ee8SDavid du Colombier error("out of memory");
1093219b2ee8SDavid du Colombier return 0; /* not reached */
1094219b2ee8SDavid du Colombier }
1095219b2ee8SDavid du Colombier
1096219b2ee8SDavid du Colombier void
warning(void)1097219b2ee8SDavid du Colombier warning(void)
1098219b2ee8SDavid du Colombier {
10997dd7cddfSDavid du Colombier int i;
1100219b2ee8SDavid du Colombier char buf[64];
1101219b2ee8SDavid du Colombier
1102219b2ee8SDavid du Colombier snprint(buf, sizeof buf, "-%s", warnarg);
11037dd7cddfSDavid du Colombier switch(rfork(RFPROC|RFNAMEG|RFNOTEG|RFNOWAIT|RFENVG|RFFDG)){
1104219b2ee8SDavid du Colombier case 0:
11057dd7cddfSDavid du Colombier i = open("/sys/log/auth", OWRITE);
11067dd7cddfSDavid du Colombier if(i >= 0){
11077dd7cddfSDavid du Colombier dup(i, 2);
11087dd7cddfSDavid du Colombier seek(2, 0, 2);
11097dd7cddfSDavid du Colombier close(i);
1110219b2ee8SDavid du Colombier }
1111f19e7b74SDavid du Colombier execl("/bin/auth/warning", "warning", warnarg, nil);
11127dd7cddfSDavid du Colombier error("can't exec warning");
11137dd7cddfSDavid du Colombier }
11147dd7cddfSDavid du Colombier }
1115