xref: /plan9/sys/src/cmd/fossil/9auth.c (revision 00580da515719bdf55c166b53ba7eac22c2e4dd7)
1 #include "stdinc.h"
2 #include "9.h"
3 
4 int
authRead(Fid * afid,void * data,int count)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
authWrite(Fid * afid,void * data,int count)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
authCheck(Fcall * t,Fid * fid,Fsys * fsys)64 authCheck(Fcall* t, Fid* fid, Fsys* 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",
116 			fsysGetName(fsys), fid->uname);
117 		vtSetError("bad authentication fid");
118 		return 0;
119 	}
120 
121 	/*
122 	 * Check valid afid;
123 	 * check uname and aname match.
124 	 */
125 	if(!(afid->qid.type & QTAUTH)){
126 		consPrint("attach %s as %s: afid not an auth file\n",
127 			fsysGetName(fsys), fid->uname);
128 		fidPut(afid);
129 		vtSetError("bad authentication fid");
130 		return 0;
131 	}
132 	if(strcmp(afid->uname, fid->uname) != 0 || afid->fsys != fsys){
133 		consPrint("attach %s as %s: afid is for %s as %s\n",
134 			fsysGetName(fsys), fid->uname,
135 			fsysGetName(afid->fsys), afid->uname);
136 		fidPut(afid);
137 		vtSetError("attach/auth mismatch");
138 		return 0;
139 	}
140 
141 	vtLock(afid->alock);
142 	if(afid->cuname == nil){
143 		if(authRead(afid, buf, 0) != 0 || afid->cuname == nil){
144 			vtUnlock(afid->alock);
145 			consPrint("attach %s as %s: %R\n",
146 				fsysGetName(fsys), fid->uname);
147 			fidPut(afid);
148 			vtSetError("fossil authCheck: auth protocol not finished");
149 			return 0;
150 		}
151 	}
152 	vtUnlock(afid->alock);
153 
154 	assert(fid->uid == nil);
155 	if((fid->uid = uidByUname(afid->cuname)) == nil){
156 		consPrint("attach %s as %s: unknown cuname %s\n",
157 			fsysGetName(fsys), fid->uname, afid->cuname);
158 		fidPut(afid);
159 		vtSetError("unknown user");
160 		return 0;
161 	}
162 
163 	vtMemFree(fid->uname);
164 	fid->uname = vtStrDup(afid->cuname);
165 	fidPut(afid);
166 
167 	/*
168 	 * Allow "none" once the connection has been authenticated.
169 	 */
170 	vtLock(con->alock);
171 	con->aok = 1;
172 	vtUnlock(con->alock);
173 
174 	return 1;
175 }
176