rx: Remove RX_CALL_BUSY
[openafs.git] / src / WINNT / afsd / fs_acl.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12 #include <roken.h>
13
14 #include <afs/opr.h>
15 #include <afs/stds.h>
16 #include <afs/afs_consts.h>
17
18 #include <windows.h>
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <winioctl.h>
22 #include <winsock2.h>
23 #include <nb30.h>
24
25 #include <errno.h>
26 #include <malloc.h>
27 #include <string.h>
28 #include <strsafe.h>
29 #include <afs/opr_assert.h>
30 #include <afs/ptserver.h>
31 #include <afs/ptuser.h>
32
33
34 #include "fs_acl.h"
35
36 static int BadName(char *aname, char *cellname);
37
38 void
39 ZapAcl (struct Acl *acl)
40 {
41     if (!acl)
42         return;
43
44     ZapList(acl->pluslist);
45     ZapList(acl->minuslist);
46     free(acl);
47 }
48
49 void
50 ZapList (struct AclEntry *alist)
51 {
52     struct AclEntry *tp, *np;
53     for (tp = alist; tp; tp = np) {
54         np = tp->next;
55         free(tp);
56     }
57 }
58
59 int
60 PruneList (struct AclEntry **ae, int dfs)
61 {
62     struct AclEntry **lp;
63     struct AclEntry *te, *ne;
64     afs_int32 ctr;
65     ctr = 0;
66     lp = ae;
67     for(te = *ae;te;te=ne) {
68         if ((!dfs && te->rights == 0) || te->rights == -1) {
69             *lp = te->next;
70             ne = te->next;
71             free(te);
72             ctr++;
73         } else {
74             ne = te->next;
75             lp = &te->next;
76         }
77     }
78     return ctr;
79 }
80
81 static char *
82 SkipLine (char *astr)
83 {
84     while (*astr !='\n')
85         astr++;
86     astr++;
87     return astr;
88 }
89
90 struct AclEntry *
91 FindList (struct AclEntry *alist, char *aname)
92 {
93     while (alist) {
94         if (!strcasecmp(alist->name, aname))
95             return alist;
96         alist = alist->next;
97     }
98     return 0;
99 }
100
101 void
102 ChangeList (struct Acl *al, afs_int32 plus, char *aname, afs_int32 arights,
103             enum rtype *artypep)
104 {
105     struct AclEntry *tlist;
106     tlist = (plus ? al->pluslist : al->minuslist);
107     tlist = FindList (tlist, aname);
108     if (tlist) {
109         /* Found the item already in the list. */
110                                 /* modify rights in case of reladd    */
111                                 /* and reladd only, use standard -    */
112                                 /* add, ie. set - otherwise           */
113         if ( artypep == NULL )
114             tlist->rights = arights;
115         else if ( *artypep == reladd )
116             tlist->rights |= arights;
117         else if ( *artypep == reldel )
118             tlist->rights &= ~arights;
119         else
120             tlist->rights = arights;
121
122         if (plus)
123             al->nplus -= PruneList(&al->pluslist, al->dfs);
124         else
125             al->nminus -= PruneList(&al->minuslist, al->dfs);
126         return;
127     }
128     if ( artypep != NULL && *artypep == reldel )
129                                 /* can't reduce non-existing rights   */
130         return;
131
132     /* Otherwise we make a new item and plug in the new data. */
133     tlist = (struct AclEntry *) malloc(sizeof (struct AclEntry));
134     assert(tlist);
135     if( FAILED(StringCbCopy(tlist->name, sizeof(tlist->name), aname))) {
136         fprintf (stderr, "name - not enough space");
137         exit(1);
138     }
139     tlist->rights = arights;
140     if (plus) {
141         tlist->next = al->pluslist;
142         al->pluslist = tlist;
143         al->nplus++;
144         if (arights == 0 || arights == -1)
145             al->nplus -= PruneList(&al->pluslist, al->dfs);
146     } else {
147         tlist->next = al->minuslist;
148         al->minuslist = tlist;
149         al->nminus++;
150         if (arights == 0)
151             al->nminus -= PruneList(&al->minuslist, al->dfs);
152     }
153 }
154
155
156 /*
157  * Create an empty acl, taking into account whether the acl pointed
158  * to by astr is an AFS or DFS acl. Only parse this minimally, so we
159  * can recover from problems caused by bogus ACL's (in that case, always
160  * assume that the acl is AFS: for DFS, the user can always resort to
161  * acl_edit, but for AFS there may be no other way out).
162  */
163 struct Acl *
164 EmptyAcl(char *astr)
165 {
166     struct Acl *tp;
167     int junk;
168
169     tp = (struct Acl *)malloc(sizeof (struct Acl));
170     assert(tp);
171     tp->nplus = tp->nminus = 0;
172     tp->pluslist = tp->minuslist = 0;
173     tp->dfs = 0;
174 #if _MSC_VER < 1400
175     if (astr == NULL || sscanf(astr, "%d dfs:%d %s", &junk, &tp->dfs, tp->cell) <= 0) {
176         tp->dfs = 0;
177         tp->cell[0] = '\0';
178     }
179 #else
180     if (astr == NULL || sscanf_s(astr, "%d dfs:%d %s", &junk, &tp->dfs, tp->cell, sizeof(tp->cell)) <= 0) {
181         tp->dfs = 0;
182         tp->cell[0] = '\0';
183     }
184 #endif
185     return tp;
186 }
187
188 /* clean up an access control list of its bad entries; return 1 if we made
189    any changes to the list, and 0 otherwise */
190 int
191 CleanAcl(struct Acl *aa, char *cellname)
192 {
193     struct AclEntry *te, **le, *ne;
194     int changes;
195
196     /* Don't correct DFS ACL's for now */
197     if (aa->dfs)
198         return 0;
199
200     /* prune out bad entries */
201     changes = 0;            /* count deleted entries */
202     le = &aa->pluslist;
203     for(te = aa->pluslist; te; te=ne) {
204         ne = te->next;
205         if (BadName(te->name, cellname)) {
206             /* zap this dude */
207             *le = te->next;
208             aa->nplus--;
209             free(te);
210             changes++;
211         } else {
212             le = &te->next;
213         }
214     }
215     le = &aa->minuslist;
216     for(te = aa->minuslist; te; te=ne) {
217         ne = te->next;
218         if (BadName(te->name, cellname)) {
219             /* zap this dude */
220             *le = te->next;
221             aa->nminus--;
222             free(te);
223             changes++;
224         } else {
225             le = &te->next;
226         }
227     }
228     return changes;
229 }
230
231 struct Acl *
232 ParseAcl (char *astr, int astr_size)
233 {
234     int nplus, nminus, i, trights, ret;
235     size_t len;
236     char tname[ACL_MAXNAME];
237     struct AclEntry *first, *next, *last, *tl;
238     struct Acl *ta;
239
240     ta = EmptyAcl(NULL);
241     if( FAILED(StringCbLength(astr, astr_size, &len))) {
242         fprintf (stderr, "StringCbLength failure on astr");
243         exit(1);
244     }
245     if (astr == NULL || len == 0)
246         return ta;
247
248 #if _MSC_VER < 1400
249     ret = sscanf(astr, "%d dfs:%d %s", &ta->nplus, &ta->dfs, ta->cell);
250 #else
251     ret = sscanf_s(astr, "%d dfs:%d %s", &ta->nplus, &ta->dfs, ta->cell, sizeof(ta->cell));
252 #endif
253     if (ret <= 0) {
254         free(ta);
255         return NULL;
256     }
257     astr = SkipLine(astr);
258 #if _MSC_VER < 1400
259     ret = sscanf(astr, "%d", &ta->nminus);
260 #else
261     ret = sscanf_s(astr, "%d", &ta->nminus);
262 #endif
263     if (ret <= 0) {
264         free(ta);
265         return NULL;
266     }
267     astr = SkipLine(astr);
268
269     nplus = ta->nplus;
270     nminus = ta->nminus;
271
272     last = 0;
273     first = 0;
274     for(i=0;i<nplus;i++) {
275 #if _MSC_VER < 1400
276         ret = sscanf(astr, "%100s %d", tname, &trights);
277 #else
278         ret = sscanf_s(astr, "%100s %d", tname, sizeof(tname), &trights);
279 #endif
280         if (ret <= 0)
281             goto nplus_err;
282         astr = SkipLine(astr);
283         tl = (struct AclEntry *) malloc(sizeof (struct AclEntry));
284         if (tl == NULL)
285             goto nplus_err;
286         if (!first)
287             first = tl;
288         if( FAILED(StringCbCopy(tl->name, sizeof(tl->name), tname))) {
289             fprintf (stderr, "name - not enough space");
290             exit(1);
291         }
292         tl->rights = trights;
293         tl->next = 0;
294         if (last)
295             last->next = tl;
296         last = tl;
297     }
298     ta->pluslist = first;
299
300     last = 0;
301     first = 0;
302     for(i=0;i<nminus;i++) {
303 #if _MSC_VER < 1400
304         ret = sscanf(astr, "%100s %d", tname, &trights);
305 #else
306         ret = sscanf_s(astr, "%100s %d", tname, sizeof(tname), &trights);
307 #endif
308         if (ret <= 0)
309             goto nminus_err;
310         astr = SkipLine(astr);
311         tl = (struct AclEntry *) malloc(sizeof (struct AclEntry));
312         if (tl == NULL)
313             goto nminus_err;
314         if (!first)
315             first = tl;
316         if( FAILED(StringCbCopy(tl->name, sizeof(tl->name), tname))) {
317             fprintf (stderr, "name - not enough space");
318             exit(1);
319         }
320         tl->rights = trights;
321         tl->next = 0;
322         if (last)
323             last->next = tl;
324         last = tl;
325     }
326     ta->minuslist = first;
327
328     return ta;
329
330   nminus_err:
331     for (;first; first = next) {
332         next = first->next;
333         free(first);
334     }
335     first = ta->pluslist;
336
337   nplus_err:
338     for (;first; first = next) {
339         next = first->next;
340         free(first);
341     }
342     free(ta);
343     return NULL;
344 }
345
346 char *
347 AclToString(struct Acl *acl)
348 {
349     static char mydata[AFS_PIOCTL_MAXSIZE];
350     char tstring[AFS_PIOCTL_MAXSIZE];
351     char dfsstring[30];
352     struct AclEntry *tp;
353
354     if (acl->dfs) {
355         if( FAILED(StringCbPrintf(dfsstring, sizeof(dfsstring), " dfs:%d %s", acl->dfs, acl->cell))) {
356             fprintf (stderr, "dfsstring - cannot be populated");
357             exit(1);
358         }
359     } else {
360         dfsstring[0] = '\0';
361     }
362     if( FAILED(StringCbPrintf(mydata, sizeof(mydata), "%d%s\n%d\n", acl->nplus, dfsstring, acl->nminus))) {
363         fprintf (stderr, "mydata - cannot be populated");
364         exit(1);
365     }
366     for (tp = acl->pluslist;tp;tp=tp->next) {
367         if( FAILED(StringCbPrintf(tstring, sizeof(tstring), "%s %d\n", tp->name, tp->rights))) {
368             fprintf (stderr, "tstring - cannot be populated");
369             exit(1);
370         }
371         if( FAILED(StringCbCat(mydata, sizeof(mydata), tstring))) {
372             fprintf (stderr, "mydata - not enough space");
373             exit(1);
374         }
375     }
376     for (tp = acl->minuslist;tp;tp=tp->next) {
377         if( FAILED(StringCbPrintf(tstring, sizeof(tstring), "%s %d\n", tp->name, tp->rights))) {
378             fprintf (stderr, "tstring - cannot be populated");
379             exit(1);
380         }
381         if( FAILED(StringCbCat(mydata, sizeof(mydata), tstring))) {
382             fprintf (stderr, "mydata - not enough space");
383             exit(1);
384         }
385     }
386     return mydata;
387 }
388
389 /*
390  * Check if a username is valid: If it contains only digits (or a
391  * negative sign), then it might be bad.  If we know the cellname,
392  * then query the ptserver to see if the entry is recognized.
393  */
394 static int
395 BadName(char *aname, char *cellname)
396 {
397     afs_int32 tc, code, id = 0;
398     char *nm;
399
400     for ( nm = aname; tc = *nm; nm++) {
401         /* all must be '-' or digit to be bad */
402         if (tc != '-' && (tc < '0' || tc > '9'))
403             return 0;
404     }
405
406     if (cellname) {
407         char confDir[257];
408
409         /* Go to the PRDB and see if this all number username is valid */
410         cm_GetConfigDir(confDir, sizeof(confDir));
411
412         pr_Initialize(1, confDir, cellname);
413         code = pr_SNameToId(aname, &id);
414         pr_End();
415     }
416
417     /* 1=>Not-valid; 0=>Valid */
418     return ((!code && (id == ANONYMOUSID)) ? 1 : 0);
419 }
420
421