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 <afs/param.h> |
---|
11 | |
---|
12 | #include <afs/stds.h> |
---|
13 | #include <sys/types.h> |
---|
14 | #include <stdio.h> |
---|
15 | #ifdef AFS_NT40_ENV |
---|
16 | #include <winsock2.h> |
---|
17 | #else |
---|
18 | #include <netinet/in.h> |
---|
19 | #endif |
---|
20 | #include <string.h> |
---|
21 | #include <lock.h> |
---|
22 | #include <ubik.h> |
---|
23 | #include <rx/xdr.h> |
---|
24 | #include <afs/com_err.h> |
---|
25 | #include <afs/cellconfig.h> |
---|
26 | #include "ptserver.h" |
---|
27 | #include "pterror.h" |
---|
28 | #include <stdlib.h> |
---|
29 | |
---|
30 | /* Foreign cells are represented by the group system:authuser@cell*/ |
---|
31 | #define AUTHUSER_GROUP "system:authuser" |
---|
32 | |
---|
33 | |
---|
34 | extern struct ubik_dbase *dbase; |
---|
35 | extern struct afsconf_dir *prdir; |
---|
36 | extern int pr_noAuth; |
---|
37 | extern int IDCmp(); |
---|
38 | |
---|
39 | extern afs_int32 AddToEntry(); |
---|
40 | static char *whoami = "ptserver"; |
---|
41 | |
---|
42 | /* CorrectUserName - Check to make sure a user name is OK. It must not include |
---|
43 | * either a colon (or it would look like a group) or an atsign (or it would |
---|
44 | * look like a foreign user). The length is checked as well to make sure |
---|
45 | * that the user name, an atsign, and the local cell name will fit in |
---|
46 | * PR_MAXNAMELEN. This is so this user can fit in another cells database as |
---|
47 | * a foreign user with our cell name tacked on. This is a predicate, so it |
---|
48 | * return one if name is OK and zero if name is bogus. */ |
---|
49 | |
---|
50 | static int CorrectUserName (name) |
---|
51 | char *name; |
---|
52 | { |
---|
53 | extern int pr_realmNameLen; |
---|
54 | |
---|
55 | /* We accept foreign names, so we will deal with '@' later */ |
---|
56 | if (strchr (name, ':') || strchr(name, '\n')) return 0; |
---|
57 | if (strlen (name) >= PR_MAXNAMELEN - pr_realmNameLen - 1) return 0; |
---|
58 | return 1; |
---|
59 | } |
---|
60 | |
---|
61 | /* CorrectGroupName - Like the above but handles more complicated cases caused |
---|
62 | * by including the ownership in the name. The interface works by calculating |
---|
63 | * the correct name based on a given name and owner. This allows easy use by |
---|
64 | * rename, which then compares the correct name with the requested new name. */ |
---|
65 | |
---|
66 | static afs_int32 CorrectGroupName (ut, aname, cid, oid, cname) |
---|
67 | struct ubik_trans *ut; |
---|
68 | char aname[PR_MAXNAMELEN]; /* name for group */ |
---|
69 | afs_int32 cid; /* caller id */ |
---|
70 | afs_int32 oid; /* owner of group */ |
---|
71 | char cname[PR_MAXNAMELEN]; /* correct name for group */ |
---|
72 | { |
---|
73 | afs_int32 code; |
---|
74 | int admin; |
---|
75 | char *prefix; /* ptr to group owner part */ |
---|
76 | char *suffix; /* ptr to group name part */ |
---|
77 | char name[PR_MAXNAMELEN]; /* correct name for group */ |
---|
78 | struct prentry tentry; |
---|
79 | |
---|
80 | if (strlen (aname) >= PR_MAXNAMELEN) return PRBADNAM; |
---|
81 | admin = pr_noAuth || IsAMemberOf (ut, cid, SYSADMINID); |
---|
82 | |
---|
83 | if (oid == 0) oid = cid; |
---|
84 | |
---|
85 | /* Determine the correct prefix for the name. */ |
---|
86 | if (oid == SYSADMINID) prefix = "system"; |
---|
87 | else { |
---|
88 | afs_int32 loc = FindByID (ut, oid); |
---|
89 | if (loc == 0) { |
---|
90 | /* let admin create groups owned by non-existent ids (probably |
---|
91 | * setting a group to own itself). Check that they look like |
---|
92 | * groups (with a colon) or otherwise are good user names. */ |
---|
93 | if (admin) { |
---|
94 | strcpy (cname, aname); |
---|
95 | goto done; |
---|
96 | } |
---|
97 | return PRNOENT; |
---|
98 | } |
---|
99 | code = pr_Read (ut, 0, loc, &tentry, sizeof(tentry)); |
---|
100 | if (code) return code; |
---|
101 | if (ntohl(tentry.flags) & PRGRP) { |
---|
102 | if ((tentry.count == 0) && !admin) return PRGROUPEMPTY; |
---|
103 | /* terminate prefix at colon if there is one */ |
---|
104 | if ((prefix = strchr(tentry.name, ':'))) *prefix = 0; |
---|
105 | } |
---|
106 | prefix = tentry.name; |
---|
107 | } |
---|
108 | /* only sysadmin allow to use 'system:' prefix */ |
---|
109 | if ((strcmp (prefix, "system") == 0) && !admin) return PRPERM; |
---|
110 | |
---|
111 | strcpy (name, aname); /* in case aname & cname are same */ |
---|
112 | suffix = strchr(name, ':'); |
---|
113 | if (suffix == 0) { |
---|
114 | /* sysadmin can make groups w/o ':', but they must still look like |
---|
115 | * legal user names. */ |
---|
116 | if (!admin) return PRBADNAM; |
---|
117 | strcpy (cname, name); |
---|
118 | } |
---|
119 | else { |
---|
120 | if (strlen(prefix)+strlen(suffix) >= PR_MAXNAMELEN) return PRBADNAM; |
---|
121 | strcpy (cname, prefix); |
---|
122 | strcat (cname, suffix); |
---|
123 | } |
---|
124 | done: |
---|
125 | /* check for legal name with either group rules or user rules */ |
---|
126 | if ((suffix = strchr(cname, ':'))) { |
---|
127 | /* check for confusing characters */ |
---|
128 | if (strchr(cname, '\n') || /* restrict so recreate can work */ |
---|
129 | strchr(suffix+1, ':')) /* avoid multiple colons */ |
---|
130 | return PRBADNAM; |
---|
131 | } else { |
---|
132 | if (!CorrectUserName (cname)) return PRBADNAM; |
---|
133 | } |
---|
134 | return 0; |
---|
135 | } |
---|
136 | |
---|
137 | int AccessOK (ut, cid, tentry, mem, any) |
---|
138 | struct ubik_trans *ut; |
---|
139 | afs_int32 cid; /* caller id */ |
---|
140 | struct prentry *tentry; /* object being accessed */ |
---|
141 | int mem; /* check membership in aid, if group */ |
---|
142 | int any; /* if set return true */ |
---|
143 | { afs_int32 flags; |
---|
144 | afs_int32 oid; |
---|
145 | afs_int32 aid; |
---|
146 | |
---|
147 | if (pr_noAuth) return 1; |
---|
148 | if (cid == SYSADMINID) return 1; /* special case fileserver */ |
---|
149 | if (tentry) { |
---|
150 | flags = tentry->flags; |
---|
151 | oid = tentry->owner; |
---|
152 | aid = tentry->id; |
---|
153 | } else { |
---|
154 | flags = oid = aid = 0; |
---|
155 | } |
---|
156 | if (!(flags & PRACCESS)) { /* provide default access */ |
---|
157 | if (flags & PRGRP) |
---|
158 | flags |= PRP_GROUP_DEFAULT; |
---|
159 | else |
---|
160 | flags |= PRP_USER_DEFAULT; |
---|
161 | } |
---|
162 | |
---|
163 | if (flags & any) return 1; |
---|
164 | if (oid) { |
---|
165 | if ((cid == oid) || |
---|
166 | IsAMemberOf (ut, cid, oid)) return 1; |
---|
167 | } |
---|
168 | if (aid > 0) { /* checking on a user */ |
---|
169 | if (aid == cid) return 1; |
---|
170 | } else if (aid < 0) { /* checking on group */ |
---|
171 | if ((flags & mem) && IsAMemberOf (ut, cid, aid)) return 1; |
---|
172 | } |
---|
173 | /* Allow members of SYSVIEWERID to get membership and status only */ |
---|
174 | if (((mem == PRP_STATUS_MEM)||(mem == PRP_MEMBER_MEM))&&(IsAMemberOf (ut, cid, SYSVIEWERID))) return 1; |
---|
175 | if (IsAMemberOf (ut, cid, SYSADMINID)) return 1; |
---|
176 | return 0; /* no access */ |
---|
177 | } |
---|
178 | |
---|
179 | afs_int32 CreateEntry (at, aname, aid, idflag, flag, oid, creator) |
---|
180 | struct ubik_trans *at; |
---|
181 | char aname[PR_MAXNAMELEN]; |
---|
182 | afs_int32 *aid; |
---|
183 | afs_int32 idflag; |
---|
184 | afs_int32 flag; |
---|
185 | afs_int32 oid; |
---|
186 | afs_int32 creator; |
---|
187 | { |
---|
188 | /* get and init a new entry */ |
---|
189 | afs_int32 code; |
---|
190 | afs_int32 newEntry; |
---|
191 | struct prentry tentry, tent; |
---|
192 | char *atsign; |
---|
193 | |
---|
194 | memset(&tentry, 0, sizeof(tentry)); |
---|
195 | |
---|
196 | if ((oid == 0) || (oid == ANONYMOUSID)) oid = creator; |
---|
197 | |
---|
198 | if (flag & PRGRP) { |
---|
199 | code = CorrectGroupName (at, aname, creator, oid, tentry.name); |
---|
200 | if (code) return code; |
---|
201 | if (strcmp (aname, tentry.name) != 0) return PRBADNAM; |
---|
202 | } else { /* non-group must not have colon */ |
---|
203 | if (!CorrectUserName(aname)) return PRBADNAM; |
---|
204 | strcpy (tentry.name, aname); |
---|
205 | } |
---|
206 | |
---|
207 | if (FindByName(at,aname, &tent)) return PREXIST; |
---|
208 | |
---|
209 | newEntry = AllocBlock(at); |
---|
210 | if (!newEntry) return PRDBFAIL; |
---|
211 | #ifdef PR_REMEMBER_TIMES |
---|
212 | tentry.createTime = time(0); |
---|
213 | #endif |
---|
214 | |
---|
215 | if (flag & PRGRP) { |
---|
216 | tentry.flags = PRGRP; |
---|
217 | tentry.owner = oid; |
---|
218 | } else if (flag == 0) { |
---|
219 | tentry.flags = 0; |
---|
220 | tentry.owner = SYSADMINID; |
---|
221 | } else { |
---|
222 | return PRBADARG; |
---|
223 | } |
---|
224 | |
---|
225 | atsign = strchr(aname, '@'); |
---|
226 | if (!atsign) { |
---|
227 | /* A normal user or group. Pick an id for it */ |
---|
228 | if (idflag) |
---|
229 | tentry.id = *aid; |
---|
230 | else { |
---|
231 | code= AllocID(at,flag,&tentry.id); |
---|
232 | if (code != PRSUCCESS) return code; |
---|
233 | } |
---|
234 | } else if (flag & PRGRP) { |
---|
235 | /* A foreign group. Its format must be AUTHUSER_GROUP@cellname |
---|
236 | * Then pick an id for the group. |
---|
237 | */ |
---|
238 | int badFormat; |
---|
239 | |
---|
240 | *atsign = '\0'; |
---|
241 | badFormat = strcmp(AUTHUSER_GROUP, aname); |
---|
242 | *atsign = '@'; |
---|
243 | if (badFormat) return PRBADNAM; |
---|
244 | |
---|
245 | if (idflag) |
---|
246 | tentry.id = *aid; |
---|
247 | else { |
---|
248 | code= AllocID(at,flag,&tentry.id); |
---|
249 | if (code != PRSUCCESS) return code; |
---|
250 | } |
---|
251 | } else { |
---|
252 | /* A foreign user: <name>@<cell>. The foreign user is added to |
---|
253 | * its representing group. It is |
---|
254 | */ |
---|
255 | char *cellGroup; |
---|
256 | afs_int32 pos, n; |
---|
257 | struct prentry centry; |
---|
258 | extern afs_int32 allocNextId(); |
---|
259 | |
---|
260 | /* To create the user <name>@<cell> the group AUTHUSER_GROUP@<cell> |
---|
261 | * must exist. |
---|
262 | */ |
---|
263 | cellGroup = (char *)malloc(strlen(AUTHUSER_GROUP) + strlen(atsign) + 1); |
---|
264 | strcpy(cellGroup, AUTHUSER_GROUP); |
---|
265 | strcat(cellGroup, atsign); |
---|
266 | pos = FindByName(at, cellGroup, ¢ry); |
---|
267 | if (!pos) return PRBADNAM; |
---|
268 | code = pr_Read (at, 0, pos, ¢ry, sizeof(centry)); |
---|
269 | if (code) return code; |
---|
270 | |
---|
271 | /* cellid is the id of the group representing the cell */ |
---|
272 | tentry.cellid = ntohl(centry.id); |
---|
273 | |
---|
274 | if (idflag) { |
---|
275 | /* Check if id is good */ |
---|
276 | if (!inRange(¢ry,*aid)) return PRBADARG; |
---|
277 | tentry.id = *aid; |
---|
278 | } else { |
---|
279 | /* Allocate an ID special for this foreign user. It is based |
---|
280 | * on the representing group's id and nusers count. |
---|
281 | */ |
---|
282 | tentry.id = allocNextId(¢ry); |
---|
283 | } |
---|
284 | |
---|
285 | /* The foreign user will be added to the representing foreign |
---|
286 | * group. The group can hold up to 30 entries. |
---|
287 | */ |
---|
288 | if (!(ntohl(centry.flags) & PRQUOTA)) { |
---|
289 | centry.flags = htonl (ntohl(centry.flags) | PRQUOTA); |
---|
290 | centry.ngroups = htonl(30); |
---|
291 | } |
---|
292 | n = ntohl(centry.ngroups); |
---|
293 | if ( (n <= 0) && !pr_noAuth ) return PRNOMORE; |
---|
294 | centry.ngroups = htonl(n - 1); |
---|
295 | |
---|
296 | /* write updated entry for group */ |
---|
297 | code = pr_Write (at, 0, pos, ¢ry, sizeof(centry)); |
---|
298 | |
---|
299 | /* Now add the new user entry to the database */ |
---|
300 | tentry.creator = creator; |
---|
301 | *aid = tentry.id; |
---|
302 | code = pr_WriteEntry(at, 0, newEntry, &tentry); |
---|
303 | if (code) return PRDBFAIL; |
---|
304 | code = AddToIDHash(at, *aid, newEntry); |
---|
305 | if (code != PRSUCCESS) return code; |
---|
306 | code = AddToNameHash(at, aname, newEntry); |
---|
307 | if (code != PRSUCCESS) return code; |
---|
308 | if (inc_header_word (at, foreigncount, 1)) return PRDBFAIL; |
---|
309 | |
---|
310 | /* Now add the entry to the authuser group for this cell. |
---|
311 | * We will reread the entries for the user and the group |
---|
312 | * instead of modifying them before writing them in the |
---|
313 | * previous steps. Although not very efficient, much simpler |
---|
314 | */ |
---|
315 | pos = FindByID(at, tentry.cellid); |
---|
316 | if (!pos) return PRBADNAM; |
---|
317 | code = pr_ReadEntry (at, 0, pos, ¢ry); |
---|
318 | if (code) return code; |
---|
319 | code = AddToEntry(at, ¢ry, pos, *aid); |
---|
320 | if (code) return code; |
---|
321 | /* and now the user entry */ |
---|
322 | pos = FindByID(at,*aid); |
---|
323 | if (!pos) return PRBADNAM; |
---|
324 | code = pr_ReadEntry (at, 0, pos, &tentry); |
---|
325 | if (code) return code; |
---|
326 | code = AddToEntry(at, &tentry, pos, tentry.cellid); |
---|
327 | if (code) return code; |
---|
328 | |
---|
329 | return PRSUCCESS; |
---|
330 | } |
---|
331 | |
---|
332 | /* Remember the largest group id or largest user id */ |
---|
333 | if (flag & PRGRP) { |
---|
334 | /* group ids are negative */ |
---|
335 | if (tentry.id < (afs_int32)ntohl(cheader.maxGroup)) { |
---|
336 | code = set_header_word (at, maxGroup, htonl(tentry.id)); |
---|
337 | if (code) return PRDBFAIL; |
---|
338 | } |
---|
339 | } |
---|
340 | else { |
---|
341 | if (tentry.id > (afs_int32)ntohl(cheader.maxID)) { |
---|
342 | code = set_header_word (at, maxID, htonl(tentry.id)); |
---|
343 | if (code) return PRDBFAIL; |
---|
344 | } |
---|
345 | } |
---|
346 | |
---|
347 | /* Charge the creator for this group */ |
---|
348 | if (flag & PRGRP) { |
---|
349 | afs_int32 loc = FindByID (at, creator); |
---|
350 | struct prentry centry; |
---|
351 | int admin; |
---|
352 | |
---|
353 | if (loc) { /* this should only fail during initialization */ |
---|
354 | code = pr_Read (at, 0, loc, ¢ry, sizeof(centry)); |
---|
355 | if (code) return code; |
---|
356 | |
---|
357 | /* If quota is uninitialized, do it */ |
---|
358 | if (!(ntohl(centry.flags) & PRQUOTA)) { |
---|
359 | centry.flags = htonl (ntohl(centry.flags) | PRQUOTA); |
---|
360 | centry.ngroups = centry.nusers = htonl(20); |
---|
361 | } |
---|
362 | |
---|
363 | /* Admins don't get charged for creating a group. |
---|
364 | * If in noAuth mode, you get changed for it but you |
---|
365 | * are still allowed to create as many groups as you want. |
---|
366 | */ |
---|
367 | admin = ( (creator == SYSADMINID) || |
---|
368 | IsAMemberOf(at,creator,SYSADMINID) ); |
---|
369 | if (!admin) { |
---|
370 | if (ntohl(centry.ngroups) <= 0) { |
---|
371 | if (!pr_noAuth) return PRNOMORE; |
---|
372 | } else { |
---|
373 | centry.ngroups = htonl(ntohl(centry.ngroups)-1); |
---|
374 | } |
---|
375 | } |
---|
376 | |
---|
377 | code = pr_Write (at, 0, loc, ¢ry, sizeof(centry)); |
---|
378 | if (code) return code; |
---|
379 | } /* if (loc) */ |
---|
380 | } |
---|
381 | else { |
---|
382 | /* Initialize the quota for the user. Groups don't have their |
---|
383 | * quota initialized. |
---|
384 | */ |
---|
385 | tentry.flags |= PRQUOTA; |
---|
386 | tentry.ngroups = tentry.nusers = 20; |
---|
387 | } |
---|
388 | |
---|
389 | tentry.creator = creator; |
---|
390 | *aid = tentry.id; |
---|
391 | code = pr_WriteEntry(at, 0, newEntry, &tentry); |
---|
392 | if (code) return PRDBFAIL; |
---|
393 | code = AddToIDHash(at,*aid,newEntry); |
---|
394 | if (code != PRSUCCESS) return code; |
---|
395 | code = AddToNameHash(at,aname,newEntry); |
---|
396 | if (code != PRSUCCESS) return code; |
---|
397 | if (tentry.flags & PRGRP) { |
---|
398 | code = AddToOwnerChain(at,tentry.id,oid); |
---|
399 | if (code) return code; |
---|
400 | } |
---|
401 | if (tentry.flags & PRGRP) { |
---|
402 | if (inc_header_word (at, groupcount, 1)) return PRDBFAIL; |
---|
403 | } |
---|
404 | else if (tentry.flags & PRINST) { |
---|
405 | if (inc_header_word (at, instcount, 1)) return PRDBFAIL; |
---|
406 | } |
---|
407 | else { |
---|
408 | if (inc_header_word (at, usercount, 1)) return PRDBFAIL; |
---|
409 | } |
---|
410 | return PRSUCCESS; |
---|
411 | } |
---|
412 | |
---|
413 | |
---|
414 | /* RemoveFromEntry - remove aid from bid's entries list, freeing a continuation |
---|
415 | * entry if appropriate */ |
---|
416 | |
---|
417 | afs_int32 RemoveFromEntry (at, aid, bid) |
---|
418 | struct ubik_trans *at; |
---|
419 | afs_int32 aid; |
---|
420 | afs_int32 bid; |
---|
421 | { |
---|
422 | afs_int32 code; |
---|
423 | struct prentry tentry; |
---|
424 | struct contentry centry; |
---|
425 | struct contentry hentry; |
---|
426 | afs_int32 temp; |
---|
427 | afs_int32 i,j; |
---|
428 | afs_int32 nptr; |
---|
429 | afs_int32 hloc; |
---|
430 | |
---|
431 | if (aid == bid) return PRINCONSISTENT; |
---|
432 | memset(&hentry, 0, sizeof(hentry)); |
---|
433 | temp = FindByID(at,bid); |
---|
434 | if (temp == 0) return PRNOENT; |
---|
435 | code = pr_ReadEntry(at, 0, temp, &tentry); |
---|
436 | if (code != 0) return code; |
---|
437 | #ifdef PR_REMEMBER_TIMES |
---|
438 | tentry.removeTime = time(0); |
---|
439 | #endif |
---|
440 | for (i=0;i<PRSIZE;i++) { |
---|
441 | if (tentry.entries[i] == aid) { |
---|
442 | tentry.entries[i] = PRBADID; |
---|
443 | tentry.count--; |
---|
444 | code = pr_WriteEntry(at,0,temp,&tentry); |
---|
445 | if (code != 0) return code; |
---|
446 | return PRSUCCESS; |
---|
447 | } |
---|
448 | if (tentry.entries[i] == 0) /* found end of list */ |
---|
449 | return PRNOENT; |
---|
450 | } |
---|
451 | hloc = 0; |
---|
452 | nptr = tentry.next; |
---|
453 | while (nptr != 0) { |
---|
454 | code = pr_ReadCoEntry(at,0,nptr,¢ry); |
---|
455 | if (code != 0) return code; |
---|
456 | if ((centry.id != bid) || !(centry.flags & PRCONT)) return PRDBBAD; |
---|
457 | for (i=0;i<COSIZE;i++) { |
---|
458 | if (centry.entries[i] == aid) { |
---|
459 | centry.entries[i] = PRBADID; |
---|
460 | for (j=0;j<COSIZE;j++) |
---|
461 | if (centry.entries[j] != PRBADID && |
---|
462 | centry.entries[j] != 0) break; |
---|
463 | if (j == COSIZE) { /* can free this block */ |
---|
464 | if (hloc == 0) { |
---|
465 | tentry.next = centry.next; |
---|
466 | } |
---|
467 | else { |
---|
468 | hentry.next = centry.next; |
---|
469 | code = pr_WriteCoEntry (at, 0, hloc, &hentry); |
---|
470 | if (code != 0) return code; |
---|
471 | } |
---|
472 | code = FreeBlock (at, nptr); |
---|
473 | if (code) return code; |
---|
474 | } |
---|
475 | else { /* can't free it yet */ |
---|
476 | code = pr_WriteCoEntry(at,0,nptr,¢ry); |
---|
477 | if (code != 0) return code; |
---|
478 | } |
---|
479 | tentry.count--; |
---|
480 | code = pr_WriteEntry(at,0,temp,&tentry); |
---|
481 | if (code) return PRDBFAIL; |
---|
482 | return 0; |
---|
483 | } |
---|
484 | if (centry.entries[i] == 0) return PRNOENT; |
---|
485 | } /* for all coentry slots */ |
---|
486 | hloc = nptr; |
---|
487 | nptr = centry.next; |
---|
488 | memcpy(&hentry, ¢ry, sizeof(centry)); |
---|
489 | } /* while there are coentries */ |
---|
490 | return PRNOENT; |
---|
491 | } |
---|
492 | |
---|
493 | /* DeleteEntry - delete the entry in tentry at loc, removing it from all |
---|
494 | * groups, putting groups owned by it on orphan chain, and freeing the space */ |
---|
495 | |
---|
496 | afs_int32 DeleteEntry (at, tentry, loc) |
---|
497 | struct ubik_trans *at; |
---|
498 | struct prentry *tentry; |
---|
499 | afs_int32 loc; |
---|
500 | { |
---|
501 | afs_int32 code; |
---|
502 | struct contentry centry; |
---|
503 | afs_int32 i; |
---|
504 | afs_int32 nptr; |
---|
505 | |
---|
506 | if (strchr(tentry->name,'@')) { |
---|
507 | if (tentry->flags & PRGRP) { |
---|
508 | /* If there are still foreign user accounts from that cell |
---|
509 | don't delete the group */ |
---|
510 | if (tentry->count) return PRBADARG; |
---|
511 | } else { |
---|
512 | /* adjust quota */ |
---|
513 | |
---|
514 | afs_int32 loc = FindByID (at, tentry->cellid); |
---|
515 | struct prentry centry; |
---|
516 | if (loc) { |
---|
517 | code = pr_Read (at, 0, loc, ¢ry, sizeof(centry)); |
---|
518 | if (code) return code; |
---|
519 | if (ntohl(centry.flags) & PRQUOTA) { |
---|
520 | centry.ngroups = htonl(ntohl(centry.ngroups) + 1); |
---|
521 | } |
---|
522 | code = pr_Write (at, 0, loc, ¢ry, sizeof(centry)); |
---|
523 | if (code) return code; |
---|
524 | } |
---|
525 | } |
---|
526 | } |
---|
527 | /* First remove the entire membership list */ |
---|
528 | for (i=0;i<PRSIZE;i++) { |
---|
529 | if (tentry->entries[i] == PRBADID) continue; |
---|
530 | if (tentry->entries[i] == 0) break; |
---|
531 | code = RemoveFromEntry (at, tentry->id, tentry->entries[i]); |
---|
532 | if (code) return code; |
---|
533 | } |
---|
534 | nptr = tentry->next; |
---|
535 | while (nptr != (afs_int32)NULL) { |
---|
536 | code = pr_ReadCoEntry(at,0,nptr,¢ry); |
---|
537 | if (code != 0) return PRDBFAIL; |
---|
538 | for (i=0;i<COSIZE;i++) { |
---|
539 | if (centry.entries[i] == PRBADID) continue; |
---|
540 | if (centry.entries[i] == 0) break; |
---|
541 | code = RemoveFromEntry (at, tentry->id, centry.entries[i]); |
---|
542 | if (code) return code; |
---|
543 | } |
---|
544 | code = FreeBlock (at, nptr); /* free continuation block */ |
---|
545 | if (code) return code; |
---|
546 | nptr = centry.next; |
---|
547 | } |
---|
548 | |
---|
549 | /* Remove us from other's owned chain. Note that this will zero our owned |
---|
550 | * field (on disk) so this step must follow the above step in case we are |
---|
551 | * on our own owned list. */ |
---|
552 | if (tentry->flags & PRGRP) { |
---|
553 | if (tentry->owner) { |
---|
554 | code = RemoveFromOwnerChain (at, tentry->id, tentry->owner); |
---|
555 | if (code) return code; |
---|
556 | } |
---|
557 | else { |
---|
558 | code = RemoveFromOrphan (at, tentry->id); |
---|
559 | if (code) return code; |
---|
560 | } |
---|
561 | } |
---|
562 | |
---|
563 | code = RemoveFromIDHash(at,tentry->id,&loc); |
---|
564 | if (code != PRSUCCESS) return code; |
---|
565 | code = RemoveFromNameHash(at,tentry->name,&loc); |
---|
566 | if (code != PRSUCCESS) return code; |
---|
567 | |
---|
568 | if (tentry->flags & PRGRP) { |
---|
569 | afs_int32 loc = FindByID(at, tentry->creator); |
---|
570 | struct prentry centry; |
---|
571 | int admin; |
---|
572 | |
---|
573 | if (loc) { |
---|
574 | code = pr_Read (at, 0, loc, ¢ry, sizeof(centry)); |
---|
575 | if (code) return code; |
---|
576 | admin = ( (tentry->creator == SYSADMINID) || |
---|
577 | IsAMemberOf(at,tentry->creator,SYSADMINID) ); |
---|
578 | if (ntohl(centry.flags) & PRQUOTA) { |
---|
579 | if (!(admin && (ntohl(centry.ngroups) >= 20))) { |
---|
580 | centry.ngroups = htonl(ntohl(centry.ngroups) + 1); |
---|
581 | } |
---|
582 | } |
---|
583 | code = pr_Write (at, 0, loc, ¢ry, sizeof(centry)); |
---|
584 | if (code) return code; |
---|
585 | } |
---|
586 | } |
---|
587 | |
---|
588 | if (tentry->flags & PRGRP) { |
---|
589 | if (inc_header_word (at, groupcount, -1)) return PRDBFAIL; |
---|
590 | } |
---|
591 | else if (tentry->flags & PRINST) { |
---|
592 | if (inc_header_word (at, instcount, -1)) return PRDBFAIL; |
---|
593 | } |
---|
594 | else { |
---|
595 | if (strchr(tentry->name,'@')) { |
---|
596 | if (inc_header_word (at, foreigncount, -1)) return PRDBFAIL; |
---|
597 | } else { |
---|
598 | if (inc_header_word (at, usercount, -1)) return PRDBFAIL; |
---|
599 | } |
---|
600 | } |
---|
601 | code = FreeBlock(at, loc); |
---|
602 | return code; |
---|
603 | } |
---|
604 | |
---|
605 | /* AddToEntry - add aid to entry's entries list, alloc'ing a continuation block |
---|
606 | * if needed. |
---|
607 | * |
---|
608 | * Note the entry is written out by this routine. */ |
---|
609 | |
---|
610 | afs_int32 AddToEntry (tt, entry, loc, aid) |
---|
611 | struct ubik_trans *tt; |
---|
612 | struct prentry *entry; |
---|
613 | afs_int32 loc; |
---|
614 | afs_int32 aid; |
---|
615 | { |
---|
616 | afs_int32 code; |
---|
617 | afs_int32 i; |
---|
618 | struct contentry nentry; |
---|
619 | struct contentry aentry; |
---|
620 | afs_int32 nptr; |
---|
621 | afs_int32 last; /* addr of last cont. block */ |
---|
622 | afs_int32 first = 0; |
---|
623 | afs_int32 cloc = 0; |
---|
624 | afs_int32 slot = -1; |
---|
625 | |
---|
626 | if (entry->id == aid) return PRINCONSISTENT; |
---|
627 | #ifdef PR_REMEMBER_TIMES |
---|
628 | entry->addTime = time(0); |
---|
629 | #endif |
---|
630 | for (i=0;i<PRSIZE;i++) { |
---|
631 | if (entry->entries[i] == aid) |
---|
632 | return PRIDEXIST; |
---|
633 | if (entry->entries[i] == PRBADID) { /* remember this spot */ |
---|
634 | first = 1; |
---|
635 | slot = i; |
---|
636 | } |
---|
637 | else if (entry->entries[i] == 0) { /* end of the line */ |
---|
638 | if (slot == -1) { |
---|
639 | first = 1; |
---|
640 | slot = i; |
---|
641 | } |
---|
642 | break; |
---|
643 | } |
---|
644 | } |
---|
645 | last = 0; |
---|
646 | nptr = entry->next; |
---|
647 | while (nptr != (afs_int32)NULL) { |
---|
648 | code = pr_ReadCoEntry(tt,0,nptr,&nentry); |
---|
649 | if (code != 0) return code; |
---|
650 | last = nptr; |
---|
651 | if (!(nentry.flags & PRCONT)) return PRDBFAIL; |
---|
652 | for (i=0;i<COSIZE;i++) { |
---|
653 | if (nentry.entries[i] == aid) |
---|
654 | return PRIDEXIST; |
---|
655 | if (nentry.entries[i] == PRBADID) { |
---|
656 | if (slot == -1) { |
---|
657 | slot = i; |
---|
658 | cloc = nptr; |
---|
659 | } |
---|
660 | } |
---|
661 | else if (nentry.entries[i] == 0) { |
---|
662 | if (slot == -1) { |
---|
663 | slot = i; |
---|
664 | cloc = nptr; |
---|
665 | } |
---|
666 | break; |
---|
667 | } |
---|
668 | } |
---|
669 | nptr = nentry.next; |
---|
670 | } |
---|
671 | if (slot != -1) { /* we found a place */ |
---|
672 | entry->count++; |
---|
673 | if (first) { /* place is in first block */ |
---|
674 | entry->entries[slot] = aid; |
---|
675 | code = pr_WriteEntry (tt, 0, loc, entry); |
---|
676 | if (code != 0) return code; |
---|
677 | return PRSUCCESS; |
---|
678 | } |
---|
679 | code = pr_WriteEntry (tt, 0, loc, entry); |
---|
680 | if (code) return code; |
---|
681 | code = pr_ReadCoEntry(tt,0,cloc,&aentry); |
---|
682 | if (code != 0) return code; |
---|
683 | aentry.entries[slot] = aid; |
---|
684 | code = pr_WriteCoEntry(tt,0,cloc,&aentry); |
---|
685 | if (code != 0) return code; |
---|
686 | return PRSUCCESS; |
---|
687 | } |
---|
688 | /* have to allocate a continuation block if we got here */ |
---|
689 | nptr = AllocBlock(tt); |
---|
690 | if (last) { |
---|
691 | /* then we should tack new block after last block in cont. chain */ |
---|
692 | nentry.next = nptr; |
---|
693 | code = pr_WriteCoEntry(tt,0,last,&nentry); |
---|
694 | if (code != 0) return code; |
---|
695 | } |
---|
696 | else { |
---|
697 | entry->next = nptr; |
---|
698 | } |
---|
699 | memset(&aentry, 0, sizeof(aentry)); |
---|
700 | aentry.flags |= PRCONT; |
---|
701 | aentry.id = entry->id; |
---|
702 | aentry.next = 0; |
---|
703 | aentry.entries[0] = aid; |
---|
704 | code = pr_WriteCoEntry(tt,0,nptr,&aentry); |
---|
705 | if (code != 0) return code; |
---|
706 | /* don't forget to update count, here! */ |
---|
707 | entry->count++; |
---|
708 | code = pr_WriteEntry (tt, 0, loc, entry); |
---|
709 | return code; |
---|
710 | |
---|
711 | } |
---|
712 | |
---|
713 | afs_int32 AddToPRList (alist, sizeP, id) |
---|
714 | prlist *alist; |
---|
715 | int *sizeP; |
---|
716 | afs_int32 id; |
---|
717 | { |
---|
718 | char *tmp; |
---|
719 | int count; |
---|
720 | |
---|
721 | if (alist->prlist_len >= *sizeP) { |
---|
722 | count = alist->prlist_len + 100; |
---|
723 | if (alist->prlist_val) { |
---|
724 | tmp = (char *) realloc(alist->prlist_val, count*sizeof(afs_int32)); |
---|
725 | } else { |
---|
726 | tmp = (char *) malloc(count*sizeof(afs_int32)); |
---|
727 | } |
---|
728 | if (!tmp) return(PRNOMEM); |
---|
729 | alist->prlist_val = (afs_int32 *)tmp; |
---|
730 | *sizeP = count; |
---|
731 | } |
---|
732 | alist->prlist_val[alist->prlist_len++] = id; |
---|
733 | return 0; |
---|
734 | } |
---|
735 | |
---|
736 | afs_int32 GetList (at, tentry, alist, add) |
---|
737 | struct ubik_trans *at; |
---|
738 | struct prentry *tentry; |
---|
739 | prlist *alist; |
---|
740 | afs_int32 add; |
---|
741 | { |
---|
742 | afs_int32 code; |
---|
743 | afs_int32 i; |
---|
744 | struct contentry centry; |
---|
745 | afs_int32 nptr; |
---|
746 | int size; |
---|
747 | int count = 0; |
---|
748 | |
---|
749 | size = 0; |
---|
750 | alist->prlist_val = 0; |
---|
751 | alist->prlist_len = 0; |
---|
752 | |
---|
753 | for (i=0;i<PRSIZE;i++) { |
---|
754 | if (tentry->entries[i] == PRBADID) continue; |
---|
755 | if (tentry->entries[i] == 0) break; |
---|
756 | code = AddToPRList (alist, &size, tentry->entries[i]); |
---|
757 | if (code) return code; |
---|
758 | } |
---|
759 | |
---|
760 | for (nptr = tentry->next; nptr != 0; nptr = centry.next) { |
---|
761 | /* look through cont entries */ |
---|
762 | code = pr_ReadCoEntry(at,0,nptr,¢ry); |
---|
763 | if (code != 0) return code; |
---|
764 | for (i=0;i<COSIZE;i++) { |
---|
765 | if (centry.entries[i] == PRBADID) continue; |
---|
766 | if (centry.entries[i] == 0) break; |
---|
767 | code = AddToPRList (alist, &size, centry.entries[i]); |
---|
768 | if (code) return code; |
---|
769 | } |
---|
770 | if (count++ > 50) IOMGR_Poll(), count = 0; |
---|
771 | } |
---|
772 | |
---|
773 | if (add) { /* this is for a CPS, so tack on appropriate stuff */ |
---|
774 | if (tentry->id != ANONYMOUSID && tentry->id != ANYUSERID) { |
---|
775 | if ((code = AddToPRList (alist, &size, ANYUSERID)) || |
---|
776 | (code = AddAuthGroup(tentry, alist, &size)) || |
---|
777 | (code = AddToPRList (alist, &size, tentry->id))) return code; |
---|
778 | } |
---|
779 | else { |
---|
780 | if ((code = AddToPRList (alist, &size, ANYUSERID)) || |
---|
781 | (code = AddToPRList (alist, &size, tentry->id))) return code; |
---|
782 | } |
---|
783 | } |
---|
784 | if (alist->prlist_len > 100) IOMGR_Poll(); |
---|
785 | qsort(alist->prlist_val,alist->prlist_len,sizeof(afs_int32),IDCmp); |
---|
786 | return PRSUCCESS; |
---|
787 | } |
---|
788 | |
---|
789 | |
---|
790 | afs_int32 GetList2 (at, tentry, tentry2 , alist, add) |
---|
791 | struct ubik_trans *at; |
---|
792 | struct prentry *tentry; |
---|
793 | struct prentry *tentry2; |
---|
794 | prlist *alist; |
---|
795 | afs_int32 add; |
---|
796 | { |
---|
797 | afs_int32 code = 0; |
---|
798 | afs_int32 i; |
---|
799 | struct contentry centry; |
---|
800 | afs_int32 nptr; |
---|
801 | afs_int32 size; |
---|
802 | int count = 0; |
---|
803 | |
---|
804 | size = 0; |
---|
805 | alist->prlist_val = 0; |
---|
806 | alist->prlist_len = 0; |
---|
807 | for (i=0;i<PRSIZE;i++) { |
---|
808 | if (tentry->entries[i] == PRBADID) continue; |
---|
809 | if (tentry->entries[i] == 0) break; |
---|
810 | code = AddToPRList (alist, &size, tentry->entries[i]); |
---|
811 | if (code) return code; |
---|
812 | } |
---|
813 | |
---|
814 | nptr = tentry->next; |
---|
815 | while (nptr != (afs_uint32)NULL) { |
---|
816 | /* look through cont entries */ |
---|
817 | code = pr_ReadCoEntry(at,0,nptr,¢ry); |
---|
818 | if (code != 0) return code; |
---|
819 | for (i=0;i<COSIZE;i++) { |
---|
820 | if (centry.entries[i] == PRBADID) continue; |
---|
821 | if (centry.entries[i] == 0) break; |
---|
822 | code = AddToPRList (alist, &size, centry.entries[i]); |
---|
823 | if (code) return code; |
---|
824 | } |
---|
825 | nptr = centry.next; |
---|
826 | if (count++ > 50) IOMGR_Poll(), count = 0; |
---|
827 | } |
---|
828 | |
---|
829 | for (i=0;i<PRSIZE;i++) { |
---|
830 | if (tentry2->entries[i] == PRBADID) continue; |
---|
831 | if (tentry2->entries[i] == 0) break; |
---|
832 | code = AddToPRList (alist, &size, tentry2->entries[i]); |
---|
833 | if (code) break; |
---|
834 | } |
---|
835 | |
---|
836 | if (!code) { |
---|
837 | nptr = tentry2->next; |
---|
838 | while (nptr != (afs_uint32)NULL) { |
---|
839 | /* look through cont entries */ |
---|
840 | code = pr_ReadCoEntry(at,0,nptr,¢ry); |
---|
841 | if (code != 0) break; |
---|
842 | for (i=0;i<COSIZE;i++) { |
---|
843 | if (centry.entries[i] == PRBADID) continue; |
---|
844 | if (centry.entries[i] == 0) break; |
---|
845 | code = AddToPRList (alist, &size, centry.entries[i]); |
---|
846 | if (code) break; |
---|
847 | } |
---|
848 | nptr = centry.next; |
---|
849 | if (count++ > 50) IOMGR_Poll(), count = 0; |
---|
850 | } |
---|
851 | } |
---|
852 | if (add) { /* this is for a CPS, so tack on appropriate stuff */ |
---|
853 | if (tentry->id != ANONYMOUSID && tentry->id != ANYUSERID) { |
---|
854 | if ((code = AddToPRList (alist, &size, ANYUSERID)) || |
---|
855 | (code = AddToPRList (alist, &size, AUTHUSERID)) || |
---|
856 | (code = AddToPRList (alist, &size, tentry->id))) return code; |
---|
857 | } |
---|
858 | else { |
---|
859 | if ((code = AddToPRList (alist, &size, ANYUSERID)) || |
---|
860 | (code = AddToPRList (alist, &size, tentry->id))) return code; |
---|
861 | } |
---|
862 | } |
---|
863 | if (alist->prlist_len > 100) IOMGR_Poll(); |
---|
864 | qsort(alist->prlist_val,alist->prlist_len,sizeof(afs_int32),IDCmp); |
---|
865 | return PRSUCCESS; |
---|
866 | } |
---|
867 | |
---|
868 | afs_int32 GetOwnedChain (ut, next, alist) |
---|
869 | struct ubik_trans *ut; |
---|
870 | afs_int32 *next; |
---|
871 | prlist *alist; |
---|
872 | { afs_int32 code; |
---|
873 | struct prentry tentry; |
---|
874 | int size; |
---|
875 | int count = 0; |
---|
876 | |
---|
877 | size = 0; |
---|
878 | alist->prlist_val = 0; |
---|
879 | alist->prlist_len = 0; |
---|
880 | |
---|
881 | for (; *next; *next = ntohl(tentry.nextOwned)) { |
---|
882 | code = pr_Read (ut, 0, *next, &tentry, sizeof(tentry)); |
---|
883 | if (code) return code; |
---|
884 | code = AddToPRList (alist, &size, ntohl(tentry.id)); |
---|
885 | if (alist->prlist_len >= PR_MAXGROUPS) { |
---|
886 | return PRTOOMANY; |
---|
887 | } |
---|
888 | if (code) return code; |
---|
889 | if (count++ > 50) IOMGR_Poll(), count = 0; |
---|
890 | } |
---|
891 | if (alist->prlist_len > 100) IOMGR_Poll(); |
---|
892 | qsort(alist->prlist_val,alist->prlist_len,sizeof(afs_int32),IDCmp); |
---|
893 | return PRSUCCESS; |
---|
894 | } |
---|
895 | |
---|
896 | afs_int32 GetMax(at,uid,gid) |
---|
897 | struct ubik_trans *at; |
---|
898 | afs_int32 *uid; |
---|
899 | afs_int32 *gid; |
---|
900 | { |
---|
901 | *uid = ntohl(cheader.maxID); |
---|
902 | *gid = ntohl(cheader.maxGroup); |
---|
903 | return PRSUCCESS; |
---|
904 | } |
---|
905 | |
---|
906 | afs_int32 SetMax(at,id,flag) |
---|
907 | struct ubik_trans *at; |
---|
908 | afs_int32 id; |
---|
909 | afs_int32 flag; |
---|
910 | { |
---|
911 | afs_int32 code; |
---|
912 | if (flag & PRGRP) { |
---|
913 | cheader.maxGroup = htonl(id); |
---|
914 | code = pr_Write(at,0,16,(char *)&cheader.maxGroup,sizeof(cheader.maxGroup)); |
---|
915 | if (code != 0) return code; |
---|
916 | } |
---|
917 | else { |
---|
918 | cheader.maxID = htonl(id); |
---|
919 | code = pr_Write(at,0,20,(char *)&cheader.maxID,sizeof(cheader.maxID)); |
---|
920 | if (code != 0) return code; |
---|
921 | } |
---|
922 | return PRSUCCESS; |
---|
923 | } |
---|
924 | |
---|
925 | afs_int32 read_DbHeader(tt) |
---|
926 | struct ubik_trans *tt; |
---|
927 | { |
---|
928 | afs_int32 code; |
---|
929 | |
---|
930 | if (!ubik_CacheUpdate(tt)) return 0; |
---|
931 | |
---|
932 | code = pr_Read(tt, 0, 0, (char *)&cheader, sizeof(cheader)); |
---|
933 | if (code != 0) { |
---|
934 | com_err (whoami, code, "Couldn't read header"); |
---|
935 | } |
---|
936 | return code; |
---|
937 | } |
---|
938 | |
---|
939 | int pr_noAuth; |
---|
940 | afs_int32 initd=0; |
---|
941 | |
---|
942 | afs_int32 Initdb() |
---|
943 | { |
---|
944 | afs_int32 code; |
---|
945 | struct ubik_trans *tt; |
---|
946 | afs_int32 len; |
---|
947 | |
---|
948 | /* init the database. We'll try reading it, but if we're starting |
---|
949 | * from scratch, we'll have to do a write transaction. */ |
---|
950 | |
---|
951 | pr_noAuth = afsconf_GetNoAuthFlag(prdir); |
---|
952 | |
---|
953 | code = ubik_BeginTransReadAny(dbase,UBIK_READTRANS, &tt); |
---|
954 | if (code) return code; |
---|
955 | code = ubik_SetLock(tt,1,1,LOCKREAD); |
---|
956 | if (code) { |
---|
957 | ubik_AbortTrans(tt); |
---|
958 | return code; |
---|
959 | } |
---|
960 | if (!initd) { |
---|
961 | initd = 1; |
---|
962 | } else if (!ubik_CacheUpdate (tt)) { |
---|
963 | code = ubik_EndTrans(tt); |
---|
964 | return code; |
---|
965 | } |
---|
966 | |
---|
967 | len = sizeof(cheader); |
---|
968 | code = pr_Read(tt, 0, 0, (char *) &cheader, len); |
---|
969 | if (code != 0) { |
---|
970 | com_err (whoami, code, "couldn't read header"); |
---|
971 | ubik_AbortTrans(tt); |
---|
972 | return code; |
---|
973 | } |
---|
974 | if ((ntohl(cheader.version) == PRDBVERSION) && |
---|
975 | ntohl(cheader.headerSize) == sizeof(cheader) && |
---|
976 | ntohl(cheader.eofPtr) != (afs_uint32)NULL && |
---|
977 | FindByID(tt,ANONYMOUSID) != 0){ |
---|
978 | /* database exists, so we don't have to build it */ |
---|
979 | code = ubik_EndTrans(tt); |
---|
980 | if (code) return code; |
---|
981 | return PRSUCCESS; |
---|
982 | } |
---|
983 | /* else we need to build a database */ |
---|
984 | code = ubik_EndTrans(tt); |
---|
985 | if (code) return code; |
---|
986 | |
---|
987 | /* Only rebuild database if the db was deleted (the header is zero) and we |
---|
988 | are running noAuth. */ |
---|
989 | { char *bp = (char *)&cheader; |
---|
990 | int i; |
---|
991 | for (i=0; i<sizeof(cheader); i++) |
---|
992 | if (bp[i]) { |
---|
993 | code = PRDBBAD; |
---|
994 | com_err (whoami, code, |
---|
995 | "Can't rebuild database because it is not empty"); |
---|
996 | return code; |
---|
997 | } |
---|
998 | } |
---|
999 | if (!pr_noAuth) { |
---|
1000 | code = PRDBBAD; |
---|
1001 | com_err (whoami, code, |
---|
1002 | "Can't rebuild database because not running NoAuth"); |
---|
1003 | return code; |
---|
1004 | } |
---|
1005 | |
---|
1006 | code = ubik_BeginTrans(dbase,UBIK_WRITETRANS, &tt); |
---|
1007 | if (code) return code; |
---|
1008 | |
---|
1009 | code = ubik_SetLock(tt,1,1,LOCKWRITE); |
---|
1010 | if (code) { |
---|
1011 | ubik_AbortTrans(tt); |
---|
1012 | return code; |
---|
1013 | } |
---|
1014 | |
---|
1015 | /* before doing a rebuild, check again that the dbase looks bad, because |
---|
1016 | * the previous check was only under a ReadAny transaction, and there could |
---|
1017 | * actually have been a good database out there. Now that we have a |
---|
1018 | * real write transaction, make sure things are still bad. |
---|
1019 | */ |
---|
1020 | if ((ntohl(cheader.version) == PRDBVERSION) && |
---|
1021 | ntohl(cheader.headerSize) == sizeof(cheader) && |
---|
1022 | ntohl(cheader.eofPtr) != (afs_uint32)NULL && |
---|
1023 | FindByID(tt,ANONYMOUSID) != 0){ |
---|
1024 | /* database exists, so we don't have to build it */ |
---|
1025 | code = ubik_EndTrans(tt); |
---|
1026 | if (code) return code; |
---|
1027 | return PRSUCCESS; |
---|
1028 | } |
---|
1029 | |
---|
1030 | /* Initialize the database header */ |
---|
1031 | if ((code = set_header_word (tt, version, htonl(PRDBVERSION))) || |
---|
1032 | (code = set_header_word (tt, headerSize, htonl(sizeof(cheader)))) || |
---|
1033 | (code = set_header_word (tt, eofPtr, cheader.headerSize))) { |
---|
1034 | com_err (whoami, code, "couldn't write header words"); |
---|
1035 | ubik_AbortTrans(tt); |
---|
1036 | return code; |
---|
1037 | } |
---|
1038 | |
---|
1039 | #define InitialGroup(id,name) do { \ |
---|
1040 | afs_int32 temp = (id); \ |
---|
1041 | afs_int32 flag = (id) < 0 ? PRGRP : 0; \ |
---|
1042 | code = CreateEntry \ |
---|
1043 | (tt, (name), &temp, /*idflag*/1, flag, SYSADMINID, SYSADMINID); \ |
---|
1044 | if (code) { \ |
---|
1045 | com_err (whoami, code, "couldn't create %s with id %di.", \ |
---|
1046 | (name), (id)); \ |
---|
1047 | ubik_AbortTrans(tt); \ |
---|
1048 | return code; \ |
---|
1049 | } \ |
---|
1050 | } while (0) |
---|
1051 | |
---|
1052 | InitialGroup (SYSADMINID, "system:administrators"); |
---|
1053 | InitialGroup (SYSBACKUPID, "system:backup"); |
---|
1054 | InitialGroup (ANYUSERID, "system:anyuser"); |
---|
1055 | InitialGroup (AUTHUSERID, "system:authuser"); |
---|
1056 | InitialGroup (SYSVIEWERID, "system:ptsviewers"); |
---|
1057 | InitialGroup (ANONYMOUSID, "anonymous"); |
---|
1058 | |
---|
1059 | /* Well, we don't really want the max id set to anonymousid, so we'll set |
---|
1060 | * it back to 0 */ |
---|
1061 | code = set_header_word (tt, maxID, 0); /* correct in any byte order */ |
---|
1062 | if (code) { |
---|
1063 | com_err (whoami, code, "couldn't reset max id"); |
---|
1064 | ubik_AbortTrans(tt); |
---|
1065 | return code; |
---|
1066 | } |
---|
1067 | |
---|
1068 | code = ubik_EndTrans(tt); |
---|
1069 | if (code) return code; |
---|
1070 | return PRSUCCESS; |
---|
1071 | } |
---|
1072 | |
---|
1073 | afs_int32 ChangeEntry (at, aid, cid, name, oid, newid) |
---|
1074 | struct ubik_trans *at; |
---|
1075 | afs_int32 aid; |
---|
1076 | afs_int32 cid; |
---|
1077 | char *name; |
---|
1078 | afs_int32 oid; |
---|
1079 | afs_int32 newid; |
---|
1080 | { |
---|
1081 | afs_int32 code; |
---|
1082 | afs_int32 i, nptr, pos; |
---|
1083 | struct contentry centry; |
---|
1084 | struct prentry tentry, tent; |
---|
1085 | afs_int32 loc; |
---|
1086 | afs_int32 oldowner; |
---|
1087 | char holder[PR_MAXNAMELEN]; |
---|
1088 | char temp[PR_MAXNAMELEN]; |
---|
1089 | char oldname[PR_MAXNAMELEN]; |
---|
1090 | char *atsign; |
---|
1091 | |
---|
1092 | memset(holder, 0, PR_MAXNAMELEN); |
---|
1093 | memset(temp, 0, PR_MAXNAMELEN); |
---|
1094 | loc = FindByID(at,aid); |
---|
1095 | if (!loc) return PRNOENT; |
---|
1096 | code = pr_ReadEntry(at,0,loc,&tentry); |
---|
1097 | if (code) return PRDBFAIL; |
---|
1098 | if (tentry.owner != cid && |
---|
1099 | !IsAMemberOf(at,cid,SYSADMINID) && |
---|
1100 | !IsAMemberOf(at,cid,tentry.owner) && |
---|
1101 | !pr_noAuth) return PRPERM; |
---|
1102 | #ifdef PR_REMEMBER_TIMES |
---|
1103 | tentry.changeTime = time(0); |
---|
1104 | #endif |
---|
1105 | |
---|
1106 | /* we're actually trying to change the id */ |
---|
1107 | if (newid && (newid != aid)) { |
---|
1108 | if (!IsAMemberOf(at,cid,SYSADMINID) && !pr_noAuth) return PRPERM; |
---|
1109 | |
---|
1110 | pos = FindByID(at,newid); |
---|
1111 | if (pos) return PRIDEXIST; /* new id already in use! */ |
---|
1112 | if ((aid < 0 && newid > 0) || (aid > 0 && newid < 0)) return PRPERM; |
---|
1113 | |
---|
1114 | /* Should check that foreign users id to change to is good: inRange() */ |
---|
1115 | |
---|
1116 | /* if new id is not in use, rehash things */ |
---|
1117 | code = RemoveFromIDHash(at,aid,&loc); |
---|
1118 | if (code != PRSUCCESS) return code; |
---|
1119 | tentry.id = newid; |
---|
1120 | code = pr_WriteEntry(at,0,loc,&tentry); |
---|
1121 | if (code) return code; |
---|
1122 | code = AddToIDHash(at,tentry.id,loc); |
---|
1123 | if (code) return code; |
---|
1124 | |
---|
1125 | /* get current data */ |
---|
1126 | code = pr_ReadEntry(at, 0, loc, &tentry); |
---|
1127 | if (code) return PRDBFAIL; |
---|
1128 | |
---|
1129 | /* Also change the references from the membership list */ |
---|
1130 | for (i=0; i<PRSIZE; i++) { |
---|
1131 | if (tentry.entries[i] == PRBADID) continue; |
---|
1132 | if (tentry.entries[i] == 0) break; |
---|
1133 | pos = FindByID(at, tentry.entries[i]); |
---|
1134 | if (!pos) return(PRDBFAIL); |
---|
1135 | code = RemoveFromEntry(at, aid, tentry.entries[i]); |
---|
1136 | if (code) return code; |
---|
1137 | code = pr_ReadEntry(at, 0, pos, &tent); |
---|
1138 | if (code) return code; |
---|
1139 | code = AddToEntry(at, &tent, pos, newid); |
---|
1140 | if (code) return code; |
---|
1141 | } |
---|
1142 | /* Look through cont entries too. This needs to be broken into |
---|
1143 | * seperate transaction so that no one transaction becomes too |
---|
1144 | * large to complete. |
---|
1145 | */ |
---|
1146 | for (nptr=tentry.next; nptr; nptr=centry.next) { |
---|
1147 | code = pr_ReadCoEntry(at, 0, nptr, ¢ry); |
---|
1148 | if (code) return code; |
---|
1149 | for (i=0; i<COSIZE; i++) { |
---|
1150 | if (centry.entries[i] == PRBADID) continue; |
---|
1151 | if (centry.entries[i] == 0) break; |
---|
1152 | pos = FindByID(at, centry.entries[i]); |
---|
1153 | if (!pos) return(PRDBFAIL); |
---|
1154 | code = RemoveFromEntry(at, aid, centry.entries[i]); |
---|
1155 | if (code) return code; |
---|
1156 | code = pr_ReadEntry(at, 0, pos, &tent); |
---|
1157 | if (code) return code; |
---|
1158 | code = AddToEntry(at, &tent, pos, newid); |
---|
1159 | if (code) return code; |
---|
1160 | } |
---|
1161 | } |
---|
1162 | } |
---|
1163 | |
---|
1164 | atsign = strchr(tentry.name, '@'); /* check for foreign entry */ |
---|
1165 | |
---|
1166 | /* Change the owner */ |
---|
1167 | if (oid && (oid != tentry.owner)) { |
---|
1168 | /* only groups can have their owner's changed */ |
---|
1169 | if (!(tentry.flags & PRGRP)) return PRPERM; |
---|
1170 | if (atsign != NULL) return PRPERM; |
---|
1171 | oldowner = tentry.owner; |
---|
1172 | tentry.owner = oid; |
---|
1173 | /* The entry must be written through first so Remove and Add routines |
---|
1174 | * can operate on disk data */ |
---|
1175 | code = pr_WriteEntry(at,0,loc,(char *)&tentry); |
---|
1176 | if (code) return PRDBFAIL; |
---|
1177 | |
---|
1178 | /* switch owner chains */ |
---|
1179 | if (oldowner) /* if it has an owner */ |
---|
1180 | code = RemoveFromOwnerChain(at,tentry.id,oldowner); |
---|
1181 | else /* must be an orphan */ |
---|
1182 | code = RemoveFromOrphan(at,tentry.id); |
---|
1183 | if (code) return code; |
---|
1184 | code = AddToOwnerChain(at,tentry.id,tentry.owner); |
---|
1185 | if (code) return code; |
---|
1186 | |
---|
1187 | /* fix up the name */ |
---|
1188 | if (strlen(name) == 0) name = tentry.name; |
---|
1189 | /* get current data */ |
---|
1190 | code = pr_ReadEntry(at,0,loc,&tentry); |
---|
1191 | if (code) return PRDBFAIL; |
---|
1192 | } |
---|
1193 | |
---|
1194 | /* Change the name, if name is a ptr to tentry.name then this name change |
---|
1195 | * is due to a chown, otherwise caller has specified a new name */ |
---|
1196 | if ((name == tentry.name) || |
---|
1197 | (*name && (strcmp (tentry.name, name) != 0))) { |
---|
1198 | strncpy (oldname, tentry.name, PR_MAXNAMELEN); |
---|
1199 | if (tentry.flags & PRGRP) { |
---|
1200 | /* don't let foreign cell groups change name */ |
---|
1201 | if (atsign != NULL) return PRPERM; |
---|
1202 | code = CorrectGroupName (at, name, cid, tentry.owner, tentry.name); |
---|
1203 | if (code) return code; |
---|
1204 | |
---|
1205 | if (name == tentry.name) { /* owner fixup */ |
---|
1206 | if (strcmp (oldname, tentry.name) == 0) goto nameOK; |
---|
1207 | } else { /* new name, caller must be correct */ |
---|
1208 | if (strcmp (name, tentry.name) != 0) return PRBADNAM; |
---|
1209 | } |
---|
1210 | } |
---|
1211 | else |
---|
1212 | /* Allow a foreign name change only if the cellname part is |
---|
1213 | the same */ |
---|
1214 | { |
---|
1215 | char *newatsign; |
---|
1216 | |
---|
1217 | newatsign = strchr(name, '@'); |
---|
1218 | if (newatsign != atsign){ /* if they are the same no problem*/ |
---|
1219 | /*if the pointers are not equal the strings better be */ |
---|
1220 | if ((atsign == NULL) || (newatsign == NULL) || |
---|
1221 | strcmp (atsign,newatsign)) return PRPERM; |
---|
1222 | } |
---|
1223 | if (!CorrectUserName(name)) return PRBADNAM; |
---|
1224 | } |
---|
1225 | |
---|
1226 | pos = FindByName(at,name, &tent); |
---|
1227 | if (pos) return PREXIST; |
---|
1228 | code = RemoveFromNameHash (at, oldname, &loc); |
---|
1229 | if (code != PRSUCCESS) return code; |
---|
1230 | strncpy (tentry.name, name, PR_MAXNAMELEN); |
---|
1231 | code = pr_WriteEntry(at,0,loc,(char *)&tentry); |
---|
1232 | if (code) return PRDBFAIL; |
---|
1233 | code = AddToNameHash(at,tentry.name,loc); |
---|
1234 | if (code != PRSUCCESS) return code; |
---|
1235 | nameOK:; |
---|
1236 | } |
---|
1237 | return PRSUCCESS; |
---|
1238 | } |
---|
1239 | |
---|
1240 | |
---|
1241 | afs_int32 allocNextId(cellEntry) |
---|
1242 | struct prentry *cellEntry; |
---|
1243 | { |
---|
1244 | /* Id's for foreign cell entries are constructed as follows: |
---|
1245 | The 16 low order bits are the group id of the cell and the |
---|
1246 | top 16 bits identify the particular users in that cell */ |
---|
1247 | |
---|
1248 | afs_int32 id; |
---|
1249 | |
---|
1250 | |
---|
1251 | id = (ntohl(cellEntry -> nusers) +1); |
---|
1252 | cellEntry->nusers = htonl(id); |
---|
1253 | /* use the field nusers to keep |
---|
1254 | the next available id in that |
---|
1255 | foreign cell's group. Note : |
---|
1256 | It would seem more appropriate |
---|
1257 | to use ngroup for that and nusers |
---|
1258 | to enforce the quota, however pts |
---|
1259 | does not have an option to change |
---|
1260 | foreign users quota yet */ |
---|
1261 | |
---|
1262 | id = (id << 16) | ((ntohl(cellEntry-> id)) & 0x0000ffff); |
---|
1263 | return id; |
---|
1264 | } |
---|
1265 | |
---|
1266 | int inRange(cellEntry,aid) |
---|
1267 | struct prentry *cellEntry; |
---|
1268 | afs_int32 aid; |
---|
1269 | { |
---|
1270 | afs_uint32 id,cellid,groupid; |
---|
1271 | |
---|
1272 | |
---|
1273 | /* |
---|
1274 | The only thing that we want to make sure here is that |
---|
1275 | the id is in the legal range of this group. If it is |
---|
1276 | a duplicate we don't care since it will get caught |
---|
1277 | in a different check. |
---|
1278 | */ |
---|
1279 | |
---|
1280 | cellid = aid & 0x0000ffff; |
---|
1281 | groupid = (ntohl(cellEntry-> id)) & 0x0000ffff; |
---|
1282 | if (cellid != groupid) return 0; /* not in range */ |
---|
1283 | |
---|
1284 | /* |
---|
1285 | if we got here we're ok but we need to update the nusers |
---|
1286 | field in order to get the id correct the next time that |
---|
1287 | we try to allocate it automatically |
---|
1288 | */ |
---|
1289 | |
---|
1290 | id = aid >> 16; |
---|
1291 | if (id > ntohl(cellEntry -> nusers)) |
---|
1292 | cellEntry -> nusers = htonl(id); |
---|
1293 | return 1; |
---|
1294 | |
---|
1295 | } |
---|
1296 | |
---|
1297 | AddAuthGroup(tentry, alist, size) |
---|
1298 | struct prentry *tentry; |
---|
1299 | prlist *alist; |
---|
1300 | afs_int32 *size; |
---|
1301 | { |
---|
1302 | if (!(strchr(tentry->name, '@'))) |
---|
1303 | return (AddToPRList (alist, size, AUTHUSERID)); |
---|
1304 | else |
---|
1305 | return PRSUCCESS; |
---|
1306 | } |
---|