2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include <afs/param.h>
16 #include <sys/types.h>
21 #include <netinet/in.h>
27 #include <afs/com_err.h>
28 #include <afs/cellconfig.h>
33 /* Foreign cells are represented by the group system:authuser@cell*/
34 #define AUTHUSER_GROUP "system:authuser"
37 extern struct ubik_dbase *dbase;
38 extern struct afsconf_dir *prdir;
42 extern afs_int32 AddToEntry();
43 static char *whoami = "ptserver";
45 /* CorrectUserName - Check to make sure a user name is OK. It must not include
46 * either a colon (or it would look like a group) or an atsign (or it would
47 * look like a foreign user). The length is checked as well to make sure
48 * that the user name, an atsign, and the local cell name will fit in
49 * PR_MAXNAMELEN. This is so this user can fit in another cells database as
50 * a foreign user with our cell name tacked on. This is a predicate, so it
51 * return one if name is OK and zero if name is bogus. */
53 static int CorrectUserName (name)
56 extern int pr_realmNameLen;
58 /* We accept foreign names, so we will deal with '@' later */
59 if (strchr (name, ':') || strchr(name, '\n')) return 0;
60 if (strlen (name) >= PR_MAXNAMELEN - pr_realmNameLen - 1) return 0;
64 /* CorrectGroupName - Like the above but handles more complicated cases caused
65 * by including the ownership in the name. The interface works by calculating
66 * the correct name based on a given name and owner. This allows easy use by
67 * rename, which then compares the correct name with the requested new name. */
69 static afs_int32 CorrectGroupName (ut, aname, cid, oid, cname)
70 struct ubik_trans *ut;
71 char aname[PR_MAXNAMELEN]; /* name for group */
72 afs_int32 cid; /* caller id */
73 afs_int32 oid; /* owner of group */
74 char cname[PR_MAXNAMELEN]; /* correct name for group */
78 char *prefix; /* ptr to group owner part */
79 char *suffix; /* ptr to group name part */
80 char name[PR_MAXNAMELEN]; /* correct name for group */
81 struct prentry tentry;
83 if (strlen (aname) >= PR_MAXNAMELEN) return PRBADNAM;
84 admin = pr_noAuth || IsAMemberOf (ut, cid, SYSADMINID);
86 if (oid == 0) oid = cid;
88 /* Determine the correct prefix for the name. */
89 if (oid == SYSADMINID) prefix = "system";
91 afs_int32 loc = FindByID (ut, oid);
93 /* let admin create groups owned by non-existent ids (probably
94 * setting a group to own itself). Check that they look like
95 * groups (with a colon) or otherwise are good user names. */
97 strcpy (cname, aname);
102 code = pr_Read (ut, 0, loc, &tentry, sizeof(tentry));
103 if (code) return code;
104 if (ntohl(tentry.flags) & PRGRP) {
105 if ((tentry.count == 0) && !admin) return PRGROUPEMPTY;
106 /* terminate prefix at colon if there is one */
107 if (prefix = strchr(tentry.name, ':')) *prefix = 0;
109 prefix = tentry.name;
111 /* only sysadmin allow to use 'system:' prefix */
112 if ((strcmp (prefix, "system") == 0) && !admin) return PRPERM;
114 strcpy (name, aname); /* in case aname & cname are same */
115 suffix = strchr(name, ':');
117 /* sysadmin can make groups w/o ':', but they must still look like
118 * legal user names. */
119 if (!admin) return PRBADNAM;
120 strcpy (cname, name);
123 if (strlen(prefix)+strlen(suffix) >= PR_MAXNAMELEN) return PRBADNAM;
124 strcpy (cname, prefix);
125 strcat (cname, suffix);
128 /* check for legal name with either group rules or user rules */
129 if (suffix = strchr(cname, ':')) {
130 /* check for confusing characters */
131 if (strchr(cname, '\n') || /* restrict so recreate can work */
132 strchr(suffix+1, ':')) /* avoid multiple colons */
135 if (!CorrectUserName (cname)) return PRBADNAM;
140 int AccessOK (ut, cid, tentry, mem, any)
141 struct ubik_trans *ut;
142 afs_int32 cid; /* caller id */
143 struct prentry *tentry; /* object being accessed */
144 int mem; /* check membership in aid, if group */
145 int any; /* if set return true */
150 if (pr_noAuth) return 1;
151 if (cid == SYSADMINID) return 1; /* special case fileserver */
153 flags = tentry->flags;
157 flags = oid = aid = 0;
159 if (!(flags & PRACCESS)) /* provide default access */
161 flags |= PRP_GROUP_DEFAULT;
163 flags |= PRP_USER_DEFAULT;
165 if (flags & any) return 1;
168 IsAMemberOf (ut, cid, oid)) return 1;
170 if (aid > 0) { /* checking on a user */
171 if (aid == cid) return 1;
172 } else if (aid < 0) { /* checking on group */
173 if ((flags & mem) && IsAMemberOf (ut, cid, aid)) return 1;
175 /* Allow members of SYSVIEWERID to get membership and status only */
176 if (((mem == PRP_STATUS_MEM)||(mem == PRP_MEMBER_MEM))&&(IsAMemberOf (ut, cid, SYSVIEWERID))) return 1;
177 if (IsAMemberOf (ut, cid, SYSADMINID)) return 1;
178 return 0; /* no access */
181 afs_int32 CreateEntry (at, aname, aid, idflag, flag, oid, creator)
182 struct ubik_trans *at;
183 char aname[PR_MAXNAMELEN];
190 /* get and init a new entry */
193 struct prentry tentry, tent;
196 memset(&tentry, 0, sizeof(tentry));
198 if ((oid == 0) || (oid == ANONYMOUSID)) oid = creator;
201 code = CorrectGroupName (at, aname, creator, oid, tentry.name);
202 if (code) return code;
203 if (strcmp (aname, tentry.name) != 0) return PRBADNAM;
204 } else { /* non-group must not have colon */
205 if (!CorrectUserName(aname)) return PRBADNAM;
206 strcpy (tentry.name, aname);
209 if (FindByName(at,aname, &tent)) return PREXIST;
211 newEntry = AllocBlock(at);
212 if (!newEntry) return PRDBFAIL;
213 #ifdef PR_REMEMBER_TIMES
214 tentry.createTime = time(0);
218 tentry.flags = PRGRP;
220 } else if (flag == 0) {
222 tentry.owner = SYSADMINID;
227 atsign = strchr(aname, '@');
229 /* A normal user or group. Pick an id for it */
233 code= AllocID(at,flag,&tentry.id);
234 if (code != PRSUCCESS) return code;
236 } else if (flag & PRGRP) {
237 /* A foreign group. Its format must be AUTHUSER_GROUP@cellname
238 * Then pick an id for the group.
243 badFormat = strcmp(AUTHUSER_GROUP, aname);
245 if (badFormat) return PRBADNAM;
250 code= AllocID(at,flag,&tentry.id);
251 if (code != PRSUCCESS) return code;
254 /* A foreign user: <name>@<cell>. The foreign user is added to
255 * its representing group. It is
259 struct prentry centry;
260 extern afs_int32 allocNextId();
262 /* To create the user <name>@<cell> the group AUTHUSER_GROUP@<cell>
265 cellGroup = (char *)malloc(strlen(AUTHUSER_GROUP) + strlen(atsign) + 1);
266 strcpy(cellGroup, AUTHUSER_GROUP);
267 strcat(cellGroup, atsign);
268 pos = FindByName(at, cellGroup, ¢ry);
269 if (!pos) return PRBADNAM;
270 code = pr_Read (at, 0, pos, ¢ry, sizeof(centry));
271 if (code) return code;
273 /* cellid is the id of the group representing the cell */
274 tentry.cellid = ntohl(centry.id);
277 /* Check if id is good */
278 if (!inRange(¢ry,*aid)) return PRBADARG;
281 /* Allocate an ID special for this foreign user. It is based
282 * on the representing group's id and nusers count.
284 tentry.id = allocNextId(¢ry);
287 /* The foreign user will be added to the representing foreign
288 * group. The group can hold up to 30 entries.
290 if (!(ntohl(centry.flags) & PRQUOTA)) {
291 centry.flags = htonl (ntohl(centry.flags) | PRQUOTA);
292 centry.ngroups = htonl(30);
294 n = ntohl(centry.ngroups);
295 if ( (n <= 0) && !pr_noAuth ) return PRNOMORE;
296 centry.ngroups = htonl(n - 1);
298 /* write updated entry for group */
299 code = pr_Write (at, 0, pos, ¢ry, sizeof(centry));
301 /* Now add the new user entry to the database */
302 tentry.creator = creator;
304 code = pr_WriteEntry(at, 0, newEntry, &tentry);
305 if (code) return PRDBFAIL;
306 code = AddToIDHash(at, *aid, newEntry);
307 if (code != PRSUCCESS) return code;
308 code = AddToNameHash(at, aname, newEntry);
309 if (code != PRSUCCESS) return code;
310 if (inc_header_word (at, foreigncount, 1)) return PRDBFAIL;
312 /* Now add the entry to the authuser group for this cell.
313 * We will reread the entries for the user and the group
314 * instead of modifying them before writing them in the
315 * previous steps. Although not very efficient, much simpler
317 pos = FindByID(at, tentry.cellid);
318 if (!pos) return PRBADNAM;
319 code = pr_ReadEntry (at, 0, pos, ¢ry);
320 if (code) return code;
321 code = AddToEntry(at, ¢ry, pos, *aid);
322 if (code) return code;
323 /* and now the user entry */
324 pos = FindByID(at,*aid);
325 if (!pos) return PRBADNAM;
326 code = pr_ReadEntry (at, 0, pos, &tentry);
327 if (code) return code;
328 code = AddToEntry(at, &tentry, pos, tentry.cellid);
329 if (code) return code;
334 /* Remember the largest group id or largest user id */
336 /* group ids are negative */
337 if (tentry.id < (afs_int32)ntohl(cheader.maxGroup)) {
338 code = set_header_word (at, maxGroup, htonl(tentry.id));
339 if (code) return PRDBFAIL;
343 if (tentry.id > (afs_int32)ntohl(cheader.maxID)) {
344 code = set_header_word (at, maxID, htonl(tentry.id));
345 if (code) return PRDBFAIL;
349 /* Charge the creator for this group */
351 afs_int32 loc = FindByID (at, creator);
352 struct prentry centry;
355 if (loc) { /* this should only fail during initialization */
356 code = pr_Read (at, 0, loc, ¢ry, sizeof(centry));
357 if (code) return code;
359 /* If quota is uninitialized, do it */
360 if (!(ntohl(centry.flags) & PRQUOTA)) {
361 centry.flags = htonl (ntohl(centry.flags) | PRQUOTA);
362 centry.ngroups = centry.nusers = htonl(20);
365 /* Admins don't get charged for creating a group.
366 * If in noAuth mode, you get changed for it but you
367 * are still allowed to create as many groups as you want.
369 admin = ( (creator == SYSADMINID) ||
370 IsAMemberOf(at,creator,SYSADMINID) );
372 if (ntohl(centry.ngroups) <= 0) {
373 if (!pr_noAuth) return PRNOMORE;
375 centry.ngroups = htonl(ntohl(centry.ngroups)-1);
379 code = pr_Write (at, 0, loc, ¢ry, sizeof(centry));
380 if (code) return code;
384 /* Initialize the quota for the user. Groups don't have their
387 tentry.flags |= PRQUOTA;
388 tentry.ngroups = tentry.nusers = 20;
391 tentry.creator = creator;
393 code = pr_WriteEntry(at, 0, newEntry, &tentry);
394 if (code) return PRDBFAIL;
395 code = AddToIDHash(at,*aid,newEntry);
396 if (code != PRSUCCESS) return code;
397 code = AddToNameHash(at,aname,newEntry);
398 if (code != PRSUCCESS) return code;
399 if (tentry.flags & PRGRP) {
400 code = AddToOwnerChain(at,tentry.id,oid);
401 if (code) return code;
403 if (tentry.flags & PRGRP) {
404 if (inc_header_word (at, groupcount, 1)) return PRDBFAIL;
406 else if (tentry.flags & PRINST) {
407 if (inc_header_word (at, instcount, 1)) return PRDBFAIL;
410 if (inc_header_word (at, usercount, 1)) return PRDBFAIL;
416 /* RemoveFromEntry - remove aid from bid's entries list, freeing a continuation
417 * entry if appropriate */
419 afs_int32 RemoveFromEntry (at, aid, bid)
420 struct ubik_trans *at;
425 struct prentry tentry;
426 struct contentry centry;
427 struct contentry hentry;
433 if (aid == bid) return PRINCONSISTENT;
434 memset(&hentry, 0, sizeof(hentry));
435 temp = FindByID(at,bid);
436 if (temp == 0) return PRNOENT;
437 code = pr_ReadEntry(at, 0, temp, &tentry);
438 if (code != 0) return code;
439 #ifdef PR_REMEMBER_TIMES
440 tentry.removeTime = time(0);
442 for (i=0;i<PRSIZE;i++) {
443 if (tentry.entries[i] == aid) {
444 tentry.entries[i] = PRBADID;
446 code = pr_WriteEntry(at,0,temp,&tentry);
447 if (code != 0) return code;
450 if (tentry.entries[i] == 0) /* found end of list */
456 code = pr_ReadCoEntry(at,0,nptr,¢ry);
457 if (code != 0) return code;
458 if ((centry.id != bid) || !(centry.flags & PRCONT)) return PRDBBAD;
459 for (i=0;i<COSIZE;i++) {
460 if (centry.entries[i] == aid) {
461 centry.entries[i] = PRBADID;
462 for (j=0;j<COSIZE;j++)
463 if (centry.entries[j] != PRBADID &&
464 centry.entries[j] != 0) break;
465 if (j == COSIZE) { /* can free this block */
467 tentry.next = centry.next;
470 hentry.next = centry.next;
471 code = pr_WriteCoEntry (at, 0, hloc, &hentry);
472 if (code != 0) return code;
474 code = FreeBlock (at, nptr);
475 if (code) return code;
477 else { /* can't free it yet */
478 code = pr_WriteCoEntry(at,0,nptr,¢ry);
479 if (code != 0) return code;
482 code = pr_WriteEntry(at,0,temp,&tentry);
483 if (code) return PRDBFAIL;
486 if (centry.entries[i] == 0) return PRNOENT;
487 } /* for all coentry slots */
490 memcpy(&hentry, ¢ry, sizeof(centry));
491 } /* while there are coentries */
495 /* DeleteEntry - delete the entry in tentry at loc, removing it from all
496 * groups, putting groups owned by it on orphan chain, and freeing the space */
498 afs_int32 DeleteEntry (at, tentry, loc)
499 struct ubik_trans *at;
500 struct prentry *tentry;
504 struct contentry centry;
508 if (strchr(tentry->name,'@')) {
509 if (tentry->flags & PRGRP) {
510 /* If there are still foreign user accounts from that cell
511 don't delete the group */
512 if (tentry->count) return PRBADARG;
516 afs_int32 loc = FindByID (at, tentry->cellid);
517 struct prentry centry;
519 code = pr_Read (at, 0, loc, ¢ry, sizeof(centry));
520 if (code) return code;
521 if (ntohl(centry.flags) & PRQUOTA) {
522 centry.ngroups = htonl(ntohl(centry.ngroups) + 1);
524 code = pr_Write (at, 0, loc, ¢ry, sizeof(centry));
525 if (code) return code;
529 /* First remove the entire membership list */
530 for (i=0;i<PRSIZE;i++) {
531 if (tentry->entries[i] == PRBADID) continue;
532 if (tentry->entries[i] == 0) break;
533 code = RemoveFromEntry (at, tentry->id, tentry->entries[i]);
534 if (code) return code;
537 while (nptr != (afs_int32)NULL) {
538 code = pr_ReadCoEntry(at,0,nptr,¢ry);
539 if (code != 0) return PRDBFAIL;
540 for (i=0;i<COSIZE;i++) {
541 if (centry.entries[i] == PRBADID) continue;
542 if (centry.entries[i] == 0) break;
543 code = RemoveFromEntry (at, tentry->id, centry.entries[i]);
544 if (code) return code;
546 code = FreeBlock (at, nptr); /* free continuation block */
547 if (code) return code;
551 /* Remove us from other's owned chain. Note that this will zero our owned
552 * field (on disk) so this step must follow the above step in case we are
553 * on our own owned list. */
554 if (tentry->flags & PRGRP) {
556 code = RemoveFromOwnerChain (at, tentry->id, tentry->owner);
557 if (code) return code;
560 code = RemoveFromOrphan (at, tentry->id);
561 if (code) return code;
565 code = RemoveFromIDHash(at,tentry->id,&loc);
566 if (code != PRSUCCESS) return code;
567 code = RemoveFromNameHash(at,tentry->name,&loc);
568 if (code != PRSUCCESS) return code;
570 if (tentry->flags & PRGRP) {
571 afs_int32 loc = FindByID(at, tentry->creator);
572 struct prentry centry;
576 code = pr_Read (at, 0, loc, ¢ry, sizeof(centry));
577 if (code) return code;
578 admin = ( (tentry->creator == SYSADMINID) ||
579 IsAMemberOf(at,tentry->creator,SYSADMINID) );
580 if (ntohl(centry.flags) & PRQUOTA) {
581 if (!(admin && (ntohl(centry.ngroups) >= 20))) {
582 centry.ngroups = htonl(ntohl(centry.ngroups) + 1);
585 code = pr_Write (at, 0, loc, ¢ry, sizeof(centry));
586 if (code) return code;
590 if (tentry->flags & PRGRP) {
591 if (inc_header_word (at, groupcount, -1)) return PRDBFAIL;
593 else if (tentry->flags & PRINST) {
594 if (inc_header_word (at, instcount, -1)) return PRDBFAIL;
597 if (strchr(tentry->name,'@')) {
598 if (inc_header_word (at, foreigncount, -1)) return PRDBFAIL;
600 if (inc_header_word (at, usercount, -1)) return PRDBFAIL;
603 code = FreeBlock(at, loc);
607 /* AddToEntry - add aid to entry's entries list, alloc'ing a continuation block
610 * Note the entry is written out by this routine. */
612 afs_int32 AddToEntry (tt, entry, loc, aid)
613 struct ubik_trans *tt;
614 struct prentry *entry;
620 struct contentry nentry;
621 struct contentry aentry;
623 afs_int32 last; /* addr of last cont. block */
628 if (entry->id == aid) return PRINCONSISTENT;
629 #ifdef PR_REMEMBER_TIMES
630 entry->addTime = time(0);
632 for (i=0;i<PRSIZE;i++) {
633 if (entry->entries[i] == aid)
635 if (entry->entries[i] == PRBADID) { /* remember this spot */
639 else if (entry->entries[i] == 0) { /* end of the line */
649 while (nptr != (afs_int32)NULL) {
650 code = pr_ReadCoEntry(tt,0,nptr,&nentry);
651 if (code != 0) return code;
653 if (!(nentry.flags & PRCONT)) return PRDBFAIL;
654 for (i=0;i<COSIZE;i++) {
655 if (nentry.entries[i] == aid)
657 if (nentry.entries[i] == PRBADID) {
663 else if (nentry.entries[i] == 0) {
673 if (slot != -1) { /* we found a place */
675 if (first) { /* place is in first block */
676 entry->entries[slot] = aid;
677 code = pr_WriteEntry (tt, 0, loc, entry);
678 if (code != 0) return code;
681 code = pr_WriteEntry (tt, 0, loc, entry);
682 if (code) return code;
683 code = pr_ReadCoEntry(tt,0,cloc,&aentry);
684 if (code != 0) return code;
685 aentry.entries[slot] = aid;
686 code = pr_WriteCoEntry(tt,0,cloc,&aentry);
687 if (code != 0) return code;
690 /* have to allocate a continuation block if we got here */
691 nptr = AllocBlock(tt);
693 /* then we should tack new block after last block in cont. chain */
695 code = pr_WriteCoEntry(tt,0,last,&nentry);
696 if (code != 0) return code;
701 memset(&aentry, 0, sizeof(aentry));
702 aentry.flags |= PRCONT;
703 aentry.id = entry->id;
705 aentry.entries[0] = aid;
706 code = pr_WriteCoEntry(tt,0,nptr,&aentry);
707 if (code != 0) return code;
708 /* don't forget to update count, here! */
710 code = pr_WriteEntry (tt, 0, loc, entry);
715 afs_int32 AddToPRList (alist, sizeP, id)
723 if (alist->prlist_len >= *sizeP) {
724 count = alist->prlist_len + 100;
725 if (alist->prlist_val) {
726 tmp = (char *) realloc(alist->prlist_val, count*sizeof(afs_int32));
728 tmp = (char *) malloc(count*sizeof(afs_int32));
730 if (!tmp) return(PRNOMEM);
731 alist->prlist_val = (afs_int32 *)tmp;
734 alist->prlist_val[alist->prlist_len++] = id;
738 afs_int32 GetList (at, tentry, alist, add)
739 struct ubik_trans *at;
740 struct prentry *tentry;
746 struct contentry centry;
752 alist->prlist_val = 0;
753 alist->prlist_len = 0;
755 for (i=0;i<PRSIZE;i++) {
756 if (tentry->entries[i] == PRBADID) continue;
757 if (tentry->entries[i] == 0) break;
758 code = AddToPRList (alist, &size, tentry->entries[i]);
759 if (code) return code;
762 for (nptr = tentry->next; nptr != 0; nptr = centry.next) {
763 /* look through cont entries */
764 code = pr_ReadCoEntry(at,0,nptr,¢ry);
765 if (code != 0) return code;
766 for (i=0;i<COSIZE;i++) {
767 if (centry.entries[i] == PRBADID) continue;
768 if (centry.entries[i] == 0) break;
769 code = AddToPRList (alist, &size, centry.entries[i]);
770 if (code) return code;
772 if (count++ > 50) IOMGR_Poll(), count = 0;
775 if (add) { /* this is for a CPS, so tack on appropriate stuff */
776 if (tentry->id != ANONYMOUSID && tentry->id != ANYUSERID) {
777 if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
778 (code = AddAuthGroup(tentry, alist, &size)) ||
779 (code = AddToPRList (alist, &size, tentry->id))) return code;
782 if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
783 (code = AddToPRList (alist, &size, tentry->id))) return code;
786 if (alist->prlist_len > 100) IOMGR_Poll();
787 qsort(alist->prlist_val,alist->prlist_len,sizeof(afs_int32),IDCmp);
792 afs_int32 GetList2 (at, tentry, tentry2 , alist, add)
793 struct ubik_trans *at;
794 struct prentry *tentry;
795 struct prentry *tentry2;
801 struct contentry centry;
807 alist->prlist_val = 0;
808 alist->prlist_len = 0;
809 for (i=0;i<PRSIZE;i++) {
810 if (tentry->entries[i] == PRBADID) continue;
811 if (tentry->entries[i] == 0) break;
812 code = AddToPRList (alist, &size, tentry->entries[i]);
813 if (code) return code;
817 while (nptr != (afs_uint32)NULL) {
818 /* look through cont entries */
819 code = pr_ReadCoEntry(at,0,nptr,¢ry);
820 if (code != 0) return code;
821 for (i=0;i<COSIZE;i++) {
822 if (centry.entries[i] == PRBADID) continue;
823 if (centry.entries[i] == 0) break;
824 code = AddToPRList (alist, &size, centry.entries[i]);
825 if (code) return code;
828 if (count++ > 50) IOMGR_Poll(), count = 0;
831 for (i=0;i<PRSIZE;i++) {
832 if (tentry2->entries[i] == PRBADID) continue;
833 if (tentry2->entries[i] == 0) break;
834 code = AddToPRList (alist, &size, tentry2->entries[i]);
839 nptr = tentry2->next;
840 while (nptr != (afs_uint32)NULL) {
841 /* look through cont entries */
842 code = pr_ReadCoEntry(at,0,nptr,¢ry);
843 if (code != 0) break;
844 for (i=0;i<COSIZE;i++) {
845 if (centry.entries[i] == PRBADID) continue;
846 if (centry.entries[i] == 0) break;
847 code = AddToPRList (alist, &size, centry.entries[i]);
851 if (count++ > 50) IOMGR_Poll(), count = 0;
854 if (add) { /* this is for a CPS, so tack on appropriate stuff */
855 if (tentry->id != ANONYMOUSID && tentry->id != ANYUSERID) {
856 if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
857 (code = AddToPRList (alist, &size, AUTHUSERID)) ||
858 (code = AddToPRList (alist, &size, tentry->id))) return code;
861 if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
862 (code = AddToPRList (alist, &size, tentry->id))) return code;
865 if (alist->prlist_len > 100) IOMGR_Poll();
866 qsort(alist->prlist_val,alist->prlist_len,sizeof(afs_int32),IDCmp);
870 afs_int32 GetOwnedChain (ut, next, alist)
871 struct ubik_trans *ut;
875 struct prentry tentry;
880 alist->prlist_val = 0;
881 alist->prlist_len = 0;
883 for (; *next; *next = ntohl(tentry.nextOwned)) {
884 code = pr_Read (ut, 0, *next, &tentry, sizeof(tentry));
885 if (code) return code;
886 code = AddToPRList (alist, &size, ntohl(tentry.id));
887 if (alist->prlist_len >= PR_MAXGROUPS) {
890 if (code) return code;
891 if (count++ > 50) IOMGR_Poll(), count = 0;
893 if (alist->prlist_len > 100) IOMGR_Poll();
894 qsort(alist->prlist_val,alist->prlist_len,sizeof(afs_int32),IDCmp);
898 afs_int32 GetMax(at,uid,gid)
899 struct ubik_trans *at;
903 *uid = ntohl(cheader.maxID);
904 *gid = ntohl(cheader.maxGroup);
908 afs_int32 SetMax(at,id,flag)
909 struct ubik_trans *at;
915 cheader.maxGroup = htonl(id);
916 code = pr_Write(at,0,16,(char *)&cheader.maxGroup,sizeof(cheader.maxGroup));
917 if (code != 0) return code;
920 cheader.maxID = htonl(id);
921 code = pr_Write(at,0,20,(char *)&cheader.maxID,sizeof(cheader.maxID));
922 if (code != 0) return code;
927 afs_int32 read_DbHeader(tt)
928 struct ubik_trans *tt;
932 if (!ubik_CacheUpdate(tt)) return 0;
934 code = pr_Read(tt, 0, 0, (char *)&cheader, sizeof(cheader));
936 com_err (whoami, code, "Couldn't read header");
947 struct ubik_trans *tt;
950 /* init the database. We'll try reading it, but if we're starting
951 * from scratch, we'll have to do a write transaction. */
953 pr_noAuth = afsconf_GetNoAuthFlag(prdir);
955 code = ubik_BeginTransReadAny(dbase,UBIK_READTRANS, &tt);
956 if (code) return code;
957 code = ubik_SetLock(tt,1,1,LOCKREAD);
964 } else if (!ubik_CacheUpdate (tt)) {
965 code = ubik_EndTrans(tt);
969 len = sizeof(cheader);
970 code = pr_Read(tt, 0, 0, (char *) &cheader, len);
972 com_err (whoami, code, "couldn't read header");
976 if ((ntohl(cheader.version) == PRDBVERSION) &&
977 ntohl(cheader.headerSize) == sizeof(cheader) &&
978 ntohl(cheader.eofPtr) != (afs_uint32)NULL &&
979 FindByID(tt,ANONYMOUSID) != 0){
980 /* database exists, so we don't have to build it */
981 code = ubik_EndTrans(tt);
982 if (code) return code;
985 /* else we need to build a database */
986 code = ubik_EndTrans(tt);
987 if (code) return code;
989 /* Only rebuild database if the db was deleted (the header is zero) and we
990 are running noAuth. */
991 { char *bp = (char *)&cheader;
993 for (i=0; i<sizeof(cheader); i++)
996 com_err (whoami, code,
997 "Can't rebuild database because it is not empty");
1003 com_err (whoami, code,
1004 "Can't rebuild database because not running NoAuth");
1008 code = ubik_BeginTrans(dbase,UBIK_WRITETRANS, &tt);
1009 if (code) return code;
1011 code = ubik_SetLock(tt,1,1,LOCKWRITE);
1013 ubik_AbortTrans(tt);
1017 /* before doing a rebuild, check again that the dbase looks bad, because
1018 * the previous check was only under a ReadAny transaction, and there could
1019 * actually have been a good database out there. Now that we have a
1020 * real write transaction, make sure things are still bad.
1022 if ((ntohl(cheader.version) == PRDBVERSION) &&
1023 ntohl(cheader.headerSize) == sizeof(cheader) &&
1024 ntohl(cheader.eofPtr) != (afs_uint32)NULL &&
1025 FindByID(tt,ANONYMOUSID) != 0){
1026 /* database exists, so we don't have to build it */
1027 code = ubik_EndTrans(tt);
1028 if (code) return code;
1032 /* Initialize the database header */
1033 if ((code = set_header_word (tt, version, htonl(PRDBVERSION))) ||
1034 (code = set_header_word (tt, headerSize, htonl(sizeof(cheader)))) ||
1035 (code = set_header_word (tt, eofPtr, cheader.headerSize))) {
1036 com_err (whoami, code, "couldn't write header words");
1037 ubik_AbortTrans(tt);
1041 #define InitialGroup(id,name) do { \
1042 afs_int32 temp = (id); \
1043 afs_int32 flag = (id) < 0 ? PRGRP : 0; \
1044 code = CreateEntry \
1045 (tt, (name), &temp, /*idflag*/1, flag, SYSADMINID, SYSADMINID); \
1047 com_err (whoami, code, "couldn't create %s with id %di.", \
1049 ubik_AbortTrans(tt); \
1054 InitialGroup (SYSADMINID, "system:administrators");
1055 InitialGroup (SYSBACKUPID, "system:backup");
1056 InitialGroup (ANYUSERID, "system:anyuser");
1057 InitialGroup (AUTHUSERID, "system:authuser");
1058 InitialGroup (SYSVIEWERID, "system:ptsviewers");
1059 InitialGroup (ANONYMOUSID, "anonymous");
1061 /* Well, we don't really want the max id set to anonymousid, so we'll set
1063 code = set_header_word (tt, maxID, 0); /* correct in any byte order */
1065 com_err (whoami, code, "couldn't reset max id");
1066 ubik_AbortTrans(tt);
1070 code = ubik_EndTrans(tt);
1071 if (code) return code;
1075 afs_int32 ChangeEntry (at, aid, cid, name, oid, newid)
1076 struct ubik_trans *at;
1084 afs_int32 i, nptr, pos;
1085 struct contentry centry;
1086 struct prentry tentry, tent;
1089 char holder[PR_MAXNAMELEN];
1090 char temp[PR_MAXNAMELEN];
1091 char oldname[PR_MAXNAMELEN];
1094 memset(holder, 0, PR_MAXNAMELEN);
1095 memset(temp, 0, PR_MAXNAMELEN);
1096 loc = FindByID(at,aid);
1097 if (!loc) return PRNOENT;
1098 code = pr_ReadEntry(at,0,loc,&tentry);
1099 if (code) return PRDBFAIL;
1100 if (tentry.owner != cid &&
1101 !IsAMemberOf(at,cid,SYSADMINID) &&
1102 !IsAMemberOf(at,cid,tentry.owner) &&
1103 !pr_noAuth) return PRPERM;
1104 #ifdef PR_REMEMBER_TIMES
1105 tentry.changeTime = time(0);
1108 /* we're actually trying to change the id */
1109 if (newid && (newid != aid)) {
1110 if (!IsAMemberOf(at,cid,SYSADMINID) && !pr_noAuth) return PRPERM;
1112 pos = FindByID(at,newid);
1113 if (pos) return PRIDEXIST; /* new id already in use! */
1114 if ((aid < 0 && newid > 0) || (aid > 0 && newid < 0)) return PRPERM;
1116 /* Should check that foreign users id to change to is good: inRange() */
1118 /* if new id is not in use, rehash things */
1119 code = RemoveFromIDHash(at,aid,&loc);
1120 if (code != PRSUCCESS) return code;
1122 code = pr_WriteEntry(at,0,loc,&tentry);
1123 if (code) return code;
1124 code = AddToIDHash(at,tentry.id,loc);
1125 if (code) return code;
1127 /* get current data */
1128 code = pr_ReadEntry(at, 0, loc, &tentry);
1129 if (code) return PRDBFAIL;
1131 /* Also change the references from the membership list */
1132 for (i=0; i<PRSIZE; i++) {
1133 if (tentry.entries[i] == PRBADID) continue;
1134 if (tentry.entries[i] == 0) break;
1135 pos = FindByID(at, tentry.entries[i]);
1136 if (!pos) return(PRDBFAIL);
1137 code = RemoveFromEntry(at, aid, tentry.entries[i]);
1138 if (code) return code;
1139 code = pr_ReadEntry(at, 0, pos, &tent);
1140 if (code) return code;
1141 code = AddToEntry(at, &tent, pos, newid);
1142 if (code) return code;
1144 /* Look through cont entries too. This needs to be broken into
1145 * seperate transaction so that no one transaction becomes too
1146 * large to complete.
1148 for (nptr=tentry.next; nptr; nptr=centry.next) {
1149 code = pr_ReadCoEntry(at, 0, nptr, ¢ry);
1150 if (code) return code;
1151 for (i=0; i<COSIZE; i++) {
1152 if (centry.entries[i] == PRBADID) continue;
1153 if (centry.entries[i] == 0) break;
1154 pos = FindByID(at, centry.entries[i]);
1155 if (!pos) return(PRDBFAIL);
1156 code = RemoveFromEntry(at, aid, centry.entries[i]);
1157 if (code) return code;
1158 code = pr_ReadEntry(at, 0, pos, &tent);
1159 if (code) return code;
1160 code = AddToEntry(at, &tent, pos, newid);
1161 if (code) return code;
1166 atsign = strchr(tentry.name, '@'); /* check for foreign entry */
1168 /* Change the owner */
1169 if (oid && (oid != tentry.owner)) {
1170 /* only groups can have their owner's changed */
1171 if (!(tentry.flags & PRGRP)) return PRPERM;
1172 if (atsign != NULL) return PRPERM;
1173 oldowner = tentry.owner;
1175 /* The entry must be written through first so Remove and Add routines
1176 * can operate on disk data */
1177 code = pr_WriteEntry(at,0,loc,(char *)&tentry);
1178 if (code) return PRDBFAIL;
1180 /* switch owner chains */
1181 if (oldowner) /* if it has an owner */
1182 code = RemoveFromOwnerChain(at,tentry.id,oldowner);
1183 else /* must be an orphan */
1184 code = RemoveFromOrphan(at,tentry.id);
1185 if (code) return code;
1186 code = AddToOwnerChain(at,tentry.id,tentry.owner);
1187 if (code) return code;
1189 /* fix up the name */
1190 if (strlen(name) == 0) name = tentry.name;
1191 /* get current data */
1192 code = pr_ReadEntry(at,0,loc,&tentry);
1193 if (code) return PRDBFAIL;
1196 /* Change the name, if name is a ptr to tentry.name then this name change
1197 * is due to a chown, otherwise caller has specified a new name */
1198 if ((name == tentry.name) ||
1199 (*name && (strcmp (tentry.name, name) != 0))) {
1200 strncpy (oldname, tentry.name, PR_MAXNAMELEN);
1201 if (tentry.flags & PRGRP) {
1202 /* don't let foreign cell groups change name */
1203 if (atsign != NULL) return PRPERM;
1204 code = CorrectGroupName (at, name, cid, tentry.owner, tentry.name);
1205 if (code) return code;
1207 if (name == tentry.name) { /* owner fixup */
1208 if (strcmp (oldname, tentry.name) == 0) goto nameOK;
1209 } else { /* new name, caller must be correct */
1210 if (strcmp (name, tentry.name) != 0) return PRBADNAM;
1214 /* Allow a foreign name change only if the cellname part is
1219 newatsign = strchr(name, '@');
1220 if (newatsign != atsign){ /* if they are the same no problem*/
1221 /*if the pointers are not equal the strings better be */
1222 if ((atsign == NULL) || (newatsign == NULL) ||
1223 strcmp (atsign,newatsign)) return PRPERM;
1225 if (!CorrectUserName(name)) return PRBADNAM;
1228 pos = FindByName(at,name, &tent);
1229 if (pos) return PREXIST;
1230 code = RemoveFromNameHash (at, oldname, &loc);
1231 if (code != PRSUCCESS) return code;
1232 strncpy (tentry.name, name, PR_MAXNAMELEN);
1233 code = pr_WriteEntry(at,0,loc,(char *)&tentry);
1234 if (code) return PRDBFAIL;
1235 code = AddToNameHash(at,tentry.name,loc);
1236 if (code != PRSUCCESS) return code;
1243 afs_int32 allocNextId(cellEntry)
1244 struct prentry *cellEntry;
1246 /* Id's for foreign cell entries are constructed as follows:
1247 The 16 low order bits are the group id of the cell and the
1248 top 16 bits identify the particular users in that cell */
1253 id = (ntohl(cellEntry -> nusers) +1);
1254 cellEntry->nusers = htonl(id);
1255 /* use the field nusers to keep
1256 the next available id in that
1257 foreign cell's group. Note :
1258 It would seem more appropriate
1259 to use ngroup for that and nusers
1260 to enforce the quota, however pts
1261 does not have an option to change
1262 foreign users quota yet */
1264 id = (id << 16) | ((ntohl(cellEntry-> id)) & 0x0000ffff);
1268 int inRange(cellEntry,aid)
1269 struct prentry *cellEntry;
1272 afs_uint32 id,cellid,groupid;
1276 The only thing that we want to make sure here is that
1277 the id is in the legal range of this group. If it is
1278 a duplicate we don't care since it will get caught
1279 in a different check.
1282 cellid = aid & 0x0000ffff;
1283 groupid = (ntohl(cellEntry-> id)) & 0x0000ffff;
1284 if (cellid != groupid) return 0; /* not in range */
1287 if we got here we're ok but we need to update the nusers
1288 field in order to get the id correct the next time that
1289 we try to allocate it automatically
1293 if (id > ntohl(cellEntry -> nusers))
1294 cellEntry -> nusers = htonl(id);
1299 AddAuthGroup(tentry, alist, size)
1300 struct prentry *tentry;
1304 if (!(strchr(tentry->name, '@')))
1305 return (AddToPRList (alist, size, AUTHUSERID));