backport to buster
[hcoop/debian/openafs.git] / src / ptserver / ptutils.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 /*
11 * (5) Add functions to process supergroups:
12 * ChangeIDEntry(), RemoveFromSGEntry(),
13 * AddToSGEntry(), GetListSG2().
14 * (6) Add code to existing functions to process
15 * supergroups.
16 * 2/1/98 jjm Add mdw's changes for bit mapping for supergroups
17 *
18 * 09/26/02 kwc Move depthsg definition here from ptserver.c since
19 * pt_util needs it defined also, and this file is
20 * common between the two programs.
21 */
22
23 #include <afsconfig.h>
24 #include <afs/param.h>
25 #include <afs/stds.h>
26
27 #include <roken.h>
28
29 #include <lock.h>
30 #include <ubik.h>
31 #include <rx/xdr.h>
32 #include <afs/com_err.h>
33 #include <afs/cellconfig.h>
34
35 #include "ptserver.h"
36 #include "pterror.h"
37 #include "ptprototypes.h"
38
39 /* Foreign cells are represented by the group system:authuser@cell*/
40 #define AUTHUSER_GROUP "system:authuser"
41
42 extern int restricted;
43 extern struct ubik_dbase *dbase;
44 extern struct afsconf_dir *prdir;
45 extern int pr_noAuth;
46
47 static int inRange(struct prentry *cellEntry, afs_int32 aid);
48 static afs_int32 allocNextId(struct ubik_trans *, struct prentry *);
49 static int AddAuthGroup(struct prentry *tentry, prlist *alist, afs_int32 *size);
50
51 static char *whoami = "ptserver";
52
53 int prp_user_default = PRP_USER_DEFAULT;
54 int prp_group_default = PRP_GROUP_DEFAULT;
55
56 #if defined(SUPERGROUPS)
57
58 #include "map.h"
59
60 afs_int32 depthsg = 5; /* Maximum iterations used during IsAMemberOF */
61 afs_int32 GetListSG2(struct ubik_trans *at, afs_int32 gid, prlist * alist,
62 afs_int32 * sizeP, afs_int32 depth);
63
64 struct map *sg_flagged;
65 struct map *sg_found;
66
67 #define NIL_MAP ((struct map *) 0)
68
69 /* pt_mywrite hooks into the logic that writes ubik records to disk
70 * at a very low level. It invalidates mappings in sg_flagged/sg_found.
71 * By hoooking in at this level, we ensure that a ubik file reload
72 * invalidates our incore cache.
73 *
74 * We assert records, cheaders and everything else are 0 mod 64.
75 * So, we can always see the first 64 bytes of any record written.
76 * The stuff we're interested in (flags, id) are in the first 8 bytes.
77 * so we can always tell if we're writing a group record.
78 */
79
80 int (*pt_save_dbase_write)(struct ubik_dbase *, afs_int32, void *, afs_int32,
81 afs_int32);
82
83 int
84 pt_mywrite(struct ubik_dbase *tdb, afs_int32 fno, void *bp, afs_int32 pos, afs_int32 count)
85 {
86 afs_uint32 headersize = ntohl(cheader.headerSize);
87
88 if (fno == 0 && pos + count > headersize) {
89 afs_int32 p, l, c, o;
90 char *cp;
91 p = pos - headersize;
92 cp = bp;
93 l = count;
94 if (p < 0) {
95 l += p;
96 p = 0;
97 }
98 while (l > 0) {
99 o = p % ENTRYSIZE;
100 c = ENTRYSIZE - o;
101 if (c > l)
102 c = l;
103 #define xPT(p,x) ((((struct prentry *)(p))->flags & htonl(PRTYPE)) == htonl(x))
104 #if DEBUG_SG_MAP
105 if (o)
106 fprintf(stderr, "Writing %d bytes of entry @ %#lx(+%d)\n", c,
107 p - o, o);
108 else if (c == ENTRYSIZE)
109 fprintf(stderr,
110 "Writing %d bytes of entry @ %#lx (%d<%s>,%d)\n",
111 c, p, ntohl(((struct prentry *)cp)->flags),
112 xPT(cp,PRUSER) ? "user" : xPT(cp,PRFREE) ? "free" :
113 xPT(cp,PRGRP) ? "group" : xPT(cp,PRCONT) ? "cont" :
114 xPT(cp,PRCELL) ? "cell" : xPT(cp,PRFOREIGN) ? "foreign" :
115 xPT(cp,PRINST) ? "sub/super instance" : "?",
116 ntohl(((struct prentry *)cp)->id));
117 else if (c >= 8)
118 fprintf(stderr,
119 "Writing first %d bytes of entry @ %#lx (%d<%s>,%d)\n",
120 c, p, ntohl(((struct prentry *)cp)->flags),
121 xPT(cp,PRUSER) ? "user" : xPT(cp,PRFREE) ? "free" :
122 xPT(cp,PRGRP) ? "group" : xPT(cp,PRCONT) ? "cont" :
123 xPT(cp,PRCELL) ? "cell" : xPT(cp,PRFOREIGN) ? "foreign" :
124 xPT(cp,PRINST) ? "sub/super instance" : "?",
125 ntohl(((struct prentry *)cp)->id));
126 else
127 fprintf(stderr, "Writing %d bytes of entry @ %#lx\n", c, p);
128 #endif
129 if (!o && c >= 8 && xPT(cp,PRGRP)) {
130 #if DEBUG_SG_MAP
131 if (in_map(sg_found, -ntohl(((struct prentry *)cp)->id)))
132 fprintf(stderr, "Unfound: Removing group %d\n",
133 ntohl(((struct prentry *)cp)->id));
134 if (in_map(sg_flagged, -ntohl(((struct prentry *)cp)->id)))
135 fprintf(stderr, "Unflag: Removing group %d\n",
136 ntohl(((struct prentry *)cp)->id));
137 #endif
138 sg_found =
139 bic_map(sg_found,
140 add_map(NIL_MAP, -ntohl(((struct prentry *)cp)->id)));
141 sg_flagged =
142 bic_map(sg_flagged,
143 add_map(NIL_MAP, -ntohl(((struct prentry *)cp)->id)));
144 }
145 cp += c;
146 p += c;
147 l -= c;
148 #undef xPT
149 }
150 }
151 return (*pt_save_dbase_write) (tdb, fno, bp, pos, count);
152 }
153
154 /*
155 * this function attaches pt_mywrite. It's called once,
156 * just after ubik_ServerInit.
157 */
158
159 void
160 pt_hook_write(void)
161 {
162 extern struct ubik_dbase *ubik_dbase;
163 if (ubik_dbase->write != pt_mywrite) {
164 pt_save_dbase_write = ubik_dbase->write;
165 ubik_dbase->write = pt_mywrite;
166 }
167 }
168
169 #endif /* SUPERGROUPS */
170
171 /* CorrectUserName - Check to make sure a user name is OK. It must not include
172 * either a colon (or it would look like a group) or a newline (which can
173 * confuse some ptdb code, depending on the format we're reading from).
174 * This is a predicate, so it return one if name is OK and zero if name is
175 * bogus. */
176
177 static int
178 CorrectUserName(char *name)
179 {
180 /* We accept foreign names, so we will deal with '@' later */
181 if (strchr(name, ':') || strchr(name, '\n'))
182 return 0;
183 if (strlen(name) >= PR_MAXNAMELEN)
184 return 0;
185 return 1;
186 }
187
188 /* CorrectGroupName - Like the above but handles more complicated cases caused
189 * by including the ownership in the name. The interface works by calculating
190 * the correct name based on a given name and owner. This allows easy use by
191 * rename, which then compares the correct name with the requested new name. */
192
193 static afs_int32
194 CorrectGroupName(struct ubik_trans *ut, char aname[PR_MAXNAMELEN], /* name for group */
195 afs_int32 cid, /* caller id */
196 afs_int32 oid, /* owner of group */
197 afs_int32 admin, /* non-zero if admin */
198 char cname[PR_MAXNAMELEN]) /* correct name for group */
199 {
200 afs_int32 code;
201 char *prefix; /* ptr to group owner part */
202 char *suffix; /* ptr to group name part */
203 char name[PR_MAXNAMELEN]; /* correct name for group */
204 struct prentry tentry;
205
206 if (strlen(aname) >= PR_MAXNAMELEN)
207 return PRBADNAM;
208
209 /* Determine the correct prefix for the name. */
210 if (oid == SYSADMINID)
211 prefix = "system";
212 else {
213 afs_int32 loc = FindByID(ut, oid);
214 if (loc == 0) {
215 /* let admin create groups owned by non-existent ids (probably
216 * setting a group to own itself). Check that they look like
217 * groups (with a colon) or otherwise are good user names. */
218 if (admin) {
219 strcpy(cname, aname);
220 goto done;
221 }
222 return PRNOENT;
223 }
224 code = pr_Read(ut, 0, loc, &tentry, sizeof(tentry));
225 if (code)
226 return code;
227 if (ntohl(tentry.flags) & PRGRP) {
228 if ((tentry.count == 0) && !admin)
229 return PRGROUPEMPTY;
230 /* terminate prefix at colon if there is one */
231 if ((prefix = strchr(tentry.name, ':')))
232 *prefix = 0;
233 }
234 prefix = tentry.name;
235 }
236 /* only sysadmin allow to use 'system:' prefix */
237 if ((strcmp(prefix, "system") == 0) && !admin)
238 return PRPERM;
239
240 strcpy(name, aname); /* in case aname & cname are same */
241 suffix = strchr(name, ':');
242 /* let e.g. pt_util create groups with "wrong" names (like
243 * an orphan whose parent ID was reused). Check that they look like
244 * groups (with a colon) or otherwise are good user names. */
245 if (pr_noAuth) {
246 strcpy(cname, aname);
247 goto done;
248 }
249 if (suffix == 0) {
250 /* sysadmin can make groups w/o ':', but they must still look like
251 * legal user names. */
252 if (!admin)
253 return PRBADNAM;
254 strcpy(cname, name);
255 } else {
256 if (strlen(prefix) + strlen(suffix) >= PR_MAXNAMELEN)
257 return PRBADNAM;
258 strcpy(cname, prefix);
259 strcat(cname, suffix);
260 }
261 done:
262 /* check for legal name with either group rules or user rules */
263 if ((suffix = strchr(cname, ':'))) {
264 /* check for confusing characters */
265 if (strchr(cname, '\n') || /* restrict so recreate can work */
266 strchr(suffix + 1, ':')) /* avoid multiple colons */
267 return PRBADNAM;
268 } else {
269 if (!CorrectUserName(cname))
270 return PRBADNAM;
271 }
272 return 0;
273 }
274
275 int
276 AccessOK(struct ubik_trans *ut, afs_int32 cid, /* caller id */
277 struct prentry *tentry, /* object being accessed */
278 int mem, /* check membership in aid, if group */
279 int any) /* if set return true */
280 {
281 afs_int32 flags;
282 afs_int32 oid;
283 afs_int32 aid;
284
285 if (pr_noAuth)
286 return 1;
287 if (cid == SYSADMINID)
288 return 1; /* special case fileserver */
289 if (restricted && !IsAMemberOf(ut, cid, SYSADMINID)) {
290 if (mem == PRP_ADD_MEM || mem == PRP_REMOVE_MEM) {
291 /* operation is for adding/removing members from a group */
292 return 0;
293 }
294 if (mem == 0 && any == 0) {
295 /* operation is for modifying an entry (or some administrative
296 * global operations) */
297 return 0;
298 }
299 }
300 if (tentry) {
301 flags = tentry->flags;
302 oid = tentry->owner;
303 aid = tentry->id;
304 } else {
305 flags = oid = aid = 0;
306 }
307 if (!(flags & PRACCESS)) { /* provide default access */
308 if (flags & PRGRP)
309 flags |= prp_group_default;
310 else
311 flags |= prp_user_default;
312 }
313
314 if (flags & any)
315 return 1;
316 if (oid) {
317 if ((cid == oid) || IsAMemberOf(ut, cid, oid))
318 return 1;
319 }
320 if (aid > 0) { /* checking on a user */
321 if (aid == cid)
322 return 1;
323 } else if (aid < 0) { /* checking on group */
324 if ((flags & mem) && IsAMemberOf(ut, cid, aid))
325 return 1;
326 }
327 /* Allow members of SYSVIEWERID to get membership and status only */
328 if (((mem == PRP_STATUS_MEM) || (mem == PRP_MEMBER_MEM)
329 || (any == PRP_OWNED_ANY)) && (IsAMemberOf(ut, cid, SYSVIEWERID)))
330 return 1;
331 if (IsAMemberOf(ut, cid, SYSADMINID))
332 return 1;
333 return 0; /* no access */
334 }
335
336 afs_int32
337 CreateEntry(struct ubik_trans *at, char aname[PR_MAXNAMELEN], afs_int32 *aid, afs_int32 idflag, afs_int32 flag, afs_int32 oid, afs_int32 creator)
338 {
339 /* get and init a new entry */
340 afs_int32 code;
341 afs_int32 newEntry;
342 afs_int32 admin;
343 struct prentry tentry, tent;
344 char *atsign;
345
346 memset(&tentry, 0, sizeof(tentry));
347
348 admin = pr_noAuth || IsAMemberOf(at, creator, SYSADMINID);
349
350 if (oid == 0 || oid == ANONYMOUSID) {
351 if (!admin && creator == 0)
352 return PRBADARG;
353 oid = creator;
354 }
355
356 if (flag & PRGRP) {
357 code = CorrectGroupName(at, aname, creator, oid, admin, tentry.name);
358 if (code)
359 return code;
360 if (strcmp(aname, tentry.name) != 0)
361 return PRBADNAM;
362 } else { /* non-group must not have colon */
363 if (!CorrectUserName(aname))
364 return PRBADNAM;
365 strcpy(tentry.name, aname);
366 }
367
368 if (FindByName(at, aname, &tent))
369 return PREXIST;
370
371 newEntry = AllocBlock(at);
372 if (!newEntry)
373 return PRDBFAIL;
374 tentry.createTime = time(0);
375
376 if (flag & PRGRP) {
377 tentry.flags = PRGRP;
378 tentry.owner = oid;
379 } else if (flag == 0) {
380 tentry.flags = 0;
381 tentry.owner = SYSADMINID;
382 } else {
383 return PRBADARG;
384 }
385
386 atsign = strchr(aname, '@');
387 if (!atsign) {
388 /* A normal user or group. Pick an id for it */
389 if (idflag)
390 tentry.id = *aid;
391 else {
392 code = AllocID(at, flag, &tentry.id);
393 if (code != PRSUCCESS)
394 return code;
395 }
396 } else if (flag & PRGRP) {
397 /* A foreign group. Its format must be AUTHUSER_GROUP@cellname
398 * Then pick an id for the group.
399 */
400 int badFormat;
401
402 *atsign = '\0';
403 badFormat = strcmp(AUTHUSER_GROUP, aname);
404 *atsign = '@';
405 if (badFormat)
406 return PRBADNAM;
407
408 if (idflag)
409 tentry.id = *aid;
410 else {
411 code = AllocID(at, flag, &tentry.id);
412 if (code != PRSUCCESS)
413 return code;
414 }
415 } else {
416 /* A foreign user: <name>@<cell>. The foreign user is added to
417 * its representing group. It is
418 */
419 char *cellGroup;
420 afs_int32 pos, n;
421 struct prentry centry;
422
423 /* To create the user <name>@<cell> the group AUTHUSER_GROUP@<cell>
424 * must exist.
425 */
426 if (asprintf(&cellGroup, "%s%s", AUTHUSER_GROUP, atsign) < 0)
427 return PRNOMEM;
428 pos = FindByName(at, cellGroup, &centry);
429 free(cellGroup);
430 if (!pos)
431 return PRBADNAM;
432 code = pr_Read(at, 0, pos, &centry, sizeof(centry));
433 if (code)
434 return code;
435
436 /* cellid is the id of the group representing the cell */
437 tentry.cellid = ntohl(centry.id);
438
439 if (idflag) {
440 /* Check if id is good */
441 if (!inRange(&centry, *aid))
442 return PRBADARG;
443 tentry.id = *aid;
444 } else {
445 /* Allocate an ID special for this foreign user. It is based
446 * on the representing group's id and nusers count.
447 */
448 tentry.id = allocNextId(at, &centry);
449 if (!tentry.id)
450 return PRNOIDS;
451 }
452
453 /* The foreign user will be added to the representing foreign
454 * group. The group can hold up to 30 entries.
455 */
456 if (!(ntohl(centry.flags) & PRQUOTA)) {
457 centry.flags = htonl(ntohl(centry.flags) | PRQUOTA);
458 centry.ngroups = htonl(30);
459 }
460 n = ntohl(centry.ngroups);
461 if ((n <= 0) && !pr_noAuth)
462 return PRNOMORE;
463 centry.ngroups = htonl(n - 1);
464
465 /* write updated entry for group */
466 code = pr_Write(at, 0, pos, &centry, sizeof(centry));
467 if (code)
468 return PRDBFAIL;
469
470 /* Now add the new user entry to the database */
471 if (creator == 0)
472 tentry.creator = tentry.id;
473 else
474 tentry.creator = creator;
475 *aid = tentry.id;
476 code = pr_WriteEntry(at, 0, newEntry, &tentry);
477 if (code)
478 return PRDBFAIL;
479 code = AddToIDHash(at, *aid, newEntry);
480 if (code != PRSUCCESS)
481 return code;
482 code = AddToNameHash(at, aname, newEntry);
483 if (code != PRSUCCESS)
484 return code;
485 if (inc_header_word(at, foreigncount, 1))
486 return PRDBFAIL;
487
488 /* Now add the entry to the authuser group for this cell.
489 * We will reread the entries for the user and the group
490 * instead of modifying them before writing them in the
491 * previous steps. Although not very efficient, much simpler
492 */
493 pos = FindByID(at, tentry.cellid);
494 if (!pos)
495 return PRBADNAM;
496 code = pr_ReadEntry(at, 0, pos, &centry);
497 if (code)
498 return code;
499 code = AddToEntry(at, &centry, pos, *aid);
500 if (code)
501 return code;
502 /* and now the user entry */
503 pos = FindByID(at, *aid);
504 if (!pos)
505 return PRBADNAM;
506 code = pr_ReadEntry(at, 0, pos, &tentry);
507 if (code)
508 return code;
509 code = AddToEntry(at, &tentry, pos, tentry.cellid);
510 if (code)
511 return code;
512
513 return PRSUCCESS;
514 }
515
516 /* Remember the largest group id or largest user id */
517 if (flag & PRGRP) {
518 /* group ids are negative */
519 if (tentry.id < (afs_int32) ntohl(cheader.maxGroup)) {
520 code = set_header_word(at, maxGroup, htonl(tentry.id));
521 if (code)
522 return PRDBFAIL;
523 }
524 } else {
525 if (tentry.id > (afs_int32) ntohl(cheader.maxID)) {
526 code = set_header_word(at, maxID, htonl(tentry.id));
527 if (code)
528 return PRDBFAIL;
529 }
530 }
531
532 /* Charge the creator for this group */
533 if (flag & PRGRP) {
534 afs_int32 loc = FindByID(at, creator);
535 struct prentry centry;
536 int admin;
537
538 if (loc) { /* this should only fail during initialization */
539 code = pr_Read(at, 0, loc, &centry, sizeof(centry));
540 if (code)
541 return code;
542
543 /* If quota is uninitialized, do it */
544 if (!(ntohl(centry.flags) & PRQUOTA)) {
545 centry.flags = htonl(ntohl(centry.flags) | PRQUOTA);
546 centry.ngroups = centry.nusers = htonl(20);
547 }
548
549 /* Admins don't get charged for creating a group.
550 * If in noAuth mode, you get changed for it but you
551 * are still allowed to create as many groups as you want.
552 */
553 admin = ((creator == SYSADMINID)
554 || IsAMemberOf(at, creator, SYSADMINID));
555 if (!admin) {
556 if (ntohl(centry.ngroups) <= 0) {
557 if (!pr_noAuth)
558 return PRNOMORE;
559 } else {
560 centry.ngroups = htonl(ntohl(centry.ngroups) - 1);
561 }
562 }
563
564 code = pr_Write(at, 0, loc, &centry, sizeof(centry));
565 if (code)
566 return code;
567 } /* if (loc) */
568 } else {
569 /* Initialize the quota for the user. Groups don't have their
570 * quota initialized.
571 */
572 tentry.flags |= PRQUOTA;
573 tentry.ngroups = tentry.nusers = 20;
574 }
575
576 if (creator == 0)
577 tentry.creator = tentry.id;
578 else
579 tentry.creator = creator;
580 *aid = tentry.id;
581 code = pr_WriteEntry(at, 0, newEntry, &tentry);
582 if (code)
583 return PRDBFAIL;
584 code = AddToIDHash(at, *aid, newEntry);
585 if (code != PRSUCCESS)
586 return code;
587 code = AddToNameHash(at, aname, newEntry);
588 if (code != PRSUCCESS)
589 return code;
590 if (tentry.flags & PRGRP) {
591 code = AddToOwnerChain(at, tentry.id, oid);
592 if (code)
593 return code;
594 }
595 if (tentry.flags & PRGRP) {
596 if (inc_header_word(at, groupcount, 1))
597 return PRDBFAIL;
598 } else if (tentry.flags & PRINST) {
599 if (inc_header_word(at, instcount, 1))
600 return PRDBFAIL;
601 } else {
602 if (inc_header_word(at, usercount, 1))
603 return PRDBFAIL;
604 }
605 return PRSUCCESS;
606 }
607
608
609 /* RemoveFromEntry - remove aid from bid's entries list, freeing a continuation
610 * entry if appropriate */
611
612 afs_int32
613 RemoveFromEntry(struct ubik_trans *at, afs_int32 aid, afs_int32 bid)
614 {
615 afs_int32 code;
616 struct prentry tentry;
617 struct contentry centry;
618 struct contentry hentry;
619 afs_int32 temp;
620 afs_int32 i, j;
621 afs_int32 nptr;
622 afs_int32 hloc;
623
624 if (aid == bid)
625 return PRINCONSISTENT;
626 memset(&hentry, 0, sizeof(hentry));
627 temp = FindByID(at, bid);
628 if (temp == 0)
629 return PRNOENT;
630 code = pr_ReadEntry(at, 0, temp, &tentry);
631 if (code != 0)
632 return code;
633 tentry.removeTime = time(0);
634 for (i = 0; i < PRSIZE; i++) {
635 if (tentry.entries[i] == aid) {
636 tentry.entries[i] = PRBADID;
637 tentry.count--;
638 code = pr_WriteEntry(at, 0, temp, &tentry);
639 if (code != 0)
640 return code;
641 return PRSUCCESS;
642 }
643 if (tentry.entries[i] == 0) /* found end of list */
644 return PRNOENT;
645 }
646 hloc = 0;
647 nptr = tentry.next;
648 while (nptr != 0) {
649 code = pr_ReadCoEntry(at, 0, nptr, &centry);
650 if (code != 0)
651 return code;
652 if ((centry.id != bid) || !(centry.flags & PRCONT))
653 return PRDBBAD;
654 for (i = 0; i < COSIZE; i++) {
655 if (centry.entries[i] == aid) {
656 centry.entries[i] = PRBADID;
657 for (j = 0; j < COSIZE; j++)
658 if (centry.entries[j] != PRBADID
659 && centry.entries[j] != 0)
660 break;
661 if (j == COSIZE) { /* can free this block */
662 if (hloc == 0) {
663 tentry.next = centry.next;
664 } else {
665 hentry.next = centry.next;
666 code = pr_WriteCoEntry(at, 0, hloc, &hentry);
667 if (code != 0)
668 return code;
669 }
670 code = FreeBlock(at, nptr);
671 if (code)
672 return code;
673 } else { /* can't free it yet */
674 code = pr_WriteCoEntry(at, 0, nptr, &centry);
675 if (code != 0)
676 return code;
677 }
678 tentry.count--;
679 code = pr_WriteEntry(at, 0, temp, &tentry);
680 if (code)
681 return PRDBFAIL;
682 return 0;
683 }
684 if (centry.entries[i] == 0)
685 return PRNOENT;
686 } /* for all coentry slots */
687 hloc = nptr;
688 nptr = centry.next;
689 memcpy(&hentry, &centry, sizeof(centry));
690 } /* while there are coentries */
691 return PRNOENT;
692 }
693
694 #if defined(SUPERGROUPS)
695 /* ChangeIDEntry - remove aid from bid's entries list, freeing a continuation
696 * entry if appropriate */
697
698 afs_int32
699 ChangeIDEntry(struct ubik_trans *at, afs_int32 aid, afs_int32 newid, afs_int32 bid)
700 {
701 afs_int32 code;
702 struct prentry tentry;
703 struct contentry centry;
704 afs_int32 temp;
705 afs_int32 i, j;
706 afs_int32 nptr;
707
708 if (aid == bid)
709 return PRINCONSISTENT;
710 temp = FindByID(at, bid);
711 if (temp == 0) {
712 return PRNOENT;
713 }
714 code = pr_ReadEntry(at, 0, temp, &tentry);
715 if (code != 0)
716 return code;
717 for (i = 0; i < PRSIZE; i++) {
718 if (tentry.entries[i] == aid) {
719 tentry.entries[i] = newid;
720 code = pr_WriteEntry(at, 0, temp, &tentry);
721 if (code != 0)
722 return code;
723 return PRSUCCESS;
724 }
725 if (tentry.entries[i] == 0) { /* found end of list */
726 return PRNOENT;
727 }
728 }
729
730 nptr = tentry.next;
731 while (nptr) {
732 code = pr_ReadCoEntry(at, 0, nptr, &centry);
733 if (code != 0)
734 return code;
735 if ((centry.id != bid) || !(centry.flags & PRCONT)) {
736 fprintf(stderr,
737 "ChangeIDEntry: bad database bid=%d centry.id=%d .flags=%d\n",
738 bid, centry.id, centry.flags);
739 return PRDBBAD;
740 }
741 for (i = 0; i < COSIZE; i++) {
742 if (centry.entries[i] == aid) {
743 centry.entries[i] = newid;
744 for (j = 0; j < COSIZE; j++)
745 if (centry.entries[j] != PRBADID
746 && centry.entries[j] != 0)
747 break;
748 code = pr_WriteCoEntry(at, 0, nptr, &centry);
749 if (code != 0)
750 return code;
751 return 0;
752 }
753 if (centry.entries[i] == 0) {
754 return PRNOENT;
755 }
756 } /* for all coentry slots */
757 nptr = centry.next;
758 } /* while there are coentries */
759 return PRNOENT;
760 }
761
762 /* #ifdef SUPERGROUPS */
763 /* RemoveFromSGEntry - remove aid from bid's supergroups list, freeing a
764 * continuation entry if appropriate */
765
766 afs_int32
767 RemoveFromSGEntry(struct ubik_trans *at, afs_int32 aid, afs_int32 bid)
768 {
769 afs_int32 code;
770 struct prentry tentry;
771 struct prentryg *tentryg;
772 struct contentry centry;
773 struct contentry hentry;
774 afs_int32 temp;
775 afs_int32 i, j;
776 afs_int32 nptr;
777 afs_int32 hloc;
778
779 if (aid == bid)
780 return PRINCONSISTENT;
781 memset(&hentry, 0, sizeof(hentry));
782 temp = FindByID(at, bid);
783 if (temp == 0) {
784 return PRNOENT;
785 }
786 code = pr_ReadEntry(at, 0, temp, &tentry);
787 if (code != 0)
788 return code;
789 tentry.removeTime = time(NULL);
790 tentryg = (struct prentryg *)&tentry;
791 for (i = 0; i < SGSIZE; i++) {
792 if (tentryg->supergroup[i] == aid) {
793 tentryg->supergroup[i] = PRBADID;
794 tentryg->countsg--;
795 code = pr_WriteEntry(at, 0, temp, &tentry);
796 if (code != 0)
797 return code;
798 return PRSUCCESS;
799 }
800 if (tentryg->supergroup[i] == 0) { /* found end of list */
801 return PRNOENT;
802 }
803 }
804 hloc = 0;
805 nptr = tentryg->nextsg;
806 while (nptr) {
807 code = pr_ReadCoEntry(at, 0, nptr, &centry);
808 if (code != 0)
809 return code;
810 if ((centry.id != bid) || !(centry.flags & PRCONT)) {
811 fprintf(stderr,
812 "ChangeIDEntry: bad database bid=%d centry.id=%d .flags=%d\n",
813 bid, centry.id, centry.flags);
814 return PRDBBAD;
815 }
816 for (i = 0; i < COSIZE; i++) {
817 if (centry.entries[i] == aid) {
818 centry.entries[i] = PRBADID;
819 for (j = 0; j < COSIZE; j++)
820 if (centry.entries[j] != PRBADID
821 && centry.entries[j] != 0)
822 break;
823 if (j == COSIZE) { /* can free this block */
824 if (hloc == 0) {
825 tentryg->nextsg = centry.next;
826 } else {
827 hentry.next = centry.next;
828 code = pr_WriteCoEntry(at, 0, hloc, &hentry);
829 if (code != 0)
830 return code;
831 }
832 code = FreeBlock(at, nptr);
833 if (code)
834 return code;
835 } else { /* can't free it yet */
836 code = pr_WriteCoEntry(at, 0, nptr, &centry);
837 if (code != 0)
838 return code;
839 }
840 tentryg->countsg--;
841 code = pr_WriteEntry(at, 0, temp, &tentry);
842 if (code)
843 return PRDBFAIL;
844 return 0;
845 }
846 if (centry.entries[i] == 0) {
847 return PRNOENT;
848 }
849 } /* for all coentry slots */
850 hloc = nptr;
851 nptr = centry.next;
852 memcpy(&hentry, &centry, sizeof(centry));
853 } /* while there are coentries */
854 return PRNOENT;
855 }
856
857 #endif /* SUPERGROUPS */
858
859 /* DeleteEntry - delete the entry in tentry at loc, removing it from all
860 * groups, putting groups owned by it on orphan chain, and freeing the space */
861
862 afs_int32
863 DeleteEntry(struct ubik_trans *at, struct prentry *tentry, afs_int32 loc)
864 {
865 afs_int32 code;
866 struct contentry centry;
867 afs_int32 i;
868 afs_int32 nptr;
869
870 if (strchr(tentry->name, '@')) {
871 if (tentry->flags & PRGRP) {
872 /* If there are still foreign user accounts from that cell
873 * don't delete the group */
874 if (tentry->count)
875 return PRBADARG;
876 } else {
877 /* adjust quota */
878
879 afs_int32 loc = FindByID(at, tentry->cellid);
880 struct prentry centry;
881 if (loc) {
882 code = pr_Read(at, 0, loc, &centry, sizeof(centry));
883 if (code)
884 return code;
885 if (ntohl(centry.flags) & PRQUOTA) {
886 centry.ngroups = htonl(ntohl(centry.ngroups) + 1);
887 }
888 code = pr_Write(at, 0, loc, &centry, sizeof(centry));
889 if (code)
890 return code;
891 }
892 }
893 }
894 /* First remove the entire membership list */
895 for (i = 0; i < PRSIZE; i++) {
896 if (tentry->entries[i] == PRBADID)
897 continue;
898 if (tentry->entries[i] == 0)
899 break;
900 #if defined(SUPERGROUPS)
901 if ((tentry->flags & PRGRP) && tentry->entries[i] < 0) /* Supergroup */
902 code = RemoveFromSGEntry(at, tentry->id, tentry->entries[i]);
903 else
904 #endif
905 code = RemoveFromEntry(at, tentry->id, tentry->entries[i]);
906 if (code)
907 return code;
908 }
909 #if defined(SUPERGROUPS)
910 {
911 struct prentryg *tentryg = (struct prentryg *)tentry;
912
913 /* Then remove the entire supergroup list */
914 for (i = 0; i < SGSIZE; i++) {
915 if (tentryg->supergroup[i] == PRBADID)
916 continue;
917 if (tentryg->supergroup[i] == 0)
918 break;
919 code = RemoveFromEntry(at, tentry->id, tentryg->supergroup[i]);
920 if (code)
921 return code;
922 }
923 }
924 #endif /* SUPERGROUPS */
925 nptr = tentry->next;
926 while (nptr != 0) {
927 code = pr_ReadCoEntry(at, 0, nptr, &centry);
928 if (code != 0)
929 return PRDBFAIL;
930 for (i = 0; i < COSIZE; i++) {
931 if (centry.entries[i] == PRBADID)
932 continue;
933 if (centry.entries[i] == 0)
934 break;
935 code = RemoveFromEntry(at, tentry->id, centry.entries[i]);
936 if (code)
937 return code;
938 }
939 code = FreeBlock(at, nptr); /* free continuation block */
940 if (code)
941 return code;
942 nptr = centry.next;
943 }
944
945 /* Remove us from other's owned chain. Note that this will zero our owned
946 * field (on disk) so this step must follow the above step in case we are
947 * on our own owned list. */
948 if (tentry->flags & PRGRP) {
949 if (tentry->owner) {
950 code = RemoveFromOwnerChain(at, tentry->id, tentry->owner);
951 if (code)
952 return code;
953 } else {
954 code = RemoveFromOrphan(at, tentry->id);
955 if (code)
956 return code;
957 }
958 }
959
960 code = RemoveFromIDHash(at, tentry->id, &loc);
961 if (code != PRSUCCESS)
962 return code;
963 code = RemoveFromNameHash(at, tentry->name, &loc);
964 if (code != PRSUCCESS)
965 return code;
966
967 if (tentry->flags & PRGRP) {
968 afs_int32 loc = FindByID(at, tentry->creator);
969 struct prentry centry;
970 int admin;
971
972 if (loc) {
973 code = pr_Read(at, 0, loc, &centry, sizeof(centry));
974 if (code)
975 return code;
976 admin = ((tentry->creator == SYSADMINID)
977 || IsAMemberOf(at, tentry->creator, SYSADMINID));
978 if (ntohl(centry.flags) & PRQUOTA) {
979 if (!(admin && (ntohl(centry.ngroups) >= 20))) {
980 centry.ngroups = htonl(ntohl(centry.ngroups) + 1);
981 }
982 }
983 code = pr_Write(at, 0, loc, &centry, sizeof(centry));
984 if (code)
985 return code;
986 }
987 }
988
989 if (tentry->flags & PRGRP) {
990 if (inc_header_word(at, groupcount, -1))
991 return PRDBFAIL;
992 } else if (tentry->flags & PRINST) {
993 if (inc_header_word(at, instcount, -1))
994 return PRDBFAIL;
995 } else {
996 if (strchr(tentry->name, '@')) {
997 if (inc_header_word(at, foreigncount, -1))
998 return PRDBFAIL;
999 } else {
1000 if (inc_header_word(at, usercount, -1))
1001 return PRDBFAIL;
1002 }
1003 }
1004 code = FreeBlock(at, loc);
1005 return code;
1006 }
1007
1008 /* AddToEntry - add aid to entry's entries list, alloc'ing a continuation block
1009 * if needed.
1010 *
1011 * Note the entry is written out by this routine. */
1012
1013 afs_int32
1014 AddToEntry(struct ubik_trans *tt, struct prentry *entry, afs_int32 loc, afs_int32 aid)
1015 {
1016 afs_int32 code;
1017 afs_int32 i;
1018 struct contentry nentry;
1019 struct contentry aentry;
1020 afs_int32 nptr;
1021 afs_int32 last; /* addr of last cont. block */
1022 afs_int32 first = 0;
1023 afs_int32 cloc = 0;
1024 afs_int32 slot = -1;
1025
1026 if (entry->id == aid)
1027 return PRINCONSISTENT;
1028 entry->addTime = time(0);
1029 for (i = 0; i < PRSIZE; i++) {
1030 if (entry->entries[i] == aid)
1031 return PRIDEXIST;
1032 if (entry->entries[i] == PRBADID) { /* remember this spot */
1033 first = 1;
1034 slot = i;
1035 } else if (entry->entries[i] == 0) { /* end of the line */
1036 if (slot == -1) {
1037 first = 1;
1038 slot = i;
1039 }
1040 break;
1041 }
1042 }
1043 last = 0;
1044 nptr = entry->next;
1045 while (nptr != 0) {
1046 code = pr_ReadCoEntry(tt, 0, nptr, &nentry);
1047 if (code != 0)
1048 return code;
1049 last = nptr;
1050 if (!(nentry.flags & PRCONT))
1051 return PRDBFAIL;
1052 for (i = 0; i < COSIZE; i++) {
1053 if (nentry.entries[i] == aid)
1054 return PRIDEXIST;
1055 if (nentry.entries[i] == PRBADID) {
1056 if (slot == -1) {
1057 slot = i;
1058 cloc = nptr;
1059 }
1060 } else if (nentry.entries[i] == 0) {
1061 if (slot == -1) {
1062 slot = i;
1063 cloc = nptr;
1064 }
1065 break;
1066 }
1067 }
1068 nptr = nentry.next;
1069 }
1070 if (slot != -1) { /* we found a place */
1071 entry->count++;
1072 if (first) { /* place is in first block */
1073 entry->entries[slot] = aid;
1074 code = pr_WriteEntry(tt, 0, loc, entry);
1075 if (code != 0)
1076 return code;
1077 return PRSUCCESS;
1078 }
1079 code = pr_WriteEntry(tt, 0, loc, entry);
1080 if (code)
1081 return code;
1082 code = pr_ReadCoEntry(tt, 0, cloc, &aentry);
1083 if (code != 0)
1084 return code;
1085 aentry.entries[slot] = aid;
1086 code = pr_WriteCoEntry(tt, 0, cloc, &aentry);
1087 if (code != 0)
1088 return code;
1089 return PRSUCCESS;
1090 }
1091 /* have to allocate a continuation block if we got here */
1092 nptr = AllocBlock(tt);
1093 if (last) {
1094 /* then we should tack new block after last block in cont. chain */
1095 nentry.next = nptr;
1096 code = pr_WriteCoEntry(tt, 0, last, &nentry);
1097 if (code != 0)
1098 return code;
1099 } else {
1100 entry->next = nptr;
1101 }
1102 memset(&aentry, 0, sizeof(aentry));
1103 aentry.flags |= PRCONT;
1104 aentry.id = entry->id;
1105 aentry.next = 0;
1106 aentry.entries[0] = aid;
1107 code = pr_WriteCoEntry(tt, 0, nptr, &aentry);
1108 if (code != 0)
1109 return code;
1110 /* don't forget to update count, here! */
1111 entry->count++;
1112 code = pr_WriteEntry(tt, 0, loc, entry);
1113 return code;
1114
1115 }
1116
1117 #if defined(SUPERGROUPS)
1118
1119 /* AddToSGEntry - add aid to entry's supergroup list, alloc'ing a
1120 * continuation block if needed.
1121 *
1122 * Note the entry is written out by this routine. */
1123
1124 afs_int32
1125 AddToSGEntry(struct ubik_trans *tt, struct prentry *entry, afs_int32 loc, afs_int32 aid)
1126 {
1127 afs_int32 code;
1128 afs_int32 i;
1129 struct contentry nentry;
1130 struct contentry aentry;
1131 struct prentryg *entryg;
1132 afs_int32 nptr;
1133 afs_int32 last; /* addr of last cont. block */
1134 afs_int32 first = 0;
1135 afs_int32 cloc = 0;
1136 afs_int32 slot = -1;
1137
1138 if (entry->id == aid)
1139 return PRINCONSISTENT;
1140 entry->addTime = time(NULL);
1141 entryg = (struct prentryg *)entry;
1142 for (i = 0; i < SGSIZE; i++) {
1143 if (entryg->supergroup[i] == aid)
1144 return PRIDEXIST;
1145 if (entryg->supergroup[i] == PRBADID) { /* remember this spot */
1146 first = 1;
1147 slot = i;
1148 } else if (entryg->supergroup[i] == 0) { /* end of the line */
1149 if (slot == -1) {
1150 first = 1;
1151 slot = i;
1152 }
1153 break;
1154 }
1155 }
1156 last = 0;
1157 nptr = entryg->nextsg;
1158 while (nptr) {
1159 code = pr_ReadCoEntry(tt, 0, nptr, &nentry);
1160 if (code != 0)
1161 return code;
1162 last = nptr;
1163 if (!(nentry.flags & PRCONT))
1164 return PRDBFAIL;
1165 for (i = 0; i < COSIZE; i++) {
1166 if (nentry.entries[i] == aid)
1167 return PRIDEXIST;
1168 if (nentry.entries[i] == PRBADID) {
1169 if (slot == -1) {
1170 slot = i;
1171 cloc = nptr;
1172 }
1173 } else if (nentry.entries[i] == 0) {
1174 if (slot == -1) {
1175 slot = i;
1176 cloc = nptr;
1177 }
1178 break;
1179 }
1180 }
1181 nptr = nentry.next;
1182 }
1183 if (slot != -1) { /* we found a place */
1184 entryg->countsg++;
1185 if (first) { /* place is in first block */
1186 entryg->supergroup[slot] = aid;
1187 code = pr_WriteEntry(tt, 0, loc, entry);
1188 if (code != 0)
1189 return code;
1190 return PRSUCCESS;
1191 }
1192 code = pr_WriteEntry(tt, 0, loc, entry);
1193 if (code)
1194 return code;
1195 code = pr_ReadCoEntry(tt, 0, cloc, &aentry);
1196 if (code != 0)
1197 return code;
1198 aentry.entries[slot] = aid;
1199 code = pr_WriteCoEntry(tt, 0, cloc, &aentry);
1200 if (code != 0)
1201 return code;
1202 return PRSUCCESS;
1203 }
1204 /* have to allocate a continuation block if we got here */
1205 nptr = AllocBlock(tt);
1206 if (last) {
1207 /* then we should tack new block after last block in cont. chain */
1208 nentry.next = nptr;
1209 code = pr_WriteCoEntry(tt, 0, last, &nentry);
1210 if (code != 0)
1211 return code;
1212 } else {
1213 entryg->nextsg = nptr;
1214 }
1215 memset(&aentry, 0, sizeof(aentry));
1216 aentry.flags |= PRCONT;
1217 aentry.id = entry->id;
1218 aentry.next = 0;
1219 aentry.entries[0] = aid;
1220 code = pr_WriteCoEntry(tt, 0, nptr, &aentry);
1221 if (code != 0)
1222 return code;
1223 /* don't forget to update count, here! */
1224 entryg->countsg++;
1225 code = pr_WriteEntry(tt, 0, loc, entry);
1226 return code;
1227
1228 }
1229 #endif /* SUPERGROUPS */
1230
1231 afs_int32
1232 AddToPRList(prlist *alist, int *sizeP, afs_int32 id)
1233 {
1234 afs_int32 *tmp;
1235 int count;
1236
1237 if (alist->prlist_len >= *sizeP) {
1238 count = alist->prlist_len + 100;
1239 if (alist->prlist_val) {
1240 tmp = realloc(alist->prlist_val, count * sizeof(afs_int32));
1241 } else {
1242 tmp = malloc(count * sizeof(afs_int32));
1243 }
1244 if (!tmp)
1245 return (PRNOMEM);
1246 alist->prlist_val = tmp;
1247 *sizeP = count;
1248 }
1249 alist->prlist_val[alist->prlist_len++] = id;
1250 return 0;
1251 }
1252
1253 afs_int32
1254 GetList(struct ubik_trans *at, struct prentry *tentry, prlist *alist, afs_int32 add)
1255 {
1256 afs_int32 code;
1257 afs_int32 i;
1258 struct contentry centry;
1259 afs_int32 nptr;
1260 int size;
1261 int count = 0;
1262
1263 size = 0;
1264 alist->prlist_val = 0;
1265 alist->prlist_len = 0;
1266
1267 for (i = 0; i < PRSIZE; i++) {
1268 if (tentry->entries[i] == PRBADID)
1269 continue;
1270 if (tentry->entries[i] == 0)
1271 break;
1272 code = AddToPRList(alist, &size, tentry->entries[i]);
1273 if (code)
1274 return code;
1275 #if defined(SUPERGROUPS)
1276 if (!add)
1277 continue;
1278 code = GetListSG2(at, tentry->entries[i], alist, &size, depthsg);
1279 if (code)
1280 return code;
1281 #endif
1282 }
1283
1284 for (nptr = tentry->next; nptr != 0; nptr = centry.next) {
1285 /* look through cont entries */
1286 code = pr_ReadCoEntry(at, 0, nptr, &centry);
1287 if (code != 0)
1288 return code;
1289 for (i = 0; i < COSIZE; i++) {
1290 if (centry.entries[i] == PRBADID)
1291 continue;
1292 if (centry.entries[i] == 0)
1293 break;
1294 code = AddToPRList(alist, &size, centry.entries[i]);
1295 if (code)
1296 return code;
1297 #if defined(SUPERGROUPS)
1298 if (!add)
1299 continue;
1300 code = GetListSG2(at, centry.entries[i], alist, &size, depthsg);
1301 if (code)
1302 return code;
1303 #endif
1304 }
1305 if (count++ > 50) {
1306 #ifndef AFS_PTHREAD_ENV
1307 IOMGR_Poll();
1308 #endif
1309 count = 0;
1310 }
1311 }
1312
1313 if (add) { /* this is for a CPS, so tack on appropriate stuff */
1314 if (tentry->id != ANONYMOUSID && tentry->id != ANYUSERID) {
1315 if ((code = AddToPRList(alist, &size, ANYUSERID))
1316 || (code = AddAuthGroup(tentry, alist, &size))
1317 || (code = AddToPRList(alist, &size, tentry->id)))
1318 return code;
1319 } else {
1320 if ((code = AddToPRList(alist, &size, ANYUSERID))
1321 || (code = AddToPRList(alist, &size, tentry->id)))
1322 return code;
1323 }
1324 }
1325 #ifndef AFS_PTHREAD_ENV
1326 if (alist->prlist_len > 100)
1327 IOMGR_Poll();
1328 #endif
1329 qsort(alist->prlist_val, alist->prlist_len, sizeof(afs_int32), IDCmp);
1330 return PRSUCCESS;
1331 }
1332
1333
1334 afs_int32
1335 GetList2(struct ubik_trans *at, struct prentry *tentry, struct prentry *tentry2, prlist *alist, afs_int32 add)
1336 {
1337 afs_int32 code = 0;
1338 afs_int32 i;
1339 struct contentry centry;
1340 afs_int32 nptr;
1341 afs_int32 size;
1342 int count = 0;
1343
1344 size = 0;
1345 alist->prlist_val = 0;
1346 alist->prlist_len = 0;
1347 for (i = 0; i < PRSIZE; i++) {
1348 if (tentry->entries[i] == PRBADID)
1349 continue;
1350 if (tentry->entries[i] == 0)
1351 break;
1352 code = AddToPRList(alist, &size, tentry->entries[i]);
1353 if (code)
1354 return code;
1355 #if defined(SUPERGROUPS)
1356 if (!add)
1357 continue;
1358 code = GetListSG2(at, tentry->entries[i], alist, &size, depthsg);
1359 if (code)
1360 return code;
1361 #endif
1362 }
1363
1364 nptr = tentry->next;
1365 while (nptr != 0) {
1366 /* look through cont entries */
1367 code = pr_ReadCoEntry(at, 0, nptr, &centry);
1368 if (code != 0)
1369 return code;
1370 for (i = 0; i < COSIZE; i++) {
1371 if (centry.entries[i] == PRBADID)
1372 continue;
1373 if (centry.entries[i] == 0)
1374 break;
1375 code = AddToPRList(alist, &size, centry.entries[i]);
1376 if (code)
1377 return code;
1378 #if defined(SUPERGROUPS)
1379 if (!add)
1380 continue;
1381 code = GetListSG2(at, centry.entries[i], alist, &size, depthsg);
1382 if (code)
1383 return code;
1384 #endif
1385 }
1386 nptr = centry.next;
1387 if (count++ > 50) {
1388 #ifndef AFS_PTHREAD_ENV
1389 IOMGR_Poll();
1390 #endif
1391 count = 0;
1392 }
1393 }
1394
1395 for (i = 0; i < PRSIZE; i++) {
1396 if (tentry2->entries[i] == PRBADID)
1397 continue;
1398 if (tentry2->entries[i] == 0)
1399 break;
1400 code = AddToPRList(alist, &size, tentry2->entries[i]);
1401 if (code)
1402 break;
1403 }
1404
1405 if (!code) {
1406 nptr = tentry2->next;
1407 while (nptr != 0) {
1408 /* look through cont entries */
1409 code = pr_ReadCoEntry(at, 0, nptr, &centry);
1410 if (code != 0)
1411 break;
1412 for (i = 0; i < COSIZE; i++) {
1413 if (centry.entries[i] == PRBADID)
1414 continue;
1415 if (centry.entries[i] == 0)
1416 break;
1417 code = AddToPRList(alist, &size, centry.entries[i]);
1418 if (code)
1419 break;
1420 }
1421 nptr = centry.next;
1422 if (count++ > 50) {
1423 #ifndef AFS_PTHREAD_ENV
1424 IOMGR_Poll();
1425 #endif
1426 count = 0;
1427 }
1428 }
1429 }
1430 if (add) { /* this is for a CPS, so tack on appropriate stuff */
1431 if (tentry->id != ANONYMOUSID && tentry->id != ANYUSERID) {
1432 if ((code = AddToPRList(alist, &size, ANYUSERID))
1433 || (code = AddToPRList(alist, &size, AUTHUSERID))
1434 || (code = AddToPRList(alist, &size, tentry->id)))
1435 return code;
1436 } else {
1437 if ((code = AddToPRList(alist, &size, ANYUSERID))
1438 || (code = AddToPRList(alist, &size, tentry->id)))
1439 return code;
1440 }
1441 }
1442 #ifndef AFS_PTHREAD_ENV
1443 if (alist->prlist_len > 100)
1444 IOMGR_Poll();
1445 #endif
1446 qsort(alist->prlist_val, alist->prlist_len, sizeof(afs_int32), IDCmp);
1447 return PRSUCCESS;
1448 }
1449
1450 #if defined(SUPERGROUPS)
1451
1452 afs_int32
1453 GetListSG2(struct ubik_trans *at, afs_int32 gid, prlist *alist, afs_int32 *sizeP, afs_int32 depth)
1454 {
1455 afs_int32 code;
1456 struct prentry tentry;
1457 struct prentryg *tentryg = (struct prentryg *)&tentry;
1458 afs_int32 i;
1459 struct contentry centry;
1460 afs_int32 nptr;
1461 int count = 0;
1462 afs_int32 temp;
1463 int didsomething;
1464 #if DEBUG_SG_MAP
1465 int predictfound, predictflagged;
1466 #endif
1467
1468 #if DEBUG_SG_MAP
1469 predictfound = 0;
1470 if (!in_map(sg_flagged, -gid)) {
1471 predictflagged = 0;
1472 fprintf(stderr, "GetListSG2: I have not yet searched for gid=%d\n",
1473 gid);
1474 } else if (predictflagged = 1, in_map(sg_found, -gid)) {
1475 predictfound = 1;
1476 fprintf(stderr,
1477 "GetListSG2: I have already searched for gid=%d, and predict success.\n",
1478 gid);
1479 }
1480 #endif
1481
1482 if (in_map(sg_flagged, -gid) && !in_map(sg_found, -gid)) {
1483 #if DEBUG_SG_MAP
1484 fprintf(stderr,
1485 "GetListSG2: I have already searched for gid=%d, and predict failure.\n",
1486 gid);
1487 #else
1488 return 0;
1489 #endif
1490 }
1491
1492 if (depth < 1)
1493 return 0;
1494 temp = FindByID(at, gid);
1495 if (!temp) {
1496 code = PRNOENT;
1497 return code;
1498 }
1499 code = pr_ReadEntry(at, 0, temp, &tentry);
1500 if (code)
1501 return code;
1502 #if DEBUG_SG_MAP
1503 fprintf(stderr, "GetListSG2: lookup for gid=%d [\n", gid);
1504 #endif
1505 didsomething = 0;
1506
1507 for (i = 0; i < SGSIZE; i++) {
1508 if (tentryg->supergroup[i] == PRBADID)
1509 continue;
1510 if (tentryg->supergroup[i] == 0)
1511 break;
1512 didsomething = 1;
1513 #if DEBUG_SG_MAP
1514 fprintf(stderr, "via gid=%d, added %d\n", gid,
1515 e.tentryg.supergroup[i]);
1516 #endif
1517 code = AddToPRList(alist, sizeP, tentryg->supergroup[i]);
1518 if (code)
1519 return code;
1520 code =
1521 GetListSG2(at, tentryg->supergroup[i], alist, sizeP, depth - 1);
1522 if (code)
1523 return code;
1524 }
1525
1526 nptr = tentryg->nextsg;
1527 while (nptr) {
1528 didsomething = 1;
1529 /* look through cont entries */
1530 code = pr_ReadCoEntry(at, 0, nptr, &centry);
1531 if (code != 0)
1532 return code;
1533 for (i = 0; i < COSIZE; i++) {
1534 if (centry.entries[i] == PRBADID)
1535 continue;
1536 if (centry.entries[i] == 0)
1537 break;
1538 #if DEBUG_SG_MAP
1539 fprintf(stderr, "via gid=%d, added %d\n", gid,
1540 e.centry.entries[i]);
1541 #endif
1542 code = AddToPRList(alist, sizeP, centry.entries[i]);
1543 if (code)
1544 return code;
1545 code = GetListSG2(at, centry.entries[i], alist, sizeP, depth - 1);
1546 if (code)
1547 return code;
1548 }
1549 nptr = centry.next;
1550 if (count++ > 50) {
1551 #ifndef AFS_PTHREAD_ENV
1552 IOMGR_Poll();
1553 #endif
1554 count = 0;
1555 }
1556 }
1557 #if DEBUG_SG_MAP
1558 fprintf(stderr, "] for gid %d, done [flag=%s]\n", gid,
1559 didsomething ? "TRUE" : "FALSE");
1560 if (predictflagged && didsomething != predictfound)
1561 fprintf(stderr, "**** for gid=%d, didsomething=%d predictfound=%d\n",
1562 didsomething, predictfound);
1563 #endif
1564 if (didsomething)
1565 sg_found = add_map(sg_found, -gid);
1566 else
1567 sg_found = bic_map(sg_found, add_map(NIL_MAP, -gid));
1568 sg_flagged = add_map(sg_flagged, -gid);
1569 return 0;
1570 }
1571
1572 afs_int32
1573 GetSGList(struct ubik_trans *at, struct prentry *tentry, prlist *alist)
1574 {
1575 afs_int32 code;
1576 afs_int32 i;
1577 struct contentry centry;
1578 struct prentryg *tentryg;
1579 afs_int32 nptr;
1580 int size;
1581 int count = 0;
1582
1583 size = 0;
1584 alist->prlist_val = 0;
1585 alist->prlist_len = 0;
1586
1587 tentryg = (struct prentryg *)tentry;
1588 for (i = 0; i < SGSIZE; i++) {
1589 if (tentryg->supergroup[i] == PRBADID)
1590 continue;
1591 if (tentryg->supergroup[i] == 0)
1592 break;
1593 code = AddToPRList(alist, &size, tentryg->supergroup[i]);
1594 if (code)
1595 return code;
1596 }
1597
1598 nptr = tentryg->nextsg;
1599 while (nptr) {
1600 /* look through cont entries */
1601 code = pr_ReadCoEntry(at, 0, nptr, &centry);
1602 if (code != 0)
1603 return code;
1604 for (i = 0; i < COSIZE; i++) {
1605 if (centry.entries[i] == PRBADID)
1606 continue;
1607 if (centry.entries[i] == 0)
1608 break;
1609 code = AddToPRList(alist, &size, centry.entries[i]);
1610 if (code)
1611 return code;
1612 }
1613 nptr = centry.next;
1614 if (count++ > 50) {
1615 #ifndef AFS_PTHREAD_ENV
1616 IOMGR_Poll();
1617 #endif
1618 count = 0;
1619 }
1620 }
1621
1622 #ifndef AFS_PTHREAD_ENV
1623 if (alist->prlist_len > 100)
1624 IOMGR_Poll();
1625 #endif
1626 qsort((char *)alist->prlist_val, (int)alist->prlist_len,
1627 sizeof(afs_int32), IDCmp);
1628 return PRSUCCESS;
1629 }
1630 #endif /* SUPERGROUPS */
1631
1632 afs_int32
1633 GetOwnedChain(struct ubik_trans *ut, afs_int32 *next, prlist *alist)
1634 {
1635 afs_int32 code;
1636 struct prentry tentry;
1637 int size;
1638 int count = 0;
1639
1640 size = 0;
1641 alist->prlist_val = 0;
1642 alist->prlist_len = 0;
1643
1644 for (; *next; *next = ntohl(tentry.nextOwned)) {
1645 code = pr_Read(ut, 0, *next, &tentry, sizeof(tentry));
1646 if (code)
1647 return code;
1648 code = AddToPRList(alist, &size, ntohl(tentry.id));
1649 if (alist->prlist_len >= PR_MAXGROUPS) {
1650 return PRTOOMANY;
1651 }
1652 if (code)
1653 return code;
1654 if (count++ > 50) {
1655 #ifndef AFS_PTHREAD_ENV
1656 IOMGR_Poll();
1657 #endif
1658 count = 0;
1659 }
1660 }
1661 #ifndef AFS_PTHREAD_ENV
1662 if (alist->prlist_len > 100)
1663 IOMGR_Poll();
1664 #endif
1665 qsort(alist->prlist_val, alist->prlist_len, sizeof(afs_int32), IDCmp);
1666 return PRSUCCESS;
1667 }
1668
1669 afs_int32
1670 GetMax(struct ubik_trans *at, afs_int32 *uid, afs_int32 *gid)
1671 {
1672 *uid = ntohl(cheader.maxID);
1673 *gid = ntohl(cheader.maxGroup);
1674 return PRSUCCESS;
1675 }
1676
1677 afs_int32
1678 SetMax(struct ubik_trans *at, afs_int32 id, afs_int32 flag)
1679 {
1680 afs_int32 code;
1681 if (flag & PRGRP) {
1682 cheader.maxGroup = htonl(id);
1683 code =
1684 pr_Write(at, 0, 16, (char *)&cheader.maxGroup,
1685 sizeof(cheader.maxGroup));
1686 if (code != 0)
1687 return code;
1688 } else {
1689 cheader.maxID = htonl(id);
1690 code =
1691 pr_Write(at, 0, 20, (char *)&cheader.maxID,
1692 sizeof(cheader.maxID));
1693 if (code != 0)
1694 return code;
1695 }
1696 return PRSUCCESS;
1697 }
1698
1699 static afs_int32
1700 UpdateCache(struct ubik_trans *tt, void *rock)
1701 {
1702 afs_int32 code;
1703
1704 code = pr_Read(tt, 0, 0, (char *)&cheader, sizeof(cheader));
1705 if (code != 0) {
1706 afs_com_err(whoami, code, "Couldn't read header");
1707 }
1708 return code;
1709 }
1710
1711 afs_int32
1712 read_DbHeader(struct ubik_trans *tt)
1713 {
1714 return ubik_CheckCache(tt, UpdateCache, NULL);
1715 }
1716
1717 int pr_noAuth;
1718
1719 /**
1720 * reads in db cache from ubik.
1721 *
1722 * @param[in] ut ubik transaction
1723 * @param[out] rock opaque pointer to an int*, which on success will be set
1724 * to 1 if we need to build the database, or 0 if we do not
1725 *
1726 * @return operation status
1727 * @retval 0 success
1728 */
1729 static afs_int32
1730 Initdb_check(struct ubik_trans *tt, void *rock)
1731 {
1732 int *build_rock = rock;
1733 afs_int32 code;
1734 afs_int32 len;
1735
1736 len = sizeof(cheader);
1737 code = pr_Read(tt, 0, 0, (char *)&cheader, len);
1738 if (code != 0) {
1739 afs_com_err(whoami, code, "couldn't read header");
1740 return code;
1741 }
1742 if ((ntohl(cheader.version) == PRDBVERSION)
1743 && ntohl(cheader.headerSize) == sizeof(cheader)
1744 && ntohl(cheader.eofPtr) != 0
1745 && FindByID(tt, ANONYMOUSID) != 0) {
1746 /* database exists, so we don't have to build it */
1747 *build_rock = 0;
1748 return 0;
1749 }
1750
1751 /* else we need to build a database */
1752 *build_rock = 1;
1753 return 0;
1754 }
1755
1756 afs_int32
1757 Initdb(void)
1758 {
1759 struct ubik_trans *tt;
1760 int build = 0;
1761 afs_int32 code;
1762
1763 /* init the database. We'll try reading it, but if we're starting
1764 * from scratch, we'll have to do a write transaction. */
1765
1766 pr_noAuth = afsconf_GetNoAuthFlag(prdir);
1767
1768 code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
1769 if (code)
1770 return code;
1771 code = ubik_SetLock(tt, 1, 1, LOCKREAD);
1772 if (code) {
1773 ubik_AbortTrans(tt);
1774 return code;
1775 }
1776
1777 code = ubik_CheckCache(tt, Initdb_check, &build);
1778 if (code) {
1779 ubik_AbortTrans(tt);
1780 return code;
1781 }
1782
1783 if (build) {
1784 /* Only rebuild database if the db was deleted (the header is zero) */
1785 char *bp = (char *)&cheader;
1786 int i;
1787 for (i = 0; i < sizeof(cheader); i++) {
1788 if (bp[i]) {
1789 code = PRDBBAD;
1790 afs_com_err(whoami, code,
1791 "Can't rebuild database because it is not empty");
1792 break;
1793 }
1794 }
1795 }
1796
1797 if (code) {
1798 ubik_EndTrans(tt);
1799 } else {
1800 code = ubik_EndTrans(tt);
1801 }
1802 if (code || !build) {
1803 /* either we encountered an error, or we don't need to build the db */
1804 return code;
1805 }
1806
1807 code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
1808 if (code)
1809 return code;
1810
1811 code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
1812 if (code) {
1813 ubik_AbortTrans(tt);
1814 return code;
1815 }
1816
1817 /* before doing a rebuild, check again that the dbase looks bad, because
1818 * the previous check was only under a ReadAny transaction, and there could
1819 * actually have been a good database out there. Now that we have a
1820 * real write transaction, make sure things are still bad.
1821 */
1822 code = pr_Read(tt, 0, 0, (char *)&cheader, sizeof(cheader));
1823 if (code != 0) {
1824 afs_com_err(whoami, code, "couldn't read header");
1825 ubik_AbortTrans(tt);
1826 return code;
1827 }
1828 if ((ntohl(cheader.version) == PRDBVERSION)
1829 && ntohl(cheader.headerSize) == sizeof(cheader)
1830 && ntohl(cheader.eofPtr) != 0
1831 && FindByID(tt, ANONYMOUSID) != 0) {
1832 /* database exists, so we don't have to build it */
1833 code = ubik_EndTrans(tt);
1834 if (code)
1835 return code;
1836 return PRSUCCESS;
1837 }
1838
1839 /* Initialize the database header */
1840 if ((code = set_header_word(tt, version, htonl(PRDBVERSION)))
1841 || (code = set_header_word(tt, headerSize, htonl(sizeof(cheader))))
1842 || (code = set_header_word(tt, eofPtr, cheader.headerSize))) {
1843 afs_com_err(whoami, code, "couldn't write header words");
1844 ubik_AbortTrans(tt);
1845 return code;
1846 }
1847 #define InitialGroup(id,name) do { \
1848 afs_int32 temp = (id); \
1849 afs_int32 flag = (id) < 0 ? PRGRP : 0; \
1850 code = CreateEntry \
1851 (tt, (name), &temp, /*idflag*/1, flag, SYSADMINID, SYSADMINID); \
1852 if (code) { \
1853 afs_com_err (whoami, code, "couldn't create %s with id %di.", \
1854 (name), (id)); \
1855 ubik_AbortTrans(tt); \
1856 return code; \
1857 } \
1858 } while (0)
1859
1860 InitialGroup(SYSADMINID, "system:administrators");
1861 InitialGroup(SYSBACKUPID, "system:backup");
1862 InitialGroup(ANYUSERID, "system:anyuser");
1863 InitialGroup(AUTHUSERID, "system:authuser");
1864 InitialGroup(SYSVIEWERID, "system:ptsviewers");
1865 InitialGroup(ANONYMOUSID, "anonymous");
1866
1867 /* Well, we don't really want the max id set to anonymousid, so we'll set
1868 * it back to 0 */
1869 code = set_header_word(tt, maxID, 0); /* correct in any byte order */
1870 if (code) {
1871 afs_com_err(whoami, code, "couldn't reset max id");
1872 ubik_AbortTrans(tt);
1873 return code;
1874 }
1875
1876 code = ubik_EndTrans(tt);
1877 if (code)
1878 return code;
1879 return PRSUCCESS;
1880 }
1881
1882 afs_int32
1883 ChangeEntry(struct ubik_trans *at, afs_int32 aid, afs_int32 cid, char *name, afs_int32 oid, afs_int32 newid)
1884 {
1885 afs_int32 code;
1886 afs_int32 i, pos;
1887 #if defined(SUPERGROUPS)
1888 afs_int32 nextpos;
1889 #else
1890 afs_int32 nptr;
1891 struct contentry centry;
1892 #endif
1893 struct prentry tentry, tent;
1894 afs_int32 loc;
1895 afs_int32 oldowner;
1896 afs_int32 admin;
1897 char holder[PR_MAXNAMELEN];
1898 char temp[PR_MAXNAMELEN];
1899 char oldname[PR_MAXNAMELEN];
1900 char *atsign;
1901
1902 memset(holder, 0, PR_MAXNAMELEN);
1903 memset(temp, 0, PR_MAXNAMELEN);
1904 loc = FindByID(at, aid);
1905 if (!loc)
1906 return PRNOENT;
1907 code = pr_ReadEntry(at, 0, loc, &tentry);
1908 if (code)
1909 return PRDBFAIL;
1910 if (restricted && !IsAMemberOf(at, cid, SYSADMINID))
1911 return PRPERM;
1912 if (tentry.owner != cid && !IsAMemberOf(at, cid, SYSADMINID)
1913 && !IsAMemberOf(at, cid, tentry.owner) && !pr_noAuth)
1914 return PRPERM;
1915 tentry.changeTime = time(0);
1916 admin = pr_noAuth || IsAMemberOf(at, cid, SYSADMINID);
1917
1918 /* we're actually trying to change the id */
1919 if (newid && (newid != aid)) {
1920 if (!admin)
1921 return PRPERM;
1922
1923 pos = FindByID(at, newid);
1924 if (pos)
1925 return PRIDEXIST; /* new id already in use! */
1926 if ((aid < 0 && newid > 0) || (aid > 0 && newid < 0))
1927 return PRPERM;
1928
1929 /* Should check that foreign users id to change to is good: inRange() */
1930
1931 /* if new id is not in use, rehash things */
1932 code = RemoveFromIDHash(at, aid, &loc);
1933 if (code != PRSUCCESS)
1934 return code;
1935 tentry.id = newid;
1936 code = pr_WriteEntry(at, 0, loc, &tentry);
1937 if (code)
1938 return code;
1939 code = AddToIDHash(at, tentry.id, loc);
1940 if (code)
1941 return code;
1942
1943 /* get current data */
1944 code = pr_ReadEntry(at, 0, loc, &tentry);
1945 if (code)
1946 return PRDBFAIL;
1947
1948 #if defined(SUPERGROUPS)
1949 if (tentry.id > (afs_int32) ntohl(cheader.maxID))
1950 code = set_header_word(at, maxID, htonl(tentry.id));
1951 if (code)
1952 return PRDBFAIL;
1953
1954 /* need to fix up: membership
1955 * (supergroups?)
1956 * ownership
1957 */
1958
1959 for (i = 0; i < PRSIZE; i++) {
1960 if (tentry.entries[i] == PRBADID)
1961 continue;
1962 if (tentry.entries[i] == 0)
1963 break;
1964 if ((tentry.flags & PRGRP) && tentry.entries[i] < 0) { /* Supergroup */
1965 return 5; /* not yet, in short. */
1966 } else {
1967 code = ChangeIDEntry(at, aid, newid, tentry.entries[i]);
1968 }
1969 if (code)
1970 return code;
1971 }
1972 for (pos = ntohl(tentry.owned); pos; pos = nextpos) {
1973 code = pr_ReadEntry(at, 0, pos, &tent);
1974 if (code)
1975 break;
1976 tent.owner = newid;
1977 nextpos = tent.nextOwned;
1978 code = pr_WriteEntry(at, 0, pos, &tent);
1979 if (code)
1980 break;
1981 }
1982 pos = tentry.next;
1983 while (pos) {
1984 #define centry (*(struct contentry*)&tent)
1985 code = pr_ReadCoEntry(at, 0, pos, &centry);
1986 if ((centry.id != aid)
1987 || !(centry.flags & PRCONT)) {
1988 fprintf(stderr,
1989 "ChangeEntry: bad database aid=%d centry.id=%d .flags=%d\n",
1990 aid, centry.id, centry.flags);
1991 return PRDBBAD;
1992 }
1993 centry.id = newid;
1994 for (i = 0; i < COSIZE; i++) {
1995 if (centry.entries[i] == PRBADID)
1996 continue;
1997 if (centry.entries[i] == 0)
1998 break;
1999 if ((centry.flags & PRGRP) && centry.entries[i] < 0) { /* Supergroup */
2000 return 5; /* not yet, in short. */
2001 } else {
2002 code = ChangeIDEntry(at, aid, newid, centry.entries[i]);
2003 }
2004 if (code)
2005 return code;
2006 }
2007 code = pr_WriteCoEntry(at, 0, pos, &centry);
2008 pos = centry.next;
2009 #undef centry
2010 }
2011 if (code)
2012 return code;
2013
2014 #else /* SUPERGROUPS */
2015
2016
2017 /* Also change the references from the membership list */
2018 for (i = 0; i < PRSIZE; i++) {
2019 if (tentry.entries[i] == PRBADID)
2020 continue;
2021 if (tentry.entries[i] == 0)
2022 break;
2023 pos = FindByID(at, tentry.entries[i]);
2024 if (!pos)
2025 return (PRDBFAIL);
2026 code = RemoveFromEntry(at, aid, tentry.entries[i]);
2027 if (code)
2028 return code;
2029 code = pr_ReadEntry(at, 0, pos, &tent);
2030 if (code)
2031 return code;
2032 code = AddToEntry(at, &tent, pos, newid);
2033 if (code)
2034 return code;
2035 }
2036 /* Look through cont entries too. This needs to be broken into
2037 * seperate transaction so that no one transaction becomes too
2038 * large to complete.
2039 */
2040 for (nptr = tentry.next; nptr; nptr = centry.next) {
2041 code = pr_ReadCoEntry(at, 0, nptr, &centry);
2042 if (code)
2043 return code;
2044 for (i = 0; i < COSIZE; i++) {
2045 if (centry.entries[i] == PRBADID)
2046 continue;
2047 if (centry.entries[i] == 0)
2048 break;
2049 pos = FindByID(at, centry.entries[i]);
2050 if (!pos)
2051 return (PRDBFAIL);
2052 code = RemoveFromEntry(at, aid, centry.entries[i]);
2053 if (code)
2054 return code;
2055 code = pr_ReadEntry(at, 0, pos, &tent);
2056 if (code)
2057 return code;
2058 code = AddToEntry(at, &tent, pos, newid);
2059 if (code)
2060 return code;
2061 }
2062 }
2063 #endif /* SUPERGROUPS */
2064 }
2065
2066 atsign = strchr(tentry.name, '@'); /* check for foreign entry */
2067
2068 /* Change the owner */
2069 if (oid && (oid != tentry.owner)) {
2070 /* only groups can have their owner's changed */
2071 if (!(tentry.flags & PRGRP))
2072 return PRPERM;
2073 if (atsign != NULL)
2074 return PRPERM;
2075 oldowner = tentry.owner;
2076 tentry.owner = oid;
2077 /* The entry must be written through first so Remove and Add routines
2078 * can operate on disk data */
2079 code = pr_WriteEntry(at, 0, loc, &tentry);
2080 if (code)
2081 return PRDBFAIL;
2082
2083 /* switch owner chains */
2084 if (oldowner) /* if it has an owner */
2085 code = RemoveFromOwnerChain(at, tentry.id, oldowner);
2086 else /* must be an orphan */
2087 code = RemoveFromOrphan(at, tentry.id);
2088 if (code)
2089 return code;
2090 code = AddToOwnerChain(at, tentry.id, tentry.owner);
2091 if (code)
2092 return code;
2093
2094 /* fix up the name */
2095 if (strlen(name) == 0)
2096 name = tentry.name;
2097 /* get current data */
2098 code = pr_ReadEntry(at, 0, loc, &tentry);
2099 if (code)
2100 return PRDBFAIL;
2101 }
2102
2103 /* Change the name, if name is a ptr to tentry.name then this name change
2104 * is due to a chown, otherwise caller has specified a new name */
2105 if ((name == tentry.name) || (*name && (strcmp(tentry.name, name) != 0))) {
2106 strncpy(oldname, tentry.name, PR_MAXNAMELEN);
2107 if (tentry.flags & PRGRP) {
2108 /* don't let foreign cell groups change name */
2109 if (atsign != NULL)
2110 return PRPERM;
2111
2112 if (tentry.owner == 0 || tentry.owner == ANONYMOUSID)
2113 tentry.owner = cid;
2114
2115 code = CorrectGroupName(at, name, cid, tentry.owner, admin, tentry.name);
2116 if (code)
2117 return code;
2118
2119 if (name == tentry.name) { /* owner fixup */
2120 if (strcmp(oldname, tentry.name) == 0)
2121 goto nameOK;
2122 } else { /* new name, caller must be correct */
2123 if (strcmp(name, tentry.name) != 0)
2124 return PRBADNAM;
2125 }
2126 } else
2127 /* Allow a foreign name change only if the cellname part is
2128 * the same */
2129 {
2130 char *newatsign;
2131
2132 newatsign = strchr(name, '@');
2133 if (newatsign != atsign) { /* if they are the same no problem */
2134 /*if the pointers are not equal the strings better be */
2135 if ((atsign == NULL) || (newatsign == NULL)
2136 || strcmp(atsign, newatsign))
2137 return PRPERM;
2138 }
2139 if (!CorrectUserName(name))
2140 return PRBADNAM;
2141 }
2142
2143 pos = FindByName(at, name, &tent);
2144 if (pos)
2145 return PREXIST;
2146 code = RemoveFromNameHash(at, oldname, &loc);
2147 if (code != PRSUCCESS)
2148 return code;
2149 strncpy(tentry.name, name, PR_MAXNAMELEN);
2150 code = pr_WriteEntry(at, 0, loc, &tentry);
2151 if (code)
2152 return PRDBFAIL;
2153 code = AddToNameHash(at, tentry.name, loc);
2154 if (code != PRSUCCESS)
2155 return code;
2156 nameOK:;
2157 }
2158 return PRSUCCESS;
2159 }
2160
2161
2162 static afs_int32
2163 allocNextId(struct ubik_trans * at, struct prentry * cellEntry)
2164 {
2165 /* Id's for foreign cell entries are constructed as follows:
2166 * The 16 low order bits are the group id of the cell and the
2167 * top 16 bits identify the particular users in that cell */
2168
2169 afs_int32 id;
2170 afs_int32 cellid = ((ntohl(cellEntry->id)) & 0x0000ffff);
2171
2172 id = (ntohl(cellEntry->nusers) + 1);
2173 while (FindByID(at, ((id << 16) | cellid))) {
2174 id++;
2175 if (id > 0xffff)
2176 return 0;
2177 }
2178
2179 cellEntry->nusers = htonl(id);
2180 /* use the field nusers to keep
2181 * the next available id in that
2182 * foreign cell's group. Note :
2183 * It would seem more appropriate
2184 * to use ngroup for that and nusers
2185 * to enforce the quota, however pts
2186 * does not have an option to change
2187 * foreign users quota yet */
2188
2189 id = (id << 16) | cellid;
2190 return id;
2191 }
2192
2193 static int
2194 inRange(struct prentry *cellEntry, afs_int32 aid)
2195 {
2196 afs_uint32 id, cellid, groupid;
2197
2198
2199 /*
2200 * The only thing that we want to make sure here is that
2201 * the id is in the legal range of this group. If it is
2202 * a duplicate we don't care since it will get caught
2203 * in a different check.
2204 */
2205
2206 cellid = aid & 0x0000ffff;
2207 groupid = (ntohl(cellEntry->id)) & 0x0000ffff;
2208 if (cellid != groupid)
2209 return 0; /* not in range */
2210
2211 /*
2212 * if we got here we're ok but we need to update the nusers
2213 * field in order to get the id correct the next time that
2214 * we try to allocate it automatically
2215 */
2216
2217 id = aid >> 16;
2218 if (id > ntohl(cellEntry->nusers))
2219 cellEntry->nusers = htonl(id);
2220 return 1;
2221
2222 }
2223
2224 static int
2225 AddAuthGroup(struct prentry *tentry, prlist *alist, afs_int32 *size)
2226 {
2227 if (!(strchr(tentry->name, '@')))
2228 return (AddToPRList(alist, size, AUTHUSERID));
2229 else
2230 return PRSUCCESS;
2231 }