--- /dev/null
+/* $Header$ */
+/* $Source$ */
+
+
+/*
+ * P_R_P_Q_# (C) COPYRIGHT IBM CORPORATION 1988
+ * LICENSED MATERIALS - PROPERTY OF IBM
+ * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
+ */
+
+/*
+ Sherri Nichols
+ Information Technology Center
+ November, 1988
+
+ Modified May, 1989 by Jeff Schiller to keep disk file in
+ network byte order
+
+*/
+
+#include <stdio.h>
+#include <strings.h>
+#include <lock.h>
+#include <ubik.h>
+#include <rx/xdr.h>
+#include "print.h"
+#include "prserver.h"
+#include "prerror.h"
+#include <netinet/in.h>
+
+extern struct prheader cheader;
+extern struct ubik_dbase *dbase;
+extern struct afsconf_dir *prdir;
+
+long CreateEntry(at, aname, aid, idflag,flag,oid,creator)
+register struct ubik_trans *at;
+char aname[PR_MAXNAMELEN];
+long *aid;
+long idflag;
+long flag;
+long oid;
+long creator;
+{
+ /* get and init a new entry */
+ register long code;
+ long newEntry;
+ long temp;
+ struct prentry tentry;
+
+ bzero(&tentry, sizeof(tentry));
+ newEntry = AllocBlock(at);
+ if (!newEntry) return PRDBFAIL;
+ if (flag & PRGRP) {
+ tentry.flags |= PRGRP;
+ tentry.owner = oid;
+ }
+ else if (flag & PRFOREIGN) {
+ tentry.flags |= PRFOREIGN;
+ tentry.owner = oid;
+ }
+ else tentry.owner = SYSADMINID;
+ if (idflag)
+ tentry.id = *aid;
+ else {
+ code= AllocID(at,flag,&tentry.id);
+ if (code != PRSUCCESS) return code;
+ }
+ if (flag & PRGRP) {
+ if (tentry.id < ntohl(cheader.maxGroup)) {
+ cheader.maxGroup = htonl(tentry.id);
+ code = pr_Write(at,0,16,(char *) &cheader.maxGroup,sizeof(cheader.maxGroup));
+ if (code) return PRDBFAIL;
+ }
+ }
+ else if (flag & PRFOREIGN) {
+ if (tentry.id > ntohl(cheader.maxForeign)) {
+ cheader.maxForeign = htonl(tentry.id);
+ code = pr_Write(at,0,24,(char *) &cheader.maxForeign,sizeof(cheader.maxForeign));
+ if (code) return PRDBFAIL;
+ }
+ }
+ else {
+ if (tentry.id > ntohl(cheader.maxID)) {
+ cheader.maxID = htonl(tentry.id);
+ code = pr_Write(at,0,20,(char *) &cheader.maxID,sizeof(cheader.maxID));
+ if (code) return PRDBFAIL;
+ }
+ }
+ tentry.creator = creator;
+ *aid = tentry.id;
+ strncpy(tentry.name, aname, PR_MAXNAMELEN);
+ code = pr_WriteEntry(at, 0, newEntry, &tentry);
+ if (code) return PRDBFAIL;
+ code = AddToIDHash(at,*aid,newEntry);
+ if (code != PRSUCCESS) return code;
+ code = AddToNameHash(at,aname,newEntry);
+ if (code != PRSUCCESS) return code;
+ if (tentry.flags & PRGRP) {
+ code = AddToOwnerChain(at,tentry.id,oid);
+ if (code) return code;
+ }
+ if (tentry.flags & PRGRP) {
+ temp = ntohl(cheader.groupcount) + 1;
+ cheader.groupcount = htonl(temp);
+ code = pr_Write(at,0,40,(char *)&cheader.groupcount,sizeof(cheader.groupcount));
+ if (code) return PRDBFAIL;
+ }
+ else if (tentry.flags & PRFOREIGN) {
+ temp = ntohl(cheader.foreigncount) + 1;
+ cheader.foreigncount = htonl(temp);
+ code = pr_Write(at,0,44,(char *)&cheader.foreigncount,sizeof(cheader.foreigncount));
+ if (code) return PRDBFAIL;
+ }
+ else if (tentry.flags & PRINST) {
+ temp = ntohl(cheader.instcount) + 1;
+ cheader.instcount = htonl(temp);
+ code = pr_Write(at,0,48,(char *)&cheader.instcount,sizeof(cheader.instcount));
+ if (code) return PRDBFAIL;
+ }
+ else {
+ temp = ntohl(cheader.usercount) + 1;
+ cheader.usercount = htonl(temp);
+ code = pr_Write(at,0,36,(char *)&cheader.usercount,sizeof(cheader.usercount));
+ if (code) return PRDBFAIL;
+ }
+ return PRSUCCESS;
+}
+
+
+
+long RemoveFromEntry(at,aid,bid)
+register struct ubik_trans *at;
+register long aid;
+register long bid;
+{
+ /* remove aid from bid's entries list, freeing a continuation entry if appropriate */
+
+ register long code;
+ struct prentry tentry;
+ struct contentry centry;
+ struct contentry hentry;
+ long temp;
+ long first;
+ long i,j;
+ long nptr;
+ long hloc = 0;
+
+ bzero(&hentry,sizeof(hentry));
+ temp = FindByID(at,bid);
+ code = pr_ReadEntry(at, 0, temp, &tentry);
+ if (code != 0) return code;
+ for (i=0;i<PRSIZE;i++) {
+ if (tentry.entries[i] == aid) {
+ tentry.entries[i] = PRBADID;
+ tentry.count--;
+ code = pr_WriteEntry(at,0,temp,&tentry);
+ if (code != 0) return code;
+ return PRSUCCESS;
+ }
+ if (tentry.entries[i] == 0) /* found end of list */
+ return PRNOENT;
+ }
+ if (tentry.next != NULL) {
+ nptr = tentry.next;
+ first = 1;
+ while (nptr != NULL) {
+ code = pr_ReadCoEntry(at,0,nptr,¢ry);
+ if (code != 0) return code;
+ for (i=0;i<COSIZE;i++) {
+ if (centry.entries[i] == aid) {
+ centry.entries[i] = PRBADID;
+ tentry.count--;
+ code = pr_WriteEntry(at,0,temp,&tentry);
+ if (code) return PRDBFAIL;
+ for (j=0;j<COSIZE;j++)
+ if (centry.entries[j] != PRBADID && centry.entries[j] != 0) break;
+ if (j == COSIZE) { /* can free this block */
+ if (first) {
+ tentry.next = centry.next;
+ code = pr_WriteEntry(at,0,temp,&tentry);
+ if (code != 0) return code;
+ }
+ else {
+ hentry.next = centry.next;
+ code = pr_WriteCoEntry(at,0,hloc,(char *) &hentry);
+ if (code != 0) return code;
+ }
+ code = FreeBlock(at,nptr);
+ return code;
+ }
+ else { /* can't free it yet */
+ code = pr_WriteCoEntry(at,0,nptr,¢ry);
+ if (code != 0) return code;
+ return PRSUCCESS;
+ }
+ }
+ if (centry.entries[i] == 0) return PRNOENT;
+ }
+ hloc = nptr;
+ nptr = centry.next;
+ bcopy(¢ry,&hentry,sizeof(centry));
+ }
+ }
+ else return PRNOENT;
+ return PRSUCCESS;
+}
+
+long DeleteEntry(at,aid,cid)
+register struct ubik_trans *at;
+long aid;
+long cid;
+{
+ /* delete the entry aid, removing it from all groups, putting groups owned by it on orphan chain, and freeing the space */
+ register long code;
+ long temp;
+ long temp1;
+ struct prentry tentry;
+ struct contentry centry;
+ struct prentry nentry;
+ register long i;
+ long nptr;
+ long noAuth;
+
+ noAuth = afsconf_GetNoAuthFlag(prdir);
+ bzero(&tentry,sizeof(tentry));
+ temp = FindByID(at,aid);
+ if (!temp) return PRNOENT;
+ code = pr_ReadEntry(at,0,temp,&tentry);
+ if (code != 0) return PRDBFAIL;
+ if (tentry.owner != cid && !IsAMemberOf(at,cid,SYSADMINID) && !IsAMemberOf(at,cid,tentry.owner) && !noAuth) return PRPERM;
+ for (i=0;i<PRSIZE;i++) {
+ if (tentry.entries[i] == 0) break;
+ RemoveFromEntry(at,aid,tentry.entries[i]);
+ }
+ nptr = tentry.next;
+ while (nptr != NULL) {
+ code = pr_ReadCoEntry(at,0,nptr,¢ry);
+ if (code != 0) return PRDBFAIL;
+ for (i=0;i<COSIZE;i++) {
+ if (centry.entries[i] == 0) break;
+ RemoveFromEntry(at,aid,centry.entries[i]);
+ }
+ nptr = centry.next;
+ }
+ if (tentry.flags & PRGRP) {
+ if (FindByID(at,tentry.owner)) {
+ code = RemoveFromOwnerChain(at,aid,tentry.owner);
+ if (code) return code;
+ }
+ else {
+ code = RemoveFromOrphan(at,aid);
+ if (code) return code;
+ }
+ }
+ if (tentry.owned) {
+ nptr = tentry.owned;
+ while (nptr != NULL) {
+ code = pr_ReadEntry(at,0,nptr,&nentry);
+ if (code != 0) return PRDBFAIL;
+ if (nentry.id != aid) /* don't add this entry to orphan chain! */
+ code = AddToOrphan(at,nentry.id);
+ nptr = nentry.nextOwned;
+ }
+ }
+ code = RemoveFromIDHash(at,tentry.id,&temp);
+ if (code != PRSUCCESS) return code;
+ code = RemoveFromNameHash(at,tentry.name,&temp);
+ if (code != PRSUCCESS) return code;
+ if (tentry.flags & PRGRP) {
+ temp1 = ntohl(cheader.groupcount) + 1;
+ cheader.groupcount = htonl(temp1);
+ code = pr_Write(at,0,40,(char *)&cheader.groupcount,sizeof(cheader.groupcount));
+ if (code) return PRDBFAIL;
+ }
+ else if (tentry.flags & PRFOREIGN) {
+ temp1 = ntohl(cheader.foreigncount) + 1;
+ cheader.foreigncount = htonl(temp1);
+ code = pr_Write(at,0,44,(char *)&cheader.foreigncount,sizeof(cheader.foreigncount));
+ if (code) return PRDBFAIL;
+ }
+ else if (tentry.flags & PRINST) {
+ temp1 = ntohl(cheader.instcount) + 1;
+ cheader.instcount = htonl(temp1);
+ code = pr_Write(at,0,48,(char *)&cheader.instcount,sizeof(cheader.instcount));
+ if (code) return PRDBFAIL;
+ }
+ else {
+ temp1 = ntohl(cheader.usercount) + 1;
+ cheader.usercount = htonl(temp1);
+ code = pr_Write(at,0,36,(char *)&cheader.usercount,sizeof(cheader.usercount));
+ if (code) return PRDBFAIL;
+ }
+ FreeBlock(at,temp);
+ return PRSUCCESS;
+}
+
+
+
+
+long AddToEntry(tt,entry,loc,aid)
+struct ubik_trans *tt;
+struct prentry entry;
+long loc;
+long aid;
+{
+ /* add aid to entry's entries list, alloc'ing a continuation block if needed */
+ register long code;
+ long i;
+ struct contentry nentry;
+ struct contentry aentry;
+ long nptr;
+ long last = 0;
+ long first = 0;
+ long cloc;
+ long slot = -1;
+
+ bzero(&nentry,sizeof(nentry));
+ bzero(&aentry,sizeof(aentry));
+ for (i=0;i<PRSIZE;i++) {
+ if (entry.entries[i] == aid)
+ return PRIDEXIST;
+ if (entry.entries[i] == PRBADID) { /* remember this spot */
+ first = 1;
+ slot = i;
+ }
+ if (entry.entries[i] == 0) { /* end of the line */
+ if (slot == -1) {
+ first = 1;
+ slot = i;
+ }
+ break;
+ }
+ }
+ nptr = entry.next;
+ while (nptr != NULL) {
+ code = pr_ReadCoEntry(tt,0,nptr,&nentry);
+ if (code != 0) return code;
+ if (!(nentry.flags & PRCONT)) return PRDBFAIL;
+ for (i=0;i<COSIZE;i++) {
+ if (nentry.entries[i] == aid)
+ return PRIDEXIST;
+ if (nentry.entries[i] == PRBADID) {
+ if (slot == -1) {
+ slot = i;
+ cloc = nptr;
+ }
+ }
+ if (nentry.entries[i] == 0) {
+ if (slot == -1) {
+ slot = i;
+ cloc = nptr;
+ }
+ break;
+ }
+ }
+ last = nptr;
+ nptr = nentry.next;
+ }
+ if (slot != -1) { /* we found a place */
+ entry.count++;
+ if (first) { /* place is in first block */
+ entry.entries[slot] = aid;
+ code = pr_WriteEntry(tt,0,loc,&entry);
+ if (code != 0) return code;
+ return PRSUCCESS;
+ }
+ code = pr_WriteEntry(tt,0,loc,&entry);
+ code = pr_ReadCoEntry(tt,0,cloc,&aentry);
+ if (code != 0) return code;
+ aentry.entries[slot] = aid;
+ code = pr_WriteCoEntry(tt,0,cloc,&aentry);
+ if (code != 0) return code;
+ return PRSUCCESS;
+ }
+ /* have to allocate a continuation block if we got here */
+ nptr = AllocBlock(tt);
+ if (nentry.flags & PRCONT) {
+ /* then we should tack new block here */
+ nentry.next = nptr;
+ code = pr_WriteCoEntry(tt,0,last,&nentry);
+ if (code != 0) return code;
+ }
+ else {
+ entry.next = nptr;
+ code = pr_WriteEntry(tt,0,loc,&entry);
+ if (code != 0) return code;
+ }
+ aentry.flags |= PRCONT;
+ aentry.id = entry.id;
+ aentry.next = NULL;
+ aentry.entries[0] = aid;
+ code = pr_WriteCoEntry(tt,0,nptr,&aentry);
+ if (code != 0) return code;
+ /* don't forget to update count, here! */
+ entry.count++;
+ code = pr_WriteEntry(tt,0,loc,&entry);
+ return PRSUCCESS;
+
+}
+
+long GetList(at,aid,alist,add)
+struct ubik_trans *at;
+long aid;
+prlist *alist;
+long add;
+{
+ register long code;
+ long temp;
+ long i;
+ long count;
+ struct prentry tentry;
+ struct contentry centry;
+ long nptr;
+ long size;
+ extern long IDCmp();
+
+ temp = FindByID(at,aid);
+ if (!temp) return PRNOENT;
+ code = pr_ReadEntry(at,0,temp,&tentry);
+ if (code != 0) return code;
+ alist->prlist_val = (long *)malloc(100*sizeof(long));
+ size = 100;
+ alist->prlist_len = 0;
+ count = 0;
+ for (i=0;i<PRSIZE;i++) {
+ if (tentry.entries[i] == PRBADID) continue;
+ if (tentry.entries[i] == 0) break;
+ alist->prlist_val[count]= tentry.entries[i];
+ count++;
+ alist->prlist_len++;
+ }
+ nptr = tentry.next;
+ while (nptr != NULL) {
+ /* look through cont entries */
+ code = pr_ReadCoEntry(at,0,nptr,¢ry);
+ if (code != 0) return code;
+ for (i=0;i<COSIZE;i++) {
+ if (centry.entries[i] == PRBADID) continue;
+ if (centry.entries[i] == 0) break;
+ if (alist->prlist_len >= size) {
+ alist->prlist_val = (long *)realloc(alist->prlist_val,(size+100)*sizeof(long));
+ size += 100;
+ }
+ alist->prlist_val[count] = centry.entries[i];
+ count++;
+ alist->prlist_len++;
+ }
+ nptr = centry.next;
+ }
+ if (add) { /* this is for a CPS, so tack on appropriate stuff */
+ if (aid != ANONYMOUSID && aid != ANYUSERID) {
+ if (alist->prlist_len >= size)
+ alist->prlist_val = (long *)realloc(alist->prlist_val,(size + 3)*sizeof(long));
+ alist->prlist_val[count] = ANYUSERID;
+ count++;
+ alist->prlist_val[count] = AUTHUSERID;
+ count++;
+ alist->prlist_val[count] = aid;
+ count++;
+ alist->prlist_len += 3;
+ }
+ else {
+ if (alist->prlist_len >= size)
+ alist->prlist_val = (long *)realloc(alist->prlist_val,(size + 2)*sizeof(long));
+ alist->prlist_val[count] = ANYUSERID;
+ count++;
+ alist->prlist_val[count] = aid;
+ count++;
+ alist->prlist_len += 2;
+ }
+ }
+ qsort(alist->prlist_val,alist->prlist_len,sizeof(long),IDCmp);
+ return PRSUCCESS;
+}
+
+long GetMax(at,uid,gid)
+register struct ubik_trans *at;
+long *uid;
+long *gid;
+{
+ *uid = ntohl(cheader.maxID);
+ *gid = ntohl(cheader.maxGroup);
+ return PRSUCCESS;
+}
+
+long SetMax(at,id,flag)
+register struct ubik_trans *at;
+long id;
+long flag;
+{
+ register long code;
+ if (flag & PRGRP) {
+ cheader.maxGroup = htonl(id);
+ code = pr_Write(at,0,16,(char *)&cheader.maxGroup,sizeof(cheader.maxGroup));
+ if (code != 0) return code;
+ }
+ else {
+ cheader.maxID = htonl(id);
+ code = pr_Write(at,0,20,(char *)&cheader.maxID,sizeof(cheader.maxID));
+ if (code != 0) return code;
+ }
+ return PRSUCCESS;
+}
+
+Initdb()
+{
+ long code;
+ struct ubik_trans *tt;
+ long len;
+ long temp;
+ long flag = 0;
+ static long initd=0;
+ static struct ubik_version curver;
+ struct ubik_version newver;
+
+ /* init the database. We'll try reading it, but if we're starting from scratch, we'll have to do a write transaction. */
+
+ code = ubik_BeginTrans(dbase,UBIK_READTRANS, &tt);
+ if (code) return code;
+ code = ubik_SetLock(tt,1,1,LOCKREAD);
+ if (code) {
+ ubik_AbortTrans(tt);
+ return code;
+ }
+ if (!initd) {
+ initd = 1;
+ bzero(&curver,sizeof(curver));
+ }
+ code = ubik_GetVersion(tt,&newver);
+ if (vcmp(curver,newver) == 0) {
+ /* same version */
+ code = ubik_EndTrans(tt);
+ if (code) return code;
+ return PRSUCCESS;
+ }
+ bcopy(&newver,&curver,sizeof(struct ubik_version));
+ len = sizeof(cheader);
+ code = pr_Read(tt, 0, 0, (char *) &cheader, len);
+ if (code != 0) {
+ printf("prserver: couldn't read header -code is %d\n",code);
+ ubik_AbortTrans(tt);
+ return code;
+ }
+ if (ntohl(cheader.headerSize) == sizeof(cheader) && ntohl(cheader.eofPtr) != NULL && FindByID(tt,ANONYMOUSID) != 0){
+ /* database exists, so we don't have to build it */
+ code = ubik_EndTrans(tt);
+ if (code) return code;
+ return PRSUCCESS;
+ }
+ /* else we need to build a database */
+ code = ubik_EndTrans(tt);
+ if (code) return code;
+ code = ubik_BeginTrans(dbase,UBIK_WRITETRANS, &tt);
+ if (code) return code;
+ code = ubik_SetLock(tt,1,1,LOCKWRITE);
+ if (code) {
+ ubik_AbortTrans(tt);
+ return code;
+ }
+ cheader.headerSize = htonl(sizeof(cheader));
+ code = pr_Write(tt,0,4,(char *)&cheader.headerSize,sizeof(cheader.headerSize));
+ if (code != 0) {
+ printf("prserver: couldn't write header size - code is %d.\n",code);
+ ubik_AbortTrans(tt);
+ return code;
+ }
+ cheader.eofPtr = cheader.headerSize; /* already in network order! */
+ code = pr_Write(tt,0,12,(char *)&cheader.eofPtr,sizeof(cheader.eofPtr));
+ if (code != 0) {
+ printf("prserver: couldn't write eof Ptr - code is %d.\n",code);
+ ubik_AbortTrans(tt);
+ return code;
+ }
+ temp = SYSADMINID;
+ if (FindByID(tt,SYSADMINID) == 0) {
+ /* init sysadmin */
+ flag |= PRGRP;
+ code = CreateEntry(tt,"system:administrators",&temp,1,flag,SYSADMINID,SYSADMINID);
+ if (code != PRSUCCESS) {
+ printf("prserver: couldn't create system:administrators.\n");
+ ubik_AbortTrans(tt);
+ return code;
+ }
+ flag = 0;
+ }
+ temp = ANYUSERID;
+ if ( FindByID(tt,temp) == 0) { /* init sysadmin */
+ flag |= PRGRP;
+ code = CreateEntry(tt,"system:anyuser",&temp,1,flag,SYSADMINID,SYSADMINID);
+ if (code != PRSUCCESS) {
+ printf("prserver: couldn't create system:anyuser.\n");
+ ubik_AbortTrans(tt);
+ return code;
+ }
+ flag = 0;
+ }
+ temp = AUTHUSERID;
+ if (FindByID(tt,temp) == 0) { /* init sysadmin */
+ flag |= PRGRP;
+ code = CreateEntry(tt,"system:authuser",&temp,1,flag,SYSADMINID,SYSADMINID);
+ if (code != PRSUCCESS) {
+ printf("prserver: couldn't create system:authuser.\n");
+ ubik_AbortTrans(tt);
+ return code;
+ }
+ flag = 0;
+ }
+ temp = ANONYMOUSID;
+ if (FindByID(tt,temp) == 0) { /* init sysadmin */
+ code = CreateEntry(tt,"anonymous",&temp,1,flag,SYSADMINID,SYSADMINID);
+ if (code != PRSUCCESS) {
+ printf("prserver: couldn't create anonymous.\n");
+ ubik_AbortTrans(tt);
+ return code;
+ }
+ /* well, we don't really want the max id set to anonymousid, so we'll set it back to 0 */
+ cheader.maxID = 0; /* Zero is in correct byte order no matter what! */
+ code = pr_Write(tt,0,20,(char *)&cheader.maxID,sizeof(cheader.maxID));
+ if (code) {
+ printf("prserver: couldn't set max id - code is %d.\n");
+ ubik_AbortTrans(tt);
+ return code;
+ }
+ }
+ code = ubik_EndTrans(tt);
+ if (code) return code;
+ return PRSUCCESS;
+}
+
+long NameToID(at, aname, aid)
+register struct ubik_trans *at;
+char aname[PR_MAXNAMELEN];
+long *aid;
+{
+ register long code;
+ long temp;
+ struct prentry tentry;
+
+ temp = FindByName(at,aname);
+ if (!temp) return PRNOENT;
+ code = pr_ReadEntry(at, 0, temp, &tentry);
+ if (code != 0) return code;
+ *aid = tentry.id;
+ return PRSUCCESS;
+}
+
+long IDToName(at, aid, aname)
+register struct ubik_trans *at;
+long aid;
+char aname[PR_MAXNAMELEN];
+{
+ long temp;
+ struct prentry tentry;
+ register long code;
+
+ temp = FindByID(at,aid);
+ if (!temp) return PRNOENT;
+ code = pr_ReadEntry(at,0,temp,&tentry);
+ if (code != 0) return code;
+ strncpy(aname,tentry.name,PR_MAXNAMELEN);
+ return PRSUCCESS;
+}
+
+long ChangeEntry(at, aid,cid,name,oid,newid)
+struct ubik_trans *at;
+long aid;
+long cid;
+char *name;
+long oid;
+long newid;
+{
+ register long code;
+ long pos;
+ struct prentry tentry;
+ long loc;
+ long noAuth;
+ char *check;
+ long tid;
+ char holder[PR_MAXNAMELEN];
+ char temp[PR_MAXNAMELEN];
+
+ noAuth = afsconf_GetNoAuthFlag(prdir);
+ bzero(holder,PR_MAXNAMELEN);
+ bzero(temp,PR_MAXNAMELEN);
+ loc = FindByID(at,aid);
+ if (!loc) return PRNOENT;
+ code = pr_ReadEntry(at,0,loc,&tentry);
+ if (code) return PRDBFAIL;
+ if (tentry.owner != cid && !IsAMemberOf(at,cid,SYSADMINID) && !IsAMemberOf(at,cid,tentry.owner) && !noAuth)
+ return PRPERM;
+ if (aid != newid && newid != 0) { /* then we're actually trying to change the id */
+ pos = FindByID(at,newid);
+ if (pos) return PRIDEXIST; /* new id already in use! */
+ if ((aid < 0 && newid) > 0 || (aid > 0 && newid < 0)) return PRPERM;
+ /* if new id is not in use, rehash things */
+ code = RemoveFromIDHash(at,aid,&loc);
+ if (code != PRSUCCESS) return code;
+ tentry.id = newid;
+ code = pr_WriteEntry(at,0,loc,&tentry);
+ code = AddToIDHash(at,tentry.id,loc);
+ if (code) return code;
+ }
+ if (tentry.owner != oid && oid) {
+ if (tentry.flags & PRGRP) {
+ /* switch owner chains before we lose old owner */
+ if (FindByID(at,tentry.owner)) /* if it has an owner */
+ code = RemoveFromOwnerChain(at,tentry.id,tentry.owner);
+ else /* must be an orphan */
+ code = RemoveFromOrphan(at,tentry.id);
+ if (code) return code;
+ code = AddToOwnerChain(at,tentry.id,oid);
+ if (code) return code;
+ }
+ tentry.owner = oid;
+ if ((tentry.flags & PRGRP) && (strlen(name) == 0)) {
+ /* if we change the owner of a group, it's name will change as well */
+ if (tentry.owner < 0) {
+ code = IDToName(at,tentry.owner,temp);
+ if (code) return code;
+ check = index(temp,':');
+ strncpy(holder,temp,check - temp);
+ }
+ else {
+ code = IDToName(at,tentry.owner,holder);
+ if (code) return code;
+ }
+ strncat(holder,":",PR_MAXNAMELEN);
+ /* now the rest of the name */
+ check = index(tentry.name,':');
+ strncat(holder,++check,PR_MAXNAMELEN);
+ if (strcmp(holder,tentry.name)) {
+ /* then the name really did change */
+ pos = FindByName(at,holder);
+ if (pos) return PREXIST;
+ code = RemoveFromNameHash(at,tentry.name,&loc);
+ if (code != PRSUCCESS) return code;
+ strncpy(tentry.name,holder,PR_MAXNAMELEN);
+ code = AddToNameHash(at,tentry.name,loc);
+ if (code != PRSUCCESS) return code;
+ }
+ }
+ code = pr_WriteEntry(at,0,loc,&tentry);
+ if (code) return PRDBFAIL;
+ }
+ if ((strcmp(tentry.name,name)) && (strlen(name)!= 0)) {
+ if (tentry.flags & PRGRP) {
+ if ((check = index(name,':')) == NULL) return PRBADNAM;
+ strncpy(temp,name,check-name);
+ code = NameToID(at,temp,&tid);
+ if (tid != tentry.owner) return PRPERM;
+ }
+ else
+ /* if it's not a group, shouldn't have a : in it */
+ if ((check = index(name,':')) != NULL)
+ return PRBADNAM;
+ pos = FindByName(at,name);
+ if (pos) return PREXIST;
+ code = RemoveFromNameHash(at,tentry.name,&loc);
+ if (code != PRSUCCESS) return code;
+ strncpy(tentry.name,name,PR_MAXNAMELEN);
+ code = pr_WriteEntry(at,0,loc,&tentry);
+ if (code) return PRDBFAIL;
+ code = AddToNameHash(at,tentry.name,loc);
+ if (code != PRSUCCESS) return code;
+ }
+ return PRSUCCESS;
+}
+
+
+
+
--- /dev/null
+/* $Header$ */
+
+#include <sys/types.h>
+#include <lock.h>
+#define UBIK_INTERNALS
+#include <ubik.h>
+#include <rx/xdr.h>
+#include "print.h"
+#include "prserver.h"
+
+
+struct ubik_dbase *dbase;
+
+long ubik_BeginTrans()
+{
+ return(0);
+}
+
+long ubik_SetLock()
+{
+ return(0);
+}
+
+long ubik_AbortTrans()
+{
+ return(0);
+}
+
+long ubik_GetVersion(dummy, ver)
+int dummy;
+struct ubik_version *ver;
+{
+ bzero(ver, sizeof(struct ubik_version));
+ return(0);
+}
+
+long ubik_EndTrans()
+{
+ return(0);
+}
+
+
+extern int dbase_fd;
+
+long ubik_Seek(tt, afd, pos)
+struct ubik_trans *tt;
+long afd;
+long pos;
+{
+ if (lseek(dbase_fd, pos+HDRSIZE, 0) < 0) {
+ perror("ubik_Seek");
+ return(-1);
+ }
+ return(0);
+}
+
+long ubik_Write(tt, buf, len)
+struct ubik_trans *tt;
+char *buf;
+long len;
+{
+ int status;
+
+ status = write(dbase_fd, buf, len);
+ if (status < len) {
+ perror("ubik_Write");
+ return(1);
+ }
+ return(0);
+}
+
+long ubik_Read(tt, buf, len)
+struct ubik_trans *tt;
+char *buf;
+long len;
+{
+ int status;
+
+ status = read(dbase_fd, buf, len);
+ if (status < 0) {
+ perror("ubik_Read");
+ return(1);
+ }
+ if (status < len)
+ bzero(&buf[status], len - status);
+ return(0);
+}
+
+
+char *prdir = "/dev/null";
+
+afsconf_GetNoAuthFlag()
+{
+ return(1);
+}
+
+
+struct prheader cheader;
--- /dev/null
+/* $Header$ */
+/* $Source$ */
+
+
+/*
+ * P_R_P_Q_# (C) COPYRIGHT IBM CORPORATION 1988
+ * LICENSED MATERIALS - PROPERTY OF IBM
+ * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
+ */
+
+/*
+ Sherri Nichols
+ Information Technology Center
+ November, 1988
+
+ Modified May, 1989 by Jeff Schiller to keep disk file in
+ network byte order
+
+*/
+
+
+#include <sys/types.h>
+#include <lock.h>
+#include <ubik.h>
+#include <stdio.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <rx/xdr.h>
+#include <rx/rx.h>
+#include <rx/rx_vab.h>
+#include <rx/rxkad.h>
+#include "print.h"
+#include "prserver.h"
+#include "prerror.h"
+
+extern struct prheader cheader;
+extern struct ubik_dbase *dbase;
+
+long IDHash(x)
+long x;
+{
+ /* returns hash bucket for x */
+ return ((abs(x)) % HASHSIZE);
+}
+
+long NameHash(aname)
+register unsigned char *aname;
+{
+ /* returns hash bucket for aname */
+ register unsigned int hash=0;
+ register int i;
+/* stolen directly from the HashString function in the vol package */
+ for (i=strlen(aname),aname += i-1;i--;aname--)
+ hash = (hash*31) + (*aname-31);
+ return(hash % HASHSIZE);
+}
+
+
+long pr_Write(tt,afd,pos,buff,len)
+struct ubik_trans *tt;
+long afd;
+long pos;
+char *buff;
+long len;
+{
+ /* package up seek and write into one procedure for ease of use */
+ long code;
+ code = ubik_Seek(tt,afd,pos);
+ if (code) return code;
+ code = ubik_Write(tt,buff,len);
+ return code;
+}
+
+long pr_Read(tt,afd,pos,buff,len)
+struct ubik_trans *tt;
+long afd;
+long pos;
+char *buff;
+long len;
+{
+ /* same thing for read */
+ long code;
+ code = ubik_Seek(tt,afd,pos);
+ if (code) return code;
+ code = ubik_Read(tt,buff,len);
+ return code;
+}
+
+pr_WriteEntry(tt, afd, pos, tentry)
+struct ubik_trans *tt;
+long afd;
+long pos;
+struct prentry *tentry;
+{
+ long code;
+ register long i;
+ struct prentry nentry;
+ if (ntohl(1) != 1) { /* Need to swap bytes. */
+ nentry.flags = htonl(tentry->flags);
+ nentry.id = htonl(tentry->id);
+ nentry.cellid = htonl(tentry->cellid);
+ nentry.next = htonl(tentry->next);
+ nentry.nextID = htonl(tentry->nextID);
+ nentry.nextName = htonl(tentry->nextName);
+ nentry.owner = htonl(tentry->owner);
+ nentry.creator = htonl(tentry->creator);
+ nentry.ngroups = htonl(tentry->ngroups);
+ nentry.nusers = htonl(tentry->nusers);
+ nentry.count = htonl(tentry->count);
+ nentry.instance = htonl(tentry->instance);
+ nentry.owned = htonl(tentry->owned);
+ nentry.nextOwned = htonl(tentry->nextOwned);
+ nentry.parent = htonl(tentry->parent);
+ nentry.sibling = htonl(tentry->sibling);
+ nentry.child = htonl(tentry->child);
+ strncpy(nentry.name, tentry->name, PR_MAXNAMELEN);
+ for (i = 0; i < PRSIZE; i++)
+ nentry.entries[i] = htonl(tentry->entries[i]);
+ code = ubik_Seek(tt, afd, pos);
+ if (code) return (code);
+ code = ubik_Write(tt, (char *) &nentry, sizeof(struct prentry));
+ return(code);
+ } else {
+ code = ubik_Seek(tt, afd, pos);
+ if (code) return (code);
+ code = ubik_Write(tt, (char *) tentry, sizeof(struct prentry));
+ return(code);
+ }
+}
+
+pr_ReadEntry(tt, afd, pos, tentry)
+struct ubik_trans *tt;
+long afd;
+long pos;
+struct prentry *tentry;
+{
+ long code;
+ register long i;
+ struct prentry nentry;
+ code = ubik_Seek(tt, afd, pos);
+ if (code) return (code);
+ if (ntohl(1) == 1) { /* no swapping needed */
+ code = ubik_Read(tt, (char *) tentry, sizeof(struct prentry));
+ return(code);
+ }
+ code = ubik_Read(tt, (char *) &nentry, sizeof(struct prentry));
+ if (code) return (code);
+ tentry->flags = ntohl(nentry.flags);
+ tentry->id = ntohl(nentry.id);
+ tentry->cellid = ntohl(nentry.cellid);
+ tentry->next = ntohl(nentry.next);
+ tentry->nextID = ntohl(nentry.nextID);
+ tentry->nextName = ntohl(nentry.nextName);
+ tentry->owner = ntohl(nentry.owner);
+ tentry->creator = ntohl(nentry.creator);
+ tentry->ngroups = ntohl(nentry.ngroups);
+ tentry->nusers = ntohl(nentry.nusers);
+ tentry->count = ntohl(nentry.count);
+ tentry->instance = ntohl(nentry.instance);
+ tentry->owned = ntohl(nentry.owned);
+ tentry->nextOwned = ntohl(nentry.nextOwned);
+ tentry->parent = ntohl(nentry.parent);
+ tentry->sibling = ntohl(nentry.sibling);
+ tentry->child = ntohl(nentry.child);
+ strncpy(tentry->name, nentry.name, PR_MAXNAMELEN);
+ for (i = 0; i < PRSIZE; i++)
+ tentry->entries[i] = ntohl(nentry.entries[i]);
+ return(code);
+}
+
+pr_WriteCoEntry(tt, afd, pos, tentry)
+struct ubik_trans *tt;
+long afd;
+long pos;
+struct contentry *tentry;
+{
+ long code;
+ register long i;
+ struct contentry nentry;
+ if (ntohl(1) == 1) { /* No need to swap */
+ code = ubik_Seek(tt, afd, pos);
+ if (code) return(code);
+ code = ubik_Write(tt, (char *) tentry, sizeof(struct contentry));
+ return(code);
+ }
+ nentry.flags = htonl(tentry->flags);
+ nentry.id = htonl(tentry->id);
+ nentry.cellid = htonl(tentry->cellid);
+ nentry.next = htonl(tentry->next);
+ for (i = 0; i < COSIZE; i++)
+ nentry.entries[i] = htonl(tentry->entries[i]);
+ code = ubik_Seek(tt, afd, pos);
+ if (code) return (code);
+ code = ubik_Write(tt, (char *) &nentry, sizeof(struct contentry));
+ return(code);
+}
+
+pr_ReadCoEntry(tt, afd, pos, tentry)
+struct ubik_trans *tt;
+long afd;
+long pos;
+struct contentry *tentry;
+{
+ long code;
+ register long i;
+ struct contentry nentry;
+ code = ubik_Seek(tt, afd, pos);
+ if (code) return (code);
+ if (ntohl(1) == 1) { /* No swapping needed. */
+ code = ubik_Read(tt, (char *) tentry, sizeof(struct contentry));
+ return(code);
+ }
+ code = ubik_Read(tt, (char *) &nentry, sizeof(struct contentry));
+ if (code) return (code);
+ tentry->flags = ntohl(nentry.flags);
+ tentry->id = ntohl(nentry.id);
+ tentry->cellid = ntohl(nentry.cellid);
+ tentry->next = ntohl(nentry.next);
+ for (i = 0; i < COSIZE; i++)
+ tentry->entries[i] = ntohl(nentry.entries[i]);
+ return(code);
+}
+
+long AllocBlock(at)
+register struct ubik_trans *at;
+{
+ /* allocate a free block of storage for entry, returning address of new entry */
+ register long code;
+ long temp;
+ struct prentry tentry;
+
+ if (cheader.freePtr) {
+ /* allocate this dude */
+ temp = ntohl(cheader.freePtr);
+ code = pr_ReadEntry(at, 0, temp, &tentry);
+ if (code) return 0;
+ cheader.freePtr = htonl(tentry.next);
+ code = pr_Write(at, 0, 8, (char *)&cheader.freePtr, sizeof(cheader.freePtr));
+ if (code != 0) return 0;
+ return temp;
+ }
+ else {
+ /* hosed, nothing on free list, grow file */
+ temp = ntohl(cheader.eofPtr); /* remember this guy */
+ cheader.eofPtr = htonl(temp + ENTRYSIZE);
+ code = pr_Write(at, 0, 12,(char *) &cheader.eofPtr, sizeof(cheader.eofPtr));
+ if (code != 0) return 0;
+ return temp;
+ }
+}
+
+long FreeBlock(at, pos)
+register struct ubik_trans *at;
+long pos;
+{
+ /* add a block of storage to the free list */
+ register long code;
+ struct prentry tentry;
+
+ bzero(&tentry,sizeof(tentry));
+ tentry.next = ntohl(cheader.freePtr);
+ tentry.flags |= PRFREE;
+ cheader.freePtr = htonl(pos);
+ code = pr_Write(at,0,8, (char *) &cheader.freePtr,sizeof(cheader.freePtr));
+ if (code != 0) return code;
+ code = pr_WriteEntry(at,0,pos,&tentry);
+ if (code != 0) return code;
+ return PRSUCCESS;
+}
+
+long FindByID(at,aid)
+register struct ubik_trans *at;
+long aid;
+{
+ /* returns address of entry if found, 0 otherwise */
+ register long code;
+ long i;
+ struct prentry tentry;
+ long entry;
+
+ i = IDHash(aid);
+ entry = ntohl(cheader.idHash[i]);
+ if (entry == 0) return entry;
+ bzero(&tentry,sizeof(tentry));
+ code = pr_ReadEntry(at, 0, entry, &tentry);
+ if (code != 0) return 0;
+ if (aid == tentry.id) return entry;
+ entry = tentry.nextID;
+ while (entry != NULL) {
+ bzero(&tentry,sizeof(tentry));
+ code = pr_ReadEntry(at,0,entry,&tentry);
+ if (code != 0) return 0;
+ if (aid == tentry.id) return entry;
+ entry = tentry.nextID;
+ }
+ return 0;
+}
+
+
+
+long FindByName(at,aname)
+register struct ubik_trans *at;
+char aname[PR_MAXNAMELEN];
+{
+ /* ditto */
+ register long code;
+ long i;
+ struct prentry tentry;
+ long entry;
+
+ i = NameHash(aname);
+ entry = ntohl(cheader.nameHash[i]);
+ if (entry == 0) return entry;
+ bzero(&tentry,sizeof(tentry));
+ code = pr_ReadEntry(at, 0, entry,&tentry);
+ if (code != 0) return 0;
+ if ((strncmp(aname,tentry.name,PR_MAXNAMELEN)) == 0) return entry;
+ entry = tentry.nextName;
+ while (entry != NULL) {
+ bzero(&tentry,sizeof(tentry));
+ code = pr_ReadEntry(at,0,entry,&tentry);
+ if (code != 0) return 0;
+ if ((strncmp(aname,tentry.name,PR_MAXNAMELEN)) == 0) return entry;
+ entry = tentry.nextName;
+ }
+ return 0;
+}
+
+long AllocID(at,flag,aid)
+register struct ubik_trans *at;
+long flag;
+long *aid;
+{
+ /* allocs an id from the proper area of address space, based on flag */
+ register long code = 1;
+ register long i = 0;
+ register maxcount = 50; /* to prevent infinite loops */
+
+ if (flag & PRGRP) {
+ *aid = ntohl(cheader.maxGroup);
+ while (code && i<maxcount) {
+ --(*aid);
+ code = FindByID(at,*aid);
+ i++;
+ }
+ if (code) return PRNOIDS;
+ cheader.maxGroup = htonl(*aid);
+ code = pr_Write(at,0,16,(char *)&cheader.maxGroup,sizeof(cheader.maxGroup));
+ if (code) return PRDBFAIL;
+ return PRSUCCESS;
+ }
+ else if (flag & PRFOREIGN) {
+ *aid = ntohl(cheader.maxForeign);
+ while (code && i<maxcount) {
+ ++(*aid);
+ code = FindByID(at,*aid);
+ i++;
+ }
+ if (code) return PRNOIDS;
+ cheader.maxForeign = htonl(*aid);
+ code = pr_Write(at,0,24,(char *)&cheader.maxForeign,sizeof(cheader.maxForeign));
+ if (code) return PRDBFAIL;
+ return PRSUCCESS;
+ }
+ else {
+ *aid = ntohl(cheader.maxID);
+ while (code && i<maxcount) {
+ ++(*aid);
+ code = FindByID(at,*aid);
+ i++;
+ }
+ if (code) return PRNOIDS;
+ cheader.maxID = htonl(*aid);
+ code = pr_Write(at,0,20,(char *)&cheader.maxID,sizeof(cheader.maxID));
+ if (code) return PRDBFAIL;
+ return PRSUCCESS;
+ }
+}
+
+long IDCmp(a,b)
+long *a;
+long *b;
+{
+ /* used to sort CPS's so that comparison with acl's is easier */
+ if (*a > *b) return 1;
+ if (*a == *b) return 0;
+ if (*a < *b) return -1;
+}
+
+long RemoveFromIDHash(tt,aid,loc)
+struct ubik_trans *tt;
+long aid;
+long *loc;
+{
+ /* remove entry designated by aid from id hash table */
+ register long code;
+ long current, trail, i;
+ struct prentry tentry;
+ struct prentry bentry;
+
+ i = IDHash(aid);
+ current = ntohl(cheader.idHash[i]);
+ bzero(&tentry,sizeof(tentry));
+ bzero(&bentry,sizeof(bentry));
+ trail = 0;
+ if (current == NULL) return PRNOENT;
+ code = pr_ReadEntry(tt,0,current,&tentry);
+ if (code) return PRDBFAIL;
+ while (aid != tentry.id) {
+ trail = current;
+ current = tentry.nextID;
+ if (current == NULL) break;
+ code = pr_ReadEntry(tt,0,current,&tentry);
+ if (code) return PRDBFAIL;
+ }
+ if (current == NULL) return PRNOENT; /* we didn't find him */
+ if (trail == NULL) {
+ /* it's the first entry! */
+ cheader.idHash[i] = htonl(tentry.nextID);
+ code = pr_Write(tt,0,72+HASHSIZE*4+i*4,(char *)&cheader.idHash[i],sizeof(cheader.idHash[i]));
+ if (code) return PRDBFAIL;
+ }
+ else {
+ code = pr_ReadEntry(tt,0,trail, &bentry);
+ if (code) return PRDBFAIL;
+ bentry.nextID = tentry.nextID;
+ code = pr_WriteEntry(tt,0,trail,&bentry);
+ }
+ *loc = current;
+ return PRSUCCESS;
+}
+
+long AddToIDHash(tt, aid, loc)
+struct ubik_trans *tt;
+long aid;
+long loc;
+{
+ /* add entry at loc designated by aid to id hash table */
+ register long code;
+ long i;
+ struct prentry tentry;
+
+ i = IDHash(aid);
+ bzero(&tentry,sizeof(tentry));
+ code = pr_ReadEntry(tt,0,loc,&tentry);
+ if (code) return PRDBFAIL;
+ tentry.nextID = ntohl(cheader.idHash[i]);
+ cheader.idHash[i] = htonl(loc);
+ code = pr_WriteEntry(tt,0,loc,&tentry);
+ if (code) return PRDBFAIL;
+ code = pr_Write(tt,0,72+HASHSIZE*4+i*4,(char *)&cheader.idHash[i],sizeof(cheader.idHash[i]));
+ if (code) return PRDBFAIL;
+ return PRSUCCESS;
+}
+
+long RemoveFromNameHash(tt,aname,loc)
+struct ubik_trans *tt;
+char *aname;
+long *loc;
+{
+ /* remove from name hash */
+ register long code;
+ long current, trail, i;
+ struct prentry tentry;
+ struct prentry bentry;
+
+ i = NameHash(aname);
+ current = ntohl(cheader.nameHash[i]);
+ bzero(&tentry,sizeof(tentry));
+ bzero(&bentry,sizeof(bentry));
+ trail = 0;
+ if (current == NULL) return PRNOENT;
+ code = pr_ReadEntry(tt,0,current,&tentry);
+ if (code) return PRDBFAIL;
+ while (strcmp(aname,tentry.name)) {
+ trail = current;
+ current = tentry.nextName;
+ if (current == NULL) break;
+ code = pr_ReadEntry(tt,0,current,&tentry);
+ if (code) return PRDBFAIL;
+ }
+ if (current == NULL) return PRNOENT; /* we dnamen't find him */
+ if (trail == NULL) {
+ /* it's the first entry! */
+ cheader.nameHash[i] = htonl(tentry.nextName);
+ code = pr_Write(tt,0,72+i*4,(char *)&cheader.nameHash[i],sizeof(cheader.nameHash[i]));
+ if (code) return PRDBFAIL;
+ }
+ else {
+ code = pr_ReadEntry(tt,0,trail, &bentry);
+ if (code) return PRDBFAIL;
+ bentry.nextName = tentry.nextName;
+ code = pr_WriteEntry(tt,0,trail,&bentry);
+ }
+ *loc = current;
+ return PRSUCCESS;
+}
+
+long AddToNameHash(tt, aname, loc)
+struct ubik_trans *tt;
+char *aname;
+long loc;
+{
+ /* add to name hash */
+ register long code;
+ long i;
+ struct prentry tentry;
+
+ i = NameHash(aname);
+ bzero(&tentry,sizeof(tentry));
+ code = pr_ReadEntry(tt,0,loc,&tentry);
+ if (code) return PRDBFAIL;
+ tentry.nextName = ntohl(cheader.nameHash[i]);
+ cheader.nameHash[i] = htonl(loc);
+ code = pr_WriteEntry(tt,0,loc,&tentry);
+ if (code) return PRDBFAIL;
+ code = pr_Write(tt,0,72+i*4,(char *)&cheader.nameHash[i],sizeof(cheader.nameHash[i]));
+ if (code) return PRDBFAIL;
+ return PRSUCCESS;
+}
+
+long AddToOwnerChain(at,gid,oid)
+struct ubik_trans *at;
+long gid;
+long oid;
+{
+ /* add entry designated by gid to owner chain of entry designated by oid */
+ register long code;
+ long loc;
+ long gloc;
+ struct prentry tentry;
+ struct prentry gentry;
+
+ loc = FindByID(at,oid);
+ if (!loc) return PRNOENT;
+ code = pr_ReadEntry(at,0,loc,&tentry);
+ if (code != 0) return PRDBFAIL;
+ gloc = FindByID(at,gid);
+ code = pr_ReadEntry(at,0,gloc,&gentry);
+ if (code != 0) return PRDBFAIL;
+ gentry.nextOwned = tentry.owned;
+ tentry.owned = gloc;
+ code = pr_WriteEntry(at,0,loc,&tentry);
+ if (code != 0) return PRDBFAIL;
+ code = pr_WriteEntry(at,0,gloc,&gentry);
+ if (code != 0) return PRDBFAIL;
+ return PRSUCCESS;
+}
+
+long RemoveFromOwnerChain(at,gid,oid)
+struct ubik_trans *at;
+long gid;
+long oid;
+{
+ /* remove gid from owner chain for oid */
+ register long code;
+ long nptr;
+ struct prentry tentry;
+ struct prentry bentry;
+ long loc;
+
+ loc = FindByID(at,oid);
+ if (!loc) return PRNOENT;
+ code = pr_ReadEntry(at,0,loc,&tentry);
+ if (code != 0) return PRDBFAIL;
+ if (!tentry.owned) return PRNOENT;
+ nptr = tentry.owned;
+ bcopy(&tentry,&bentry,sizeof(tentry));
+ while (nptr != NULL) {
+ code = pr_ReadEntry(at,0,nptr,&tentry);
+ if (code != 0) return PRDBFAIL;
+ if (tentry.id == gid) {
+ /* found it */
+ if (nptr == bentry.owned) /* modifying first of chain */
+ bentry.owned = tentry.nextOwned;
+ else bentry.nextOwned = tentry.nextOwned;
+ tentry.nextOwned = 0;
+ code = pr_WriteEntry(at,0,loc,&bentry);
+ if (code != 0) return PRDBFAIL;
+ code = pr_WriteEntry(at,0,nptr,&tentry);
+ if (code != 0) return PRDBFAIL;
+ return PRSUCCESS;
+ }
+ loc = nptr;
+ nptr = tentry.nextOwned;
+ bcopy(&tentry,&bentry,sizeof(tentry));
+ }
+ return PRNOENT;
+}
+
+long AddToOrphan(at,gid)
+struct ubik_trans *at;
+long gid;
+{
+ /* add gid to orphan list, as it's owner has died */
+ register long code;
+ long loc;
+ struct prentry tentry;
+
+ loc = FindByID(at,gid);
+ if (!loc) return PRNOENT;
+ code = pr_ReadEntry(at,0,loc,&tentry);
+ if (code != 0) return PRDBFAIL;
+ tentry.nextOwned = ntohl(cheader.orphan);
+ cheader.orphan = htonl(loc);
+ code = pr_WriteEntry(at,0,loc,&tentry);
+ if (code != 0) return PRDBFAIL;
+ code = pr_Write(at,0,32,(char *)&cheader.orphan,sizeof(cheader.orphan));
+ if (code != 0) return PRDBFAIL;
+ return PRSUCCESS;
+}
+
+long RemoveFromOrphan(at,gid)
+struct ubik_trans *at;
+long gid;
+{
+ /* remove gid from the orphan list */
+ register long code;
+ long loc;
+ long nptr;
+ struct prentry tentry;
+ struct prentry bentry;
+
+ loc = FindByID(at,gid);
+ if (!loc) return PRNOENT;
+ code = pr_ReadEntry(at,0,loc,&tentry);
+ if (code != 0) return PRDBFAIL;
+ if (cheader.orphan == htonl(loc)) {
+ cheader.orphan = htonl(tentry.nextOwned);
+ tentry.nextOwned = 0;
+ code = pr_Write(at,0,32,(char *)&cheader.orphan,sizeof(cheader.orphan));
+ if (code != 0) return PRDBFAIL;
+ code = pr_WriteEntry(at,0,loc,&tentry);
+ if (code != 0) return PRDBFAIL;
+ return PRSUCCESS;
+ }
+ nptr = ntohl(cheader.orphan);
+ bzero(&bentry,sizeof(bentry));
+ loc = 0;
+ while (nptr != NULL) {
+ code = pr_ReadEntry(at,0,nptr,&tentry);
+ if (code != 0) return PRDBFAIL;
+ if (gid == tentry.id) {
+ /* found it */
+ bentry.nextOwned = tentry.nextOwned;
+ tentry.nextOwned = 0;
+ code = pr_WriteEntry(at,0,loc,&bentry);
+ if (code != 0) return PRDBFAIL;
+ code = pr_WriteEntry(at,0,nptr,&tentry);
+ if (code != 0) return PRDBFAIL;
+ return PRSUCCESS;
+ }
+ loc = nptr;
+ nptr = tentry.nextOwned;
+ bcopy(&tentry,&bentry,sizeof(tentry));
+ }
+ return PRNOENT;
+}
+
+long IsOwnerOf(at,aid,gid)
+struct ubik_trans *at;
+long aid;
+long gid;
+{
+ /* returns 1 if aid is the owner of gid, 0 otherwise */
+ register long code;
+ struct prentry tentry;
+ long loc;
+
+ loc = FindByID(at,gid);
+ if (!loc) return 0;
+ code = pr_ReadEntry(at,0,loc,&tentry);
+ if (code != 0) return 0;
+ if (tentry.owner == aid) return 1;
+ return 0;
+}
+
+long OwnerOf(at,gid)
+struct ubik_trans *at;
+long gid;
+{
+ /* returns the owner of gid */
+ register long code;
+ long loc;
+ struct prentry tentry;
+
+ loc = FindByID(at,gid);
+ if (!loc) return 0;
+ code = pr_ReadEntry(at,0,loc,&tentry);
+ if (code != 0) return 0;
+ return tentry.owner;
+}
+
+
+long WhoIsThis(acall, at, aid)
+struct rx_call *acall;
+struct ubik_trans *at;
+long *aid;
+{
+ /* aid is set to the identity of the caller, if known, ANONYMOUSID otherwise */
+ /* returns -1 and sets aid to ANONYMOUSID on any failure */
+ register struct rx_connection *tconn;
+ struct rxvab_conn *tc;
+ register long code;
+ char tcell[64];
+ long exp;
+ char vname[256];
+
+ tconn = rx_ConnectionOf(acall);
+ code = rx_SecurityClassOf(tconn);
+ if (code == 0)
+ *aid = ANONYMOUSID;
+ else if (code == 1) {
+ /* vab class */
+ tc = (struct rxvab_conn *) tconn->securityData;
+ if (!tc) {
+ *aid = ANONYMOUSID; /* set it to something harmless */
+ return -1;
+ }
+ *aid = ntohl(tc->viceID);
+ }
+ else if (code == 2) {
+ /* kad class */
+ code = rxkad_GetServerInfo(acall->conn,(long *) 0, &exp, vname, (char *) 0, tcell, (long *) 0);
+ if (code) {
+ *aid = ANONYMOUSID;
+ return -1;
+ }
+ if (exp < FT_ApproxTime()) return -1;
+ code = NameToID(at,vname,aid);
+ if (code) {
+ *aid = ANONYMOUSID;
+ return -1;
+ }
+ return 0;
+ }
+ else {
+ *aid = ANONYMOUSID;
+ return -1;
+ }
+ return 0;
+}
+
+long IsAMemberOf(at,aid,gid)
+struct ubik_trans *at;
+long aid;
+long gid;
+{
+ /* returns true if aid is a member of gid */
+ struct prentry tentry;
+ struct contentry centry;
+ register long code;
+ long i;
+ long loc;
+
+ loc = FindByID(at,gid);
+ if (!loc) return 0;
+ bzero(&tentry,sizeof(tentry));
+ code = pr_ReadEntry(at, 0, loc,&tentry);
+ if (code) return 0;
+ if (!(tentry.flags & PRGRP)) return 0;
+ for (i= 0;i<PRSIZE;i++) {
+ if (tentry.entries[i] == aid) return 1;
+ if (tentry.entries[i] == 0) return 0;
+ }
+ if (tentry.next) {
+ loc = tentry.next;
+ while (loc) {
+ bzero(¢ry,sizeof(centry));
+ code = pr_ReadCoEntry(at,0,loc,¢ry);
+ if (code) return 0;
+ for (i=0;i<COSIZE;i++) {
+ if (centry.entries[i] == aid) return 1;
+ if (centry.entries[i] == 0) return 0;
+ }
+ loc = centry.next;
+ }
+ }
+ return 0; /* actually, should never get here */
+}