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 <afs/param.h>
12 #include <sys/types.h>
17 #include <netinet/in.h>
23 #include <afs/com_err.h>
28 /* Foreign cells are represented by the group system:authuser@cell*/
29 #define AUTHUSER_GROUP "system:authuser"
32 extern struct ubik_dbase *dbase;
33 extern struct afsconf_dir *prdir;
36 extern afs_int32 AddToEntry();
37 static char *whoami = "ptserver";
39 /* CorrectUserName - Check to make sure a user name is OK. It must not include
40 * either a colon (or it would look like a group) or an atsign (or it would
41 * look like a foreign user). The length is checked as well to make sure
42 * that the user name, an atsign, and the local cell name will fit in
43 * PR_MAXNAMELEN. This is so this user can fit in another cells database as
44 * a foreign user with our cell name tacked on. This is a predicate, so it
45 * return one if name is OK and zero if name is bogus. */
47 static int CorrectUserName (name)
50 extern int pr_realmNameLen;
52 /* We accept foreign names, so we will deal with '@' later */
53 if (index (name, ':') || index(name, '\n')) return 0;
54 if (strlen (name) >= PR_MAXNAMELEN - pr_realmNameLen - 1) return 0;
58 /* CorrectGroupName - Like the above but handles more complicated cases caused
59 * by including the ownership in the name. The interface works by calculating
60 * the correct name based on a given name and owner. This allows easy use by
61 * rename, which then compares the correct name with the requested new name. */
63 static afs_int32 CorrectGroupName (ut, aname, cid, oid, cname)
64 struct ubik_trans *ut;
65 char aname[PR_MAXNAMELEN]; /* name for group */
66 afs_int32 cid; /* caller id */
67 afs_int32 oid; /* owner of group */
68 char cname[PR_MAXNAMELEN]; /* correct name for group */
72 char *prefix; /* ptr to group owner part */
73 char *suffix; /* ptr to group name part */
74 char name[PR_MAXNAMELEN]; /* correct name for group */
75 struct prentry tentry;
77 if (strlen (aname) >= PR_MAXNAMELEN) return PRBADNAM;
78 admin = pr_noAuth || IsAMemberOf (ut, cid, SYSADMINID);
80 if (oid == 0) oid = cid;
82 /* Determine the correct prefix for the name. */
83 if (oid == SYSADMINID) prefix = "system";
85 afs_int32 loc = FindByID (ut, oid);
87 /* let admin create groups owned by non-existent ids (probably
88 * setting a group to own itself). Check that they look like
89 * groups (with a colon) or otherwise are good user names. */
91 strcpy (cname, aname);
96 code = pr_Read (ut, 0, loc, &tentry, sizeof(tentry));
97 if (code) return code;
98 if (ntohl(tentry.flags) & PRGRP) {
99 if ((tentry.count == 0) && !admin) return PRGROUPEMPTY;
100 /* terminate prefix at colon if there is one */
101 if (prefix = index(tentry.name, ':')) *prefix = 0;
103 prefix = tentry.name;
105 /* only sysadmin allow to use 'system:' prefix */
106 if ((strcmp (prefix, "system") == 0) && !admin) return PRPERM;
108 strcpy (name, aname); /* in case aname & cname are same */
109 suffix = index(name, ':');
111 /* sysadmin can make groups w/o ':', but they must still look like
112 * legal user names. */
113 if (!admin) return PRBADNAM;
114 strcpy (cname, name);
117 if (strlen(prefix)+strlen(suffix) >= PR_MAXNAMELEN) return PRBADNAM;
118 strcpy (cname, prefix);
119 strcat (cname, suffix);
122 /* check for legal name with either group rules or user rules */
123 if (suffix = index(cname, ':')) {
124 /* check for confusing characters */
125 if (index(cname, '\n') || /* restrict so recreate can work */
126 index(suffix+1, ':')) /* avoid multiple colons */
129 if (!CorrectUserName (cname)) return PRBADNAM;
134 int AccessOK (ut, cid, tentry, mem, any)
135 struct ubik_trans *ut;
136 afs_int32 cid; /* caller id */
137 struct prentry *tentry; /* object being accessed */
138 int mem; /* check membership in aid, if group */
139 int any; /* if set return true */
144 if (pr_noAuth) return 1;
145 if (cid == SYSADMINID) return 1; /* special case fileserver */
147 flags = tentry->flags;
151 flags = oid = aid = 0;
153 if (!(flags & PRACCESS)) /* provide default access */
155 flags |= PRP_GROUP_DEFAULT;
157 flags |= PRP_USER_DEFAULT;
159 if (flags & any) return 1;
162 IsAMemberOf (ut, cid, oid)) return 1;
164 if (aid > 0) { /* checking on a user */
165 if (aid == cid) return 1;
166 } else if (aid < 0) { /* checking on group */
167 if ((flags & mem) && IsAMemberOf (ut, cid, aid)) return 1;
169 if (IsAMemberOf (ut, cid, SYSADMINID)) return 1;
170 return 0; /* no access */
173 afs_int32 CreateEntry (at, aname, aid, idflag, flag, oid, creator)
174 struct ubik_trans *at;
175 char aname[PR_MAXNAMELEN];
182 /* get and init a new entry */
185 struct prentry tentry, tent;
188 bzero(&tentry, sizeof(tentry));
190 if ((oid == 0) || (oid == ANONYMOUSID)) oid = creator;
193 code = CorrectGroupName (at, aname, creator, oid, tentry.name);
194 if (code) return code;
195 if (strcmp (aname, tentry.name) != 0) return PRBADNAM;
196 } else { /* non-group must not have colon */
197 if (!CorrectUserName(aname)) return PRBADNAM;
198 strcpy (tentry.name, aname);
201 if (FindByName(at,aname, &tent)) return PREXIST;
203 newEntry = AllocBlock(at);
204 if (!newEntry) return PRDBFAIL;
205 #ifdef PR_REMEMBER_TIMES
206 tentry.createTime = time(0);
210 tentry.flags = PRGRP;
212 } else if (flag == 0) {
214 tentry.owner = SYSADMINID;
219 atsign = index(aname,'@');
221 /* A normal user or group. Pick an id for it */
225 code= AllocID(at,flag,&tentry.id);
226 if (code != PRSUCCESS) return code;
228 } else if (flag & PRGRP) {
229 /* A foreign group. Its format must be AUTHUSER_GROUP@cellname
230 * Then pick an id for the group.
235 badFormat = strcmp(AUTHUSER_GROUP, aname);
237 if (badFormat) return PRBADNAM;
242 code= AllocID(at,flag,&tentry.id);
243 if (code != PRSUCCESS) return code;
246 /* A foreign user: <name>@<cell>. The foreign user is added to
247 * its representing group. It is
251 struct prentry centry;
252 extern afs_int32 allocNextId();
254 /* To create the user <name>@<cell> the group AUTHUSER_GROUP@<cell>
257 cellGroup = (char *)malloc(strlen(AUTHUSER_GROUP) + strlen(atsign) + 1);
258 strcpy(cellGroup, AUTHUSER_GROUP);
259 strcat(cellGroup, atsign);
260 pos = FindByName(at, cellGroup, ¢ry);
261 if (!pos) return PRBADNAM;
262 code = pr_Read (at, 0, pos, ¢ry, sizeof(centry));
263 if (code) return code;
265 /* cellid is the id of the group representing the cell */
266 tentry.cellid = ntohl(centry.id);
269 /* Check if id is good */
270 if (!inRange(¢ry,*aid)) return PRBADARG;
273 /* Allocate an ID special for this foreign user. It is based
274 * on the representing group's id and nusers count.
276 tentry.id = allocNextId(¢ry);
279 /* The foreign user will be added to the representing foreign
280 * group. The group can hold up to 30 entries.
282 if (!(ntohl(centry.flags) & PRQUOTA)) {
283 centry.flags = htonl (ntohl(centry.flags) | PRQUOTA);
284 centry.ngroups = htonl(30);
286 n = ntohl(centry.ngroups);
287 if ( (n <= 0) && !pr_noAuth ) return PRNOMORE;
288 centry.ngroups = htonl(n - 1);
290 /* write updated entry for group */
291 code = pr_Write (at, 0, pos, ¢ry, sizeof(centry));
293 /* Now add the new user entry to the database */
294 tentry.creator = creator;
296 code = pr_WriteEntry(at, 0, newEntry, &tentry);
297 if (code) return PRDBFAIL;
298 code = AddToIDHash(at, *aid, newEntry);
299 if (code != PRSUCCESS) return code;
300 code = AddToNameHash(at, aname, newEntry);
301 if (code != PRSUCCESS) return code;
302 if (inc_header_word (at, foreigncount, 1)) return PRDBFAIL;
304 /* Now add the entry to the authuser group for this cell.
305 * We will reread the entries for the user and the group
306 * instead of modifying them before writing them in the
307 * previous steps. Although not very efficient, much simpler
309 pos = FindByID(at, tentry.cellid);
310 if (!pos) return PRBADNAM;
311 code = pr_ReadEntry (at, 0, pos, ¢ry);
312 if (code) return code;
313 code = AddToEntry(at, ¢ry, pos, *aid);
314 if (code) return code;
315 /* and now the user entry */
316 pos = FindByID(at,*aid);
317 if (!pos) return PRBADNAM;
318 code = pr_ReadEntry (at, 0, pos, &tentry);
319 if (code) return code;
320 code = AddToEntry(at, &tentry, pos, tentry.cellid);
321 if (code) return code;
326 /* Remember the largest group id or largest user id */
328 /* group ids are negative */
329 if (tentry.id < (afs_int32)ntohl(cheader.maxGroup)) {
330 code = set_header_word (at, maxGroup, htonl(tentry.id));
331 if (code) return PRDBFAIL;
335 if (tentry.id > (afs_int32)ntohl(cheader.maxID)) {
336 code = set_header_word (at, maxID, htonl(tentry.id));
337 if (code) return PRDBFAIL;
341 /* Charge the creator for this group */
343 afs_int32 loc = FindByID (at, creator);
344 struct prentry centry;
347 if (loc) { /* this should only fail during initialization */
348 code = pr_Read (at, 0, loc, ¢ry, sizeof(centry));
349 if (code) return code;
351 /* If quota is uninitialized, do it */
352 if (!(ntohl(centry.flags) & PRQUOTA)) {
353 centry.flags = htonl (ntohl(centry.flags) | PRQUOTA);
354 centry.ngroups = centry.nusers = htonl(20);
357 /* Admins don't get charged for creating a group.
358 * If in noAuth mode, you get changed for it but you
359 * are still allowed to create as many groups as you want.
361 admin = ( (creator == SYSADMINID) ||
362 IsAMemberOf(at,creator,SYSADMINID) );
364 if (ntohl(centry.ngroups) <= 0) {
365 if (!pr_noAuth) return PRNOMORE;
367 centry.ngroups = htonl(ntohl(centry.ngroups)-1);
371 code = pr_Write (at, 0, loc, ¢ry, sizeof(centry));
372 if (code) return code;
376 /* Initialize the quota for the user. Groups don't have their
379 tentry.flags |= PRQUOTA;
380 tentry.ngroups = tentry.nusers = 20;
383 tentry.creator = creator;
385 code = pr_WriteEntry(at, 0, newEntry, &tentry);
386 if (code) return PRDBFAIL;
387 code = AddToIDHash(at,*aid,newEntry);
388 if (code != PRSUCCESS) return code;
389 code = AddToNameHash(at,aname,newEntry);
390 if (code != PRSUCCESS) return code;
391 if (tentry.flags & PRGRP) {
392 code = AddToOwnerChain(at,tentry.id,oid);
393 if (code) return code;
395 if (tentry.flags & PRGRP) {
396 if (inc_header_word (at, groupcount, 1)) return PRDBFAIL;
398 else if (tentry.flags & PRINST) {
399 if (inc_header_word (at, instcount, 1)) return PRDBFAIL;
402 if (inc_header_word (at, usercount, 1)) return PRDBFAIL;
408 /* RemoveFromEntry - remove aid from bid's entries list, freeing a continuation
409 * entry if appropriate */
411 afs_int32 RemoveFromEntry (at, aid, bid)
412 struct ubik_trans *at;
417 struct prentry tentry;
418 struct contentry centry;
419 struct contentry hentry;
425 if (aid == bid) return PRINCONSISTENT;
426 bzero(&hentry,sizeof(hentry));
427 temp = FindByID(at,bid);
428 if (temp == 0) return PRNOENT;
429 code = pr_ReadEntry(at, 0, temp, &tentry);
430 if (code != 0) return code;
431 #ifdef PR_REMEMBER_TIMES
432 tentry.removeTime = time(0);
434 for (i=0;i<PRSIZE;i++) {
435 if (tentry.entries[i] == aid) {
436 tentry.entries[i] = PRBADID;
438 code = pr_WriteEntry(at,0,temp,&tentry);
439 if (code != 0) return code;
442 if (tentry.entries[i] == 0) /* found end of list */
447 while (nptr != NULL) {
448 code = pr_ReadCoEntry(at,0,nptr,¢ry);
449 if (code != 0) return code;
450 if ((centry.id != bid) || !(centry.flags & PRCONT)) return PRDBBAD;
451 for (i=0;i<COSIZE;i++) {
452 if (centry.entries[i] == aid) {
453 centry.entries[i] = PRBADID;
454 for (j=0;j<COSIZE;j++)
455 if (centry.entries[j] != PRBADID &&
456 centry.entries[j] != 0) break;
457 if (j == COSIZE) { /* can free this block */
459 tentry.next = centry.next;
462 hentry.next = centry.next;
463 code = pr_WriteCoEntry (at, 0, hloc, &hentry);
464 if (code != 0) return code;
466 code = FreeBlock (at, nptr);
467 if (code) return code;
469 else { /* can't free it yet */
470 code = pr_WriteCoEntry(at,0,nptr,¢ry);
471 if (code != 0) return code;
474 code = pr_WriteEntry(at,0,temp,&tentry);
475 if (code) return PRDBFAIL;
478 if (centry.entries[i] == 0) return PRNOENT;
479 } /* for all coentry slots */
482 bcopy(¢ry,&hentry,sizeof(centry));
483 } /* while there are coentries */
487 /* DeleteEntry - delete the entry in tentry at loc, removing it from all
488 * groups, putting groups owned by it on orphan chain, and freeing the space */
490 afs_int32 DeleteEntry (at, tentry, loc)
491 struct ubik_trans *at;
492 struct prentry *tentry;
496 struct contentry centry;
500 if (index(tentry->name,'@')) {
501 if (tentry->flags & PRGRP) {
502 /* If there are still foreign user accounts from that cell
503 don't delete the group */
504 if (tentry->count) return PRBADARG;
508 afs_int32 loc = FindByID (at, tentry->cellid);
509 struct prentry centry;
511 code = pr_Read (at, 0, loc, ¢ry, sizeof(centry));
512 if (code) return code;
513 if (ntohl(centry.flags) & PRQUOTA) {
514 centry.ngroups = htonl(ntohl(centry.ngroups) + 1);
516 code = pr_Write (at, 0, loc, ¢ry, sizeof(centry));
517 if (code) return code;
521 /* First remove the entire membership list */
522 for (i=0;i<PRSIZE;i++) {
523 if (tentry->entries[i] == PRBADID) continue;
524 if (tentry->entries[i] == 0) break;
525 code = RemoveFromEntry (at, tentry->id, tentry->entries[i]);
526 if (code) return code;
529 while (nptr != NULL) {
530 code = pr_ReadCoEntry(at,0,nptr,¢ry);
531 if (code != 0) return PRDBFAIL;
532 for (i=0;i<COSIZE;i++) {
533 if (centry.entries[i] == PRBADID) continue;
534 if (centry.entries[i] == 0) break;
535 code = RemoveFromEntry (at, tentry->id, centry.entries[i]);
536 if (code) return code;
538 code = FreeBlock (at, nptr); /* free continuation block */
539 if (code) return code;
543 /* Remove us from other's owned chain. Note that this will zero our owned
544 * field (on disk) so this step must follow the above step in case we are
545 * on our own owned list. */
546 if (tentry->flags & PRGRP) {
548 code = RemoveFromOwnerChain (at, tentry->id, tentry->owner);
549 if (code) return code;
552 code = RemoveFromOrphan (at, tentry->id);
553 if (code) return code;
557 code = RemoveFromIDHash(at,tentry->id,&loc);
558 if (code != PRSUCCESS) return code;
559 code = RemoveFromNameHash(at,tentry->name,&loc);
560 if (code != PRSUCCESS) return code;
562 if (tentry->flags & PRGRP) {
563 afs_int32 loc = FindByID(at, tentry->creator);
564 struct prentry centry;
568 code = pr_Read (at, 0, loc, ¢ry, sizeof(centry));
569 if (code) return code;
570 admin = ( (tentry->creator == SYSADMINID) ||
571 IsAMemberOf(at,tentry->creator,SYSADMINID) );
572 if (ntohl(centry.flags) & PRQUOTA) {
573 if (!(admin && (ntohl(centry.ngroups) >= 20))) {
574 centry.ngroups = htonl(ntohl(centry.ngroups) + 1);
577 code = pr_Write (at, 0, loc, ¢ry, sizeof(centry));
578 if (code) return code;
582 if (tentry->flags & PRGRP) {
583 if (inc_header_word (at, groupcount, -1)) return PRDBFAIL;
585 else if (tentry->flags & PRINST) {
586 if (inc_header_word (at, instcount, -1)) return PRDBFAIL;
589 if (index(tentry->name,'@')) {
590 if (inc_header_word (at, foreigncount, -1)) return PRDBFAIL;
592 if (inc_header_word (at, usercount, -1)) return PRDBFAIL;
595 code = FreeBlock(at, loc);
599 /* AddToEntry - add aid to entry's entries list, alloc'ing a continuation block
602 * Note the entry is written out by this routine. */
604 afs_int32 AddToEntry (tt, entry, loc, aid)
605 struct ubik_trans *tt;
606 struct prentry *entry;
612 struct contentry nentry;
613 struct contentry aentry;
615 afs_int32 last; /* addr of last cont. block */
620 if (entry->id == aid) return PRINCONSISTENT;
621 #ifdef PR_REMEMBER_TIMES
622 entry->addTime = time(0);
624 for (i=0;i<PRSIZE;i++) {
625 if (entry->entries[i] == aid)
627 if (entry->entries[i] == PRBADID) { /* remember this spot */
631 else if (entry->entries[i] == 0) { /* end of the line */
641 while (nptr != NULL) {
642 code = pr_ReadCoEntry(tt,0,nptr,&nentry);
643 if (code != 0) return code;
645 if (!(nentry.flags & PRCONT)) return PRDBFAIL;
646 for (i=0;i<COSIZE;i++) {
647 if (nentry.entries[i] == aid)
649 if (nentry.entries[i] == PRBADID) {
655 else if (nentry.entries[i] == 0) {
665 if (slot != -1) { /* we found a place */
667 if (first) { /* place is in first block */
668 entry->entries[slot] = aid;
669 code = pr_WriteEntry (tt, 0, loc, entry);
670 if (code != 0) return code;
673 code = pr_WriteEntry (tt, 0, loc, entry);
674 if (code) return code;
675 code = pr_ReadCoEntry(tt,0,cloc,&aentry);
676 if (code != 0) return code;
677 aentry.entries[slot] = aid;
678 code = pr_WriteCoEntry(tt,0,cloc,&aentry);
679 if (code != 0) return code;
682 /* have to allocate a continuation block if we got here */
683 nptr = AllocBlock(tt);
685 /* then we should tack new block after last block in cont. chain */
687 code = pr_WriteCoEntry(tt,0,last,&nentry);
688 if (code != 0) return code;
693 bzero(&aentry,sizeof(aentry));
694 aentry.flags |= PRCONT;
695 aentry.id = entry->id;
697 aentry.entries[0] = aid;
698 code = pr_WriteCoEntry(tt,0,nptr,&aentry);
699 if (code != 0) return code;
700 /* don't forget to update count, here! */
702 code = pr_WriteEntry (tt, 0, loc, entry);
707 afs_int32 AddToPRList (alist, sizeP, id)
715 if (alist->prlist_len >= *sizeP) {
716 count = alist->prlist_len + 100;
717 if (alist->prlist_val) {
718 tmp = (char *) realloc(alist->prlist_val, count*sizeof(afs_int32));
720 tmp = (char *) malloc(count*sizeof(afs_int32));
722 if (!tmp) return(PRNOMEM);
723 alist->prlist_val = (afs_int32 *)tmp;
726 alist->prlist_val[alist->prlist_len++] = id;
730 afs_int32 GetList (at, tentry, alist, add)
731 struct ubik_trans *at;
732 struct prentry *tentry;
738 struct contentry centry;
742 extern afs_int32 IDCmp();
745 alist->prlist_val = 0;
746 alist->prlist_len = 0;
748 for (i=0;i<PRSIZE;i++) {
749 if (tentry->entries[i] == PRBADID) continue;
750 if (tentry->entries[i] == 0) break;
751 code = AddToPRList (alist, &size, tentry->entries[i]);
752 if (code) return code;
755 for (nptr = tentry->next; nptr != NULL; nptr = centry.next) {
756 /* look through cont entries */
757 code = pr_ReadCoEntry(at,0,nptr,¢ry);
758 if (code != 0) return code;
759 for (i=0;i<COSIZE;i++) {
760 if (centry.entries[i] == PRBADID) continue;
761 if (centry.entries[i] == 0) break;
762 code = AddToPRList (alist, &size, centry.entries[i]);
763 if (code) return code;
765 if (count++ > 50) IOMGR_Poll(), count = 0;
768 if (add) { /* this is for a CPS, so tack on appropriate stuff */
769 if (tentry->id != ANONYMOUSID && tentry->id != ANYUSERID) {
770 if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
771 (code = AddAuthGroup(tentry, alist, &size)) ||
772 (code = AddToPRList (alist, &size, tentry->id))) return code;
775 if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
776 (code = AddToPRList (alist, &size, tentry->id))) return code;
779 if (alist->prlist_len > 100) IOMGR_Poll();
780 qsort(alist->prlist_val,alist->prlist_len,sizeof(afs_int32),IDCmp);
785 afs_int32 GetList2 (at, tentry, tentry2 , alist, add)
786 struct ubik_trans *at;
787 struct prentry *tentry;
788 struct prentry *tentry2;
794 struct contentry centry;
798 extern afs_int32 IDCmp();
801 alist->prlist_val = 0;
802 alist->prlist_len = 0;
803 for (i=0;i<PRSIZE;i++) {
804 if (tentry->entries[i] == PRBADID) continue;
805 if (tentry->entries[i] == 0) break;
806 code = AddToPRList (alist, &size, tentry->entries[i]);
807 if (code) return code;
811 while (nptr != NULL) {
812 /* look through cont entries */
813 code = pr_ReadCoEntry(at,0,nptr,¢ry);
814 if (code != 0) return code;
815 for (i=0;i<COSIZE;i++) {
816 if (centry.entries[i] == PRBADID) continue;
817 if (centry.entries[i] == 0) break;
818 code = AddToPRList (alist, &size, centry.entries[i]);
819 if (code) return code;
822 if (count++ > 50) IOMGR_Poll(), count = 0;
825 for (i=0;i<PRSIZE;i++) {
826 if (tentry2->entries[i] == PRBADID) continue;
827 if (tentry2->entries[i] == 0) break;
828 code = AddToPRList (alist, &size, tentry2->entries[i]);
833 nptr = tentry2->next;
834 while (nptr != NULL) {
835 /* look through cont entries */
836 code = pr_ReadCoEntry(at,0,nptr,¢ry);
837 if (code != 0) break;
838 for (i=0;i<COSIZE;i++) {
839 if (centry.entries[i] == PRBADID) continue;
840 if (centry.entries[i] == 0) break;
841 code = AddToPRList (alist, &size, centry.entries[i]);
845 if (count++ > 50) IOMGR_Poll(), count = 0;
848 if (add) { /* this is for a CPS, so tack on appropriate stuff */
849 if (tentry->id != ANONYMOUSID && tentry->id != ANYUSERID) {
850 if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
851 (code = AddToPRList (alist, &size, AUTHUSERID)) ||
852 (code = AddToPRList (alist, &size, tentry->id))) return code;
855 if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
856 (code = AddToPRList (alist, &size, tentry->id))) return code;
859 if (alist->prlist_len > 100) IOMGR_Poll();
860 qsort(alist->prlist_val,alist->prlist_len,sizeof(afs_int32),IDCmp);
864 afs_int32 GetOwnedChain (ut, next, alist)
865 struct ubik_trans *ut;
869 struct prentry tentry;
872 extern afs_int32 IDCmp();
875 alist->prlist_val = 0;
876 alist->prlist_len = 0;
878 for (; *next; *next = ntohl(tentry.nextOwned)) {
879 code = pr_Read (ut, 0, *next, &tentry, sizeof(tentry));
880 if (code) return code;
881 code = AddToPRList (alist, &size, ntohl(tentry.id));
882 if (alist->prlist_len >= PR_MAXGROUPS) {
885 if (code) return code;
886 if (count++ > 50) IOMGR_Poll(), count = 0;
888 if (alist->prlist_len > 100) IOMGR_Poll();
889 qsort(alist->prlist_val,alist->prlist_len,sizeof(afs_int32),IDCmp);
893 afs_int32 GetMax(at,uid,gid)
894 struct ubik_trans *at;
898 *uid = ntohl(cheader.maxID);
899 *gid = ntohl(cheader.maxGroup);
903 afs_int32 SetMax(at,id,flag)
904 struct ubik_trans *at;
910 cheader.maxGroup = htonl(id);
911 code = pr_Write(at,0,16,(char *)&cheader.maxGroup,sizeof(cheader.maxGroup));
912 if (code != 0) return code;
915 cheader.maxID = htonl(id);
916 code = pr_Write(at,0,20,(char *)&cheader.maxID,sizeof(cheader.maxID));
917 if (code != 0) return code;
922 afs_int32 read_DbHeader(tt)
923 struct ubik_trans *tt;
927 if (!ubik_CacheUpdate(tt)) return 0;
929 code = pr_Read(tt, 0, 0, (char *)&cheader, sizeof(cheader));
931 com_err (whoami, code, "Couldn't read header");
942 struct ubik_trans *tt;
945 /* init the database. We'll try reading it, but if we're starting
946 * from scratch, we'll have to do a write transaction. */
948 pr_noAuth = afsconf_GetNoAuthFlag(prdir);
950 code = ubik_BeginTransReadAny(dbase,UBIK_READTRANS, &tt);
951 if (code) return code;
952 code = ubik_SetLock(tt,1,1,LOCKREAD);
959 } else if (!ubik_CacheUpdate (tt)) {
960 code = ubik_EndTrans(tt);
964 len = sizeof(cheader);
965 code = pr_Read(tt, 0, 0, (char *) &cheader, len);
967 com_err (whoami, code, "couldn't read header");
971 if ((ntohl(cheader.version) == PRDBVERSION) &&
972 ntohl(cheader.headerSize) == sizeof(cheader) &&
973 ntohl(cheader.eofPtr) != NULL &&
974 FindByID(tt,ANONYMOUSID) != 0){
975 /* database exists, so we don't have to build it */
976 code = ubik_EndTrans(tt);
977 if (code) return code;
980 /* else we need to build a database */
981 code = ubik_EndTrans(tt);
982 if (code) return code;
984 /* Only rebuild database if the db was deleted (the header is zero) and we
985 are running noAuth. */
986 { char *bp = (char *)&cheader;
988 for (i=0; i<sizeof(cheader); i++)
991 com_err (whoami, code,
992 "Can't rebuild database because it is not empty");
998 com_err (whoami, code,
999 "Can't rebuild database because not running NoAuth");
1003 code = ubik_BeginTrans(dbase,UBIK_WRITETRANS, &tt);
1004 if (code) return code;
1006 code = ubik_SetLock(tt,1,1,LOCKWRITE);
1008 ubik_AbortTrans(tt);
1012 /* before doing a rebuild, check again that the dbase looks bad, because
1013 * the previous check was only under a ReadAny transaction, and there could
1014 * actually have been a good database out there. Now that we have a
1015 * real write transaction, make sure things are still bad.
1017 if ((ntohl(cheader.version) == PRDBVERSION) &&
1018 ntohl(cheader.headerSize) == sizeof(cheader) &&
1019 ntohl(cheader.eofPtr) != NULL &&
1020 FindByID(tt,ANONYMOUSID) != 0){
1021 /* database exists, so we don't have to build it */
1022 code = ubik_EndTrans(tt);
1023 if (code) return code;
1027 /* Initialize the database header */
1028 if ((code = set_header_word (tt, version, htonl(PRDBVERSION))) ||
1029 (code = set_header_word (tt, headerSize, htonl(sizeof(cheader)))) ||
1030 (code = set_header_word (tt, eofPtr, cheader.headerSize))) {
1031 com_err (whoami, code, "couldn't write header words");
1032 ubik_AbortTrans(tt);
1036 #define InitialGroup(id,name) do { \
1037 afs_int32 temp = (id); \
1038 afs_int32 flag = (id) < 0 ? PRGRP : 0; \
1039 code = CreateEntry \
1040 (tt, (name), &temp, /*idflag*/1, flag, SYSADMINID, SYSADMINID); \
1042 com_err (whoami, code, "couldn't create %s with id %di.", \
1044 ubik_AbortTrans(tt); \
1049 InitialGroup (SYSADMINID, "system:administrators");
1050 InitialGroup (SYSBACKUPID, "system:backup");
1051 InitialGroup (ANYUSERID, "system:anyuser");
1052 InitialGroup (AUTHUSERID, "system:authuser");
1053 InitialGroup (ANONYMOUSID, "anonymous");
1055 /* Well, we don't really want the max id set to anonymousid, so we'll set
1057 code = set_header_word (tt, maxID, 0); /* correct in any byte order */
1059 com_err (whoami, code, "couldn't reset max id");
1060 ubik_AbortTrans(tt);
1064 code = ubik_EndTrans(tt);
1065 if (code) return code;
1069 afs_int32 ChangeEntry (at, aid, cid, name, oid, newid)
1070 struct ubik_trans *at;
1078 afs_int32 i, nptr, pos;
1079 struct contentry centry;
1080 struct prentry tentry, tent;
1083 char holder[PR_MAXNAMELEN];
1084 char temp[PR_MAXNAMELEN];
1085 char oldname[PR_MAXNAMELEN];
1088 bzero(holder,PR_MAXNAMELEN);
1089 bzero(temp,PR_MAXNAMELEN);
1090 loc = FindByID(at,aid);
1091 if (!loc) return PRNOENT;
1092 code = pr_ReadEntry(at,0,loc,&tentry);
1093 if (code) return PRDBFAIL;
1094 if (tentry.owner != cid &&
1095 !IsAMemberOf(at,cid,SYSADMINID) &&
1096 !IsAMemberOf(at,cid,tentry.owner) &&
1097 !pr_noAuth) return PRPERM;
1098 #ifdef PR_REMEMBER_TIMES
1099 tentry.changeTime = time(0);
1102 /* we're actually trying to change the id */
1103 if (newid && (newid != aid)) {
1104 if (!IsAMemberOf(at,cid,SYSADMINID) && !pr_noAuth) return PRPERM;
1106 pos = FindByID(at,newid);
1107 if (pos) return PRIDEXIST; /* new id already in use! */
1108 if ((aid < 0 && newid > 0) || (aid > 0 && newid < 0)) return PRPERM;
1110 /* Should check that foreign users id to change to is good: inRange() */
1112 /* if new id is not in use, rehash things */
1113 code = RemoveFromIDHash(at,aid,&loc);
1114 if (code != PRSUCCESS) return code;
1116 code = pr_WriteEntry(at,0,loc,&tentry);
1117 if (code) return code;
1118 code = AddToIDHash(at,tentry.id,loc);
1119 if (code) return code;
1121 /* get current data */
1122 code = pr_ReadEntry(at, 0, loc, &tentry);
1123 if (code) return PRDBFAIL;
1125 /* Also change the references from the membership list */
1126 for (i=0; i<PRSIZE; i++) {
1127 if (tentry.entries[i] == PRBADID) continue;
1128 if (tentry.entries[i] == 0) break;
1129 pos = FindByID(at, tentry.entries[i]);
1130 if (!pos) return(PRDBFAIL);
1131 code = RemoveFromEntry(at, aid, tentry.entries[i]);
1132 if (code) return code;
1133 code = pr_ReadEntry(at, 0, pos, &tent);
1134 if (code) return code;
1135 code = AddToEntry(at, &tent, pos, newid);
1136 if (code) return code;
1138 /* Look through cont entries too. This needs to be broken into
1139 * seperate transaction so that no one transaction becomes too
1140 * large to complete.
1142 for (nptr=tentry.next; nptr; nptr=centry.next) {
1143 code = pr_ReadCoEntry(at, 0, nptr, ¢ry);
1144 if (code) return code;
1145 for (i=0; i<COSIZE; i++) {
1146 if (centry.entries[i] == PRBADID) continue;
1147 if (centry.entries[i] == 0) break;
1148 pos = FindByID(at, centry.entries[i]);
1149 if (!pos) return(PRDBFAIL);
1150 code = RemoveFromEntry(at, aid, centry.entries[i]);
1151 if (code) return code;
1152 code = pr_ReadEntry(at, 0, pos, &tent);
1153 if (code) return code;
1154 code = AddToEntry(at, &tent, pos, newid);
1155 if (code) return code;
1160 atsign = index(tentry.name, '@'); /* check for foreign entry */
1162 /* Change the owner */
1163 if (oid && (oid != tentry.owner)) {
1164 /* only groups can have their owner's changed */
1165 if (!(tentry.flags & PRGRP)) return PRPERM;
1166 if (atsign != NULL) return PRPERM;
1167 oldowner = tentry.owner;
1169 /* The entry must be written through first so Remove and Add routines
1170 * can operate on disk data */
1171 code = pr_WriteEntry(at,0,loc,(char *)&tentry);
1172 if (code) return PRDBFAIL;
1174 /* switch owner chains */
1175 if (oldowner) /* if it has an owner */
1176 code = RemoveFromOwnerChain(at,tentry.id,oldowner);
1177 else /* must be an orphan */
1178 code = RemoveFromOrphan(at,tentry.id);
1179 if (code) return code;
1180 code = AddToOwnerChain(at,tentry.id,tentry.owner);
1181 if (code) return code;
1183 /* fix up the name */
1184 if (strlen(name) == 0) name = tentry.name;
1185 /* get current data */
1186 code = pr_ReadEntry(at,0,loc,&tentry);
1187 if (code) return PRDBFAIL;
1190 /* Change the name, if name is a ptr to tentry.name then this name change
1191 * is due to a chown, otherwise caller has specified a new name */
1192 if ((name == tentry.name) ||
1193 (*name && (strcmp (tentry.name, name) != 0))) {
1194 strncpy (oldname, tentry.name, PR_MAXNAMELEN);
1195 if (tentry.flags & PRGRP) {
1196 /* don't let foreign cell groups change name */
1197 if (atsign != NULL) return PRPERM;
1198 code = CorrectGroupName (at, name, cid, tentry.owner, tentry.name);
1199 if (code) return code;
1201 if (name == tentry.name) { /* owner fixup */
1202 if (strcmp (oldname, tentry.name) == 0) goto nameOK;
1203 } else { /* new name, caller must be correct */
1204 if (strcmp (name, tentry.name) != 0) return PRBADNAM;
1208 /* Allow a foreign name change only if the cellname part is
1213 newatsign = index (name, '@');
1214 if (newatsign != atsign){ /* if they are the same no problem*/
1215 /*if the pointers are not equal the strings better be */
1216 if ((atsign == NULL) || (newatsign == NULL) ||
1217 strcmp (atsign,newatsign)) return PRPERM;
1219 if (!CorrectUserName(name)) return PRBADNAM;
1222 pos = FindByName(at,name, &tent);
1223 if (pos) return PREXIST;
1224 code = RemoveFromNameHash (at, oldname, &loc);
1225 if (code != PRSUCCESS) return code;
1226 strncpy (tentry.name, name, PR_MAXNAMELEN);
1227 code = pr_WriteEntry(at,0,loc,(char *)&tentry);
1228 if (code) return PRDBFAIL;
1229 code = AddToNameHash(at,tentry.name,loc);
1230 if (code != PRSUCCESS) return code;
1237 afs_int32 allocNextId(cellEntry)
1238 struct prentry *cellEntry;
1240 /* Id's for foreign cell entries are constructed as follows:
1241 The 16 low order bits are the group id of the cell and the
1242 top 16 bits identify the particular users in that cell */
1247 id = (ntohl(cellEntry -> nusers) +1);
1248 cellEntry->nusers = htonl(id);
1249 /* use the field nusers to keep
1250 the next available id in that
1251 foreign cell's group. Note :
1252 It would seem more appropriate
1253 to use ngroup for that and nusers
1254 to enforce the quota, however pts
1255 does not have an option to change
1256 foreign users quota yet */
1258 id = (id << 16) | ((ntohl(cellEntry-> id)) & 0x0000ffff);
1262 int inRange(cellEntry,aid)
1263 struct prentry *cellEntry;
1266 afs_uint32 id,cellid,groupid;
1270 The only thing that we want to make sure here is that
1271 the id is in the legal range of this group. If it is
1272 a duplicate we don't care since it will get caught
1273 in a different check.
1276 cellid = aid & 0x0000ffff;
1277 groupid = (ntohl(cellEntry-> id)) & 0x0000ffff;
1278 if (cellid != groupid) return 0; /* not in range */
1281 if we got here we're ok but we need to update the nusers
1282 field in order to get the id correct the next time that
1283 we try to allocate it automatically
1287 if (id > ntohl(cellEntry -> nusers))
1288 cellEntry -> nusers = htonl(id);
1293 AddAuthGroup(tentry, alist, size)
1294 struct prentry *tentry;
1298 if (!(index(tentry->name, '@')))
1299 return (AddToPRList (alist, size, AUTHUSERID));