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>
33 #include <afs/com_err.h>
34 #include <afs/cellconfig.h>
39 /* Foreign cells are represented by the group system:authuser@cell*/
40 #define AUTHUSER_GROUP "system:authuser"
43 extern struct ubik_dbase *dbase;
44 extern struct afsconf_dir *prdir;
48 extern afs_int32 AddToEntry();
49 static char *whoami = "ptserver";
51 /* CorrectUserName - Check to make sure a user name is OK. It must not include
52 * either a colon (or it would look like a group) or an atsign (or it would
53 * look like a foreign user). The length is checked as well to make sure
54 * that the user name, an atsign, and the local cell name will fit in
55 * PR_MAXNAMELEN. This is so this user can fit in another cells database as
56 * a foreign user with our cell name tacked on. This is a predicate, so it
57 * return one if name is OK and zero if name is bogus. */
59 static int CorrectUserName (name)
62 extern int pr_realmNameLen;
64 /* We accept foreign names, so we will deal with '@' later */
65 if (strchr (name, ':') || strchr(name, '\n')) return 0;
66 if (strlen (name) >= PR_MAXNAMELEN - pr_realmNameLen - 1) return 0;
70 /* CorrectGroupName - Like the above but handles more complicated cases caused
71 * by including the ownership in the name. The interface works by calculating
72 * the correct name based on a given name and owner. This allows easy use by
73 * rename, which then compares the correct name with the requested new name. */
75 static afs_int32 CorrectGroupName (ut, aname, cid, oid, cname)
76 struct ubik_trans *ut;
77 char aname[PR_MAXNAMELEN]; /* name for group */
78 afs_int32 cid; /* caller id */
79 afs_int32 oid; /* owner of group */
80 char cname[PR_MAXNAMELEN]; /* correct name for group */
84 char *prefix; /* ptr to group owner part */
85 char *suffix; /* ptr to group name part */
86 char name[PR_MAXNAMELEN]; /* correct name for group */
87 struct prentry tentry;
89 if (strlen (aname) >= PR_MAXNAMELEN) return PRBADNAM;
90 admin = pr_noAuth || IsAMemberOf (ut, cid, SYSADMINID);
92 if (oid == 0) oid = cid;
94 /* Determine the correct prefix for the name. */
95 if (oid == SYSADMINID) prefix = "system";
97 afs_int32 loc = FindByID (ut, oid);
99 /* let admin create groups owned by non-existent ids (probably
100 * setting a group to own itself). Check that they look like
101 * groups (with a colon) or otherwise are good user names. */
103 strcpy (cname, aname);
108 code = pr_Read (ut, 0, loc, &tentry, sizeof(tentry));
109 if (code) return code;
110 if (ntohl(tentry.flags) & PRGRP) {
111 if ((tentry.count == 0) && !admin) return PRGROUPEMPTY;
112 /* terminate prefix at colon if there is one */
113 if ((prefix = strchr(tentry.name, ':'))) *prefix = 0;
115 prefix = tentry.name;
117 /* only sysadmin allow to use 'system:' prefix */
118 if ((strcmp (prefix, "system") == 0) && !admin) return PRPERM;
120 strcpy (name, aname); /* in case aname & cname are same */
121 suffix = strchr(name, ':');
123 /* sysadmin can make groups w/o ':', but they must still look like
124 * legal user names. */
125 if (!admin) return PRBADNAM;
126 strcpy (cname, name);
129 if (strlen(prefix)+strlen(suffix) >= PR_MAXNAMELEN) return PRBADNAM;
130 strcpy (cname, prefix);
131 strcat (cname, suffix);
134 /* check for legal name with either group rules or user rules */
135 if ((suffix = strchr(cname, ':'))) {
136 /* check for confusing characters */
137 if (strchr(cname, '\n') || /* restrict so recreate can work */
138 strchr(suffix+1, ':')) /* avoid multiple colons */
141 if (!CorrectUserName (cname)) return PRBADNAM;
146 int AccessOK (ut, cid, tentry, mem, any)
147 struct ubik_trans *ut;
148 afs_int32 cid; /* caller id */
149 struct prentry *tentry; /* object being accessed */
150 int mem; /* check membership in aid, if group */
151 int any; /* if set return true */
156 if (pr_noAuth) return 1;
157 if (cid == SYSADMINID) return 1; /* special case fileserver */
159 flags = tentry->flags;
163 flags = oid = aid = 0;
165 if (!(flags & PRACCESS)) { /* provide default access */
167 flags |= PRP_GROUP_DEFAULT;
169 flags |= PRP_USER_DEFAULT;
172 if (flags & any) return 1;
175 IsAMemberOf (ut, cid, oid)) return 1;
177 if (aid > 0) { /* checking on a user */
178 if (aid == cid) return 1;
179 } else if (aid < 0) { /* checking on group */
180 if ((flags & mem) && IsAMemberOf (ut, cid, aid)) return 1;
182 /* Allow members of SYSVIEWERID to get membership and status only */
183 if (((mem == PRP_STATUS_MEM)||(mem == PRP_MEMBER_MEM)||
184 (any == PRP_OWNED_ANY))&&(IsAMemberOf (ut, cid, SYSVIEWERID)))
186 if (IsAMemberOf (ut, cid, SYSADMINID)) return 1;
187 return 0; /* no access */
190 afs_int32 CreateEntry (at, aname, aid, idflag, flag, oid, creator)
191 struct ubik_trans *at;
192 char aname[PR_MAXNAMELEN];
199 /* get and init a new entry */
202 struct prentry tentry, tent;
205 memset(&tentry, 0, sizeof(tentry));
207 if ((oid == 0) || (oid == ANONYMOUSID)) oid = creator;
210 code = CorrectGroupName (at, aname, creator, oid, tentry.name);
211 if (code) return code;
212 if (strcmp (aname, tentry.name) != 0) return PRBADNAM;
213 } else { /* non-group must not have colon */
214 if (!CorrectUserName(aname)) return PRBADNAM;
215 strcpy (tentry.name, aname);
218 if (FindByName(at,aname, &tent)) return PREXIST;
220 newEntry = AllocBlock(at);
221 if (!newEntry) return PRDBFAIL;
222 #ifdef PR_REMEMBER_TIMES
223 tentry.createTime = time(0);
227 tentry.flags = PRGRP;
229 } else if (flag == 0) {
231 tentry.owner = SYSADMINID;
236 atsign = strchr(aname, '@');
238 /* A normal user or group. Pick an id for it */
242 code= AllocID(at,flag,&tentry.id);
243 if (code != PRSUCCESS) return code;
245 } else if (flag & PRGRP) {
246 /* A foreign group. Its format must be AUTHUSER_GROUP@cellname
247 * Then pick an id for the group.
252 badFormat = strcmp(AUTHUSER_GROUP, aname);
254 if (badFormat) return PRBADNAM;
259 code= AllocID(at,flag,&tentry.id);
260 if (code != PRSUCCESS) return code;
263 /* A foreign user: <name>@<cell>. The foreign user is added to
264 * its representing group. It is
268 struct prentry centry;
269 extern afs_int32 allocNextId();
271 /* To create the user <name>@<cell> the group AUTHUSER_GROUP@<cell>
274 cellGroup = (char *)malloc(strlen(AUTHUSER_GROUP) + strlen(atsign) + 1);
275 strcpy(cellGroup, AUTHUSER_GROUP);
276 strcat(cellGroup, atsign);
277 pos = FindByName(at, cellGroup, ¢ry);
278 if (!pos) return PRBADNAM;
279 code = pr_Read (at, 0, pos, ¢ry, sizeof(centry));
280 if (code) return code;
282 /* cellid is the id of the group representing the cell */
283 tentry.cellid = ntohl(centry.id);
286 /* Check if id is good */
287 if (!inRange(¢ry,*aid)) return PRBADARG;
290 /* Allocate an ID special for this foreign user. It is based
291 * on the representing group's id and nusers count.
293 tentry.id = allocNextId(¢ry);
296 /* The foreign user will be added to the representing foreign
297 * group. The group can hold up to 30 entries.
299 if (!(ntohl(centry.flags) & PRQUOTA)) {
300 centry.flags = htonl (ntohl(centry.flags) | PRQUOTA);
301 centry.ngroups = htonl(30);
303 n = ntohl(centry.ngroups);
304 if ( (n <= 0) && !pr_noAuth ) return PRNOMORE;
305 centry.ngroups = htonl(n - 1);
307 /* write updated entry for group */
308 code = pr_Write (at, 0, pos, ¢ry, sizeof(centry));
310 /* Now add the new user entry to the database */
311 tentry.creator = creator;
313 code = pr_WriteEntry(at, 0, newEntry, &tentry);
314 if (code) return PRDBFAIL;
315 code = AddToIDHash(at, *aid, newEntry);
316 if (code != PRSUCCESS) return code;
317 code = AddToNameHash(at, aname, newEntry);
318 if (code != PRSUCCESS) return code;
319 if (inc_header_word (at, foreigncount, 1)) return PRDBFAIL;
321 /* Now add the entry to the authuser group for this cell.
322 * We will reread the entries for the user and the group
323 * instead of modifying them before writing them in the
324 * previous steps. Although not very efficient, much simpler
326 pos = FindByID(at, tentry.cellid);
327 if (!pos) return PRBADNAM;
328 code = pr_ReadEntry (at, 0, pos, ¢ry);
329 if (code) return code;
330 code = AddToEntry(at, ¢ry, pos, *aid);
331 if (code) return code;
332 /* and now the user entry */
333 pos = FindByID(at,*aid);
334 if (!pos) return PRBADNAM;
335 code = pr_ReadEntry (at, 0, pos, &tentry);
336 if (code) return code;
337 code = AddToEntry(at, &tentry, pos, tentry.cellid);
338 if (code) return code;
343 /* Remember the largest group id or largest user id */
345 /* group ids are negative */
346 if (tentry.id < (afs_int32)ntohl(cheader.maxGroup)) {
347 code = set_header_word (at, maxGroup, htonl(tentry.id));
348 if (code) return PRDBFAIL;
352 if (tentry.id > (afs_int32)ntohl(cheader.maxID)) {
353 code = set_header_word (at, maxID, htonl(tentry.id));
354 if (code) return PRDBFAIL;
358 /* Charge the creator for this group */
360 afs_int32 loc = FindByID (at, creator);
361 struct prentry centry;
364 if (loc) { /* this should only fail during initialization */
365 code = pr_Read (at, 0, loc, ¢ry, sizeof(centry));
366 if (code) return code;
368 /* If quota is uninitialized, do it */
369 if (!(ntohl(centry.flags) & PRQUOTA)) {
370 centry.flags = htonl (ntohl(centry.flags) | PRQUOTA);
371 centry.ngroups = centry.nusers = htonl(20);
374 /* Admins don't get charged for creating a group.
375 * If in noAuth mode, you get changed for it but you
376 * are still allowed to create as many groups as you want.
378 admin = ( (creator == SYSADMINID) ||
379 IsAMemberOf(at,creator,SYSADMINID) );
381 if (ntohl(centry.ngroups) <= 0) {
382 if (!pr_noAuth) return PRNOMORE;
384 centry.ngroups = htonl(ntohl(centry.ngroups)-1);
388 code = pr_Write (at, 0, loc, ¢ry, sizeof(centry));
389 if (code) return code;
393 /* Initialize the quota for the user. Groups don't have their
396 tentry.flags |= PRQUOTA;
397 tentry.ngroups = tentry.nusers = 20;
400 tentry.creator = creator;
402 code = pr_WriteEntry(at, 0, newEntry, &tentry);
403 if (code) return PRDBFAIL;
404 code = AddToIDHash(at,*aid,newEntry);
405 if (code != PRSUCCESS) return code;
406 code = AddToNameHash(at,aname,newEntry);
407 if (code != PRSUCCESS) return code;
408 if (tentry.flags & PRGRP) {
409 code = AddToOwnerChain(at,tentry.id,oid);
410 if (code) return code;
412 if (tentry.flags & PRGRP) {
413 if (inc_header_word (at, groupcount, 1)) return PRDBFAIL;
415 else if (tentry.flags & PRINST) {
416 if (inc_header_word (at, instcount, 1)) return PRDBFAIL;
419 if (inc_header_word (at, usercount, 1)) return PRDBFAIL;
425 /* RemoveFromEntry - remove aid from bid's entries list, freeing a continuation
426 * entry if appropriate */
428 afs_int32 RemoveFromEntry (at, aid, bid)
429 struct ubik_trans *at;
434 struct prentry tentry;
435 struct contentry centry;
436 struct contentry hentry;
442 if (aid == bid) return PRINCONSISTENT;
443 memset(&hentry, 0, sizeof(hentry));
444 temp = FindByID(at,bid);
445 if (temp == 0) return PRNOENT;
446 code = pr_ReadEntry(at, 0, temp, &tentry);
447 if (code != 0) return code;
448 #ifdef PR_REMEMBER_TIMES
449 tentry.removeTime = time(0);
451 for (i=0;i<PRSIZE;i++) {
452 if (tentry.entries[i] == aid) {
453 tentry.entries[i] = PRBADID;
455 code = pr_WriteEntry(at,0,temp,&tentry);
456 if (code != 0) return code;
459 if (tentry.entries[i] == 0) /* found end of list */
465 code = pr_ReadCoEntry(at,0,nptr,¢ry);
466 if (code != 0) return code;
467 if ((centry.id != bid) || !(centry.flags & PRCONT)) return PRDBBAD;
468 for (i=0;i<COSIZE;i++) {
469 if (centry.entries[i] == aid) {
470 centry.entries[i] = PRBADID;
471 for (j=0;j<COSIZE;j++)
472 if (centry.entries[j] != PRBADID &&
473 centry.entries[j] != 0) break;
474 if (j == COSIZE) { /* can free this block */
476 tentry.next = centry.next;
479 hentry.next = centry.next;
480 code = pr_WriteCoEntry (at, 0, hloc, &hentry);
481 if (code != 0) return code;
483 code = FreeBlock (at, nptr);
484 if (code) return code;
486 else { /* can't free it yet */
487 code = pr_WriteCoEntry(at,0,nptr,¢ry);
488 if (code != 0) return code;
491 code = pr_WriteEntry(at,0,temp,&tentry);
492 if (code) return PRDBFAIL;
495 if (centry.entries[i] == 0) return PRNOENT;
496 } /* for all coentry slots */
499 memcpy(&hentry, ¢ry, sizeof(centry));
500 } /* while there are coentries */
504 /* DeleteEntry - delete the entry in tentry at loc, removing it from all
505 * groups, putting groups owned by it on orphan chain, and freeing the space */
507 afs_int32 DeleteEntry (at, tentry, loc)
508 struct ubik_trans *at;
509 struct prentry *tentry;
513 struct contentry centry;
517 if (strchr(tentry->name,'@')) {
518 if (tentry->flags & PRGRP) {
519 /* If there are still foreign user accounts from that cell
520 don't delete the group */
521 if (tentry->count) return PRBADARG;
525 afs_int32 loc = FindByID (at, tentry->cellid);
526 struct prentry centry;
528 code = pr_Read (at, 0, loc, ¢ry, sizeof(centry));
529 if (code) return code;
530 if (ntohl(centry.flags) & PRQUOTA) {
531 centry.ngroups = htonl(ntohl(centry.ngroups) + 1);
533 code = pr_Write (at, 0, loc, ¢ry, sizeof(centry));
534 if (code) return code;
538 /* First remove the entire membership list */
539 for (i=0;i<PRSIZE;i++) {
540 if (tentry->entries[i] == PRBADID) continue;
541 if (tentry->entries[i] == 0) break;
542 code = RemoveFromEntry (at, tentry->id, tentry->entries[i]);
543 if (code) return code;
546 while (nptr != (afs_int32)NULL) {
547 code = pr_ReadCoEntry(at,0,nptr,¢ry);
548 if (code != 0) return PRDBFAIL;
549 for (i=0;i<COSIZE;i++) {
550 if (centry.entries[i] == PRBADID) continue;
551 if (centry.entries[i] == 0) break;
552 code = RemoveFromEntry (at, tentry->id, centry.entries[i]);
553 if (code) return code;
555 code = FreeBlock (at, nptr); /* free continuation block */
556 if (code) return code;
560 /* Remove us from other's owned chain. Note that this will zero our owned
561 * field (on disk) so this step must follow the above step in case we are
562 * on our own owned list. */
563 if (tentry->flags & PRGRP) {
565 code = RemoveFromOwnerChain (at, tentry->id, tentry->owner);
566 if (code) return code;
569 code = RemoveFromOrphan (at, tentry->id);
570 if (code) return code;
574 code = RemoveFromIDHash(at,tentry->id,&loc);
575 if (code != PRSUCCESS) return code;
576 code = RemoveFromNameHash(at,tentry->name,&loc);
577 if (code != PRSUCCESS) return code;
579 if (tentry->flags & PRGRP) {
580 afs_int32 loc = FindByID(at, tentry->creator);
581 struct prentry centry;
585 code = pr_Read (at, 0, loc, ¢ry, sizeof(centry));
586 if (code) return code;
587 admin = ( (tentry->creator == SYSADMINID) ||
588 IsAMemberOf(at,tentry->creator,SYSADMINID) );
589 if (ntohl(centry.flags) & PRQUOTA) {
590 if (!(admin && (ntohl(centry.ngroups) >= 20))) {
591 centry.ngroups = htonl(ntohl(centry.ngroups) + 1);
594 code = pr_Write (at, 0, loc, ¢ry, sizeof(centry));
595 if (code) return code;
599 if (tentry->flags & PRGRP) {
600 if (inc_header_word (at, groupcount, -1)) return PRDBFAIL;
602 else if (tentry->flags & PRINST) {
603 if (inc_header_word (at, instcount, -1)) return PRDBFAIL;
606 if (strchr(tentry->name,'@')) {
607 if (inc_header_word (at, foreigncount, -1)) return PRDBFAIL;
609 if (inc_header_word (at, usercount, -1)) return PRDBFAIL;
612 code = FreeBlock(at, loc);
616 /* AddToEntry - add aid to entry's entries list, alloc'ing a continuation block
619 * Note the entry is written out by this routine. */
621 afs_int32 AddToEntry (tt, entry, loc, aid)
622 struct ubik_trans *tt;
623 struct prentry *entry;
629 struct contentry nentry;
630 struct contentry aentry;
632 afs_int32 last; /* addr of last cont. block */
637 if (entry->id == aid) return PRINCONSISTENT;
638 #ifdef PR_REMEMBER_TIMES
639 entry->addTime = time(0);
641 for (i=0;i<PRSIZE;i++) {
642 if (entry->entries[i] == aid)
644 if (entry->entries[i] == PRBADID) { /* remember this spot */
648 else if (entry->entries[i] == 0) { /* end of the line */
658 while (nptr != (afs_int32)NULL) {
659 code = pr_ReadCoEntry(tt,0,nptr,&nentry);
660 if (code != 0) return code;
662 if (!(nentry.flags & PRCONT)) return PRDBFAIL;
663 for (i=0;i<COSIZE;i++) {
664 if (nentry.entries[i] == aid)
666 if (nentry.entries[i] == PRBADID) {
672 else if (nentry.entries[i] == 0) {
682 if (slot != -1) { /* we found a place */
684 if (first) { /* place is in first block */
685 entry->entries[slot] = aid;
686 code = pr_WriteEntry (tt, 0, loc, entry);
687 if (code != 0) return code;
690 code = pr_WriteEntry (tt, 0, loc, entry);
691 if (code) return code;
692 code = pr_ReadCoEntry(tt,0,cloc,&aentry);
693 if (code != 0) return code;
694 aentry.entries[slot] = aid;
695 code = pr_WriteCoEntry(tt,0,cloc,&aentry);
696 if (code != 0) return code;
699 /* have to allocate a continuation block if we got here */
700 nptr = AllocBlock(tt);
702 /* then we should tack new block after last block in cont. chain */
704 code = pr_WriteCoEntry(tt,0,last,&nentry);
705 if (code != 0) return code;
710 memset(&aentry, 0, sizeof(aentry));
711 aentry.flags |= PRCONT;
712 aentry.id = entry->id;
714 aentry.entries[0] = aid;
715 code = pr_WriteCoEntry(tt,0,nptr,&aentry);
716 if (code != 0) return code;
717 /* don't forget to update count, here! */
719 code = pr_WriteEntry (tt, 0, loc, entry);
724 afs_int32 AddToPRList (alist, sizeP, id)
732 if (alist->prlist_len >= *sizeP) {
733 count = alist->prlist_len + 100;
734 if (alist->prlist_val) {
735 tmp = (char *) realloc(alist->prlist_val, count*sizeof(afs_int32));
737 tmp = (char *) malloc(count*sizeof(afs_int32));
739 if (!tmp) return(PRNOMEM);
740 alist->prlist_val = (afs_int32 *)tmp;
743 alist->prlist_val[alist->prlist_len++] = id;
747 afs_int32 GetList (at, tentry, alist, add)
748 struct ubik_trans *at;
749 struct prentry *tentry;
755 struct contentry centry;
761 alist->prlist_val = 0;
762 alist->prlist_len = 0;
764 for (i=0;i<PRSIZE;i++) {
765 if (tentry->entries[i] == PRBADID) continue;
766 if (tentry->entries[i] == 0) break;
767 code = AddToPRList (alist, &size, tentry->entries[i]);
768 if (code) return code;
771 for (nptr = tentry->next; nptr != 0; nptr = centry.next) {
772 /* look through cont entries */
773 code = pr_ReadCoEntry(at,0,nptr,¢ry);
774 if (code != 0) return code;
775 for (i=0;i<COSIZE;i++) {
776 if (centry.entries[i] == PRBADID) continue;
777 if (centry.entries[i] == 0) break;
778 code = AddToPRList (alist, &size, centry.entries[i]);
779 if (code) return code;
781 if (count++ > 50) IOMGR_Poll(), count = 0;
784 if (add) { /* this is for a CPS, so tack on appropriate stuff */
785 if (tentry->id != ANONYMOUSID && tentry->id != ANYUSERID) {
786 if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
787 (code = AddAuthGroup(tentry, alist, &size)) ||
788 (code = AddToPRList (alist, &size, tentry->id))) return code;
791 if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
792 (code = AddToPRList (alist, &size, tentry->id))) return code;
795 if (alist->prlist_len > 100) IOMGR_Poll();
796 qsort(alist->prlist_val,alist->prlist_len,sizeof(afs_int32),IDCmp);
801 afs_int32 GetList2 (at, tentry, tentry2 , alist, add)
802 struct ubik_trans *at;
803 struct prentry *tentry;
804 struct prentry *tentry2;
810 struct contentry centry;
816 alist->prlist_val = 0;
817 alist->prlist_len = 0;
818 for (i=0;i<PRSIZE;i++) {
819 if (tentry->entries[i] == PRBADID) continue;
820 if (tentry->entries[i] == 0) break;
821 code = AddToPRList (alist, &size, tentry->entries[i]);
822 if (code) return code;
826 while (nptr != (afs_uint32)NULL) {
827 /* look through cont entries */
828 code = pr_ReadCoEntry(at,0,nptr,¢ry);
829 if (code != 0) return code;
830 for (i=0;i<COSIZE;i++) {
831 if (centry.entries[i] == PRBADID) continue;
832 if (centry.entries[i] == 0) break;
833 code = AddToPRList (alist, &size, centry.entries[i]);
834 if (code) return code;
837 if (count++ > 50) IOMGR_Poll(), count = 0;
840 for (i=0;i<PRSIZE;i++) {
841 if (tentry2->entries[i] == PRBADID) continue;
842 if (tentry2->entries[i] == 0) break;
843 code = AddToPRList (alist, &size, tentry2->entries[i]);
848 nptr = tentry2->next;
849 while (nptr != (afs_uint32)NULL) {
850 /* look through cont entries */
851 code = pr_ReadCoEntry(at,0,nptr,¢ry);
852 if (code != 0) break;
853 for (i=0;i<COSIZE;i++) {
854 if (centry.entries[i] == PRBADID) continue;
855 if (centry.entries[i] == 0) break;
856 code = AddToPRList (alist, &size, centry.entries[i]);
860 if (count++ > 50) IOMGR_Poll(), count = 0;
863 if (add) { /* this is for a CPS, so tack on appropriate stuff */
864 if (tentry->id != ANONYMOUSID && tentry->id != ANYUSERID) {
865 if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
866 (code = AddToPRList (alist, &size, AUTHUSERID)) ||
867 (code = AddToPRList (alist, &size, tentry->id))) return code;
870 if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
871 (code = AddToPRList (alist, &size, tentry->id))) return code;
874 if (alist->prlist_len > 100) IOMGR_Poll();
875 qsort(alist->prlist_val,alist->prlist_len,sizeof(afs_int32),IDCmp);
879 afs_int32 GetOwnedChain (ut, next, alist)
880 struct ubik_trans *ut;
884 struct prentry tentry;
889 alist->prlist_val = 0;
890 alist->prlist_len = 0;
892 for (; *next; *next = ntohl(tentry.nextOwned)) {
893 code = pr_Read (ut, 0, *next, &tentry, sizeof(tentry));
894 if (code) return code;
895 code = AddToPRList (alist, &size, ntohl(tentry.id));
896 if (alist->prlist_len >= PR_MAXGROUPS) {
899 if (code) return code;
900 if (count++ > 50) IOMGR_Poll(), count = 0;
902 if (alist->prlist_len > 100) IOMGR_Poll();
903 qsort(alist->prlist_val,alist->prlist_len,sizeof(afs_int32),IDCmp);
907 afs_int32 GetMax(at,uid,gid)
908 struct ubik_trans *at;
912 *uid = ntohl(cheader.maxID);
913 *gid = ntohl(cheader.maxGroup);
917 afs_int32 SetMax(at,id,flag)
918 struct ubik_trans *at;
924 cheader.maxGroup = htonl(id);
925 code = pr_Write(at,0,16,(char *)&cheader.maxGroup,sizeof(cheader.maxGroup));
926 if (code != 0) return code;
929 cheader.maxID = htonl(id);
930 code = pr_Write(at,0,20,(char *)&cheader.maxID,sizeof(cheader.maxID));
931 if (code != 0) return code;
936 afs_int32 read_DbHeader(tt)
937 struct ubik_trans *tt;
941 if (!ubik_CacheUpdate(tt)) return 0;
943 code = pr_Read(tt, 0, 0, (char *)&cheader, sizeof(cheader));
945 com_err (whoami, code, "Couldn't read header");
956 struct ubik_trans *tt;
959 /* init the database. We'll try reading it, but if we're starting
960 * from scratch, we'll have to do a write transaction. */
962 pr_noAuth = afsconf_GetNoAuthFlag(prdir);
964 code = ubik_BeginTransReadAny(dbase,UBIK_READTRANS, &tt);
965 if (code) return code;
966 code = ubik_SetLock(tt,1,1,LOCKREAD);
973 } else if (!ubik_CacheUpdate (tt)) {
974 code = ubik_EndTrans(tt);
978 len = sizeof(cheader);
979 code = pr_Read(tt, 0, 0, (char *) &cheader, len);
981 com_err (whoami, code, "couldn't read header");
985 if ((ntohl(cheader.version) == PRDBVERSION) &&
986 ntohl(cheader.headerSize) == sizeof(cheader) &&
987 ntohl(cheader.eofPtr) != (afs_uint32)NULL &&
988 FindByID(tt,ANONYMOUSID) != 0){
989 /* database exists, so we don't have to build it */
990 code = ubik_EndTrans(tt);
991 if (code) return code;
994 /* else we need to build a database */
995 code = ubik_EndTrans(tt);
996 if (code) return code;
998 /* Only rebuild database if the db was deleted (the header is zero) and we
999 are running noAuth. */
1000 { char *bp = (char *)&cheader;
1002 for (i=0; i<sizeof(cheader); i++)
1005 com_err (whoami, code,
1006 "Can't rebuild database because it is not empty");
1012 com_err (whoami, code,
1013 "Can't rebuild database because not running NoAuth");
1017 code = ubik_BeginTrans(dbase,UBIK_WRITETRANS, &tt);
1018 if (code) return code;
1020 code = ubik_SetLock(tt,1,1,LOCKWRITE);
1022 ubik_AbortTrans(tt);
1026 /* before doing a rebuild, check again that the dbase looks bad, because
1027 * the previous check was only under a ReadAny transaction, and there could
1028 * actually have been a good database out there. Now that we have a
1029 * real write transaction, make sure things are still bad.
1031 if ((ntohl(cheader.version) == PRDBVERSION) &&
1032 ntohl(cheader.headerSize) == sizeof(cheader) &&
1033 ntohl(cheader.eofPtr) != (afs_uint32)NULL &&
1034 FindByID(tt,ANONYMOUSID) != 0){
1035 /* database exists, so we don't have to build it */
1036 code = ubik_EndTrans(tt);
1037 if (code) return code;
1041 /* Initialize the database header */
1042 if ((code = set_header_word (tt, version, htonl(PRDBVERSION))) ||
1043 (code = set_header_word (tt, headerSize, htonl(sizeof(cheader)))) ||
1044 (code = set_header_word (tt, eofPtr, cheader.headerSize))) {
1045 com_err (whoami, code, "couldn't write header words");
1046 ubik_AbortTrans(tt);
1050 #define InitialGroup(id,name) do { \
1051 afs_int32 temp = (id); \
1052 afs_int32 flag = (id) < 0 ? PRGRP : 0; \
1053 code = CreateEntry \
1054 (tt, (name), &temp, /*idflag*/1, flag, SYSADMINID, SYSADMINID); \
1056 com_err (whoami, code, "couldn't create %s with id %di.", \
1058 ubik_AbortTrans(tt); \
1063 InitialGroup (SYSADMINID, "system:administrators");
1064 InitialGroup (SYSBACKUPID, "system:backup");
1065 InitialGroup (ANYUSERID, "system:anyuser");
1066 InitialGroup (AUTHUSERID, "system:authuser");
1067 InitialGroup (SYSVIEWERID, "system:ptsviewers");
1068 InitialGroup (ANONYMOUSID, "anonymous");
1070 /* Well, we don't really want the max id set to anonymousid, so we'll set
1072 code = set_header_word (tt, maxID, 0); /* correct in any byte order */
1074 com_err (whoami, code, "couldn't reset max id");
1075 ubik_AbortTrans(tt);
1079 code = ubik_EndTrans(tt);
1080 if (code) return code;
1084 afs_int32 ChangeEntry (at, aid, cid, name, oid, newid)
1085 struct ubik_trans *at;
1093 afs_int32 i, nptr, pos;
1094 struct contentry centry;
1095 struct prentry tentry, tent;
1098 char holder[PR_MAXNAMELEN];
1099 char temp[PR_MAXNAMELEN];
1100 char oldname[PR_MAXNAMELEN];
1103 memset(holder, 0, PR_MAXNAMELEN);
1104 memset(temp, 0, PR_MAXNAMELEN);
1105 loc = FindByID(at,aid);
1106 if (!loc) return PRNOENT;
1107 code = pr_ReadEntry(at,0,loc,&tentry);
1108 if (code) return PRDBFAIL;
1109 if (tentry.owner != cid &&
1110 !IsAMemberOf(at,cid,SYSADMINID) &&
1111 !IsAMemberOf(at,cid,tentry.owner) &&
1112 !pr_noAuth) return PRPERM;
1113 #ifdef PR_REMEMBER_TIMES
1114 tentry.changeTime = time(0);
1117 /* we're actually trying to change the id */
1118 if (newid && (newid != aid)) {
1119 if (!IsAMemberOf(at,cid,SYSADMINID) && !pr_noAuth) return PRPERM;
1121 pos = FindByID(at,newid);
1122 if (pos) return PRIDEXIST; /* new id already in use! */
1123 if ((aid < 0 && newid > 0) || (aid > 0 && newid < 0)) return PRPERM;
1125 /* Should check that foreign users id to change to is good: inRange() */
1127 /* if new id is not in use, rehash things */
1128 code = RemoveFromIDHash(at,aid,&loc);
1129 if (code != PRSUCCESS) return code;
1131 code = pr_WriteEntry(at,0,loc,&tentry);
1132 if (code) return code;
1133 code = AddToIDHash(at,tentry.id,loc);
1134 if (code) return code;
1136 /* get current data */
1137 code = pr_ReadEntry(at, 0, loc, &tentry);
1138 if (code) return PRDBFAIL;
1140 /* Also change the references from the membership list */
1141 for (i=0; i<PRSIZE; i++) {
1142 if (tentry.entries[i] == PRBADID) continue;
1143 if (tentry.entries[i] == 0) break;
1144 pos = FindByID(at, tentry.entries[i]);
1145 if (!pos) return(PRDBFAIL);
1146 code = RemoveFromEntry(at, aid, tentry.entries[i]);
1147 if (code) return code;
1148 code = pr_ReadEntry(at, 0, pos, &tent);
1149 if (code) return code;
1150 code = AddToEntry(at, &tent, pos, newid);
1151 if (code) return code;
1153 /* Look through cont entries too. This needs to be broken into
1154 * seperate transaction so that no one transaction becomes too
1155 * large to complete.
1157 for (nptr=tentry.next; nptr; nptr=centry.next) {
1158 code = pr_ReadCoEntry(at, 0, nptr, ¢ry);
1159 if (code) return code;
1160 for (i=0; i<COSIZE; i++) {
1161 if (centry.entries[i] == PRBADID) continue;
1162 if (centry.entries[i] == 0) break;
1163 pos = FindByID(at, centry.entries[i]);
1164 if (!pos) return(PRDBFAIL);
1165 code = RemoveFromEntry(at, aid, centry.entries[i]);
1166 if (code) return code;
1167 code = pr_ReadEntry(at, 0, pos, &tent);
1168 if (code) return code;
1169 code = AddToEntry(at, &tent, pos, newid);
1170 if (code) return code;
1175 atsign = strchr(tentry.name, '@'); /* check for foreign entry */
1177 /* Change the owner */
1178 if (oid && (oid != tentry.owner)) {
1179 /* only groups can have their owner's changed */
1180 if (!(tentry.flags & PRGRP)) return PRPERM;
1181 if (atsign != NULL) return PRPERM;
1182 oldowner = tentry.owner;
1184 /* The entry must be written through first so Remove and Add routines
1185 * can operate on disk data */
1186 code = pr_WriteEntry(at,0,loc,(char *)&tentry);
1187 if (code) return PRDBFAIL;
1189 /* switch owner chains */
1190 if (oldowner) /* if it has an owner */
1191 code = RemoveFromOwnerChain(at,tentry.id,oldowner);
1192 else /* must be an orphan */
1193 code = RemoveFromOrphan(at,tentry.id);
1194 if (code) return code;
1195 code = AddToOwnerChain(at,tentry.id,tentry.owner);
1196 if (code) return code;
1198 /* fix up the name */
1199 if (strlen(name) == 0) name = tentry.name;
1200 /* get current data */
1201 code = pr_ReadEntry(at,0,loc,&tentry);
1202 if (code) return PRDBFAIL;
1205 /* Change the name, if name is a ptr to tentry.name then this name change
1206 * is due to a chown, otherwise caller has specified a new name */
1207 if ((name == tentry.name) ||
1208 (*name && (strcmp (tentry.name, name) != 0))) {
1209 strncpy (oldname, tentry.name, PR_MAXNAMELEN);
1210 if (tentry.flags & PRGRP) {
1211 /* don't let foreign cell groups change name */
1212 if (atsign != NULL) return PRPERM;
1213 code = CorrectGroupName (at, name, cid, tentry.owner, tentry.name);
1214 if (code) return code;
1216 if (name == tentry.name) { /* owner fixup */
1217 if (strcmp (oldname, tentry.name) == 0) goto nameOK;
1218 } else { /* new name, caller must be correct */
1219 if (strcmp (name, tentry.name) != 0) return PRBADNAM;
1223 /* Allow a foreign name change only if the cellname part is
1228 newatsign = strchr(name, '@');
1229 if (newatsign != atsign){ /* if they are the same no problem*/
1230 /*if the pointers are not equal the strings better be */
1231 if ((atsign == NULL) || (newatsign == NULL) ||
1232 strcmp (atsign,newatsign)) return PRPERM;
1234 if (!CorrectUserName(name)) return PRBADNAM;
1237 pos = FindByName(at,name, &tent);
1238 if (pos) return PREXIST;
1239 code = RemoveFromNameHash (at, oldname, &loc);
1240 if (code != PRSUCCESS) return code;
1241 strncpy (tentry.name, name, PR_MAXNAMELEN);
1242 code = pr_WriteEntry(at,0,loc,(char *)&tentry);
1243 if (code) return PRDBFAIL;
1244 code = AddToNameHash(at,tentry.name,loc);
1245 if (code != PRSUCCESS) return code;
1252 afs_int32 allocNextId(cellEntry)
1253 struct prentry *cellEntry;
1255 /* Id's for foreign cell entries are constructed as follows:
1256 The 16 low order bits are the group id of the cell and the
1257 top 16 bits identify the particular users in that cell */
1262 id = (ntohl(cellEntry -> nusers) +1);
1263 cellEntry->nusers = htonl(id);
1264 /* use the field nusers to keep
1265 the next available id in that
1266 foreign cell's group. Note :
1267 It would seem more appropriate
1268 to use ngroup for that and nusers
1269 to enforce the quota, however pts
1270 does not have an option to change
1271 foreign users quota yet */
1273 id = (id << 16) | ((ntohl(cellEntry-> id)) & 0x0000ffff);
1277 int inRange(cellEntry,aid)
1278 struct prentry *cellEntry;
1281 afs_uint32 id,cellid,groupid;
1285 The only thing that we want to make sure here is that
1286 the id is in the legal range of this group. If it is
1287 a duplicate we don't care since it will get caught
1288 in a different check.
1291 cellid = aid & 0x0000ffff;
1292 groupid = (ntohl(cellEntry-> id)) & 0x0000ffff;
1293 if (cellid != groupid) return 0; /* not in range */
1296 if we got here we're ok but we need to update the nusers
1297 field in order to get the id correct the next time that
1298 we try to allocate it automatically
1302 if (id > ntohl(cellEntry -> nusers))
1303 cellEntry -> nusers = htonl(id);
1308 AddAuthGroup(tentry, alist, size)
1309 struct prentry *tentry;
1313 if (!(strchr(tentry->name, '@')))
1314 return (AddToPRList (alist, size, AUTHUSERID));