Merge 1.8.0~pre4 packaging into master
[pkg-k5-afs_openafs.git] / src / ptserver / ptutils.c
blob511f57af51a352274e1545244d6402aa4470a7db
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
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 */
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
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.
23 #include <afsconfig.h>
24 #include <afs/param.h>
25 #include <afs/stds.h>
27 #include <roken.h>
29 #include <lock.h>
30 #include <ubik.h>
31 #include <rx/xdr.h>
32 #include <afs/com_err.h>
33 #include <afs/cellconfig.h>
35 #include "ptserver.h"
36 #include "pterror.h"
37 #include "ptprototypes.h"
39 /* Foreign cells are represented by the group system:authuser@cell*/
40 #define AUTHUSER_GROUP "system:authuser"
42 extern int restricted;
43 extern struct ubik_dbase *dbase;
44 extern struct afsconf_dir *prdir;
45 extern int pr_noAuth;
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);
51 static char *whoami = "ptserver";
53 int prp_user_default = PRP_USER_DEFAULT;
54 int prp_group_default = PRP_GROUP_DEFAULT;
56 #if defined(SUPERGROUPS)
58 #include "map.h"
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);
64 struct map *sg_flagged;
65 struct map *sg_found;
67 #define NIL_MAP ((struct map *) 0)
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.
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.
80 int (*pt_save_dbase_write)(struct ubik_dbase *, afs_int32, void *, afs_int32,
81 afs_int32);
83 int
84 pt_mywrite(struct ubik_dbase *tdb, afs_int32 fno, void *bp, afs_int32 pos, afs_int32 count)
86 afs_uint32 headersize = ntohl(cheader.headerSize);
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;
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)));
145 cp += c;
146 p += c;
147 l -= c;
148 #undef xPT
151 return (*pt_save_dbase_write) (tdb, fno, bp, pos, count);
155 * this function attaches pt_mywrite. It's called once,
156 * just after ubik_ServerInit.
159 void
160 pt_hook_write(void)
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;
169 #endif /* SUPERGROUPS */
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. */
177 static int
178 CorrectUserName(char *name)
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;
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. */
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 */
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;
206 if (strlen(aname) >= PR_MAXNAMELEN)
207 return PRBADNAM;
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;
222 return PRNOENT;
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;
234 prefix = tentry.name;
236 /* only sysadmin allow to use 'system:' prefix */
237 if ((strcmp(prefix, "system") == 0) && !admin)
238 return PRPERM;
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;
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);
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;
272 return 0;
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 */
281 afs_int32 flags;
282 afs_int32 oid;
283 afs_int32 aid;
285 if (pr_noAuth)
286 return 1;
287 if (cid == SYSADMINID)
288 return 1; /* special case fileserver */
289 if (restricted && ((mem == PRP_ADD_MEM) || (mem == PRP_REMOVE_MEM)) && (any == 0))
290 return 0;
291 if (tentry) {
292 flags = tentry->flags;
293 oid = tentry->owner;
294 aid = tentry->id;
295 } else {
296 flags = oid = aid = 0;
298 if (!(flags & PRACCESS)) { /* provide default access */
299 if (flags & PRGRP)
300 flags |= prp_group_default;
301 else
302 flags |= prp_user_default;
305 if (flags & any)
306 return 1;
307 if (oid) {
308 if ((cid == oid) || IsAMemberOf(ut, cid, oid))
309 return 1;
311 if (aid > 0) { /* checking on a user */
312 if (aid == cid)
313 return 1;
314 } else if (aid < 0) { /* checking on group */
315 if ((flags & mem) && IsAMemberOf(ut, cid, aid))
316 return 1;
318 /* Allow members of SYSVIEWERID to get membership and status only */
319 if (((mem == PRP_STATUS_MEM) || (mem == PRP_MEMBER_MEM)
320 || (any == PRP_OWNED_ANY)) && (IsAMemberOf(ut, cid, SYSVIEWERID)))
321 return 1;
322 if (IsAMemberOf(ut, cid, SYSADMINID))
323 return 1;
324 return 0; /* no access */
327 afs_int32
328 CreateEntry(struct ubik_trans *at, char aname[PR_MAXNAMELEN], afs_int32 *aid, afs_int32 idflag, afs_int32 flag, afs_int32 oid, afs_int32 creator)
330 /* get and init a new entry */
331 afs_int32 code;
332 afs_int32 newEntry;
333 afs_int32 admin;
334 struct prentry tentry, tent;
335 char *atsign;
337 memset(&tentry, 0, sizeof(tentry));
339 admin = pr_noAuth || IsAMemberOf(at, creator, SYSADMINID);
341 if (oid == 0 || oid == ANONYMOUSID) {
342 if (!admin && creator == 0)
343 return PRBADARG;
344 oid = creator;
347 if (flag & PRGRP) {
348 code = CorrectGroupName(at, aname, creator, oid, admin, tentry.name);
349 if (code)
350 return code;
351 if (strcmp(aname, tentry.name) != 0)
352 return PRBADNAM;
353 } else { /* non-group must not have colon */
354 if (!CorrectUserName(aname))
355 return PRBADNAM;
356 strcpy(tentry.name, aname);
359 if (FindByName(at, aname, &tent))
360 return PREXIST;
362 newEntry = AllocBlock(at);
363 if (!newEntry)
364 return PRDBFAIL;
365 tentry.createTime = time(0);
367 if (flag & PRGRP) {
368 tentry.flags = PRGRP;
369 tentry.owner = oid;
370 } else if (flag == 0) {
371 tentry.flags = 0;
372 tentry.owner = SYSADMINID;
373 } else {
374 return PRBADARG;
377 atsign = strchr(aname, '@');
378 if (!atsign) {
379 /* A normal user or group. Pick an id for it */
380 if (idflag)
381 tentry.id = *aid;
382 else {
383 code = AllocID(at, flag, &tentry.id);
384 if (code != PRSUCCESS)
385 return code;
387 } else if (flag & PRGRP) {
388 /* A foreign group. Its format must be AUTHUSER_GROUP@cellname
389 * Then pick an id for the group.
391 int badFormat;
393 *atsign = '\0';
394 badFormat = strcmp(AUTHUSER_GROUP, aname);
395 *atsign = '@';
396 if (badFormat)
397 return PRBADNAM;
399 if (idflag)
400 tentry.id = *aid;
401 else {
402 code = AllocID(at, flag, &tentry.id);
403 if (code != PRSUCCESS)
404 return code;
406 } else {
407 /* A foreign user: <name>@<cell>. The foreign user is added to
408 * its representing group. It is
410 char *cellGroup;
411 afs_int32 pos, n;
412 struct prentry centry;
414 /* To create the user <name>@<cell> the group AUTHUSER_GROUP@<cell>
415 * must exist.
417 if (asprintf(&cellGroup, "%s%s", AUTHUSER_GROUP, atsign) < 0)
418 return PRNOMEM;
419 pos = FindByName(at, cellGroup, &centry);
420 free(cellGroup);
421 if (!pos)
422 return PRBADNAM;
423 code = pr_Read(at, 0, pos, &centry, sizeof(centry));
424 if (code)
425 return code;
427 /* cellid is the id of the group representing the cell */
428 tentry.cellid = ntohl(centry.id);
430 if (idflag) {
431 /* Check if id is good */
432 if (!inRange(&centry, *aid))
433 return PRBADARG;
434 tentry.id = *aid;
435 } else {
436 /* Allocate an ID special for this foreign user. It is based
437 * on the representing group's id and nusers count.
439 tentry.id = allocNextId(at, &centry);
440 if (!tentry.id)
441 return PRNOIDS;
444 /* The foreign user will be added to the representing foreign
445 * group. The group can hold up to 30 entries.
447 if (!(ntohl(centry.flags) & PRQUOTA)) {
448 centry.flags = htonl(ntohl(centry.flags) | PRQUOTA);
449 centry.ngroups = htonl(30);
451 n = ntohl(centry.ngroups);
452 if ((n <= 0) && !pr_noAuth)
453 return PRNOMORE;
454 centry.ngroups = htonl(n - 1);
456 /* write updated entry for group */
457 code = pr_Write(at, 0, pos, &centry, sizeof(centry));
458 if (code)
459 return PRDBFAIL;
461 /* Now add the new user entry to the database */
462 if (creator == 0)
463 tentry.creator = tentry.id;
464 else
465 tentry.creator = creator;
466 *aid = tentry.id;
467 code = pr_WriteEntry(at, 0, newEntry, &tentry);
468 if (code)
469 return PRDBFAIL;
470 code = AddToIDHash(at, *aid, newEntry);
471 if (code != PRSUCCESS)
472 return code;
473 code = AddToNameHash(at, aname, newEntry);
474 if (code != PRSUCCESS)
475 return code;
476 if (inc_header_word(at, foreigncount, 1))
477 return PRDBFAIL;
479 /* Now add the entry to the authuser group for this cell.
480 * We will reread the entries for the user and the group
481 * instead of modifying them before writing them in the
482 * previous steps. Although not very efficient, much simpler
484 pos = FindByID(at, tentry.cellid);
485 if (!pos)
486 return PRBADNAM;
487 code = pr_ReadEntry(at, 0, pos, &centry);
488 if (code)
489 return code;
490 code = AddToEntry(at, &centry, pos, *aid);
491 if (code)
492 return code;
493 /* and now the user entry */
494 pos = FindByID(at, *aid);
495 if (!pos)
496 return PRBADNAM;
497 code = pr_ReadEntry(at, 0, pos, &tentry);
498 if (code)
499 return code;
500 code = AddToEntry(at, &tentry, pos, tentry.cellid);
501 if (code)
502 return code;
504 return PRSUCCESS;
507 /* Remember the largest group id or largest user id */
508 if (flag & PRGRP) {
509 /* group ids are negative */
510 if (tentry.id < (afs_int32) ntohl(cheader.maxGroup)) {
511 code = set_header_word(at, maxGroup, htonl(tentry.id));
512 if (code)
513 return PRDBFAIL;
515 } else {
516 if (tentry.id > (afs_int32) ntohl(cheader.maxID)) {
517 code = set_header_word(at, maxID, htonl(tentry.id));
518 if (code)
519 return PRDBFAIL;
523 /* Charge the creator for this group */
524 if (flag & PRGRP) {
525 afs_int32 loc = FindByID(at, creator);
526 struct prentry centry;
527 int admin;
529 if (loc) { /* this should only fail during initialization */
530 code = pr_Read(at, 0, loc, &centry, sizeof(centry));
531 if (code)
532 return code;
534 /* If quota is uninitialized, do it */
535 if (!(ntohl(centry.flags) & PRQUOTA)) {
536 centry.flags = htonl(ntohl(centry.flags) | PRQUOTA);
537 centry.ngroups = centry.nusers = htonl(20);
540 /* Admins don't get charged for creating a group.
541 * If in noAuth mode, you get changed for it but you
542 * are still allowed to create as many groups as you want.
544 admin = ((creator == SYSADMINID)
545 || IsAMemberOf(at, creator, SYSADMINID));
546 if (!admin) {
547 if (ntohl(centry.ngroups) <= 0) {
548 if (!pr_noAuth)
549 return PRNOMORE;
550 } else {
551 centry.ngroups = htonl(ntohl(centry.ngroups) - 1);
555 code = pr_Write(at, 0, loc, &centry, sizeof(centry));
556 if (code)
557 return code;
558 } /* if (loc) */
559 } else {
560 /* Initialize the quota for the user. Groups don't have their
561 * quota initialized.
563 tentry.flags |= PRQUOTA;
564 tentry.ngroups = tentry.nusers = 20;
567 if (creator == 0)
568 tentry.creator = tentry.id;
569 else
570 tentry.creator = creator;
571 *aid = tentry.id;
572 code = pr_WriteEntry(at, 0, newEntry, &tentry);
573 if (code)
574 return PRDBFAIL;
575 code = AddToIDHash(at, *aid, newEntry);
576 if (code != PRSUCCESS)
577 return code;
578 code = AddToNameHash(at, aname, newEntry);
579 if (code != PRSUCCESS)
580 return code;
581 if (tentry.flags & PRGRP) {
582 code = AddToOwnerChain(at, tentry.id, oid);
583 if (code)
584 return code;
586 if (tentry.flags & PRGRP) {
587 if (inc_header_word(at, groupcount, 1))
588 return PRDBFAIL;
589 } else if (tentry.flags & PRINST) {
590 if (inc_header_word(at, instcount, 1))
591 return PRDBFAIL;
592 } else {
593 if (inc_header_word(at, usercount, 1))
594 return PRDBFAIL;
596 return PRSUCCESS;
600 /* RemoveFromEntry - remove aid from bid's entries list, freeing a continuation
601 * entry if appropriate */
603 afs_int32
604 RemoveFromEntry(struct ubik_trans *at, afs_int32 aid, afs_int32 bid)
606 afs_int32 code;
607 struct prentry tentry;
608 struct contentry centry;
609 struct contentry hentry;
610 afs_int32 temp;
611 afs_int32 i, j;
612 afs_int32 nptr;
613 afs_int32 hloc;
615 if (aid == bid)
616 return PRINCONSISTENT;
617 memset(&hentry, 0, sizeof(hentry));
618 temp = FindByID(at, bid);
619 if (temp == 0)
620 return PRNOENT;
621 code = pr_ReadEntry(at, 0, temp, &tentry);
622 if (code != 0)
623 return code;
624 tentry.removeTime = time(0);
625 for (i = 0; i < PRSIZE; i++) {
626 if (tentry.entries[i] == aid) {
627 tentry.entries[i] = PRBADID;
628 tentry.count--;
629 code = pr_WriteEntry(at, 0, temp, &tentry);
630 if (code != 0)
631 return code;
632 return PRSUCCESS;
634 if (tentry.entries[i] == 0) /* found end of list */
635 return PRNOENT;
637 hloc = 0;
638 nptr = tentry.next;
639 while (nptr != 0) {
640 code = pr_ReadCoEntry(at, 0, nptr, &centry);
641 if (code != 0)
642 return code;
643 if ((centry.id != bid) || !(centry.flags & PRCONT))
644 return PRDBBAD;
645 for (i = 0; i < COSIZE; i++) {
646 if (centry.entries[i] == aid) {
647 centry.entries[i] = PRBADID;
648 for (j = 0; j < COSIZE; j++)
649 if (centry.entries[j] != PRBADID
650 && centry.entries[j] != 0)
651 break;
652 if (j == COSIZE) { /* can free this block */
653 if (hloc == 0) {
654 tentry.next = centry.next;
655 } else {
656 hentry.next = centry.next;
657 code = pr_WriteCoEntry(at, 0, hloc, &hentry);
658 if (code != 0)
659 return code;
661 code = FreeBlock(at, nptr);
662 if (code)
663 return code;
664 } else { /* can't free it yet */
665 code = pr_WriteCoEntry(at, 0, nptr, &centry);
666 if (code != 0)
667 return code;
669 tentry.count--;
670 code = pr_WriteEntry(at, 0, temp, &tentry);
671 if (code)
672 return PRDBFAIL;
673 return 0;
675 if (centry.entries[i] == 0)
676 return PRNOENT;
677 } /* for all coentry slots */
678 hloc = nptr;
679 nptr = centry.next;
680 memcpy(&hentry, &centry, sizeof(centry));
681 } /* while there are coentries */
682 return PRNOENT;
685 #if defined(SUPERGROUPS)
686 /* ChangeIDEntry - remove aid from bid's entries list, freeing a continuation
687 * entry if appropriate */
689 afs_int32
690 ChangeIDEntry(struct ubik_trans *at, afs_int32 aid, afs_int32 newid, afs_int32 bid)
692 afs_int32 code;
693 struct prentry tentry;
694 struct contentry centry;
695 afs_int32 temp;
696 afs_int32 i, j;
697 afs_int32 nptr;
699 if (aid == bid)
700 return PRINCONSISTENT;
701 temp = FindByID(at, bid);
702 if (temp == 0) {
703 return PRNOENT;
705 code = pr_ReadEntry(at, 0, temp, &tentry);
706 if (code != 0)
707 return code;
708 for (i = 0; i < PRSIZE; i++) {
709 if (tentry.entries[i] == aid) {
710 tentry.entries[i] = newid;
711 code = pr_WriteEntry(at, 0, temp, &tentry);
712 if (code != 0)
713 return code;
714 return PRSUCCESS;
716 if (tentry.entries[i] == 0) { /* found end of list */
717 return PRNOENT;
721 nptr = tentry.next;
722 while (nptr) {
723 code = pr_ReadCoEntry(at, 0, nptr, &centry);
724 if (code != 0)
725 return code;
726 if ((centry.id != bid) || !(centry.flags & PRCONT)) {
727 fprintf(stderr,
728 "ChangeIDEntry: bad database bid=%d centry.id=%d .flags=%d\n",
729 bid, centry.id, centry.flags);
730 return PRDBBAD;
732 for (i = 0; i < COSIZE; i++) {
733 if (centry.entries[i] == aid) {
734 centry.entries[i] = newid;
735 for (j = 0; j < COSIZE; j++)
736 if (centry.entries[j] != PRBADID
737 && centry.entries[j] != 0)
738 break;
739 code = pr_WriteCoEntry(at, 0, nptr, &centry);
740 if (code != 0)
741 return code;
742 return 0;
744 if (centry.entries[i] == 0) {
745 return PRNOENT;
747 } /* for all coentry slots */
748 nptr = centry.next;
749 } /* while there are coentries */
750 return PRNOENT;
753 /* #ifdef SUPERGROUPS */
754 /* RemoveFromSGEntry - remove aid from bid's supergroups list, freeing a
755 * continuation entry if appropriate */
757 afs_int32
758 RemoveFromSGEntry(struct ubik_trans *at, afs_int32 aid, afs_int32 bid)
760 afs_int32 code;
761 struct prentry tentry;
762 struct prentryg *tentryg;
763 struct contentry centry;
764 struct contentry hentry;
765 afs_int32 temp;
766 afs_int32 i, j;
767 afs_int32 nptr;
768 afs_int32 hloc;
770 if (aid == bid)
771 return PRINCONSISTENT;
772 memset(&hentry, 0, sizeof(hentry));
773 temp = FindByID(at, bid);
774 if (temp == 0) {
775 return PRNOENT;
777 code = pr_ReadEntry(at, 0, temp, &tentry);
778 if (code != 0)
779 return code;
780 tentry.removeTime = time(NULL);
781 tentryg = (struct prentryg *)&tentry;
782 for (i = 0; i < SGSIZE; i++) {
783 if (tentryg->supergroup[i] == aid) {
784 tentryg->supergroup[i] = PRBADID;
785 tentryg->countsg--;
786 code = pr_WriteEntry(at, 0, temp, &tentry);
787 if (code != 0)
788 return code;
789 return PRSUCCESS;
791 if (tentryg->supergroup[i] == 0) { /* found end of list */
792 return PRNOENT;
795 hloc = 0;
796 nptr = tentryg->nextsg;
797 while (nptr) {
798 code = pr_ReadCoEntry(at, 0, nptr, &centry);
799 if (code != 0)
800 return code;
801 if ((centry.id != bid) || !(centry.flags & PRCONT)) {
802 fprintf(stderr,
803 "ChangeIDEntry: bad database bid=%d centry.id=%d .flags=%d\n",
804 bid, centry.id, centry.flags);
805 return PRDBBAD;
807 for (i = 0; i < COSIZE; i++) {
808 if (centry.entries[i] == aid) {
809 centry.entries[i] = PRBADID;
810 for (j = 0; j < COSIZE; j++)
811 if (centry.entries[j] != PRBADID
812 && centry.entries[j] != 0)
813 break;
814 if (j == COSIZE) { /* can free this block */
815 if (hloc == 0) {
816 tentryg->nextsg = centry.next;
817 } else {
818 hentry.next = centry.next;
819 code = pr_WriteCoEntry(at, 0, hloc, &hentry);
820 if (code != 0)
821 return code;
823 code = FreeBlock(at, nptr);
824 if (code)
825 return code;
826 } else { /* can't free it yet */
827 code = pr_WriteCoEntry(at, 0, nptr, &centry);
828 if (code != 0)
829 return code;
831 tentryg->countsg--;
832 code = pr_WriteEntry(at, 0, temp, &tentry);
833 if (code)
834 return PRDBFAIL;
835 return 0;
837 if (centry.entries[i] == 0) {
838 return PRNOENT;
840 } /* for all coentry slots */
841 hloc = nptr;
842 nptr = centry.next;
843 memcpy(&hentry, &centry, sizeof(centry));
844 } /* while there are coentries */
845 return PRNOENT;
848 #endif /* SUPERGROUPS */
850 /* DeleteEntry - delete the entry in tentry at loc, removing it from all
851 * groups, putting groups owned by it on orphan chain, and freeing the space */
853 afs_int32
854 DeleteEntry(struct ubik_trans *at, struct prentry *tentry, afs_int32 loc)
856 afs_int32 code;
857 struct contentry centry;
858 afs_int32 i;
859 afs_int32 nptr;
861 if (strchr(tentry->name, '@')) {
862 if (tentry->flags & PRGRP) {
863 /* If there are still foreign user accounts from that cell
864 * don't delete the group */
865 if (tentry->count)
866 return PRBADARG;
867 } else {
868 /* adjust quota */
870 afs_int32 loc = FindByID(at, tentry->cellid);
871 struct prentry centry;
872 if (loc) {
873 code = pr_Read(at, 0, loc, &centry, sizeof(centry));
874 if (code)
875 return code;
876 if (ntohl(centry.flags) & PRQUOTA) {
877 centry.ngroups = htonl(ntohl(centry.ngroups) + 1);
879 code = pr_Write(at, 0, loc, &centry, sizeof(centry));
880 if (code)
881 return code;
885 /* First remove the entire membership list */
886 for (i = 0; i < PRSIZE; i++) {
887 if (tentry->entries[i] == PRBADID)
888 continue;
889 if (tentry->entries[i] == 0)
890 break;
891 #if defined(SUPERGROUPS)
892 if ((tentry->flags & PRGRP) && tentry->entries[i] < 0) /* Supergroup */
893 code = RemoveFromSGEntry(at, tentry->id, tentry->entries[i]);
894 else
895 #endif
896 code = RemoveFromEntry(at, tentry->id, tentry->entries[i]);
897 if (code)
898 return code;
900 #if defined(SUPERGROUPS)
902 struct prentryg *tentryg = (struct prentryg *)tentry;
904 /* Then remove the entire supergroup list */
905 for (i = 0; i < SGSIZE; i++) {
906 if (tentryg->supergroup[i] == PRBADID)
907 continue;
908 if (tentryg->supergroup[i] == 0)
909 break;
910 code = RemoveFromEntry(at, tentry->id, tentryg->supergroup[i]);
911 if (code)
912 return code;
915 #endif /* SUPERGROUPS */
916 nptr = tentry->next;
917 while (nptr != 0) {
918 code = pr_ReadCoEntry(at, 0, nptr, &centry);
919 if (code != 0)
920 return PRDBFAIL;
921 for (i = 0; i < COSIZE; i++) {
922 if (centry.entries[i] == PRBADID)
923 continue;
924 if (centry.entries[i] == 0)
925 break;
926 code = RemoveFromEntry(at, tentry->id, centry.entries[i]);
927 if (code)
928 return code;
930 code = FreeBlock(at, nptr); /* free continuation block */
931 if (code)
932 return code;
933 nptr = centry.next;
936 /* Remove us from other's owned chain. Note that this will zero our owned
937 * field (on disk) so this step must follow the above step in case we are
938 * on our own owned list. */
939 if (tentry->flags & PRGRP) {
940 if (tentry->owner) {
941 code = RemoveFromOwnerChain(at, tentry->id, tentry->owner);
942 if (code)
943 return code;
944 } else {
945 code = RemoveFromOrphan(at, tentry->id);
946 if (code)
947 return code;
951 code = RemoveFromIDHash(at, tentry->id, &loc);
952 if (code != PRSUCCESS)
953 return code;
954 code = RemoveFromNameHash(at, tentry->name, &loc);
955 if (code != PRSUCCESS)
956 return code;
958 if (tentry->flags & PRGRP) {
959 afs_int32 loc = FindByID(at, tentry->creator);
960 struct prentry centry;
961 int admin;
963 if (loc) {
964 code = pr_Read(at, 0, loc, &centry, sizeof(centry));
965 if (code)
966 return code;
967 admin = ((tentry->creator == SYSADMINID)
968 || IsAMemberOf(at, tentry->creator, SYSADMINID));
969 if (ntohl(centry.flags) & PRQUOTA) {
970 if (!(admin && (ntohl(centry.ngroups) >= 20))) {
971 centry.ngroups = htonl(ntohl(centry.ngroups) + 1);
974 code = pr_Write(at, 0, loc, &centry, sizeof(centry));
975 if (code)
976 return code;
980 if (tentry->flags & PRGRP) {
981 if (inc_header_word(at, groupcount, -1))
982 return PRDBFAIL;
983 } else if (tentry->flags & PRINST) {
984 if (inc_header_word(at, instcount, -1))
985 return PRDBFAIL;
986 } else {
987 if (strchr(tentry->name, '@')) {
988 if (inc_header_word(at, foreigncount, -1))
989 return PRDBFAIL;
990 } else {
991 if (inc_header_word(at, usercount, -1))
992 return PRDBFAIL;
995 code = FreeBlock(at, loc);
996 return code;
999 /* AddToEntry - add aid to entry's entries list, alloc'ing a continuation block
1000 * if needed.
1002 * Note the entry is written out by this routine. */
1004 afs_int32
1005 AddToEntry(struct ubik_trans *tt, struct prentry *entry, afs_int32 loc, afs_int32 aid)
1007 afs_int32 code;
1008 afs_int32 i;
1009 struct contentry nentry;
1010 struct contentry aentry;
1011 afs_int32 nptr;
1012 afs_int32 last; /* addr of last cont. block */
1013 afs_int32 first = 0;
1014 afs_int32 cloc = 0;
1015 afs_int32 slot = -1;
1017 if (entry->id == aid)
1018 return PRINCONSISTENT;
1019 entry->addTime = time(0);
1020 for (i = 0; i < PRSIZE; i++) {
1021 if (entry->entries[i] == aid)
1022 return PRIDEXIST;
1023 if (entry->entries[i] == PRBADID) { /* remember this spot */
1024 first = 1;
1025 slot = i;
1026 } else if (entry->entries[i] == 0) { /* end of the line */
1027 if (slot == -1) {
1028 first = 1;
1029 slot = i;
1031 break;
1034 last = 0;
1035 nptr = entry->next;
1036 while (nptr != 0) {
1037 code = pr_ReadCoEntry(tt, 0, nptr, &nentry);
1038 if (code != 0)
1039 return code;
1040 last = nptr;
1041 if (!(nentry.flags & PRCONT))
1042 return PRDBFAIL;
1043 for (i = 0; i < COSIZE; i++) {
1044 if (nentry.entries[i] == aid)
1045 return PRIDEXIST;
1046 if (nentry.entries[i] == PRBADID) {
1047 if (slot == -1) {
1048 slot = i;
1049 cloc = nptr;
1051 } else if (nentry.entries[i] == 0) {
1052 if (slot == -1) {
1053 slot = i;
1054 cloc = nptr;
1056 break;
1059 nptr = nentry.next;
1061 if (slot != -1) { /* we found a place */
1062 entry->count++;
1063 if (first) { /* place is in first block */
1064 entry->entries[slot] = aid;
1065 code = pr_WriteEntry(tt, 0, loc, entry);
1066 if (code != 0)
1067 return code;
1068 return PRSUCCESS;
1070 code = pr_WriteEntry(tt, 0, loc, entry);
1071 if (code)
1072 return code;
1073 code = pr_ReadCoEntry(tt, 0, cloc, &aentry);
1074 if (code != 0)
1075 return code;
1076 aentry.entries[slot] = aid;
1077 code = pr_WriteCoEntry(tt, 0, cloc, &aentry);
1078 if (code != 0)
1079 return code;
1080 return PRSUCCESS;
1082 /* have to allocate a continuation block if we got here */
1083 nptr = AllocBlock(tt);
1084 if (last) {
1085 /* then we should tack new block after last block in cont. chain */
1086 nentry.next = nptr;
1087 code = pr_WriteCoEntry(tt, 0, last, &nentry);
1088 if (code != 0)
1089 return code;
1090 } else {
1091 entry->next = nptr;
1093 memset(&aentry, 0, sizeof(aentry));
1094 aentry.flags |= PRCONT;
1095 aentry.id = entry->id;
1096 aentry.next = 0;
1097 aentry.entries[0] = aid;
1098 code = pr_WriteCoEntry(tt, 0, nptr, &aentry);
1099 if (code != 0)
1100 return code;
1101 /* don't forget to update count, here! */
1102 entry->count++;
1103 code = pr_WriteEntry(tt, 0, loc, entry);
1104 return code;
1108 #if defined(SUPERGROUPS)
1110 /* AddToSGEntry - add aid to entry's supergroup list, alloc'ing a
1111 * continuation block if needed.
1113 * Note the entry is written out by this routine. */
1115 afs_int32
1116 AddToSGEntry(struct ubik_trans *tt, struct prentry *entry, afs_int32 loc, afs_int32 aid)
1118 afs_int32 code;
1119 afs_int32 i;
1120 struct contentry nentry;
1121 struct contentry aentry;
1122 struct prentryg *entryg;
1123 afs_int32 nptr;
1124 afs_int32 last; /* addr of last cont. block */
1125 afs_int32 first = 0;
1126 afs_int32 cloc = 0;
1127 afs_int32 slot = -1;
1129 if (entry->id == aid)
1130 return PRINCONSISTENT;
1131 entry->addTime = time(NULL);
1132 entryg = (struct prentryg *)entry;
1133 for (i = 0; i < SGSIZE; i++) {
1134 if (entryg->supergroup[i] == aid)
1135 return PRIDEXIST;
1136 if (entryg->supergroup[i] == PRBADID) { /* remember this spot */
1137 first = 1;
1138 slot = i;
1139 } else if (entryg->supergroup[i] == 0) { /* end of the line */
1140 if (slot == -1) {
1141 first = 1;
1142 slot = i;
1144 break;
1147 last = 0;
1148 nptr = entryg->nextsg;
1149 while (nptr) {
1150 code = pr_ReadCoEntry(tt, 0, nptr, &nentry);
1151 if (code != 0)
1152 return code;
1153 last = nptr;
1154 if (!(nentry.flags & PRCONT))
1155 return PRDBFAIL;
1156 for (i = 0; i < COSIZE; i++) {
1157 if (nentry.entries[i] == aid)
1158 return PRIDEXIST;
1159 if (nentry.entries[i] == PRBADID) {
1160 if (slot == -1) {
1161 slot = i;
1162 cloc = nptr;
1164 } else if (nentry.entries[i] == 0) {
1165 if (slot == -1) {
1166 slot = i;
1167 cloc = nptr;
1169 break;
1172 nptr = nentry.next;
1174 if (slot != -1) { /* we found a place */
1175 entryg->countsg++;
1176 if (first) { /* place is in first block */
1177 entryg->supergroup[slot] = aid;
1178 code = pr_WriteEntry(tt, 0, loc, entry);
1179 if (code != 0)
1180 return code;
1181 return PRSUCCESS;
1183 code = pr_WriteEntry(tt, 0, loc, entry);
1184 if (code)
1185 return code;
1186 code = pr_ReadCoEntry(tt, 0, cloc, &aentry);
1187 if (code != 0)
1188 return code;
1189 aentry.entries[slot] = aid;
1190 code = pr_WriteCoEntry(tt, 0, cloc, &aentry);
1191 if (code != 0)
1192 return code;
1193 return PRSUCCESS;
1195 /* have to allocate a continuation block if we got here */
1196 nptr = AllocBlock(tt);
1197 if (last) {
1198 /* then we should tack new block after last block in cont. chain */
1199 nentry.next = nptr;
1200 code = pr_WriteCoEntry(tt, 0, last, &nentry);
1201 if (code != 0)
1202 return code;
1203 } else {
1204 entryg->nextsg = nptr;
1206 memset(&aentry, 0, sizeof(aentry));
1207 aentry.flags |= PRCONT;
1208 aentry.id = entry->id;
1209 aentry.next = 0;
1210 aentry.entries[0] = aid;
1211 code = pr_WriteCoEntry(tt, 0, nptr, &aentry);
1212 if (code != 0)
1213 return code;
1214 /* don't forget to update count, here! */
1215 entryg->countsg++;
1216 code = pr_WriteEntry(tt, 0, loc, entry);
1217 return code;
1220 #endif /* SUPERGROUPS */
1222 afs_int32
1223 AddToPRList(prlist *alist, int *sizeP, afs_int32 id)
1225 afs_int32 *tmp;
1226 int count;
1228 if (alist->prlist_len >= *sizeP) {
1229 count = alist->prlist_len + 100;
1230 if (alist->prlist_val) {
1231 tmp = realloc(alist->prlist_val, count * sizeof(afs_int32));
1232 } else {
1233 tmp = malloc(count * sizeof(afs_int32));
1235 if (!tmp)
1236 return (PRNOMEM);
1237 alist->prlist_val = tmp;
1238 *sizeP = count;
1240 alist->prlist_val[alist->prlist_len++] = id;
1241 return 0;
1244 afs_int32
1245 GetList(struct ubik_trans *at, struct prentry *tentry, prlist *alist, afs_int32 add)
1247 afs_int32 code;
1248 afs_int32 i;
1249 struct contentry centry;
1250 afs_int32 nptr;
1251 int size;
1252 int count = 0;
1254 size = 0;
1255 alist->prlist_val = 0;
1256 alist->prlist_len = 0;
1258 for (i = 0; i < PRSIZE; i++) {
1259 if (tentry->entries[i] == PRBADID)
1260 continue;
1261 if (tentry->entries[i] == 0)
1262 break;
1263 code = AddToPRList(alist, &size, tentry->entries[i]);
1264 if (code)
1265 return code;
1266 #if defined(SUPERGROUPS)
1267 if (!add)
1268 continue;
1269 code = GetListSG2(at, tentry->entries[i], alist, &size, depthsg);
1270 if (code)
1271 return code;
1272 #endif
1275 for (nptr = tentry->next; nptr != 0; nptr = centry.next) {
1276 /* look through cont entries */
1277 code = pr_ReadCoEntry(at, 0, nptr, &centry);
1278 if (code != 0)
1279 return code;
1280 for (i = 0; i < COSIZE; i++) {
1281 if (centry.entries[i] == PRBADID)
1282 continue;
1283 if (centry.entries[i] == 0)
1284 break;
1285 code = AddToPRList(alist, &size, centry.entries[i]);
1286 if (code)
1287 return code;
1288 #if defined(SUPERGROUPS)
1289 if (!add)
1290 continue;
1291 code = GetListSG2(at, centry.entries[i], alist, &size, depthsg);
1292 if (code)
1293 return code;
1294 #endif
1296 if (count++ > 50) {
1297 #ifndef AFS_PTHREAD_ENV
1298 IOMGR_Poll();
1299 #endif
1300 count = 0;
1304 if (add) { /* this is for a CPS, so tack on appropriate stuff */
1305 if (tentry->id != ANONYMOUSID && tentry->id != ANYUSERID) {
1306 if ((code = AddToPRList(alist, &size, ANYUSERID))
1307 || (code = AddAuthGroup(tentry, alist, &size))
1308 || (code = AddToPRList(alist, &size, tentry->id)))
1309 return code;
1310 } else {
1311 if ((code = AddToPRList(alist, &size, ANYUSERID))
1312 || (code = AddToPRList(alist, &size, tentry->id)))
1313 return code;
1316 #ifndef AFS_PTHREAD_ENV
1317 if (alist->prlist_len > 100)
1318 IOMGR_Poll();
1319 #endif
1320 qsort(alist->prlist_val, alist->prlist_len, sizeof(afs_int32), IDCmp);
1321 return PRSUCCESS;
1325 afs_int32
1326 GetList2(struct ubik_trans *at, struct prentry *tentry, struct prentry *tentry2, prlist *alist, afs_int32 add)
1328 afs_int32 code = 0;
1329 afs_int32 i;
1330 struct contentry centry;
1331 afs_int32 nptr;
1332 afs_int32 size;
1333 int count = 0;
1335 size = 0;
1336 alist->prlist_val = 0;
1337 alist->prlist_len = 0;
1338 for (i = 0; i < PRSIZE; i++) {
1339 if (tentry->entries[i] == PRBADID)
1340 continue;
1341 if (tentry->entries[i] == 0)
1342 break;
1343 code = AddToPRList(alist, &size, tentry->entries[i]);
1344 if (code)
1345 return code;
1346 #if defined(SUPERGROUPS)
1347 if (!add)
1348 continue;
1349 code = GetListSG2(at, tentry->entries[i], alist, &size, depthsg);
1350 if (code)
1351 return code;
1352 #endif
1355 nptr = tentry->next;
1356 while (nptr != 0) {
1357 /* look through cont entries */
1358 code = pr_ReadCoEntry(at, 0, nptr, &centry);
1359 if (code != 0)
1360 return code;
1361 for (i = 0; i < COSIZE; i++) {
1362 if (centry.entries[i] == PRBADID)
1363 continue;
1364 if (centry.entries[i] == 0)
1365 break;
1366 code = AddToPRList(alist, &size, centry.entries[i]);
1367 if (code)
1368 return code;
1369 #if defined(SUPERGROUPS)
1370 if (!add)
1371 continue;
1372 code = GetListSG2(at, centry.entries[i], alist, &size, depthsg);
1373 if (code)
1374 return code;
1375 #endif
1377 nptr = centry.next;
1378 if (count++ > 50) {
1379 #ifndef AFS_PTHREAD_ENV
1380 IOMGR_Poll();
1381 #endif
1382 count = 0;
1386 for (i = 0; i < PRSIZE; i++) {
1387 if (tentry2->entries[i] == PRBADID)
1388 continue;
1389 if (tentry2->entries[i] == 0)
1390 break;
1391 code = AddToPRList(alist, &size, tentry2->entries[i]);
1392 if (code)
1393 break;
1396 if (!code) {
1397 nptr = tentry2->next;
1398 while (nptr != 0) {
1399 /* look through cont entries */
1400 code = pr_ReadCoEntry(at, 0, nptr, &centry);
1401 if (code != 0)
1402 break;
1403 for (i = 0; i < COSIZE; i++) {
1404 if (centry.entries[i] == PRBADID)
1405 continue;
1406 if (centry.entries[i] == 0)
1407 break;
1408 code = AddToPRList(alist, &size, centry.entries[i]);
1409 if (code)
1410 break;
1412 nptr = centry.next;
1413 if (count++ > 50) {
1414 #ifndef AFS_PTHREAD_ENV
1415 IOMGR_Poll();
1416 #endif
1417 count = 0;
1421 if (add) { /* this is for a CPS, so tack on appropriate stuff */
1422 if (tentry->id != ANONYMOUSID && tentry->id != ANYUSERID) {
1423 if ((code = AddToPRList(alist, &size, ANYUSERID))
1424 || (code = AddToPRList(alist, &size, AUTHUSERID))
1425 || (code = AddToPRList(alist, &size, tentry->id)))
1426 return code;
1427 } else {
1428 if ((code = AddToPRList(alist, &size, ANYUSERID))
1429 || (code = AddToPRList(alist, &size, tentry->id)))
1430 return code;
1433 #ifndef AFS_PTHREAD_ENV
1434 if (alist->prlist_len > 100)
1435 IOMGR_Poll();
1436 #endif
1437 qsort(alist->prlist_val, alist->prlist_len, sizeof(afs_int32), IDCmp);
1438 return PRSUCCESS;
1441 #if defined(SUPERGROUPS)
1443 afs_int32
1444 GetListSG2(struct ubik_trans *at, afs_int32 gid, prlist *alist, afs_int32 *sizeP, afs_int32 depth)
1446 afs_int32 code;
1447 struct prentry tentry;
1448 struct prentryg *tentryg = (struct prentryg *)&tentry;
1449 afs_int32 i;
1450 struct contentry centry;
1451 afs_int32 nptr;
1452 int count = 0;
1453 afs_int32 temp;
1454 int didsomething;
1455 #if DEBUG_SG_MAP
1456 int predictfound, predictflagged;
1457 #endif
1459 #if DEBUG_SG_MAP
1460 predictfound = 0;
1461 if (!in_map(sg_flagged, -gid)) {
1462 predictflagged = 0;
1463 fprintf(stderr, "GetListSG2: I have not yet searched for gid=%d\n",
1464 gid);
1465 } else if (predictflagged = 1, in_map(sg_found, -gid)) {
1466 predictfound = 1;
1467 fprintf(stderr,
1468 "GetListSG2: I have already searched for gid=%d, and predict success.\n",
1469 gid);
1471 #endif
1473 if (in_map(sg_flagged, -gid) && !in_map(sg_found, -gid)) {
1474 #if DEBUG_SG_MAP
1475 fprintf(stderr,
1476 "GetListSG2: I have already searched for gid=%d, and predict failure.\n",
1477 gid);
1478 #else
1479 return 0;
1480 #endif
1483 if (depth < 1)
1484 return 0;
1485 temp = FindByID(at, gid);
1486 if (!temp) {
1487 code = PRNOENT;
1488 return code;
1490 code = pr_ReadEntry(at, 0, temp, &tentry);
1491 if (code)
1492 return code;
1493 #if DEBUG_SG_MAP
1494 fprintf(stderr, "GetListSG2: lookup for gid=%d [\n", gid);
1495 #endif
1496 didsomething = 0;
1498 for (i = 0; i < SGSIZE; i++) {
1499 if (tentryg->supergroup[i] == PRBADID)
1500 continue;
1501 if (tentryg->supergroup[i] == 0)
1502 break;
1503 didsomething = 1;
1504 #if DEBUG_SG_MAP
1505 fprintf(stderr, "via gid=%d, added %d\n", gid,
1506 e.tentryg.supergroup[i]);
1507 #endif
1508 code = AddToPRList(alist, sizeP, tentryg->supergroup[i]);
1509 if (code)
1510 return code;
1511 code =
1512 GetListSG2(at, tentryg->supergroup[i], alist, sizeP, depth - 1);
1513 if (code)
1514 return code;
1517 nptr = tentryg->nextsg;
1518 while (nptr) {
1519 didsomething = 1;
1520 /* look through cont entries */
1521 code = pr_ReadCoEntry(at, 0, nptr, &centry);
1522 if (code != 0)
1523 return code;
1524 for (i = 0; i < COSIZE; i++) {
1525 if (centry.entries[i] == PRBADID)
1526 continue;
1527 if (centry.entries[i] == 0)
1528 break;
1529 #if DEBUG_SG_MAP
1530 fprintf(stderr, "via gid=%d, added %d\n", gid,
1531 e.centry.entries[i]);
1532 #endif
1533 code = AddToPRList(alist, sizeP, centry.entries[i]);
1534 if (code)
1535 return code;
1536 code = GetListSG2(at, centry.entries[i], alist, sizeP, depth - 1);
1537 if (code)
1538 return code;
1540 nptr = centry.next;
1541 if (count++ > 50) {
1542 #ifndef AFS_PTHREAD_ENV
1543 IOMGR_Poll();
1544 #endif
1545 count = 0;
1548 #if DEBUG_SG_MAP
1549 fprintf(stderr, "] for gid %d, done [flag=%s]\n", gid,
1550 didsomething ? "TRUE" : "FALSE");
1551 if (predictflagged && didsomething != predictfound)
1552 fprintf(stderr, "**** for gid=%d, didsomething=%d predictfound=%d\n",
1553 didsomething, predictfound);
1554 #endif
1555 if (didsomething)
1556 sg_found = add_map(sg_found, -gid);
1557 else
1558 sg_found = bic_map(sg_found, add_map(NIL_MAP, -gid));
1559 sg_flagged = add_map(sg_flagged, -gid);
1560 return 0;
1563 afs_int32
1564 GetSGList(struct ubik_trans *at, struct prentry *tentry, prlist *alist)
1566 afs_int32 code;
1567 afs_int32 i;
1568 struct contentry centry;
1569 struct prentryg *tentryg;
1570 afs_int32 nptr;
1571 int size;
1572 int count = 0;
1574 size = 0;
1575 alist->prlist_val = 0;
1576 alist->prlist_len = 0;
1578 tentryg = (struct prentryg *)tentry;
1579 for (i = 0; i < SGSIZE; i++) {
1580 if (tentryg->supergroup[i] == PRBADID)
1581 continue;
1582 if (tentryg->supergroup[i] == 0)
1583 break;
1584 code = AddToPRList(alist, &size, tentryg->supergroup[i]);
1585 if (code)
1586 return code;
1589 nptr = tentryg->nextsg;
1590 while (nptr) {
1591 /* look through cont entries */
1592 code = pr_ReadCoEntry(at, 0, nptr, &centry);
1593 if (code != 0)
1594 return code;
1595 for (i = 0; i < COSIZE; i++) {
1596 if (centry.entries[i] == PRBADID)
1597 continue;
1598 if (centry.entries[i] == 0)
1599 break;
1600 code = AddToPRList(alist, &size, centry.entries[i]);
1601 if (code)
1602 return code;
1604 nptr = centry.next;
1605 if (count++ > 50) {
1606 #ifndef AFS_PTHREAD_ENV
1607 IOMGR_Poll();
1608 #endif
1609 count = 0;
1613 #ifndef AFS_PTHREAD_ENV
1614 if (alist->prlist_len > 100)
1615 IOMGR_Poll();
1616 #endif
1617 qsort((char *)alist->prlist_val, (int)alist->prlist_len,
1618 sizeof(afs_int32), IDCmp);
1619 return PRSUCCESS;
1621 #endif /* SUPERGROUPS */
1623 afs_int32
1624 GetOwnedChain(struct ubik_trans *ut, afs_int32 *next, prlist *alist)
1626 afs_int32 code;
1627 struct prentry tentry;
1628 int size;
1629 int count = 0;
1631 size = 0;
1632 alist->prlist_val = 0;
1633 alist->prlist_len = 0;
1635 for (; *next; *next = ntohl(tentry.nextOwned)) {
1636 code = pr_Read(ut, 0, *next, &tentry, sizeof(tentry));
1637 if (code)
1638 return code;
1639 code = AddToPRList(alist, &size, ntohl(tentry.id));
1640 if (alist->prlist_len >= PR_MAXGROUPS) {
1641 return PRTOOMANY;
1643 if (code)
1644 return code;
1645 if (count++ > 50) {
1646 #ifndef AFS_PTHREAD_ENV
1647 IOMGR_Poll();
1648 #endif
1649 count = 0;
1652 #ifndef AFS_PTHREAD_ENV
1653 if (alist->prlist_len > 100)
1654 IOMGR_Poll();
1655 #endif
1656 qsort(alist->prlist_val, alist->prlist_len, sizeof(afs_int32), IDCmp);
1657 return PRSUCCESS;
1660 afs_int32
1661 GetMax(struct ubik_trans *at, afs_int32 *uid, afs_int32 *gid)
1663 *uid = ntohl(cheader.maxID);
1664 *gid = ntohl(cheader.maxGroup);
1665 return PRSUCCESS;
1668 afs_int32
1669 SetMax(struct ubik_trans *at, afs_int32 id, afs_int32 flag)
1671 afs_int32 code;
1672 if (flag & PRGRP) {
1673 cheader.maxGroup = htonl(id);
1674 code =
1675 pr_Write(at, 0, 16, (char *)&cheader.maxGroup,
1676 sizeof(cheader.maxGroup));
1677 if (code != 0)
1678 return code;
1679 } else {
1680 cheader.maxID = htonl(id);
1681 code =
1682 pr_Write(at, 0, 20, (char *)&cheader.maxID,
1683 sizeof(cheader.maxID));
1684 if (code != 0)
1685 return code;
1687 return PRSUCCESS;
1690 static afs_int32
1691 UpdateCache(struct ubik_trans *tt, void *rock)
1693 afs_int32 code;
1695 code = pr_Read(tt, 0, 0, (char *)&cheader, sizeof(cheader));
1696 if (code != 0) {
1697 afs_com_err(whoami, code, "Couldn't read header");
1699 return code;
1702 afs_int32
1703 read_DbHeader(struct ubik_trans *tt)
1705 return ubik_CheckCache(tt, UpdateCache, NULL);
1708 int pr_noAuth;
1711 * reads in db cache from ubik.
1713 * @param[in] ut ubik transaction
1714 * @param[out] rock opaque pointer to an int*, which on success will be set
1715 * to 1 if we need to build the database, or 0 if we do not
1717 * @return operation status
1718 * @retval 0 success
1720 static afs_int32
1721 Initdb_check(struct ubik_trans *tt, void *rock)
1723 int *build_rock = rock;
1724 afs_int32 code;
1725 afs_int32 len;
1727 len = sizeof(cheader);
1728 code = pr_Read(tt, 0, 0, (char *)&cheader, len);
1729 if (code != 0) {
1730 afs_com_err(whoami, code, "couldn't read header");
1731 return code;
1733 if ((ntohl(cheader.version) == PRDBVERSION)
1734 && ntohl(cheader.headerSize) == sizeof(cheader)
1735 && ntohl(cheader.eofPtr) != 0
1736 && FindByID(tt, ANONYMOUSID) != 0) {
1737 /* database exists, so we don't have to build it */
1738 *build_rock = 0;
1739 return 0;
1742 /* else we need to build a database */
1743 *build_rock = 1;
1744 return 0;
1747 afs_int32
1748 Initdb(void)
1750 struct ubik_trans *tt;
1751 int build = 0;
1752 afs_int32 code;
1754 /* init the database. We'll try reading it, but if we're starting
1755 * from scratch, we'll have to do a write transaction. */
1757 pr_noAuth = afsconf_GetNoAuthFlag(prdir);
1759 code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
1760 if (code)
1761 return code;
1762 code = ubik_SetLock(tt, 1, 1, LOCKREAD);
1763 if (code) {
1764 ubik_AbortTrans(tt);
1765 return code;
1768 code = ubik_CheckCache(tt, Initdb_check, &build);
1769 if (code) {
1770 ubik_AbortTrans(tt);
1771 return code;
1774 if (build) {
1775 /* Only rebuild database if the db was deleted (the header is zero) */
1776 char *bp = (char *)&cheader;
1777 int i;
1778 for (i = 0; i < sizeof(cheader); i++) {
1779 if (bp[i]) {
1780 code = PRDBBAD;
1781 afs_com_err(whoami, code,
1782 "Can't rebuild database because it is not empty");
1783 break;
1788 if (code) {
1789 ubik_EndTrans(tt);
1790 } else {
1791 code = ubik_EndTrans(tt);
1793 if (code || !build) {
1794 /* either we encountered an error, or we don't need to build the db */
1795 return code;
1798 code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
1799 if (code)
1800 return code;
1802 code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
1803 if (code) {
1804 ubik_AbortTrans(tt);
1805 return code;
1808 /* before doing a rebuild, check again that the dbase looks bad, because
1809 * the previous check was only under a ReadAny transaction, and there could
1810 * actually have been a good database out there. Now that we have a
1811 * real write transaction, make sure things are still bad.
1813 code = pr_Read(tt, 0, 0, (char *)&cheader, sizeof(cheader));
1814 if (code != 0) {
1815 afs_com_err(whoami, code, "couldn't read header");
1816 ubik_AbortTrans(tt);
1817 return code;
1819 if ((ntohl(cheader.version) == PRDBVERSION)
1820 && ntohl(cheader.headerSize) == sizeof(cheader)
1821 && ntohl(cheader.eofPtr) != 0
1822 && FindByID(tt, ANONYMOUSID) != 0) {
1823 /* database exists, so we don't have to build it */
1824 code = ubik_EndTrans(tt);
1825 if (code)
1826 return code;
1827 return PRSUCCESS;
1830 /* Initialize the database header */
1831 if ((code = set_header_word(tt, version, htonl(PRDBVERSION)))
1832 || (code = set_header_word(tt, headerSize, htonl(sizeof(cheader))))
1833 || (code = set_header_word(tt, eofPtr, cheader.headerSize))) {
1834 afs_com_err(whoami, code, "couldn't write header words");
1835 ubik_AbortTrans(tt);
1836 return code;
1838 #define InitialGroup(id,name) do { \
1839 afs_int32 temp = (id); \
1840 afs_int32 flag = (id) < 0 ? PRGRP : 0; \
1841 code = CreateEntry \
1842 (tt, (name), &temp, /*idflag*/1, flag, SYSADMINID, SYSADMINID); \
1843 if (code) { \
1844 afs_com_err (whoami, code, "couldn't create %s with id %di.", \
1845 (name), (id)); \
1846 ubik_AbortTrans(tt); \
1847 return code; \
1849 } while (0)
1851 InitialGroup(SYSADMINID, "system:administrators");
1852 InitialGroup(SYSBACKUPID, "system:backup");
1853 InitialGroup(ANYUSERID, "system:anyuser");
1854 InitialGroup(AUTHUSERID, "system:authuser");
1855 InitialGroup(SYSVIEWERID, "system:ptsviewers");
1856 InitialGroup(ANONYMOUSID, "anonymous");
1858 /* Well, we don't really want the max id set to anonymousid, so we'll set
1859 * it back to 0 */
1860 code = set_header_word(tt, maxID, 0); /* correct in any byte order */
1861 if (code) {
1862 afs_com_err(whoami, code, "couldn't reset max id");
1863 ubik_AbortTrans(tt);
1864 return code;
1867 code = ubik_EndTrans(tt);
1868 if (code)
1869 return code;
1870 return PRSUCCESS;
1873 afs_int32
1874 ChangeEntry(struct ubik_trans *at, afs_int32 aid, afs_int32 cid, char *name, afs_int32 oid, afs_int32 newid)
1876 afs_int32 code;
1877 afs_int32 i, pos;
1878 #if defined(SUPERGROUPS)
1879 afs_int32 nextpos;
1880 #else
1881 afs_int32 nptr;
1882 struct contentry centry;
1883 #endif
1884 struct prentry tentry, tent;
1885 afs_int32 loc;
1886 afs_int32 oldowner;
1887 afs_int32 admin;
1888 char holder[PR_MAXNAMELEN];
1889 char temp[PR_MAXNAMELEN];
1890 char oldname[PR_MAXNAMELEN];
1891 char *atsign;
1893 memset(holder, 0, PR_MAXNAMELEN);
1894 memset(temp, 0, PR_MAXNAMELEN);
1895 loc = FindByID(at, aid);
1896 if (!loc)
1897 return PRNOENT;
1898 code = pr_ReadEntry(at, 0, loc, &tentry);
1899 if (code)
1900 return PRDBFAIL;
1901 if (restricted && !IsAMemberOf(at, cid, SYSADMINID))
1902 return PRPERM;
1903 if (tentry.owner != cid && !IsAMemberOf(at, cid, SYSADMINID)
1904 && !IsAMemberOf(at, cid, tentry.owner) && !pr_noAuth)
1905 return PRPERM;
1906 tentry.changeTime = time(0);
1907 admin = pr_noAuth || IsAMemberOf(at, cid, SYSADMINID);
1909 /* we're actually trying to change the id */
1910 if (newid && (newid != aid)) {
1911 if (!admin)
1912 return PRPERM;
1914 pos = FindByID(at, newid);
1915 if (pos)
1916 return PRIDEXIST; /* new id already in use! */
1917 if ((aid < 0 && newid > 0) || (aid > 0 && newid < 0))
1918 return PRPERM;
1920 /* Should check that foreign users id to change to is good: inRange() */
1922 /* if new id is not in use, rehash things */
1923 code = RemoveFromIDHash(at, aid, &loc);
1924 if (code != PRSUCCESS)
1925 return code;
1926 tentry.id = newid;
1927 code = pr_WriteEntry(at, 0, loc, &tentry);
1928 if (code)
1929 return code;
1930 code = AddToIDHash(at, tentry.id, loc);
1931 if (code)
1932 return code;
1934 /* get current data */
1935 code = pr_ReadEntry(at, 0, loc, &tentry);
1936 if (code)
1937 return PRDBFAIL;
1939 #if defined(SUPERGROUPS)
1940 if (tentry.id > (afs_int32) ntohl(cheader.maxID))
1941 code = set_header_word(at, maxID, htonl(tentry.id));
1942 if (code)
1943 return PRDBFAIL;
1945 /* need to fix up: membership
1946 * (supergroups?)
1947 * ownership
1950 for (i = 0; i < PRSIZE; i++) {
1951 if (tentry.entries[i] == PRBADID)
1952 continue;
1953 if (tentry.entries[i] == 0)
1954 break;
1955 if ((tentry.flags & PRGRP) && tentry.entries[i] < 0) { /* Supergroup */
1956 return 5; /* not yet, in short. */
1957 } else {
1958 code = ChangeIDEntry(at, aid, newid, tentry.entries[i]);
1960 if (code)
1961 return code;
1963 for (pos = ntohl(tentry.owned); pos; pos = nextpos) {
1964 code = pr_ReadEntry(at, 0, pos, &tent);
1965 if (code)
1966 break;
1967 tent.owner = newid;
1968 nextpos = tent.nextOwned;
1969 code = pr_WriteEntry(at, 0, pos, &tent);
1970 if (code)
1971 break;
1973 pos = tentry.next;
1974 while (pos) {
1975 #define centry (*(struct contentry*)&tent)
1976 code = pr_ReadCoEntry(at, 0, pos, &centry);
1977 if ((centry.id != aid)
1978 || !(centry.flags & PRCONT)) {
1979 fprintf(stderr,
1980 "ChangeEntry: bad database aid=%d centry.id=%d .flags=%d\n",
1981 aid, centry.id, centry.flags);
1982 return PRDBBAD;
1984 centry.id = newid;
1985 for (i = 0; i < COSIZE; i++) {
1986 if (centry.entries[i] == PRBADID)
1987 continue;
1988 if (centry.entries[i] == 0)
1989 break;
1990 if ((centry.flags & PRGRP) && centry.entries[i] < 0) { /* Supergroup */
1991 return 5; /* not yet, in short. */
1992 } else {
1993 code = ChangeIDEntry(at, aid, newid, centry.entries[i]);
1995 if (code)
1996 return code;
1998 code = pr_WriteCoEntry(at, 0, pos, &centry);
1999 pos = centry.next;
2000 #undef centry
2002 if (code)
2003 return code;
2005 #else /* SUPERGROUPS */
2008 /* Also change the references from the membership list */
2009 for (i = 0; i < PRSIZE; i++) {
2010 if (tentry.entries[i] == PRBADID)
2011 continue;
2012 if (tentry.entries[i] == 0)
2013 break;
2014 pos = FindByID(at, tentry.entries[i]);
2015 if (!pos)
2016 return (PRDBFAIL);
2017 code = RemoveFromEntry(at, aid, tentry.entries[i]);
2018 if (code)
2019 return code;
2020 code = pr_ReadEntry(at, 0, pos, &tent);
2021 if (code)
2022 return code;
2023 code = AddToEntry(at, &tent, pos, newid);
2024 if (code)
2025 return code;
2027 /* Look through cont entries too. This needs to be broken into
2028 * seperate transaction so that no one transaction becomes too
2029 * large to complete.
2031 for (nptr = tentry.next; nptr; nptr = centry.next) {
2032 code = pr_ReadCoEntry(at, 0, nptr, &centry);
2033 if (code)
2034 return code;
2035 for (i = 0; i < COSIZE; i++) {
2036 if (centry.entries[i] == PRBADID)
2037 continue;
2038 if (centry.entries[i] == 0)
2039 break;
2040 pos = FindByID(at, centry.entries[i]);
2041 if (!pos)
2042 return (PRDBFAIL);
2043 code = RemoveFromEntry(at, aid, centry.entries[i]);
2044 if (code)
2045 return code;
2046 code = pr_ReadEntry(at, 0, pos, &tent);
2047 if (code)
2048 return code;
2049 code = AddToEntry(at, &tent, pos, newid);
2050 if (code)
2051 return code;
2054 #endif /* SUPERGROUPS */
2057 atsign = strchr(tentry.name, '@'); /* check for foreign entry */
2059 /* Change the owner */
2060 if (oid && (oid != tentry.owner)) {
2061 /* only groups can have their owner's changed */
2062 if (!(tentry.flags & PRGRP))
2063 return PRPERM;
2064 if (atsign != NULL)
2065 return PRPERM;
2066 oldowner = tentry.owner;
2067 tentry.owner = oid;
2068 /* The entry must be written through first so Remove and Add routines
2069 * can operate on disk data */
2070 code = pr_WriteEntry(at, 0, loc, &tentry);
2071 if (code)
2072 return PRDBFAIL;
2074 /* switch owner chains */
2075 if (oldowner) /* if it has an owner */
2076 code = RemoveFromOwnerChain(at, tentry.id, oldowner);
2077 else /* must be an orphan */
2078 code = RemoveFromOrphan(at, tentry.id);
2079 if (code)
2080 return code;
2081 code = AddToOwnerChain(at, tentry.id, tentry.owner);
2082 if (code)
2083 return code;
2085 /* fix up the name */
2086 if (strlen(name) == 0)
2087 name = tentry.name;
2088 /* get current data */
2089 code = pr_ReadEntry(at, 0, loc, &tentry);
2090 if (code)
2091 return PRDBFAIL;
2094 /* Change the name, if name is a ptr to tentry.name then this name change
2095 * is due to a chown, otherwise caller has specified a new name */
2096 if ((name == tentry.name) || (*name && (strcmp(tentry.name, name) != 0))) {
2097 strncpy(oldname, tentry.name, PR_MAXNAMELEN);
2098 if (tentry.flags & PRGRP) {
2099 /* don't let foreign cell groups change name */
2100 if (atsign != NULL)
2101 return PRPERM;
2103 if (tentry.owner == 0 || tentry.owner == ANONYMOUSID)
2104 tentry.owner = cid;
2106 code = CorrectGroupName(at, name, cid, tentry.owner, admin, tentry.name);
2107 if (code)
2108 return code;
2110 if (name == tentry.name) { /* owner fixup */
2111 if (strcmp(oldname, tentry.name) == 0)
2112 goto nameOK;
2113 } else { /* new name, caller must be correct */
2114 if (strcmp(name, tentry.name) != 0)
2115 return PRBADNAM;
2117 } else
2118 /* Allow a foreign name change only if the cellname part is
2119 * the same */
2121 char *newatsign;
2123 newatsign = strchr(name, '@');
2124 if (newatsign != atsign) { /* if they are the same no problem */
2125 /*if the pointers are not equal the strings better be */
2126 if ((atsign == NULL) || (newatsign == NULL)
2127 || strcmp(atsign, newatsign))
2128 return PRPERM;
2130 if (!CorrectUserName(name))
2131 return PRBADNAM;
2134 pos = FindByName(at, name, &tent);
2135 if (pos)
2136 return PREXIST;
2137 code = RemoveFromNameHash(at, oldname, &loc);
2138 if (code != PRSUCCESS)
2139 return code;
2140 strncpy(tentry.name, name, PR_MAXNAMELEN);
2141 code = pr_WriteEntry(at, 0, loc, &tentry);
2142 if (code)
2143 return PRDBFAIL;
2144 code = AddToNameHash(at, tentry.name, loc);
2145 if (code != PRSUCCESS)
2146 return code;
2147 nameOK:;
2149 return PRSUCCESS;
2153 static afs_int32
2154 allocNextId(struct ubik_trans * at, struct prentry * cellEntry)
2156 /* Id's for foreign cell entries are constructed as follows:
2157 * The 16 low order bits are the group id of the cell and the
2158 * top 16 bits identify the particular users in that cell */
2160 afs_int32 id;
2161 afs_int32 cellid = ((ntohl(cellEntry->id)) & 0x0000ffff);
2163 id = (ntohl(cellEntry->nusers) + 1);
2164 while (FindByID(at, ((id << 16) | cellid))) {
2165 id++;
2166 if (id > 0xffff)
2167 return 0;
2170 cellEntry->nusers = htonl(id);
2171 /* use the field nusers to keep
2172 * the next available id in that
2173 * foreign cell's group. Note :
2174 * It would seem more appropriate
2175 * to use ngroup for that and nusers
2176 * to enforce the quota, however pts
2177 * does not have an option to change
2178 * foreign users quota yet */
2180 id = (id << 16) | cellid;
2181 return id;
2184 static int
2185 inRange(struct prentry *cellEntry, afs_int32 aid)
2187 afs_uint32 id, cellid, groupid;
2191 * The only thing that we want to make sure here is that
2192 * the id is in the legal range of this group. If it is
2193 * a duplicate we don't care since it will get caught
2194 * in a different check.
2197 cellid = aid & 0x0000ffff;
2198 groupid = (ntohl(cellEntry->id)) & 0x0000ffff;
2199 if (cellid != groupid)
2200 return 0; /* not in range */
2203 * if we got here we're ok but we need to update the nusers
2204 * field in order to get the id correct the next time that
2205 * we try to allocate it automatically
2208 id = aid >> 16;
2209 if (id > ntohl(cellEntry->nusers))
2210 cellEntry->nusers = htonl(id);
2211 return 1;
2215 static int
2216 AddAuthGroup(struct prentry *tentry, prlist *alist, afs_int32 *size)
2218 if (!(strchr(tentry->name, '@')))
2219 return (AddToPRList(alist, size, AUTHUSERID));
2220 else
2221 return PRSUCCESS;