6 * P_R_P_Q_# (C) COPYRIGHT IBM CORPORATION 1988
7 * LICENSED MATERIALS - PROPERTY OF IBM
8 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
13 Information Technology Center
16 Modified May, 1989 by Jeff Schiller to keep disk file in
24 #define UBIK_INTERNALS
30 #include <netinet/in.h>
32 extern struct prheader cheader;
33 extern struct ubik_dbase *dbase;
34 extern struct afsconf_dir *prdir;
36 long CreateEntry(at, aname, aid, idflag,flag,oid,creator)
37 register struct ubik_trans *at;
38 char aname[PR_MAXNAMELEN];
45 /* get and init a new entry */
49 struct prentry tentry;
51 bzero(&tentry, sizeof(tentry));
52 newEntry = AllocBlock(at);
53 if (!newEntry) return PRDBFAIL;
55 tentry.flags |= PRGRP;
58 else if (flag & PRFOREIGN) {
59 tentry.flags |= PRFOREIGN;
62 else tentry.owner = SYSADMINID;
66 code= AllocID(at,flag,&tentry.id);
67 if (code != PRSUCCESS) return code;
70 if (tentry.id < ntohl(cheader.maxGroup)) {
71 cheader.maxGroup = htonl(tentry.id);
72 code = pr_Write(at,0,16,(char *) &cheader.maxGroup,sizeof(cheader.maxGroup));
73 if (code) return PRDBFAIL;
76 else if (flag & PRFOREIGN) {
77 if (tentry.id > ntohl(cheader.maxForeign)) {
78 cheader.maxForeign = htonl(tentry.id);
79 code = pr_Write(at,0,24,(char *) &cheader.maxForeign,sizeof(cheader.maxForeign));
80 if (code) return PRDBFAIL;
84 if (tentry.id > ntohl(cheader.maxID)) {
85 cheader.maxID = htonl(tentry.id);
86 code = pr_Write(at,0,20,(char *) &cheader.maxID,sizeof(cheader.maxID));
87 if (code) return PRDBFAIL;
90 tentry.creator = creator;
92 strncpy(tentry.name, aname, PR_MAXNAMELEN);
93 code = pr_WriteEntry(at, 0, newEntry, &tentry);
94 if (code) return PRDBFAIL;
95 code = AddToIDHash(at,*aid,newEntry);
96 if (code != PRSUCCESS) return code;
97 code = AddToNameHash(at,aname,newEntry);
98 if (code != PRSUCCESS) return code;
99 if (tentry.flags & PRGRP) {
100 code = AddToOwnerChain(at,tentry.id,oid);
101 if (code) return code;
103 if (tentry.flags & PRGRP) {
104 temp = ntohl(cheader.groupcount) + 1;
105 cheader.groupcount = htonl(temp);
106 code = pr_Write(at,0,40,(char *)&cheader.groupcount,sizeof(cheader.groupcount));
107 if (code) return PRDBFAIL;
109 else if (tentry.flags & PRFOREIGN) {
110 temp = ntohl(cheader.foreigncount) + 1;
111 cheader.foreigncount = htonl(temp);
112 code = pr_Write(at,0,44,(char *)&cheader.foreigncount,sizeof(cheader.foreigncount));
113 if (code) return PRDBFAIL;
115 else if (tentry.flags & PRINST) {
116 temp = ntohl(cheader.instcount) + 1;
117 cheader.instcount = htonl(temp);
118 code = pr_Write(at,0,48,(char *)&cheader.instcount,sizeof(cheader.instcount));
119 if (code) return PRDBFAIL;
122 temp = ntohl(cheader.usercount) + 1;
123 cheader.usercount = htonl(temp);
124 code = pr_Write(at,0,36,(char *)&cheader.usercount,sizeof(cheader.usercount));
125 if (code) return PRDBFAIL;
132 long RemoveFromEntry(at,aid,bid)
133 register struct ubik_trans *at;
137 /* remove aid from bid's entries list, freeing a continuation entry if appropriate */
140 struct prentry tentry;
141 struct contentry centry;
142 struct contentry hentry;
149 bzero(&hentry,sizeof(hentry));
150 temp = FindByID(at,bid);
151 code = pr_ReadEntry(at, 0, temp, &tentry);
152 if (code != 0) return code;
153 for (i=0;i<PRSIZE;i++) {
154 if (tentry.entries[i] == aid) {
155 tentry.entries[i] = PRBADID;
157 code = pr_WriteEntry(at,0,temp,&tentry);
158 if (code != 0) return code;
161 if (tentry.entries[i] == 0) /* found end of list */
164 if (tentry.next != NULL) {
167 while (nptr != NULL) {
168 code = pr_ReadCoEntry(at,0,nptr,¢ry);
169 if (code != 0) return code;
170 for (i=0;i<COSIZE;i++) {
171 if (centry.entries[i] == aid) {
172 centry.entries[i] = PRBADID;
174 code = pr_WriteEntry(at,0,temp,&tentry);
175 if (code) return PRDBFAIL;
176 for (j=0;j<COSIZE;j++)
177 if (centry.entries[j] != PRBADID && centry.entries[j] != 0) break;
178 if (j == COSIZE) { /* can free this block */
180 tentry.next = centry.next;
181 code = pr_WriteEntry(at,0,temp,&tentry);
182 if (code != 0) return code;
185 hentry.next = centry.next;
186 code = pr_WriteCoEntry(at,0,hloc,(char *) &hentry);
187 if (code != 0) return code;
189 code = FreeBlock(at,nptr);
192 else { /* can't free it yet */
193 code = pr_WriteCoEntry(at,0,nptr,¢ry);
194 if (code != 0) return code;
198 if (centry.entries[i] == 0) return PRNOENT;
202 bcopy(¢ry,&hentry,sizeof(centry));
209 long DeleteEntry(at,aid,cid)
210 register struct ubik_trans *at;
214 /* delete the entry aid, removing it from all groups, putting groups owned by it on orphan chain, and freeing the space */
218 struct prentry tentry;
219 struct contentry centry;
220 struct prentry nentry;
225 noAuth = afsconf_GetNoAuthFlag(prdir);
226 bzero(&tentry,sizeof(tentry));
227 temp = FindByID(at,aid);
228 if (!temp) return PRNOENT;
229 code = pr_ReadEntry(at,0,temp,&tentry);
230 if (code != 0) return PRDBFAIL;
231 if (tentry.owner != cid && !IsAMemberOf(at,cid,SYSADMINID) && !IsAMemberOf(at,cid,tentry.owner) && !noAuth) return PRPERM;
232 for (i=0;i<PRSIZE;i++) {
233 if (tentry.entries[i] == 0) break;
234 RemoveFromEntry(at,aid,tentry.entries[i]);
237 while (nptr != NULL) {
238 code = pr_ReadCoEntry(at,0,nptr,¢ry);
239 if (code != 0) return PRDBFAIL;
240 for (i=0;i<COSIZE;i++) {
241 if (centry.entries[i] == 0) break;
242 RemoveFromEntry(at,aid,centry.entries[i]);
246 if (tentry.flags & PRGRP) {
247 if (FindByID(at,tentry.owner)) {
248 code = RemoveFromOwnerChain(at,aid,tentry.owner);
249 if (code) return code;
252 code = RemoveFromOrphan(at,aid);
253 if (code) return code;
258 while (nptr != NULL) {
259 code = pr_ReadEntry(at,0,nptr,&nentry);
260 if (code != 0) return PRDBFAIL;
261 if (nentry.id != aid) /* don't add this entry to orphan chain! */
262 code = AddToOrphan(at,nentry.id);
263 nptr = nentry.nextOwned;
266 code = RemoveFromIDHash(at,tentry.id,&temp);
267 if (code != PRSUCCESS) return code;
268 code = RemoveFromNameHash(at,tentry.name,&temp);
269 if (code != PRSUCCESS) return code;
270 if (tentry.flags & PRGRP) {
271 temp1 = ntohl(cheader.groupcount) + 1;
272 cheader.groupcount = htonl(temp1);
273 code = pr_Write(at,0,40,(char *)&cheader.groupcount,sizeof(cheader.groupcount));
274 if (code) return PRDBFAIL;
276 else if (tentry.flags & PRFOREIGN) {
277 temp1 = ntohl(cheader.foreigncount) + 1;
278 cheader.foreigncount = htonl(temp1);
279 code = pr_Write(at,0,44,(char *)&cheader.foreigncount,sizeof(cheader.foreigncount));
280 if (code) return PRDBFAIL;
282 else if (tentry.flags & PRINST) {
283 temp1 = ntohl(cheader.instcount) + 1;
284 cheader.instcount = htonl(temp1);
285 code = pr_Write(at,0,48,(char *)&cheader.instcount,sizeof(cheader.instcount));
286 if (code) return PRDBFAIL;
289 temp1 = ntohl(cheader.usercount) + 1;
290 cheader.usercount = htonl(temp1);
291 code = pr_Write(at,0,36,(char *)&cheader.usercount,sizeof(cheader.usercount));
292 if (code) return PRDBFAIL;
301 long AddToEntry(tt,entry,loc,aid)
302 struct ubik_trans *tt;
303 struct prentry entry;
307 /* add aid to entry's entries list, alloc'ing a continuation block if needed */
310 struct contentry nentry;
311 struct contentry aentry;
318 bzero(&nentry,sizeof(nentry));
319 bzero(&aentry,sizeof(aentry));
320 for (i=0;i<PRSIZE;i++) {
321 if (entry.entries[i] == aid)
323 if (entry.entries[i] == PRBADID) { /* remember this spot */
327 if (entry.entries[i] == 0) { /* end of the line */
336 while (nptr != NULL) {
337 code = pr_ReadCoEntry(tt,0,nptr,&nentry);
338 if (code != 0) return code;
339 if (!(nentry.flags & PRCONT)) return PRDBFAIL;
340 for (i=0;i<COSIZE;i++) {
341 if (nentry.entries[i] == aid)
343 if (nentry.entries[i] == PRBADID) {
349 if (nentry.entries[i] == 0) {
360 if (slot != -1) { /* we found a place */
362 if (first) { /* place is in first block */
363 entry.entries[slot] = aid;
364 code = pr_WriteEntry(tt,0,loc,&entry);
365 if (code != 0) return code;
368 code = pr_WriteEntry(tt,0,loc,&entry);
369 code = pr_ReadCoEntry(tt,0,cloc,&aentry);
370 if (code != 0) return code;
371 aentry.entries[slot] = aid;
372 code = pr_WriteCoEntry(tt,0,cloc,&aentry);
373 if (code != 0) return code;
376 /* have to allocate a continuation block if we got here */
377 nptr = AllocBlock(tt);
378 if (nentry.flags & PRCONT) {
379 /* then we should tack new block here */
381 code = pr_WriteCoEntry(tt,0,last,&nentry);
382 if (code != 0) return code;
386 code = pr_WriteEntry(tt,0,loc,&entry);
387 if (code != 0) return code;
389 aentry.flags |= PRCONT;
390 aentry.id = entry.id;
392 aentry.entries[0] = aid;
393 code = pr_WriteCoEntry(tt,0,nptr,&aentry);
394 if (code != 0) return code;
395 /* don't forget to update count, here! */
397 code = pr_WriteEntry(tt,0,loc,&entry);
402 long GetList(at,aid,alist,add)
403 struct ubik_trans *at;
412 struct prentry tentry;
413 struct contentry centry;
418 temp = FindByID(at,aid);
419 if (!temp) return PRNOENT;
420 code = pr_ReadEntry(at,0,temp,&tentry);
421 if (code != 0) return code;
422 alist->prlist_val = (long *)malloc(100*sizeof(long));
424 alist->prlist_len = 0;
426 for (i=0;i<PRSIZE;i++) {
427 if (tentry.entries[i] == PRBADID) continue;
428 if (tentry.entries[i] == 0) break;
429 alist->prlist_val[count]= tentry.entries[i];
434 while (nptr != NULL) {
435 /* look through cont entries */
436 code = pr_ReadCoEntry(at,0,nptr,¢ry);
437 if (code != 0) return code;
438 for (i=0;i<COSIZE;i++) {
439 if (centry.entries[i] == PRBADID) continue;
440 if (centry.entries[i] == 0) break;
441 if (alist->prlist_len >= size) {
442 alist->prlist_val = (long *)realloc(alist->prlist_val,(size+100)*sizeof(long));
445 alist->prlist_val[count] = centry.entries[i];
451 if (add) { /* this is for a CPS, so tack on appropriate stuff */
452 if (aid != ANONYMOUSID && aid != ANYUSERID) {
453 if (alist->prlist_len >= size)
454 alist->prlist_val = (long *)realloc(alist->prlist_val,(size + 3)*sizeof(long));
455 alist->prlist_val[count] = ANYUSERID;
457 alist->prlist_val[count] = AUTHUSERID;
459 alist->prlist_val[count] = aid;
461 alist->prlist_len += 3;
464 if (alist->prlist_len >= size)
465 alist->prlist_val = (long *)realloc(alist->prlist_val,(size + 2)*sizeof(long));
466 alist->prlist_val[count] = ANYUSERID;
468 alist->prlist_val[count] = aid;
470 alist->prlist_len += 2;
473 qsort(alist->prlist_val,alist->prlist_len,sizeof(long),IDCmp);
477 long GetMax(at,uid,gid)
478 register struct ubik_trans *at;
482 *uid = ntohl(cheader.maxID);
483 *gid = ntohl(cheader.maxGroup);
487 long SetMax(at,id,flag)
488 register struct ubik_trans *at;
494 cheader.maxGroup = htonl(id);
495 code = pr_Write(at,0,16,(char *)&cheader.maxGroup,sizeof(cheader.maxGroup));
496 if (code != 0) return code;
499 cheader.maxID = htonl(id);
500 code = pr_Write(at,0,20,(char *)&cheader.maxID,sizeof(cheader.maxID));
501 if (code != 0) return code;
509 struct ubik_trans *tt;
514 static struct ubik_version curver;
515 struct ubik_version newver;
516 struct ubik_hdr header;
518 /* init the database. We'll try reading it, but if we're starting from scratch, we'll have to do a write transaction. */
520 code = ubik_BeginTrans(dbase,UBIK_READTRANS, &tt);
521 if (code) return code;
522 code = ubik_SetLock(tt,1,1,LOCKREAD);
529 bzero(&curver,sizeof(curver));
531 len = sizeof(cheader);
532 code = pr_Read(tt, 0, 0, (char *) &cheader, len);
534 printf("prserver: couldn't read header -code is %d\n",code);
538 if (ntohl(cheader.headerSize) == sizeof(cheader) && ntohl(cheader.eofPtr) != NULL && FindByID(tt,ANONYMOUSID) != 0){
539 /* database exists, so we don't have to build it */
540 code = ubik_EndTrans(tt);
541 if (code) return code;
544 /* else we need to build a database */
545 code = ubik_EndTrans(tt);
546 if (code) return code;
547 fprintf(stderr, "Creating new database\n");
548 code = ubik_BeginTrans(dbase,UBIK_WRITETRANS, &tt);
549 if (code) return code;
550 code = ubik_SetLock(tt,1,1,LOCKWRITE);
555 header.magic = htonl(UBIK_MAGIC);
558 header.version.epoch = header.version.counter = htonl(1);
559 code = pr_Write(tt, 0, -(HDRSIZE), (char *)&header, sizeof(header));
561 printf("prserver: couldn't write ubik header - code is %d.\n", code);
564 cheader.headerSize = htonl(sizeof(cheader));
565 code = pr_Write(tt,0,4,(char *)&cheader.headerSize,sizeof(cheader.headerSize));
567 printf("prserver: couldn't write header size - code is %d.\n",code);
571 cheader.eofPtr = cheader.headerSize; /* already in network order! */
572 code = pr_Write(tt,0,12,(char *)&cheader.eofPtr,sizeof(cheader.eofPtr));
574 printf("prserver: couldn't write eof Ptr - code is %d.\n",code);
579 if (FindByID(tt,SYSADMINID) == 0) {
582 code = CreateEntry(tt,"system:administrators",&temp,1,flag,SYSADMINID,SYSADMINID);
583 if (code != PRSUCCESS) {
584 printf("prserver: couldn't create system:administrators.\n");
591 if ( FindByID(tt,temp) == 0) { /* init sysadmin */
593 code = CreateEntry(tt,"system:anyuser",&temp,1,flag,SYSADMINID,SYSADMINID);
594 if (code != PRSUCCESS) {
595 printf("prserver: couldn't create system:anyuser.\n");
602 if (FindByID(tt,temp) == 0) { /* init sysadmin */
604 code = CreateEntry(tt,"system:authuser",&temp,1,flag,SYSADMINID,SYSADMINID);
605 if (code != PRSUCCESS) {
606 printf("prserver: couldn't create system:authuser.\n");
613 if (FindByID(tt,temp) == 0) { /* init sysadmin */
614 code = CreateEntry(tt,"anonymous",&temp,1,flag,SYSADMINID,SYSADMINID);
615 if (code != PRSUCCESS) {
616 printf("prserver: couldn't create anonymous.\n");
620 /* well, we don't really want the max id set to anonymousid, so we'll set it back to 0 */
621 cheader.maxID = 0; /* Zero is in correct byte order no matter what! */
622 code = pr_Write(tt,0,20,(char *)&cheader.maxID,sizeof(cheader.maxID));
624 printf("prserver: couldn't set max id - code is %d.\n");
629 code = ubik_EndTrans(tt);
630 if (code) return code;
634 long NameToID(at, aname, aid)
635 register struct ubik_trans *at;
636 char aname[PR_MAXNAMELEN];
641 struct prentry tentry;
643 temp = FindByName(at,aname);
644 if (!temp) return PRNOENT;
645 code = pr_ReadEntry(at, 0, temp, &tentry);
646 if (code != 0) return code;
651 long IDToName(at, aid, aname)
652 register struct ubik_trans *at;
654 char aname[PR_MAXNAMELEN];
657 struct prentry tentry;
660 temp = FindByID(at,aid);
661 if (!temp) return PRNOENT;
662 code = pr_ReadEntry(at,0,temp,&tentry);
663 if (code != 0) return code;
664 strncpy(aname,tentry.name,PR_MAXNAMELEN);
668 long ChangeEntry(at, aid,cid,name,oid,newid)
669 struct ubik_trans *at;
678 struct prentry tentry;
683 char holder[PR_MAXNAMELEN];
684 char temp[PR_MAXNAMELEN];
686 noAuth = afsconf_GetNoAuthFlag(prdir);
687 bzero(holder,PR_MAXNAMELEN);
688 bzero(temp,PR_MAXNAMELEN);
689 loc = FindByID(at,aid);
690 if (!loc) return PRNOENT;
691 code = pr_ReadEntry(at,0,loc,&tentry);
692 if (code) return PRDBFAIL;
693 if (tentry.owner != cid && !IsAMemberOf(at,cid,SYSADMINID) && !IsAMemberOf(at,cid,tentry.owner) && !noAuth)
695 if (aid != newid && newid != 0) { /* then we're actually trying to change the id */
696 pos = FindByID(at,newid);
697 if (pos) return PRIDEXIST; /* new id already in use! */
698 if ((aid < 0 && newid) > 0 || (aid > 0 && newid < 0)) return PRPERM;
699 /* if new id is not in use, rehash things */
700 code = RemoveFromIDHash(at,aid,&loc);
701 if (code != PRSUCCESS) return code;
703 code = pr_WriteEntry(at,0,loc,&tentry);
704 code = AddToIDHash(at,tentry.id,loc);
705 if (code) return code;
707 if (tentry.owner != oid && oid) {
708 if (tentry.flags & PRGRP) {
709 /* switch owner chains before we lose old owner */
710 if (FindByID(at,tentry.owner)) /* if it has an owner */
711 code = RemoveFromOwnerChain(at,tentry.id,tentry.owner);
712 else /* must be an orphan */
713 code = RemoveFromOrphan(at,tentry.id);
714 if (code) return code;
715 code = AddToOwnerChain(at,tentry.id,oid);
716 if (code) return code;
719 if ((tentry.flags & PRGRP) && (strlen(name) == 0)) {
720 /* if we change the owner of a group, it's name will change as well */
721 if (tentry.owner < 0) {
722 code = IDToName(at,tentry.owner,temp);
723 if (code) return code;
724 check = index(temp,':');
725 strncpy(holder,temp,check - temp);
728 code = IDToName(at,tentry.owner,holder);
729 if (code) return code;
731 strncat(holder,":",PR_MAXNAMELEN);
732 /* now the rest of the name */
733 check = index(tentry.name,':');
734 strncat(holder,++check,PR_MAXNAMELEN);
735 if (strcmp(holder,tentry.name)) {
736 /* then the name really did change */
737 pos = FindByName(at,holder);
738 if (pos) return PREXIST;
739 code = RemoveFromNameHash(at,tentry.name,&loc);
740 if (code != PRSUCCESS) return code;
741 strncpy(tentry.name,holder,PR_MAXNAMELEN);
742 code = AddToNameHash(at,tentry.name,loc);
743 if (code != PRSUCCESS) return code;
746 code = pr_WriteEntry(at,0,loc,&tentry);
747 if (code) return PRDBFAIL;
749 if ((strcmp(tentry.name,name)) && (strlen(name)!= 0)) {
750 if (tentry.flags & PRGRP) {
751 if ((check = index(name,':')) == NULL) return PRBADNAM;
752 strncpy(temp,name,check-name);
753 code = NameToID(at,temp,&tid);
754 if (tid != tentry.owner) return PRPERM;
757 /* if it's not a group, shouldn't have a : in it */
758 if ((check = index(name,':')) != NULL)
760 pos = FindByName(at,name);
761 if (pos) return PREXIST;
762 code = RemoveFromNameHash(at,tentry.name,&loc);
763 if (code != PRSUCCESS) return code;
764 strncpy(tentry.name,name,PR_MAXNAMELEN);
765 code = pr_WriteEntry(at,0,loc,&tentry);
766 if (code) return PRDBFAIL;
767 code = AddToNameHash(at,tentry.name,loc);
768 if (code != PRSUCCESS) return code;