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;
37 extern afs_int32 AddToEntry();
38 static char *whoami = "ptserver";
40 /* CorrectUserName - Check to make sure a user name is OK. It must not include
41 * either a colon (or it would look like a group) or an atsign (or it would
42 * look like a foreign user). The length is checked as well to make sure
43 * that the user name, an atsign, and the local cell name will fit in
44 * PR_MAXNAMELEN. This is so this user can fit in another cells database as
45 * a foreign user with our cell name tacked on. This is a predicate, so it
46 * return one if name is OK and zero if name is bogus. */
48 static int CorrectUserName (name)
51 extern int pr_realmNameLen;
53 /* We accept foreign names, so we will deal with '@' later */
54 if (index (name, ':') || index(name, '\n')) return 0;
55 if (strlen (name) >= PR_MAXNAMELEN - pr_realmNameLen - 1) return 0;
59 /* CorrectGroupName - Like the above but handles more complicated cases caused
60 * by including the ownership in the name. The interface works by calculating
61 * the correct name based on a given name and owner. This allows easy use by
62 * rename, which then compares the correct name with the requested new name. */
64 static afs_int32 CorrectGroupName (ut, aname, cid, oid, cname)
65 struct ubik_trans *ut;
66 char aname[PR_MAXNAMELEN]; /* name for group */
67 afs_int32 cid; /* caller id */
68 afs_int32 oid; /* owner of group */
69 char cname[PR_MAXNAMELEN]; /* correct name for group */
73 char *prefix; /* ptr to group owner part */
74 char *suffix; /* ptr to group name part */
75 char name[PR_MAXNAMELEN]; /* correct name for group */
76 struct prentry tentry;
78 if (strlen (aname) >= PR_MAXNAMELEN) return PRBADNAM;
79 admin = pr_noAuth || IsAMemberOf (ut, cid, SYSADMINID);
81 if (oid == 0) oid = cid;
83 /* Determine the correct prefix for the name. */
84 if (oid == SYSADMINID) prefix = "system";
86 afs_int32 loc = FindByID (ut, oid);
88 /* let admin create groups owned by non-existent ids (probably
89 * setting a group to own itself). Check that they look like
90 * groups (with a colon) or otherwise are good user names. */
92 strcpy (cname, aname);
97 code = pr_Read (ut, 0, loc, &tentry, sizeof(tentry));
98 if (code) return code;
99 if (ntohl(tentry.flags) & PRGRP) {
100 if ((tentry.count == 0) && !admin) return PRGROUPEMPTY;
101 /* terminate prefix at colon if there is one */
102 if (prefix = index(tentry.name, ':')) *prefix = 0;
104 prefix = tentry.name;
106 /* only sysadmin allow to use 'system:' prefix */
107 if ((strcmp (prefix, "system") == 0) && !admin) return PRPERM;
109 strcpy (name, aname); /* in case aname & cname are same */
110 suffix = index(name, ':');
112 /* sysadmin can make groups w/o ':', but they must still look like
113 * legal user names. */
114 if (!admin) return PRBADNAM;
115 strcpy (cname, name);
118 if (strlen(prefix)+strlen(suffix) >= PR_MAXNAMELEN) return PRBADNAM;
119 strcpy (cname, prefix);
120 strcat (cname, suffix);
123 /* check for legal name with either group rules or user rules */
124 if (suffix = index(cname, ':')) {
125 /* check for confusing characters */
126 if (index(cname, '\n') || /* restrict so recreate can work */
127 index(suffix+1, ':')) /* avoid multiple colons */
130 if (!CorrectUserName (cname)) return PRBADNAM;
135 int AccessOK (ut, cid, tentry, mem, any)
136 struct ubik_trans *ut;
137 afs_int32 cid; /* caller id */
138 struct prentry *tentry; /* object being accessed */
139 int mem; /* check membership in aid, if group */
140 int any; /* if set return true */
145 if (pr_noAuth) return 1;
146 if (cid == SYSADMINID) return 1; /* special case fileserver */
148 flags = tentry->flags;
152 flags = oid = aid = 0;
154 if (!(flags & PRACCESS)) /* provide default access */
156 flags |= PRP_GROUP_DEFAULT;
158 flags |= PRP_USER_DEFAULT;
160 if (flags & any) return 1;
163 IsAMemberOf (ut, cid, oid)) return 1;
165 if (aid > 0) { /* checking on a user */
166 if (aid == cid) return 1;
167 } else if (aid < 0) { /* checking on group */
168 if ((flags & mem) && IsAMemberOf (ut, cid, aid)) return 1;
170 /* Allow members of SYSVIEWERID to get membership and status only */
171 if (((mem == PRP_STATUS_MEM)||(mem == PRP_MEMBER_MEM))&&(IsAMemberOf (ut, cid, SYSVIEWERID))) return 1;
172 if (IsAMemberOf (ut, cid, SYSADMINID)) return 1;
173 return 0; /* no access */
176 afs_int32 CreateEntry (at, aname, aid, idflag, flag, oid, creator)
177 struct ubik_trans *at;
178 char aname[PR_MAXNAMELEN];
185 /* get and init a new entry */
188 struct prentry tentry, tent;
191 bzero(&tentry, sizeof(tentry));
193 if ((oid == 0) || (oid == ANONYMOUSID)) oid = creator;
196 code = CorrectGroupName (at, aname, creator, oid, tentry.name);
197 if (code) return code;
198 if (strcmp (aname, tentry.name) != 0) return PRBADNAM;
199 } else { /* non-group must not have colon */
200 if (!CorrectUserName(aname)) return PRBADNAM;
201 strcpy (tentry.name, aname);
204 if (FindByName(at,aname, &tent)) return PREXIST;
206 newEntry = AllocBlock(at);
207 if (!newEntry) return PRDBFAIL;
208 #ifdef PR_REMEMBER_TIMES
209 tentry.createTime = time(0);
213 tentry.flags = PRGRP;
215 } else if (flag == 0) {
217 tentry.owner = SYSADMINID;
222 atsign = index(aname,'@');
224 /* A normal user or group. Pick an id for it */
228 code= AllocID(at,flag,&tentry.id);
229 if (code != PRSUCCESS) return code;
231 } else if (flag & PRGRP) {
232 /* A foreign group. Its format must be AUTHUSER_GROUP@cellname
233 * Then pick an id for the group.
238 badFormat = strcmp(AUTHUSER_GROUP, aname);
240 if (badFormat) return PRBADNAM;
245 code= AllocID(at,flag,&tentry.id);
246 if (code != PRSUCCESS) return code;
249 /* A foreign user: <name>@<cell>. The foreign user is added to
250 * its representing group. It is
254 struct prentry centry;
255 extern afs_int32 allocNextId();
257 /* To create the user <name>@<cell> the group AUTHUSER_GROUP@<cell>
260 cellGroup = (char *)malloc(strlen(AUTHUSER_GROUP) + strlen(atsign) + 1);
261 strcpy(cellGroup, AUTHUSER_GROUP);
262 strcat(cellGroup, atsign);
263 pos = FindByName(at, cellGroup, ¢ry);
264 if (!pos) return PRBADNAM;
265 code = pr_Read (at, 0, pos, ¢ry, sizeof(centry));
266 if (code) return code;
268 /* cellid is the id of the group representing the cell */
269 tentry.cellid = ntohl(centry.id);
272 /* Check if id is good */
273 if (!inRange(¢ry,*aid)) return PRBADARG;
276 /* Allocate an ID special for this foreign user. It is based
277 * on the representing group's id and nusers count.
279 tentry.id = allocNextId(¢ry);
282 /* The foreign user will be added to the representing foreign
283 * group. The group can hold up to 30 entries.
285 if (!(ntohl(centry.flags) & PRQUOTA)) {
286 centry.flags = htonl (ntohl(centry.flags) | PRQUOTA);
287 centry.ngroups = htonl(30);
289 n = ntohl(centry.ngroups);
290 if ( (n <= 0) && !pr_noAuth ) return PRNOMORE;
291 centry.ngroups = htonl(n - 1);
293 /* write updated entry for group */
294 code = pr_Write (at, 0, pos, ¢ry, sizeof(centry));
296 /* Now add the new user entry to the database */
297 tentry.creator = creator;
299 code = pr_WriteEntry(at, 0, newEntry, &tentry);
300 if (code) return PRDBFAIL;
301 code = AddToIDHash(at, *aid, newEntry);
302 if (code != PRSUCCESS) return code;
303 code = AddToNameHash(at, aname, newEntry);
304 if (code != PRSUCCESS) return code;
305 if (inc_header_word (at, foreigncount, 1)) return PRDBFAIL;
307 /* Now add the entry to the authuser group for this cell.
308 * We will reread the entries for the user and the group
309 * instead of modifying them before writing them in the
310 * previous steps. Although not very efficient, much simpler
312 pos = FindByID(at, tentry.cellid);
313 if (!pos) return PRBADNAM;
314 code = pr_ReadEntry (at, 0, pos, ¢ry);
315 if (code) return code;
316 code = AddToEntry(at, ¢ry, pos, *aid);
317 if (code) return code;
318 /* and now the user entry */
319 pos = FindByID(at,*aid);
320 if (!pos) return PRBADNAM;
321 code = pr_ReadEntry (at, 0, pos, &tentry);
322 if (code) return code;
323 code = AddToEntry(at, &tentry, pos, tentry.cellid);
324 if (code) return code;
329 /* Remember the largest group id or largest user id */
331 /* group ids are negative */
332 if (tentry.id < (afs_int32)ntohl(cheader.maxGroup)) {
333 code = set_header_word (at, maxGroup, htonl(tentry.id));
334 if (code) return PRDBFAIL;
338 if (tentry.id > (afs_int32)ntohl(cheader.maxID)) {
339 code = set_header_word (at, maxID, htonl(tentry.id));
340 if (code) return PRDBFAIL;
344 /* Charge the creator for this group */
346 afs_int32 loc = FindByID (at, creator);
347 struct prentry centry;
350 if (loc) { /* this should only fail during initialization */
351 code = pr_Read (at, 0, loc, ¢ry, sizeof(centry));
352 if (code) return code;
354 /* If quota is uninitialized, do it */
355 if (!(ntohl(centry.flags) & PRQUOTA)) {
356 centry.flags = htonl (ntohl(centry.flags) | PRQUOTA);
357 centry.ngroups = centry.nusers = htonl(20);
360 /* Admins don't get charged for creating a group.
361 * If in noAuth mode, you get changed for it but you
362 * are still allowed to create as many groups as you want.
364 admin = ( (creator == SYSADMINID) ||
365 IsAMemberOf(at,creator,SYSADMINID) );
367 if (ntohl(centry.ngroups) <= 0) {
368 if (!pr_noAuth) return PRNOMORE;
370 centry.ngroups = htonl(ntohl(centry.ngroups)-1);
374 code = pr_Write (at, 0, loc, ¢ry, sizeof(centry));
375 if (code) return code;
379 /* Initialize the quota for the user. Groups don't have their
382 tentry.flags |= PRQUOTA;
383 tentry.ngroups = tentry.nusers = 20;
386 tentry.creator = creator;
388 code = pr_WriteEntry(at, 0, newEntry, &tentry);
389 if (code) return PRDBFAIL;
390 code = AddToIDHash(at,*aid,newEntry);
391 if (code != PRSUCCESS) return code;
392 code = AddToNameHash(at,aname,newEntry);
393 if (code != PRSUCCESS) return code;
394 if (tentry.flags & PRGRP) {
395 code = AddToOwnerChain(at,tentry.id,oid);
396 if (code) return code;
398 if (tentry.flags & PRGRP) {
399 if (inc_header_word (at, groupcount, 1)) return PRDBFAIL;
401 else if (tentry.flags & PRINST) {
402 if (inc_header_word (at, instcount, 1)) return PRDBFAIL;
405 if (inc_header_word (at, usercount, 1)) return PRDBFAIL;
411 /* RemoveFromEntry - remove aid from bid's entries list, freeing a continuation
412 * entry if appropriate */
414 afs_int32 RemoveFromEntry (at, aid, bid)
415 struct ubik_trans *at;
420 struct prentry tentry;
421 struct contentry centry;
422 struct contentry hentry;
428 if (aid == bid) return PRINCONSISTENT;
429 bzero(&hentry,sizeof(hentry));
430 temp = FindByID(at,bid);
431 if (temp == 0) return PRNOENT;
432 code = pr_ReadEntry(at, 0, temp, &tentry);
433 if (code != 0) return code;
434 #ifdef PR_REMEMBER_TIMES
435 tentry.removeTime = time(0);
437 for (i=0;i<PRSIZE;i++) {
438 if (tentry.entries[i] == aid) {
439 tentry.entries[i] = PRBADID;
441 code = pr_WriteEntry(at,0,temp,&tentry);
442 if (code != 0) return code;
445 if (tentry.entries[i] == 0) /* found end of list */
451 code = pr_ReadCoEntry(at,0,nptr,¢ry);
452 if (code != 0) return code;
453 if ((centry.id != bid) || !(centry.flags & PRCONT)) return PRDBBAD;
454 for (i=0;i<COSIZE;i++) {
455 if (centry.entries[i] == aid) {
456 centry.entries[i] = PRBADID;
457 for (j=0;j<COSIZE;j++)
458 if (centry.entries[j] != PRBADID &&
459 centry.entries[j] != 0) break;
460 if (j == COSIZE) { /* can free this block */
462 tentry.next = centry.next;
465 hentry.next = centry.next;
466 code = pr_WriteCoEntry (at, 0, hloc, &hentry);
467 if (code != 0) return code;
469 code = FreeBlock (at, nptr);
470 if (code) return code;
472 else { /* can't free it yet */
473 code = pr_WriteCoEntry(at,0,nptr,¢ry);
474 if (code != 0) return code;
477 code = pr_WriteEntry(at,0,temp,&tentry);
478 if (code) return PRDBFAIL;
481 if (centry.entries[i] == 0) return PRNOENT;
482 } /* for all coentry slots */
485 bcopy(¢ry,&hentry,sizeof(centry));
486 } /* while there are coentries */
490 /* DeleteEntry - delete the entry in tentry at loc, removing it from all
491 * groups, putting groups owned by it on orphan chain, and freeing the space */
493 afs_int32 DeleteEntry (at, tentry, loc)
494 struct ubik_trans *at;
495 struct prentry *tentry;
499 struct contentry centry;
503 if (index(tentry->name,'@')) {
504 if (tentry->flags & PRGRP) {
505 /* If there are still foreign user accounts from that cell
506 don't delete the group */
507 if (tentry->count) return PRBADARG;
511 afs_int32 loc = FindByID (at, tentry->cellid);
512 struct prentry centry;
514 code = pr_Read (at, 0, loc, ¢ry, sizeof(centry));
515 if (code) return code;
516 if (ntohl(centry.flags) & PRQUOTA) {
517 centry.ngroups = htonl(ntohl(centry.ngroups) + 1);
519 code = pr_Write (at, 0, loc, ¢ry, sizeof(centry));
520 if (code) return code;
524 /* First remove the entire membership list */
525 for (i=0;i<PRSIZE;i++) {
526 if (tentry->entries[i] == PRBADID) continue;
527 if (tentry->entries[i] == 0) break;
528 code = RemoveFromEntry (at, tentry->id, tentry->entries[i]);
529 if (code) return code;
532 while (nptr != (afs_int32)NULL) {
533 code = pr_ReadCoEntry(at,0,nptr,¢ry);
534 if (code != 0) return PRDBFAIL;
535 for (i=0;i<COSIZE;i++) {
536 if (centry.entries[i] == PRBADID) continue;
537 if (centry.entries[i] == 0) break;
538 code = RemoveFromEntry (at, tentry->id, centry.entries[i]);
539 if (code) return code;
541 code = FreeBlock (at, nptr); /* free continuation block */
542 if (code) return code;
546 /* Remove us from other's owned chain. Note that this will zero our owned
547 * field (on disk) so this step must follow the above step in case we are
548 * on our own owned list. */
549 if (tentry->flags & PRGRP) {
551 code = RemoveFromOwnerChain (at, tentry->id, tentry->owner);
552 if (code) return code;
555 code = RemoveFromOrphan (at, tentry->id);
556 if (code) return code;
560 code = RemoveFromIDHash(at,tentry->id,&loc);
561 if (code != PRSUCCESS) return code;
562 code = RemoveFromNameHash(at,tentry->name,&loc);
563 if (code != PRSUCCESS) return code;
565 if (tentry->flags & PRGRP) {
566 afs_int32 loc = FindByID(at, tentry->creator);
567 struct prentry centry;
571 code = pr_Read (at, 0, loc, ¢ry, sizeof(centry));
572 if (code) return code;
573 admin = ( (tentry->creator == SYSADMINID) ||
574 IsAMemberOf(at,tentry->creator,SYSADMINID) );
575 if (ntohl(centry.flags) & PRQUOTA) {
576 if (!(admin && (ntohl(centry.ngroups) >= 20))) {
577 centry.ngroups = htonl(ntohl(centry.ngroups) + 1);
580 code = pr_Write (at, 0, loc, ¢ry, sizeof(centry));
581 if (code) return code;
585 if (tentry->flags & PRGRP) {
586 if (inc_header_word (at, groupcount, -1)) return PRDBFAIL;
588 else if (tentry->flags & PRINST) {
589 if (inc_header_word (at, instcount, -1)) return PRDBFAIL;
592 if (index(tentry->name,'@')) {
593 if (inc_header_word (at, foreigncount, -1)) return PRDBFAIL;
595 if (inc_header_word (at, usercount, -1)) return PRDBFAIL;
598 code = FreeBlock(at, loc);
602 /* AddToEntry - add aid to entry's entries list, alloc'ing a continuation block
605 * Note the entry is written out by this routine. */
607 afs_int32 AddToEntry (tt, entry, loc, aid)
608 struct ubik_trans *tt;
609 struct prentry *entry;
615 struct contentry nentry;
616 struct contentry aentry;
618 afs_int32 last; /* addr of last cont. block */
623 if (entry->id == aid) return PRINCONSISTENT;
624 #ifdef PR_REMEMBER_TIMES
625 entry->addTime = time(0);
627 for (i=0;i<PRSIZE;i++) {
628 if (entry->entries[i] == aid)
630 if (entry->entries[i] == PRBADID) { /* remember this spot */
634 else if (entry->entries[i] == 0) { /* end of the line */
644 while (nptr != (afs_int32)NULL) {
645 code = pr_ReadCoEntry(tt,0,nptr,&nentry);
646 if (code != 0) return code;
648 if (!(nentry.flags & PRCONT)) return PRDBFAIL;
649 for (i=0;i<COSIZE;i++) {
650 if (nentry.entries[i] == aid)
652 if (nentry.entries[i] == PRBADID) {
658 else if (nentry.entries[i] == 0) {
668 if (slot != -1) { /* we found a place */
670 if (first) { /* place is in first block */
671 entry->entries[slot] = aid;
672 code = pr_WriteEntry (tt, 0, loc, entry);
673 if (code != 0) return code;
676 code = pr_WriteEntry (tt, 0, loc, entry);
677 if (code) return code;
678 code = pr_ReadCoEntry(tt,0,cloc,&aentry);
679 if (code != 0) return code;
680 aentry.entries[slot] = aid;
681 code = pr_WriteCoEntry(tt,0,cloc,&aentry);
682 if (code != 0) return code;
685 /* have to allocate a continuation block if we got here */
686 nptr = AllocBlock(tt);
688 /* then we should tack new block after last block in cont. chain */
690 code = pr_WriteCoEntry(tt,0,last,&nentry);
691 if (code != 0) return code;
696 bzero(&aentry,sizeof(aentry));
697 aentry.flags |= PRCONT;
698 aentry.id = entry->id;
700 aentry.entries[0] = aid;
701 code = pr_WriteCoEntry(tt,0,nptr,&aentry);
702 if (code != 0) return code;
703 /* don't forget to update count, here! */
705 code = pr_WriteEntry (tt, 0, loc, entry);
710 afs_int32 AddToPRList (alist, sizeP, id)
718 if (alist->prlist_len >= *sizeP) {
719 count = alist->prlist_len + 100;
720 if (alist->prlist_val) {
721 tmp = (char *) realloc(alist->prlist_val, count*sizeof(afs_int32));
723 tmp = (char *) malloc(count*sizeof(afs_int32));
725 if (!tmp) return(PRNOMEM);
726 alist->prlist_val = (afs_int32 *)tmp;
729 alist->prlist_val[alist->prlist_len++] = id;
733 afs_int32 GetList (at, tentry, alist, add)
734 struct ubik_trans *at;
735 struct prentry *tentry;
741 struct contentry centry;
747 alist->prlist_val = 0;
748 alist->prlist_len = 0;
750 for (i=0;i<PRSIZE;i++) {
751 if (tentry->entries[i] == PRBADID) continue;
752 if (tentry->entries[i] == 0) break;
753 code = AddToPRList (alist, &size, tentry->entries[i]);
754 if (code) return code;
757 for (nptr = tentry->next; nptr != 0; nptr = centry.next) {
758 /* look through cont entries */
759 code = pr_ReadCoEntry(at,0,nptr,¢ry);
760 if (code != 0) return code;
761 for (i=0;i<COSIZE;i++) {
762 if (centry.entries[i] == PRBADID) continue;
763 if (centry.entries[i] == 0) break;
764 code = AddToPRList (alist, &size, centry.entries[i]);
765 if (code) return code;
767 if (count++ > 50) IOMGR_Poll(), count = 0;
770 if (add) { /* this is for a CPS, so tack on appropriate stuff */
771 if (tentry->id != ANONYMOUSID && tentry->id != ANYUSERID) {
772 if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
773 (code = AddAuthGroup(tentry, alist, &size)) ||
774 (code = AddToPRList (alist, &size, tentry->id))) return code;
777 if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
778 (code = AddToPRList (alist, &size, tentry->id))) return code;
781 if (alist->prlist_len > 100) IOMGR_Poll();
782 qsort(alist->prlist_val,alist->prlist_len,sizeof(afs_int32),IDCmp);
787 afs_int32 GetList2 (at, tentry, tentry2 , alist, add)
788 struct ubik_trans *at;
789 struct prentry *tentry;
790 struct prentry *tentry2;
796 struct contentry centry;
802 alist->prlist_val = 0;
803 alist->prlist_len = 0;
804 for (i=0;i<PRSIZE;i++) {
805 if (tentry->entries[i] == PRBADID) continue;
806 if (tentry->entries[i] == 0) break;
807 code = AddToPRList (alist, &size, tentry->entries[i]);
808 if (code) return code;
812 while (nptr != (afs_uint32)NULL) {
813 /* look through cont entries */
814 code = pr_ReadCoEntry(at,0,nptr,¢ry);
815 if (code != 0) return code;
816 for (i=0;i<COSIZE;i++) {
817 if (centry.entries[i] == PRBADID) continue;
818 if (centry.entries[i] == 0) break;
819 code = AddToPRList (alist, &size, centry.entries[i]);
820 if (code) return code;
823 if (count++ > 50) IOMGR_Poll(), count = 0;
826 for (i=0;i<PRSIZE;i++) {
827 if (tentry2->entries[i] == PRBADID) continue;
828 if (tentry2->entries[i] == 0) break;
829 code = AddToPRList (alist, &size, tentry2->entries[i]);
834 nptr = tentry2->next;
835 while (nptr != (afs_uint32)NULL) {
836 /* look through cont entries */
837 code = pr_ReadCoEntry(at,0,nptr,¢ry);
838 if (code != 0) break;
839 for (i=0;i<COSIZE;i++) {
840 if (centry.entries[i] == PRBADID) continue;
841 if (centry.entries[i] == 0) break;
842 code = AddToPRList (alist, &size, centry.entries[i]);
846 if (count++ > 50) IOMGR_Poll(), count = 0;
849 if (add) { /* this is for a CPS, so tack on appropriate stuff */
850 if (tentry->id != ANONYMOUSID && tentry->id != ANYUSERID) {
851 if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
852 (code = AddToPRList (alist, &size, AUTHUSERID)) ||
853 (code = AddToPRList (alist, &size, tentry->id))) return code;
856 if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
857 (code = AddToPRList (alist, &size, tentry->id))) return code;
860 if (alist->prlist_len > 100) IOMGR_Poll();
861 qsort(alist->prlist_val,alist->prlist_len,sizeof(afs_int32),IDCmp);
865 afs_int32 GetOwnedChain (ut, next, alist)
866 struct ubik_trans *ut;
870 struct prentry tentry;
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) != (afs_uint32)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) != (afs_uint32)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 (SYSVIEWERID, "system:ptsviewers");
1054 InitialGroup (ANONYMOUSID, "anonymous");
1056 /* Well, we don't really want the max id set to anonymousid, so we'll set
1058 code = set_header_word (tt, maxID, 0); /* correct in any byte order */
1060 com_err (whoami, code, "couldn't reset max id");
1061 ubik_AbortTrans(tt);
1065 code = ubik_EndTrans(tt);
1066 if (code) return code;
1070 afs_int32 ChangeEntry (at, aid, cid, name, oid, newid)
1071 struct ubik_trans *at;
1079 afs_int32 i, nptr, pos;
1080 struct contentry centry;
1081 struct prentry tentry, tent;
1084 char holder[PR_MAXNAMELEN];
1085 char temp[PR_MAXNAMELEN];
1086 char oldname[PR_MAXNAMELEN];
1089 bzero(holder,PR_MAXNAMELEN);
1090 bzero(temp,PR_MAXNAMELEN);
1091 loc = FindByID(at,aid);
1092 if (!loc) return PRNOENT;
1093 code = pr_ReadEntry(at,0,loc,&tentry);
1094 if (code) return PRDBFAIL;
1095 if (tentry.owner != cid &&
1096 !IsAMemberOf(at,cid,SYSADMINID) &&
1097 !IsAMemberOf(at,cid,tentry.owner) &&
1098 !pr_noAuth) return PRPERM;
1099 #ifdef PR_REMEMBER_TIMES
1100 tentry.changeTime = time(0);
1103 /* we're actually trying to change the id */
1104 if (newid && (newid != aid)) {
1105 if (!IsAMemberOf(at,cid,SYSADMINID) && !pr_noAuth) return PRPERM;
1107 pos = FindByID(at,newid);
1108 if (pos) return PRIDEXIST; /* new id already in use! */
1109 if ((aid < 0 && newid > 0) || (aid > 0 && newid < 0)) return PRPERM;
1111 /* Should check that foreign users id to change to is good: inRange() */
1113 /* if new id is not in use, rehash things */
1114 code = RemoveFromIDHash(at,aid,&loc);
1115 if (code != PRSUCCESS) return code;
1117 code = pr_WriteEntry(at,0,loc,&tentry);
1118 if (code) return code;
1119 code = AddToIDHash(at,tentry.id,loc);
1120 if (code) return code;
1122 /* get current data */
1123 code = pr_ReadEntry(at, 0, loc, &tentry);
1124 if (code) return PRDBFAIL;
1126 /* Also change the references from the membership list */
1127 for (i=0; i<PRSIZE; i++) {
1128 if (tentry.entries[i] == PRBADID) continue;
1129 if (tentry.entries[i] == 0) break;
1130 pos = FindByID(at, tentry.entries[i]);
1131 if (!pos) return(PRDBFAIL);
1132 code = RemoveFromEntry(at, aid, tentry.entries[i]);
1133 if (code) return code;
1134 code = pr_ReadEntry(at, 0, pos, &tent);
1135 if (code) return code;
1136 code = AddToEntry(at, &tent, pos, newid);
1137 if (code) return code;
1139 /* Look through cont entries too. This needs to be broken into
1140 * seperate transaction so that no one transaction becomes too
1141 * large to complete.
1143 for (nptr=tentry.next; nptr; nptr=centry.next) {
1144 code = pr_ReadCoEntry(at, 0, nptr, ¢ry);
1145 if (code) return code;
1146 for (i=0; i<COSIZE; i++) {
1147 if (centry.entries[i] == PRBADID) continue;
1148 if (centry.entries[i] == 0) break;
1149 pos = FindByID(at, centry.entries[i]);
1150 if (!pos) return(PRDBFAIL);
1151 code = RemoveFromEntry(at, aid, centry.entries[i]);
1152 if (code) return code;
1153 code = pr_ReadEntry(at, 0, pos, &tent);
1154 if (code) return code;
1155 code = AddToEntry(at, &tent, pos, newid);
1156 if (code) return code;
1161 atsign = index(tentry.name, '@'); /* check for foreign entry */
1163 /* Change the owner */
1164 if (oid && (oid != tentry.owner)) {
1165 /* only groups can have their owner's changed */
1166 if (!(tentry.flags & PRGRP)) return PRPERM;
1167 if (atsign != NULL) return PRPERM;
1168 oldowner = tentry.owner;
1170 /* The entry must be written through first so Remove and Add routines
1171 * can operate on disk data */
1172 code = pr_WriteEntry(at,0,loc,(char *)&tentry);
1173 if (code) return PRDBFAIL;
1175 /* switch owner chains */
1176 if (oldowner) /* if it has an owner */
1177 code = RemoveFromOwnerChain(at,tentry.id,oldowner);
1178 else /* must be an orphan */
1179 code = RemoveFromOrphan(at,tentry.id);
1180 if (code) return code;
1181 code = AddToOwnerChain(at,tentry.id,tentry.owner);
1182 if (code) return code;
1184 /* fix up the name */
1185 if (strlen(name) == 0) name = tentry.name;
1186 /* get current data */
1187 code = pr_ReadEntry(at,0,loc,&tentry);
1188 if (code) return PRDBFAIL;
1191 /* Change the name, if name is a ptr to tentry.name then this name change
1192 * is due to a chown, otherwise caller has specified a new name */
1193 if ((name == tentry.name) ||
1194 (*name && (strcmp (tentry.name, name) != 0))) {
1195 strncpy (oldname, tentry.name, PR_MAXNAMELEN);
1196 if (tentry.flags & PRGRP) {
1197 /* don't let foreign cell groups change name */
1198 if (atsign != NULL) return PRPERM;
1199 code = CorrectGroupName (at, name, cid, tentry.owner, tentry.name);
1200 if (code) return code;
1202 if (name == tentry.name) { /* owner fixup */
1203 if (strcmp (oldname, tentry.name) == 0) goto nameOK;
1204 } else { /* new name, caller must be correct */
1205 if (strcmp (name, tentry.name) != 0) return PRBADNAM;
1209 /* Allow a foreign name change only if the cellname part is
1214 newatsign = index (name, '@');
1215 if (newatsign != atsign){ /* if they are the same no problem*/
1216 /*if the pointers are not equal the strings better be */
1217 if ((atsign == NULL) || (newatsign == NULL) ||
1218 strcmp (atsign,newatsign)) return PRPERM;
1220 if (!CorrectUserName(name)) return PRBADNAM;
1223 pos = FindByName(at,name, &tent);
1224 if (pos) return PREXIST;
1225 code = RemoveFromNameHash (at, oldname, &loc);
1226 if (code != PRSUCCESS) return code;
1227 strncpy (tentry.name, name, PR_MAXNAMELEN);
1228 code = pr_WriteEntry(at,0,loc,(char *)&tentry);
1229 if (code) return PRDBFAIL;
1230 code = AddToNameHash(at,tentry.name,loc);
1231 if (code != PRSUCCESS) return code;
1238 afs_int32 allocNextId(cellEntry)
1239 struct prentry *cellEntry;
1241 /* Id's for foreign cell entries are constructed as follows:
1242 The 16 low order bits are the group id of the cell and the
1243 top 16 bits identify the particular users in that cell */
1248 id = (ntohl(cellEntry -> nusers) +1);
1249 cellEntry->nusers = htonl(id);
1250 /* use the field nusers to keep
1251 the next available id in that
1252 foreign cell's group. Note :
1253 It would seem more appropriate
1254 to use ngroup for that and nusers
1255 to enforce the quota, however pts
1256 does not have an option to change
1257 foreign users quota yet */
1259 id = (id << 16) | ((ntohl(cellEntry-> id)) & 0x0000ffff);
1263 int inRange(cellEntry,aid)
1264 struct prentry *cellEntry;
1267 afs_uint32 id,cellid,groupid;
1271 The only thing that we want to make sure here is that
1272 the id is in the legal range of this group. If it is
1273 a duplicate we don't care since it will get caught
1274 in a different check.
1277 cellid = aid & 0x0000ffff;
1278 groupid = (ntohl(cellEntry-> id)) & 0x0000ffff;
1279 if (cellid != groupid) return 0; /* not in range */
1282 if we got here we're ok but we need to update the nusers
1283 field in order to get the id correct the next time that
1284 we try to allocate it automatically
1288 if (id > ntohl(cellEntry -> nusers))
1289 cellEntry -> nusers = htonl(id);
1294 AddAuthGroup(tentry, alist, size)
1295 struct prentry *tentry;
1299 if (!(index(tentry->name, '@')))
1300 return (AddToPRList (alist, size, AUTHUSERID));