xref: /plan9-contrib/sys/src/cmd/fossil/9auth.c (revision 208510e168b9c00c3c6969f56b807dc03575167d)
1 #include "stdinc.h"
2 #include "9.h"
3 
4 int
5 authRead(Fid* afid, void* data, int count)
6 {
7 	AuthInfo *ai;
8 	AuthRpc *rpc;
9 
10 	if((rpc = afid->rpc) == nil){
11 		vtSetError("not an auth fid");
12 		return -1;
13 	}
14 
15 	switch(auth_rpc(rpc, "read", nil, 0)){
16 	default:
17 		vtSetError("fossil authRead: auth protocol not finished");
18 		return -1;
19 	case ARdone:
20 		if((ai = auth_getinfo(rpc)) == nil){
21 			vtSetError("%r");
22 			break;
23 		}
24 		if(ai->cuid == nil || *ai->cuid == '\0'){
25 			vtSetError("auth with no cuid");
26 			auth_freeAI(ai);
27 			break;
28 		}
29 		assert(afid->cuname == nil);
30 		afid->cuname = vtStrDup(ai->cuid);
31 		auth_freeAI(ai);
32 		if(Dflag)
33 			fprint(2, "authRead cuname %s\n", afid->cuname);
34 		assert(afid->uid == nil);
35 		if((afid->uid = uidByUname(afid->cuname)) == nil){
36 			vtSetError("unknown user %#q", afid->cuname);
37 			break;
38 		}
39 		return 0;
40 	case ARok:
41 		if(count < rpc->narg){
42 			vtSetError("not enough data in auth read");
43 			break;
44 		}
45 		memmove(data, rpc->arg, rpc->narg);
46 		return rpc->narg;
47 	case ARphase:
48 		vtSetError("%r");
49 		break;
50 	}
51 	return -1;
52 }
53 
54 int
55 authWrite(Fid* afid, void* data, int count)
56 {
57 	assert(afid->rpc != nil);
58 	if(auth_rpc(afid->rpc, "write", data, count) != ARok)
59 		return -1;
60 	return count;
61 }
62 
63 int
64 authCheck(Fcall* t, Fid* fid, Fs* fsys)
65 {
66 	Con *con;
67 	Fid *afid;
68 	uchar buf[1];
69 
70 	/*
71 	 * Can't lookup with FidWlock here as there may be
72 	 * protocol to do. Use a separate lock to protect altering
73 	 * the auth information inside afid.
74 	 */
75 	con = fid->con;
76 	if(t->afid == NOFID){
77 		/*
78 		 * If no authentication is asked for, allow
79 		 * "none" provided the connection has already
80 		 * been authenticatated.
81 		 *
82 		 * The console is allowed to attach without
83 		 * authentication.
84 		 */
85 		vtRLock(con->alock);
86 		if(con->isconsole){
87 			/* anything goes */
88 		}else if((con->flags&ConNoneAllow) || con->aok){
89 			static int noneprint;
90 
91 			if(noneprint++ < 10)
92 				consPrint("attach %s as %s: allowing as none\n",
93 					fsysGetName(fsys), fid->uname);
94 			vtMemFree(fid->uname);
95 			fid->uname = vtStrDup(unamenone);
96 		}else{
97 			vtRUnlock(con->alock);
98 			consPrint("attach %s as %s: connection not authenticated, not console\n",
99 				fsysGetName(fsys), fid->uname);
100 			vtSetError("cannot attach as none before authentication");
101 			return 0;
102 		}
103 		vtRUnlock(con->alock);
104 
105 		if((fid->uid = uidByUname(fid->uname)) == nil){
106 			consPrint("attach %s as %s: unknown uname\n",
107 				fsysGetName(fsys), fid->uname);
108 			vtSetError("unknown user");
109 			return 0;
110 		}
111 		return 1;
112 	}
113 
114 	if((afid = fidGet(con, t->afid, 0)) == nil){
115 		consPrint("attach %s as %s: bad afid\n", fsysGetName(fsys), fid->uname);
116 		vtSetError("bad authentication fid");
117 		return 0;
118 	}
119 
120 	/*
121 	 * Check valid afid;
122 	 * check uname and aname match.
123 	 */
124 	if(!(afid->qid.type & QTAUTH)){
125 		consPrint("attach %s as %s: afid not an auth file\n", fsysGetName(fsys),
126 			fid->uname);
127 		fidPut(afid);
128 		vtSetError("bad authentication fid");
129 		return 0;
130 	}
131 	if(strcmp(afid->uname, fid->uname) != 0 || afid->fsys != fsys){
132 		consPrint("attach %s as %s: afid is for %s as %s\n", fsysGetName(fsys),
133 			fid->uname, fsysGetName(afid->fsys), afid->uname);
134 		fidPut(afid);
135 		vtSetError("attach/auth mismatch");
136 		return 0;
137 	}
138 
139 	vtLock(afid->alock);
140 	if(afid->cuname == nil){
141 		if(authRead(afid, buf, 0) != 0 || afid->cuname == nil){
142 			vtUnlock(afid->alock);
143 			consPrint("attach %s as %s: %R\n", fsysGetName(fsys), fid->uname);
144 			fidPut(afid);
145 			vtSetError("fossil authCheck: auth protocol not finished");
146 			return 0;
147 		}
148 	}
149 	vtUnlock(afid->alock);
150 
151 	assert(fid->uid == nil);
152 	if((fid->uid = uidByUname(afid->cuname)) == nil){
153 		consPrint("attach %s as %s: unknown cuname %s\n", fsysGetName(fsys),
154 			fid->uname, afid->cuname);
155 		fidPut(afid);
156 		vtSetError("unknown user");
157 		return 0;
158 	}
159 
160 	vtMemFree(fid->uname);
161 	fid->uname = vtStrDup(afid->cuname);
162 	fidPut(afid);
163 
164 	/*
165 	 * Allow "none" once the connection has been authenticated.
166 	 */
167 	vtLock(con->alock);
168 	con->aok = 1;
169 	vtUnlock(con->alock);
170 
171 	return 1;
172 }
173