]> andersk Git - moira.git/blobdiff - afssync/ptutils.c
Command line printer manipulation client, and build goo.
[moira.git] / afssync / ptutils.c
index 679ccac887aa4ca573cbbbcb78f941da457a344b..b156c789fba4004b15e8f3c33dd9e84e218c220a 100644 (file)
-/* $Header$ */
-/* $Source$ */
-
-
 /*
- * P_R_P_Q_# (C) COPYRIGHT IBM CORPORATION 1988
- * LICENSED MATERIALS - PROPERTY OF IBM
- * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
+ * Copyright 2000, International Business Machines Corporation and others.
+ * All Rights Reserved.
+ * 
+ * This software has been released under the terms of the IBM Public
+ * License.  For details, see the LICENSE file in the top-level source
+ * directory or online at http://www.openafs.org/dl/license10.html
  */
 
-/*     
-             Sherri Nichols
-             Information Technology Center
-       November, 1988
-
-       Modified May, 1989 by Jeff Schiller to keep disk file in
-       network byte order
-
-*/
+#include <afs/param.h>
 
+#include <afs/stds.h>
+#include <sys/types.h>
 #include <stdio.h>
-#include <strings.h>
+#ifdef AFS_NT40_ENV 
+#include <winsock2.h>
+#else
+#include <netinet/in.h>
+#endif
+#include <string.h>
 #include <lock.h>
-#define UBIK_INTERNALS
 #include <ubik.h>
 #include <rx/xdr.h>
-#include "print.h"
-#include "prserver.h"
-#include "prerror.h"
-#include <netinet/in.h>
+#include <afs/com_err.h>
+#include <afs/cellconfig.h>
+#include "ptserver.h"
+#include "pterror.h"
+#include <stdlib.h>
+
+/* Foreign cells are represented by the group system:authuser@cell*/
+#define AUTHUSER_GROUP "system:authuser"
+
 
-extern struct prheader cheader;
 extern struct ubik_dbase *dbase;
 extern struct afsconf_dir *prdir;
+extern int pr_noAuth;
+extern int IDCmp();
+
+extern afs_int32 AddToEntry();
+static char *whoami = "ptserver";
+
+/* CorrectUserName - Check to make sure a user name is OK.  It must not include
+ *   either a colon (or it would look like a group) or an atsign (or it would
+ *   look like a foreign user).  The length is checked as well to make sure
+ *   that the user name, an atsign, and the local cell name will fit in
+ *   PR_MAXNAMELEN.  This is so this user can fit in another cells database as
+ *   a foreign user with our cell name tacked on.  This is a predicate, so it
+ *   return one if name is OK and zero if name is bogus. */
 
-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;
+static int CorrectUserName (name)
+  char *name;
 {
-    /* get and init a new entry */
-    register long code;
-    long newEntry;
-    long temp;
+    extern int pr_realmNameLen;
+
+    /* We accept foreign names, so we will deal with '@' later */
+    if (strchr (name, ':') || strchr(name, '\n')) return 0;
+    if (strlen (name) >= PR_MAXNAMELEN - pr_realmNameLen - 1) return 0; 
+    return 1;
+}
+
+/* CorrectGroupName - Like the above but handles more complicated cases caused
+ * by including the ownership in the name.  The interface works by calculating
+ * the correct name based on a given name and owner.  This allows easy use by
+ * rename, which then compares the correct name with the requested new name. */
+
+static afs_int32 CorrectGroupName (ut, aname, cid, oid, cname)
+  struct ubik_trans *ut;
+  char aname[PR_MAXNAMELEN];           /* name for group */
+  afs_int32 cid;                               /* caller id */
+  afs_int32 oid;                               /* owner of group */
+  char cname[PR_MAXNAMELEN];           /* correct name for group */
+{
+    afs_int32  code;
+    int   admin;
+    char *prefix;                      /* ptr to group owner part */
+    char *suffix;                      /* ptr to group name part */
+    char  name[PR_MAXNAMELEN];         /* correct name for group */
     struct prentry tentry;
+
+    if (strlen (aname) >= PR_MAXNAMELEN) return PRBADNAM;
+    admin = pr_noAuth || IsAMemberOf (ut, cid, SYSADMINID);
+
+    if (oid == 0) oid = cid;
+
+    /* Determine the correct prefix for the name. */
+    if (oid == SYSADMINID) prefix = "system";
+    else {
+       afs_int32 loc = FindByID (ut, oid);
+       if (loc == 0) {
+           /* let admin create groups owned by non-existent ids (probably
+             * setting a group to own itself).  Check that they look like
+             * groups (with a colon) or otherwise are good user names. */
+           if (admin) {
+               strcpy (cname, aname);
+               goto done;
+           }
+           return PRNOENT;
+       }
+       code = pr_Read (ut, 0, loc, &tentry, sizeof(tentry));
+       if (code) return code;
+       if (ntohl(tentry.flags) & PRGRP) {
+           if ((tentry.count == 0) && !admin) return PRGROUPEMPTY;
+           /* terminate prefix at colon if there is one */
+           if ((prefix = strchr(tentry.name, ':'))) *prefix = 0;
+       }
+       prefix = tentry.name;
+    }
+    /* only sysadmin allow to use 'system:' prefix */
+    if ((strcmp (prefix, "system") == 0) && !admin) return PRPERM;
+
+    strcpy (name, aname);              /* in case aname & cname are same */
+    suffix = strchr(name, ':');
+    if (suffix == 0) {
+       /* sysadmin can make groups w/o ':', but they must still look like
+         * legal user names. */
+       if (!admin) return PRBADNAM;
+       strcpy (cname, name);
+    }
+    else {
+       if (strlen(prefix)+strlen(suffix) >= PR_MAXNAMELEN) return PRBADNAM;
+       strcpy (cname, prefix);
+       strcat (cname, suffix);
+    }
+  done:
+    /* check for legal name with either group rules or user rules */
+    if ((suffix = strchr(cname, ':'))) {
+       /* check for confusing characters */
+       if (strchr(cname, '\n') ||      /* restrict so recreate can work */
+           strchr(suffix+1, ':'))      /* avoid multiple colons */
+           return PRBADNAM;
+    } else {
+       if (!CorrectUserName (cname)) return PRBADNAM;
+    }
+    return 0;
+}
+
+int AccessOK (ut, cid, tentry, mem, any)
+  struct ubik_trans *ut;
+  afs_int32 cid;                               /* caller id */
+  struct prentry *tentry;              /* object being accessed */
+  int mem;                             /* check membership in aid, if group */
+  int any;                             /* if set return true */
+{   afs_int32 flags;
+    afs_int32 oid;
+    afs_int32 aid;
+
+    if (pr_noAuth) return 1;
+    if (cid == SYSADMINID) return 1;   /* special case fileserver */
+    if (tentry) {
+       flags = tentry->flags;
+       oid = tentry->owner;
+       aid = tentry->id;
+    } else {
+       flags = oid = aid = 0;
+    }
+    if (!(flags & PRACCESS)) {         /* provide default access */
+       if (flags & PRGRP)
+           flags |= PRP_GROUP_DEFAULT;
+       else
+           flags |= PRP_USER_DEFAULT;
+    }
+
+    if (flags & any) return 1;
+    if (oid) {
+       if ((cid == oid) ||
+           IsAMemberOf (ut, cid, oid)) return 1;
+    }
+    if (aid > 0) {                     /* checking on a user */
+       if (aid == cid) return 1;
+    } else if (aid < 0) {              /* checking on group */
+       if ((flags & mem) && IsAMemberOf (ut, cid, aid)) return 1;
+    }
+    /* Allow members of SYSVIEWERID to get membership and status only */
+    if (((mem == PRP_STATUS_MEM)||(mem == PRP_MEMBER_MEM))&&(IsAMemberOf (ut, cid, SYSVIEWERID))) return 1;
+    if (IsAMemberOf (ut, cid, SYSADMINID)) return 1;
+    return 0;                          /* no access */
+}
+
+afs_int32 CreateEntry (at, aname, aid, idflag, flag, oid, creator)  
+  struct ubik_trans *at;
+  char aname[PR_MAXNAMELEN];
+  afs_int32 *aid;
+  afs_int32 idflag;
+  afs_int32 flag;
+  afs_int32 oid;
+  afs_int32 creator;
+{
+    /* get and init a new entry */
+    afs_int32 code;
+    afs_int32 newEntry;
+    struct prentry tentry, tent;
+    char *atsign;
     
-    bzero(&tentry, sizeof(tentry));
+    memset(&tentry, 0, sizeof(tentry));
+
+    if ((oid == 0) || (oid == ANONYMOUSID)) oid = creator;
+
+    if (flag & PRGRP) {
+       code = CorrectGroupName (at, aname, creator, oid, tentry.name);
+       if (code) return code;
+       if (strcmp (aname, tentry.name) != 0)  return PRBADNAM;
+    } else {                           /* non-group must not have colon */
+       if (!CorrectUserName(aname)) return PRBADNAM;
+       strcpy (tentry.name, aname);
+    }
+
+    if (FindByName(at,aname, &tent)) return PREXIST;
+
     newEntry = AllocBlock(at);
     if (!newEntry) return PRDBFAIL;
+#ifdef PR_REMEMBER_TIMES
+    tentry.createTime = time(0);
+#endif
+
     if (flag & PRGRP) {
-       tentry.flags |= PRGRP;
-       tentry.owner = oid;
-    }
-    else if (flag & PRFOREIGN) {
-       tentry.flags |= PRFOREIGN;
+       tentry.flags = PRGRP;
        tentry.owner = oid;
+    } else if (flag == 0) {
+        tentry.flags = 0;
+        tentry.owner = SYSADMINID;
+    } else {
+        return PRBADARG;
     }
-    else tentry.owner = SYSADMINID;
-    if (idflag) 
-       tentry.id = *aid;
-    else {
-       code= AllocID(at,flag,&tentry.id);
-       if (code != PRSUCCESS) return code;
+
+    atsign = strchr(aname, '@');
+    if (!atsign) {
+       /* A normal user or group. Pick an id for it */
+       if (idflag) 
+         tentry.id = *aid;
+       else {
+         code= AllocID(at,flag,&tentry.id);
+         if (code != PRSUCCESS) return code;
+       }
+    } else if (flag & PRGRP) {
+       /* A foreign group. Its format must be AUTHUSER_GROUP@cellname
+       * Then pick an id for the group.
+       */
+       int badFormat;
+           
+       *atsign = '\0';
+       badFormat = strcmp(AUTHUSER_GROUP, aname);
+       *atsign = '@';
+       if (badFormat) return PRBADNAM;
+
+       if (idflag) 
+         tentry.id = *aid;
+       else {
+         code= AllocID(at,flag,&tentry.id);
+         if (code != PRSUCCESS) return code;
+       }
+    } else {
+       /* A foreign user: <name>@<cell>. The foreign user is added to
+       * its representing group. It is 
+       */
+       char *cellGroup;
+       afs_int32 pos, n;
+       struct prentry centry;
+       extern afs_int32 allocNextId();
+
+       /* To create the user <name>@<cell> the group AUTHUSER_GROUP@<cell>
+       * must exist.
+       */
+       cellGroup = (char *)malloc(strlen(AUTHUSER_GROUP) + strlen(atsign) + 1);
+       strcpy(cellGroup, AUTHUSER_GROUP);
+       strcat(cellGroup, atsign);
+       pos = FindByName(at, cellGroup, &centry); 
+       if (!pos) return PRBADNAM;
+       code = pr_Read (at, 0, pos, &centry, sizeof(centry));
+       if (code) return code;
+
+       /* cellid is the id of the group representing the cell */
+       tentry.cellid = ntohl(centry.id); 
+
+       if (idflag) {
+         /* Check if id is good */
+         if (!inRange(&centry,*aid)) return PRBADARG;
+         tentry.id = *aid;
+       } else {
+         /* Allocate an ID special for this foreign user. It is based 
+          * on the representing group's id and nusers count.
+          */
+         tentry.id = allocNextId(&centry);
+       }
+        
+       /* The foreign user will be added to the representing foreign
+       * group. The group can hold up to 30 entries.
+       */
+       if (!(ntohl(centry.flags) & PRQUOTA)) {
+         centry.flags = htonl (ntohl(centry.flags) | PRQUOTA);
+         centry.ngroups = htonl(30);
+       }
+       n = ntohl(centry.ngroups);
+       if ( (n <= 0) && !pr_noAuth ) return PRNOMORE;
+       centry.ngroups = htonl(n - 1);
+
+       /* write updated entry for group */
+       code = pr_Write (at, 0, pos, &centry, sizeof(centry));
+
+       /* Now add the new user entry to the database */
+       tentry.creator = creator;
+       *aid = tentry.id;
+       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 (inc_header_word (at, foreigncount, 1)) return PRDBFAIL;
+
+       /* Now add the entry to the authuser group for this cell.
+       * We will reread the entries for the user and the group
+       * instead of modifying them before writing them in the
+       * previous steps. Although not very efficient, much simpler
+       */
+       pos = FindByID(at, tentry.cellid); 
+       if (!pos) return PRBADNAM;
+       code = pr_ReadEntry (at, 0, pos, &centry);
+       if (code) return code;
+       code = AddToEntry(at, &centry, pos, *aid);
+       if (code) return code;
+       /* and now the user entry */
+       pos = FindByID(at,*aid); 
+       if (!pos) return PRBADNAM;
+       code = pr_ReadEntry (at, 0, pos, &tentry);
+       if (code) return code;
+       code = AddToEntry(at, &tentry, pos, tentry.cellid);
+       if (code) return code;
+
+       return PRSUCCESS;
     }
+
+    /* Remember the largest group id or largest user id */
     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));
+       /* group ids are negative */
+       if (tentry.id < (afs_int32)ntohl(cheader.maxGroup)) {
+           code = set_header_word (at, maxGroup, htonl(tentry.id));
            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));
+    else {
+       if (tentry.id > (afs_int32)ntohl(cheader.maxID)) {
+           code = set_header_word (at, maxID, htonl(tentry.id));
            if (code) return PRDBFAIL;
        }
     }
+
+    /* Charge the creator for this group */
+    if (flag & PRGRP) {
+       afs_int32 loc = FindByID (at, creator);
+       struct prentry centry;
+       int admin;
+
+       if (loc) { /* this should only fail during initialization */
+           code = pr_Read (at, 0, loc, &centry, sizeof(centry));
+           if (code) return code;
+
+           /* If quota is uninitialized, do it */
+           if (!(ntohl(centry.flags) & PRQUOTA)) {
+              centry.flags = htonl (ntohl(centry.flags) | PRQUOTA);
+              centry.ngroups = centry.nusers = htonl(20);
+           }
+
+           /* Admins don't get charged for creating a group.
+            * If in noAuth mode, you get changed for it but you 
+            * are still allowed to create as many groups as you want.
+            */
+           admin = ( (creator == SYSADMINID) ||
+                     IsAMemberOf(at,creator,SYSADMINID) );
+           if (!admin) {
+              if (ntohl(centry.ngroups) <= 0) {
+                 if (!pr_noAuth) return PRNOMORE;
+               } else {
+                  centry.ngroups = htonl(ntohl(centry.ngroups)-1);
+             }
+           }
+
+           code = pr_Write (at, 0, loc, &centry, sizeof(centry));
+           if (code) return code;
+       } /* if (loc) */
+    }
     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;
-       }
+        /* Initialize the quota for the user. Groups don't have their
+        * quota initialized.
+        */
+        tentry.flags |= PRQUOTA;
+       tentry.ngroups = tentry.nusers = 20;
     }
+
     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);
@@ -101,55 +399,44 @@ long creator;
        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;
+       if (inc_header_word (at, groupcount, 1)) 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;
+       if (inc_header_word (at, instcount, 1)) 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;
+       if (inc_header_word (at, usercount, 1)) return PRDBFAIL;
     }
     return PRSUCCESS;
 }
     
 
+/* RemoveFromEntry - remove aid from bid's entries list, freeing a continuation
+ * entry if appropriate */
 
-long RemoveFromEntry(at,aid,bid)
-register struct ubik_trans *at;
-register long aid;
-register long bid;
+afs_int32 RemoveFromEntry (at, aid, bid)
+  struct ubik_trans *at;
+  afs_int32 aid;
+  afs_int32 bid;
 {
-    /* remove aid from bid's entries list, freeing a continuation entry if appropriate */
-
-    register long code;
+    afs_int32 code;
     struct prentry tentry;
     struct contentry centry;
     struct contentry hentry;
-    long temp;
-    long first;
-    long i,j;
-    long nptr;
-    long hloc = 0;
+    afs_int32 temp;
+    afs_int32 i,j;
+    afs_int32 nptr;
+    afs_int32 hloc;
     
-    bzero(&hentry,sizeof(hentry));
+    if (aid == bid) return PRINCONSISTENT;
+    memset(&hentry, 0, sizeof(hentry));
     temp = FindByID(at,bid);
+    if (temp == 0) return PRNOENT;
     code = pr_ReadEntry(at, 0, temp, &tentry);
     if (code != 0) return code;
+#ifdef PR_REMEMBER_TIMES
+    tentry.removeTime = time(0);
+#endif
     for (i=0;i<PRSIZE;i++) {
        if (tentry.entries[i] == aid) {  
            tentry.entries[i] = PRBADID;
@@ -161,170 +448,193 @@ register long bid;
        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,&centry);
-           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;
+    hloc = 0;
+    nptr = tentry.next;
+    while (nptr != 0) {
+       code = pr_ReadCoEntry(at,0,nptr,&centry);
+       if (code != 0) return code;
+       if ((centry.id != bid) || !(centry.flags & PRCONT)) return PRDBBAD;
+       for (i=0;i<COSIZE;i++) {
+           if (centry.entries[i] == aid) {
+               centry.entries[i] = PRBADID;
+               for (j=0;j<COSIZE;j++)
+                   if (centry.entries[j] != PRBADID &&
+                       centry.entries[j] != 0) break;
+               if (j == COSIZE) {   /* can free this block */
+                   if (hloc == 0) {
+                       tentry.next = centry.next;
                    }
-                   else { /* can't free it yet */
-                       code = pr_WriteCoEntry(at,0,nptr,&centry);
+                   else {
+                       hentry.next = centry.next;
+                       code = pr_WriteCoEntry (at, 0, hloc, &hentry);
                        if (code != 0) return code;
-                       return PRSUCCESS;
                    }
+                   code = FreeBlock (at, nptr);
+                   if (code) return code;
+               }
+               else { /* can't free it yet */
+                   code = pr_WriteCoEntry(at,0,nptr,&centry);
+                   if (code != 0) return code;
                }
-               if (centry.entries[i] == 0) return PRNOENT;
+               tentry.count--;
+               code = pr_WriteEntry(at,0,temp,&tentry);
+               if (code) return PRDBFAIL;
+               return 0;
            }
-           hloc = nptr;
-           nptr = centry.next;
-           bcopy(&centry,&hentry,sizeof(centry));
-       }
-    }
-    else return PRNOENT;
-    return PRSUCCESS;
+           if (centry.entries[i] == 0) return PRNOENT;
+       } /* for all coentry slots */
+       hloc = nptr;
+       nptr = centry.next;
+       memcpy(&hentry, &centry, sizeof(centry));
+    } /* while there are coentries */
+    return PRNOENT;
 }
 
-long DeleteEntry(at,aid,cid)
-register struct ubik_trans *at;
-long aid;
-long cid;
+/* DeleteEntry - delete the entry in tentry at loc, removing it from all
+ * groups, putting groups owned by it on orphan chain, and freeing the space */
+
+afs_int32 DeleteEntry (at, tentry, loc)
+  struct ubik_trans *at;
+  struct prentry *tentry;
+  afs_int32 loc;
 {
-    /* 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;
+    afs_int32 code;
     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;
+    afs_int32  i;
+    afs_int32 nptr;
+
+    if (strchr(tentry->name,'@')) {
+       if (tentry->flags & PRGRP) {
+       /* If there are still foreign user accounts from that cell
+          don't delete the group */
+          if (tentry->count) return PRBADARG;
+       } else {
+           /* adjust quota */
+
+          afs_int32 loc = FindByID (at, tentry->cellid);
+          struct prentry centry;
+          if (loc) {
+            code = pr_Read (at, 0, loc, &centry, sizeof(centry));
+            if (code) return code;
+            if (ntohl(centry.flags) & PRQUOTA) {
+                   centry.ngroups = htonl(ntohl(centry.ngroups) + 1);
+           }
+           code = pr_Write (at, 0, loc, &centry, sizeof(centry));
+           if (code) return code;
+         }
+       }
+    }
+    /* First remove the entire membership list */
     for (i=0;i<PRSIZE;i++) {
-       if (tentry.entries[i] == 0) break;
-       RemoveFromEntry(at,aid,tentry.entries[i]);
+       if (tentry->entries[i] == PRBADID) continue;
+       if (tentry->entries[i] == 0) break;
+       code = RemoveFromEntry (at, tentry->id, tentry->entries[i]);
+       if (code) return code;
     }
-    nptr = tentry.next;
-    while (nptr != NULL) {
+    nptr = tentry->next;
+    while (nptr != (afs_int32)NULL) {
        code = pr_ReadCoEntry(at,0,nptr,&centry);
        if (code != 0) return PRDBFAIL;
        for (i=0;i<COSIZE;i++) {
+           if (centry.entries[i] == PRBADID) continue;
            if (centry.entries[i] == 0) break;
-           RemoveFromEntry(at,aid,centry.entries[i]);
+           code = RemoveFromEntry (at, tentry->id, centry.entries[i]);
+           if (code) return code;
        }
+       code = FreeBlock (at, nptr);    /* free continuation block */
+       if (code) return code;
        nptr = centry.next;
     }
-    if (tentry.flags & PRGRP) {
-       if (FindByID(at,tentry.owner)) {
-           code = RemoveFromOwnerChain(at,aid,tentry.owner);
+
+    /* Remove us from other's owned chain.  Note that this will zero our owned
+     * field (on disk) so this step must follow the above step in case we are
+     * on our own owned list. */
+    if (tentry->flags & PRGRP) {
+       if (tentry->owner) {
+           code = RemoveFromOwnerChain (at, tentry->id, tentry->owner);
            if (code) return code;
        }
        else {
-           code = RemoveFromOrphan(at,aid);
+           code = RemoveFromOrphan (at, tentry->id);
            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);
+
+    code = RemoveFromIDHash(at,tentry->id,&loc);
     if (code != PRSUCCESS) return code;
-    code = RemoveFromNameHash(at,tentry.name,&temp);
+    code = RemoveFromNameHash(at,tentry->name,&loc);
     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;
+
+    if (tentry->flags & PRGRP) {
+       afs_int32 loc = FindByID(at, tentry->creator);
+       struct prentry centry;
+       int admin;
+
+       if (loc) {
+           code = pr_Read (at, 0, loc, &centry, sizeof(centry));
+           if (code) return code;
+           admin = ( (tentry->creator == SYSADMINID) ||
+                     IsAMemberOf(at,tentry->creator,SYSADMINID) );
+           if (ntohl(centry.flags) & PRQUOTA) {
+               if (!(admin && (ntohl(centry.ngroups) >= 20))) {
+                   centry.ngroups = htonl(ntohl(centry.ngroups) + 1);
+                }
+           }
+           code = pr_Write (at, 0, loc, &centry, sizeof(centry));
+           if (code) return code;
+       }
     }
-    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;
+
+    if (tentry->flags & PRGRP) {
+        if (inc_header_word (at, groupcount, -1)) 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 if (tentry->flags & PRINST) {
+       if (inc_header_word (at, instcount, -1)) 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;
+        if (strchr(tentry->name,'@')) {
+          if (inc_header_word (at, foreigncount, -1)) return PRDBFAIL;
+       } else {
+          if (inc_header_word (at, usercount, -1)) return PRDBFAIL;
+       }
     }
-    FreeBlock(at,temp);
-    return PRSUCCESS;
+    code = FreeBlock(at, loc);
+    return code;
 }
 
+/* AddToEntry - add aid to entry's entries list, alloc'ing a continuation block
+ * if needed.
+ *
+ * Note the entry is written out by this routine. */
 
-
-
-long AddToEntry(tt,entry,loc,aid)
-struct ubik_trans *tt;
-struct prentry entry;
-long loc;
-long aid;
+afs_int32 AddToEntry (tt, entry, loc, aid)
+  struct ubik_trans *tt;
+  struct prentry *entry;
+  afs_int32 loc;
+  afs_int32 aid;
 {
-    /* add aid to entry's entries list, alloc'ing a continuation block if needed */
-    register long code;
-    long i;
+    afs_int32 code;
+    afs_int32 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));
+    afs_int32 nptr;
+    afs_int32 last;                            /* addr of last cont. block */
+    afs_int32 first = 0;
+    afs_int32 cloc = 0;
+    afs_int32 slot = -1;
+
+    if (entry->id == aid) return PRINCONSISTENT;
+#ifdef PR_REMEMBER_TIMES
+    entry->addTime = time(0);
+#endif
     for (i=0;i<PRSIZE;i++) {
-       if (entry.entries[i] == aid)
+       if (entry->entries[i] == aid)
            return PRIDEXIST;
-       if (entry.entries[i] == PRBADID) { /* remember this spot */
+       if (entry->entries[i] == PRBADID) { /* remember this spot */
            first = 1;
            slot = i;
        }
-       if (entry.entries[i] == 0) { /* end of the line */
+       else if (entry->entries[i] == 0) { /* end of the line */
            if (slot == -1) {
                first = 1;
                slot = i;
@@ -332,10 +642,12 @@ long aid;
            break;
        }
     }
-    nptr = entry.next;
-    while (nptr != NULL) {
-       code = pr_ReadCoEntry(tt,0,nptr,&nentry);
+    last = 0;
+    nptr = entry->next;
+    while (nptr != (afs_int32)NULL) {
+       code = pr_ReadCoEntry(tt,0,nptr,&nentry);
        if (code != 0) return code;
+       last = nptr;
        if (!(nentry.flags & PRCONT)) return PRDBFAIL;
        for (i=0;i<COSIZE;i++) {
            if (nentry.entries[i] == aid)
@@ -346,7 +658,7 @@ long aid;
                    cloc = nptr;
                }
            }
-           if (nentry.entries[i] == 0) {
+           else if (nentry.entries[i] == 0) {
                if (slot == -1) {
                    slot = i;
                    cloc = nptr;
@@ -354,18 +666,18 @@ long aid;
                break;
            }
        }
-       last = nptr;
        nptr = nentry.next;
     }
-    if (slot != -1) {  /* we found a place */
-       entry.count++;
+    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);
+           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_WriteEntry (tt, 0, loc, entry);
+       if (code) return code;
        code = pr_ReadCoEntry(tt,0,cloc,&aentry);
        if (code != 0) return code;
        aentry.entries[slot] = aid;
@@ -375,121 +687,228 @@ long aid;
     }
     /* have to allocate a continuation block if we got here */
     nptr = AllocBlock(tt);
-    if (nentry.flags & PRCONT) {
-       /* then we should tack new block here */
+    if (last) {
+       /* then we should tack new block after last block in cont. chain */
        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;
+       entry->next = nptr;
     }
+    memset(&aentry, 0, sizeof(aentry));
     aentry.flags |= PRCONT;
-    aentry.id = entry.id;
-    aentry.next = NULL;
+    aentry.id = entry->id;
+    aentry.next = 0;
     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;
+    entry->count++;
+    code = pr_WriteEntry (tt, 0, loc, entry);
+    return code;
        
 }
 
-long GetList(at,aid,alist,add)
-struct ubik_trans *at;
-long aid;
-prlist *alist;
-long add;
+afs_int32 AddToPRList (alist, sizeP, id)
+  prlist *alist;
+  int *sizeP;
+  afs_int32 id;
 {
-    register long code;
-    long temp;
-    long i;
-    long count;
-    struct prentry tentry;
+    char *tmp;
+    int count;
+
+    if (alist->prlist_len >= *sizeP) {
+        count = alist->prlist_len + 100;
+       if (alist->prlist_val) {
+          tmp = (char *) realloc(alist->prlist_val, count*sizeof(afs_int32));
+       } else {
+          tmp = (char *) malloc(count*sizeof(afs_int32));
+       }
+       if (!tmp) return(PRNOMEM);
+       alist->prlist_val = (afs_int32 *)tmp;
+       *sizeP = count;
+    }
+    alist->prlist_val[alist->prlist_len++] = id;
+    return 0;
+}
+
+afs_int32 GetList (at, tentry, alist, add)
+  struct ubik_trans *at;
+  struct prentry *tentry;
+  prlist *alist;
+  afs_int32 add;
+{
+    afs_int32 code;
+    afs_int32 i;
     struct contentry centry;
-    long nptr;
-    long size;
-    extern long IDCmp();
+    afs_int32 nptr;
+    int size;
+    int count = 0;
 
-    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;
+    size = 0;
+    alist->prlist_val = 0;
     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++;
+       if (tentry->entries[i] == PRBADID) continue;
+       if (tentry->entries[i] == 0) break;
+       code = AddToPRList (alist, &size, tentry->entries[i]);
+       if (code) return code;
     }
-    nptr = tentry.next;
-    while (nptr != NULL) {
+
+    for (nptr = tentry->next; nptr != 0; nptr = centry.next) {
        /* look through cont entries */
        code = pr_ReadCoEntry(at,0,nptr,&centry);
        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++;
+           code = AddToPRList (alist, &size, centry.entries[i]);
+           if (code) return code;
+       }
+       if (count++ > 50) IOMGR_Poll(), count = 0;
+    }
+
+    if (add) { /* this is for a CPS, so tack on appropriate stuff */
+       if (tentry->id != ANONYMOUSID && tentry->id != ANYUSERID) {
+           if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
+               (code = AddAuthGroup(tentry, alist, &size)) || 
+               (code = AddToPRList (alist, &size, tentry->id))) return code;
+       }
+       else {
+           if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
+               (code = AddToPRList (alist, &size, tentry->id))) return code;
+       }
+    }
+    if (alist->prlist_len > 100) IOMGR_Poll();
+    qsort(alist->prlist_val,alist->prlist_len,sizeof(afs_int32),IDCmp);
+    return PRSUCCESS;
+}
+
+
+afs_int32 GetList2 (at, tentry, tentry2 , alist, add)
+  struct ubik_trans *at;
+  struct prentry *tentry;
+  struct prentry *tentry2;
+  prlist *alist;
+  afs_int32 add;
+{
+    afs_int32 code = 0;
+    afs_int32 i;
+    struct contentry centry;
+    afs_int32 nptr;
+    afs_int32 size;
+    int count = 0;
+
+    size = 0;
+    alist->prlist_val = 0;
+    alist->prlist_len = 0;
+    for (i=0;i<PRSIZE;i++) {
+       if (tentry->entries[i] == PRBADID) continue;
+       if (tentry->entries[i] == 0) break;
+       code = AddToPRList (alist, &size, tentry->entries[i]);
+       if (code) return code;
+    }
+
+    nptr = tentry->next;
+    while (nptr != (afs_uint32)NULL) {
+       /* look through cont entries */
+       code = pr_ReadCoEntry(at,0,nptr,&centry);
+       if (code != 0) return code;
+       for (i=0;i<COSIZE;i++) {
+           if (centry.entries[i] == PRBADID) continue;
+           if (centry.entries[i] == 0) break;
+           code = AddToPRList (alist, &size, centry.entries[i]);
+           if (code) return code;
        }
        nptr = centry.next;
+       if (count++ > 50) IOMGR_Poll(), count = 0;
+    }
+
+    for (i=0;i<PRSIZE;i++) {
+       if (tentry2->entries[i] == PRBADID) continue;
+       if (tentry2->entries[i] == 0) break;
+       code = AddToPRList (alist, &size, tentry2->entries[i]);
+       if (code) break;
+    }
+
+    if (!code) {
+           nptr = tentry2->next;
+           while (nptr != (afs_uint32)NULL) {
+               /* look through cont entries */
+               code = pr_ReadCoEntry(at,0,nptr,&centry);
+               if (code != 0) break;
+               for (i=0;i<COSIZE;i++) {
+                   if (centry.entries[i] == PRBADID) continue;
+                   if (centry.entries[i] == 0) break;
+                   code = AddToPRList (alist, &size, centry.entries[i]);
+                   if (code) break;
+               }
+               nptr = centry.next;
+               if (count++ > 50) IOMGR_Poll(), count = 0;
+           }
     }
     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;
+       if (tentry->id != ANONYMOUSID && tentry->id != ANYUSERID) {
+           if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
+               (code = AddToPRList (alist, &size, AUTHUSERID)) ||
+               (code = AddToPRList (alist, &size, tentry->id))) return code;
        }
        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;
+           if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
+               (code = AddToPRList (alist, &size, tentry->id))) return code;
+       }
+    }
+    if (alist->prlist_len > 100) IOMGR_Poll();
+    qsort(alist->prlist_val,alist->prlist_len,sizeof(afs_int32),IDCmp);
+    return PRSUCCESS;
+}
+
+afs_int32 GetOwnedChain (ut, next, alist)
+  struct ubik_trans *ut;
+  afs_int32 *next;
+  prlist *alist;
+{   afs_int32 code;
+    struct prentry tentry;
+    int size;
+    int count = 0;
+
+    size = 0;
+    alist->prlist_val = 0;
+    alist->prlist_len = 0;
+
+    for (; *next; *next = ntohl(tentry.nextOwned)) {
+       code = pr_Read (ut, 0, *next, &tentry, sizeof(tentry));
+       if (code) return code;
+       code = AddToPRList (alist, &size, ntohl(tentry.id));
+       if (alist->prlist_len >= PR_MAXGROUPS) {
+          return PRTOOMANY;
        }
+       if (code) return code;
+       if (count++ > 50) IOMGR_Poll(), count = 0;
     }
-    qsort(alist->prlist_val,alist->prlist_len,sizeof(long),IDCmp);
+    if (alist->prlist_len > 100) IOMGR_Poll();
+    qsort(alist->prlist_val,alist->prlist_len,sizeof(afs_int32),IDCmp);
     return PRSUCCESS;
 }
 
-long GetMax(at,uid,gid)
-register struct ubik_trans *at;
-long *uid;
-long *gid;
+afs_int32 GetMax(at,uid,gid)
+struct ubik_trans *at;
+afs_int32 *uid;
+afs_int32 *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;
+afs_int32 SetMax(at,id,flag)
+struct ubik_trans *at;
+afs_int32 id;
+afs_int32 flag;
 {
-    register long code;
+    afs_int32 code;
     if (flag & PRGRP) {
        cheader.maxGroup = htonl(id);
        code = pr_Write(at,0,16,(char *)&cheader.maxGroup,sizeof(cheader.maxGroup));
@@ -503,21 +922,35 @@ long flag;
     return PRSUCCESS;
 }
 
-Initdb()
+afs_int32 read_DbHeader(tt)
+     struct ubik_trans *tt;
+{
+    afs_int32 code;
+
+    if (!ubik_CacheUpdate(tt)) return 0;
+
+    code = pr_Read(tt, 0, 0, (char *)&cheader, sizeof(cheader));
+    if (code != 0) {
+        com_err (whoami, code, "Couldn't read header");
+    }
+    return code;
+}
+
+int pr_noAuth;
+afs_int32 initd=0;
+
+afs_int32 Initdb()
 {
-    long code;
+    afs_int32 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;
-    struct ubik_hdr header;
+    afs_int32 len;
+
+    /* init the database.  We'll try reading it, but if we're starting
+     * from scratch, we'll have to do a write transaction. */
 
-    /* init the database.  We'll try reading it, but if we're starting from scratch, we'll have to do a write transaction. */
+    pr_noAuth = afsconf_GetNoAuthFlag(prdir);
 
-    code = ubik_BeginTrans(dbase,UBIK_READTRANS, &tt);
+    code = ubik_BeginTransReadAny(dbase,UBIK_READTRANS, &tt);
     if (code) return code;
     code = ubik_SetLock(tt,1,1,LOCKREAD);
     if (code) {
@@ -526,16 +959,22 @@ Initdb()
     }
     if (!initd) {
        initd = 1;
-       bzero(&curver,sizeof(curver));
+    } else if (!ubik_CacheUpdate (tt)) {
+       code = ubik_EndTrans(tt);
+       return code;
     }
+
     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);
+       com_err (whoami, code, "couldn't read header");
        ubik_AbortTrans(tt);
        return code;
     }
-    if (ntohl(cheader.headerSize) == sizeof(cheader) && ntohl(cheader.eofPtr) != NULL && FindByID(tt,ANONYMOUSID) != 0){
+    if ((ntohl(cheader.version) == PRDBVERSION) &&
+       ntohl(cheader.headerSize) == sizeof(cheader) &&
+       ntohl(cheader.eofPtr) != (afs_uint32)NULL &&
+       FindByID(tt,ANONYMOUSID) != 0){
        /* database exists, so we don't have to build it */
        code = ubik_EndTrans(tt);
        if (code) return code;
@@ -544,228 +983,324 @@ Initdb()
     /* else we need to build a database */
     code = ubik_EndTrans(tt);
     if (code) return code;
-    printf("Creating new database\n");
+
+    /* Only rebuild database if the db was deleted (the header is zero) and we
+       are running noAuth. */
+    {   char *bp = (char *)&cheader;
+       int i;
+       for (i=0; i<sizeof(cheader); i++)
+           if (bp[i])  {
+               code = PRDBBAD;
+               com_err (whoami, code,
+                        "Can't rebuild database because it is not empty");
+               return code;
+           }
+    }
+    if (!pr_noAuth) {
+       code = PRDBBAD;
+       com_err (whoami, code,
+                "Can't rebuild database because not running NoAuth");
+       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;
     }
-    header.magic = htonl(UBIK_MAGIC);
-    header.pad1 = 0;
-    header.size = 0;
-    header.version.epoch = header.version.counter = htonl(1);
-    code = pr_Write(tt, 0, -(HDRSIZE), (char *)&header, sizeof(header));
-    if (code != 0) {
-       printf("prserver: couldn't write ubik header - code is %d.\n", code);
-       return code;
+
+    /* before doing a rebuild, check again that the dbase looks bad, because
+     * the previous check was only under a ReadAny transaction, and there could
+     * actually have been a good database out there.  Now that we have a
+     * real write transaction, make sure things are still bad.
+     */
+    if ((ntohl(cheader.version) == PRDBVERSION) &&
+       ntohl(cheader.headerSize) == sizeof(cheader) &&
+       ntohl(cheader.eofPtr) != (afs_uint32)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;
     }
-    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);
+
+    /* Initialize the database header */
+    if ((code = set_header_word (tt, version, htonl(PRDBVERSION))) ||
+       (code = set_header_word (tt, headerSize, htonl(sizeof(cheader)))) ||
+       (code = set_header_word (tt, eofPtr, cheader.headerSize))) {
+       com_err (whoami, code, "couldn't write header words");
        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);
+
+#define InitialGroup(id,name) do {    \
+    afs_int32 temp = (id);                   \
+    afs_int32 flag = (id) < 0 ? PRGRP : 0; \
+    code = CreateEntry               \
+       (tt, (name), &temp, /*idflag*/1, flag, SYSADMINID, SYSADMINID); \
+    if (code) {                              \
+       com_err (whoami, code, "couldn't create %s with id %di.",       \
+                (name), (id));       \
+       ubik_AbortTrans(tt);          \
+       return code;                  \
+    }                                \
+} while (0)
+
+    InitialGroup (SYSADMINID, "system:administrators");
+    InitialGroup (SYSBACKUPID, "system:backup");
+    InitialGroup (ANYUSERID, "system:anyuser");
+    InitialGroup (AUTHUSERID, "system:authuser");
+    InitialGroup (SYSVIEWERID, "system:ptsviewers");
+    InitialGroup (ANONYMOUSID, "anonymous");
+
+    /* Well, we don't really want the max id set to anonymousid, so we'll set
+     * it back to 0 */
+    code = set_header_word (tt, maxID, 0); /* correct in any byte order */
+    if (code) {
+       com_err (whoami, code, "couldn't reset max id");
        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];
+afs_int32 ChangeEntry (at, aid, cid, name, oid, newid)
+  struct ubik_trans *at;
+  afs_int32 aid;
+  afs_int32 cid;
+  char *name;
+  afs_int32 oid;
+  afs_int32 newid;
 {
-    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;
+    afs_int32 code;
+    afs_int32 i, nptr, pos;
+    struct contentry centry;
+    struct prentry tentry, tent;
+    afs_int32 loc;
+    afs_int32 oldowner;
     char holder[PR_MAXNAMELEN];
     char temp[PR_MAXNAMELEN];
+    char oldname[PR_MAXNAMELEN];
+    char *atsign;
 
-    noAuth = afsconf_GetNoAuthFlag(prdir);
-    bzero(holder,PR_MAXNAMELEN);
-    bzero(temp,PR_MAXNAMELEN);
+    memset(holder, 0, PR_MAXNAMELEN);
+    memset(temp, 0, 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 */
+    if (tentry.owner != cid &&
+       !IsAMemberOf(at,cid,SYSADMINID) &&
+       !IsAMemberOf(at,cid,tentry.owner) &&
+       !pr_noAuth) return PRPERM;
+#ifdef PR_REMEMBER_TIMES
+    tentry.changeTime = time(0);
+#endif
+
+    /* we're actually trying to change the id */
+    if (newid && (newid != aid)) {
+       if (!IsAMemberOf(at,cid,SYSADMINID) && !pr_noAuth) return PRPERM;
+
        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 ((aid < 0 && newid > 0) || (aid > 0 && newid < 0)) return PRPERM;
+
+       /* Should check that foreign users id to change to is good: inRange() */
+
        /* 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);
+       if (code) return code;
        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;
+
+       /* get current data */
+       code = pr_ReadEntry(at, 0, loc, &tentry);
+       if (code) return PRDBFAIL;
+
+       /* Also change the references from the membership list */
+       for (i=0; i<PRSIZE; i++) {
+          if (tentry.entries[i] == PRBADID) continue;
+          if (tentry.entries[i] == 0) break;
+           pos = FindByID(at, tentry.entries[i]);
+          if (!pos) return(PRDBFAIL);
+          code = RemoveFromEntry(at, aid, tentry.entries[i]);
+          if (code) return code;
+          code = pr_ReadEntry(at, 0, pos, &tent);
+          if (code) return code;
+          code = AddToEntry(at, &tent, pos, newid);
+          if (code) return code;
        }
+       /* Look through cont entries too. This needs to be broken into
+        * seperate transaction so that no one transaction becomes too 
+        * large to complete.
+        */
+       for (nptr=tentry.next; nptr; nptr=centry.next) {
+          code = pr_ReadCoEntry(at, 0, nptr, &centry);
+           if (code) return code;
+           for (i=0; i<COSIZE; i++) {
+             if (centry.entries[i] == PRBADID) continue;
+             if (centry.entries[i] == 0) break;
+             pos = FindByID(at, centry.entries[i]);
+             if (!pos) return(PRDBFAIL);
+             code = RemoveFromEntry(at, aid, centry.entries[i]);
+             if (code) return code;
+             code = pr_ReadEntry(at, 0, pos, &tent);
+             if (code) return code;
+             code = AddToEntry(at, &tent, pos, newid);
+             if (code) return code;
+          }
+       }
+    }
+
+    atsign = strchr(tentry.name, '@'); /* check for foreign entry */
+
+    /* Change the owner */
+    if (oid && (oid != tentry.owner)) {
+       /* only groups can have their owner's changed */
+       if (!(tentry.flags & PRGRP)) return PRPERM;
+       if (atsign != NULL) return PRPERM;
+       oldowner = tentry.owner;
        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);
+       /* The entry must be written through first so Remove and Add routines
+         * can operate on disk data */
+       code = pr_WriteEntry(at,0,loc,(char *)&tentry);
+       if (code) return PRDBFAIL;
+
+       /* switch owner chains */
+       if (oldowner)           /* if it has an owner */
+          code = RemoveFromOwnerChain(at,tentry.id,oldowner);
+       else                    /* must be an orphan */
+          code = RemoveFromOrphan(at,tentry.id);
+       if (code) return code;
+       code = AddToOwnerChain(at,tentry.id,tentry.owner);
+       if (code) return code;
+
+       /* fix up the name */
+       if (strlen(name) == 0) name = tentry.name;
+       /* get current data */
+       code = pr_ReadEntry(at,0,loc,&tentry);
        if (code) return PRDBFAIL;
     }
-    if ((strcmp(tentry.name,name)) && (strlen(name)!= 0)) {
+
+    /* Change the name, if name is a ptr to tentry.name then this name change
+     * is due to a chown, otherwise caller has specified a new name */
+    if ((name == tentry.name) ||
+       (*name && (strcmp (tentry.name, name) != 0))) {
+       strncpy (oldname, tentry.name, PR_MAXNAMELEN);
        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;
+           /* don't let foreign cell groups change name */
+           if (atsign != NULL) return PRPERM;
+           code = CorrectGroupName (at, name, cid, tentry.owner, tentry.name);
+           if (code) return code;
+
+           if (name == tentry.name) {  /* owner fixup */
+               if (strcmp (oldname, tentry.name) == 0) goto nameOK;
+           } else {                    /* new name, caller must be correct */
+               if (strcmp (name, tentry.name) != 0) return PRBADNAM;
+           }
        }
        else
-           /* if it's not a group, shouldn't have a : in it */
-           if ((check = index(name,':')) != NULL) 
-               return PRBADNAM;
-       pos = FindByName(at,name);
+       /* Allow a foreign name change only if the cellname part is
+          the same */
+       {
+            char *newatsign;
+
+           newatsign = strchr(name, '@');
+           if (newatsign != atsign){ /* if they are the same no problem*/
+              /*if the pointers are not equal the strings better be */
+              if ((atsign == NULL) || (newatsign == NULL) ||
+                   strcmp (atsign,newatsign)) return PRPERM;
+           } 
+           if (!CorrectUserName(name)) return PRBADNAM;
+       }
+
+       pos = FindByName(at,name, &tent);
        if (pos) return PREXIST;
-       code = RemoveFromNameHash(at,tentry.name,&loc);
+       code = RemoveFromNameHash (at, oldname, &loc);
        if (code != PRSUCCESS) return code;
-       strncpy(tentry.name,name,PR_MAXNAMELEN);
-       code = pr_WriteEntry(at,0,loc,&tentry);
+       strncpy (tentry.name, name, PR_MAXNAMELEN);
+       code = pr_WriteEntry(at,0,loc,(char *)&tentry);
        if (code) return PRDBFAIL;
        code = AddToNameHash(at,tentry.name,loc);
        if (code != PRSUCCESS) return code;
+nameOK:;
     }
     return PRSUCCESS;
 }
+
+
+afs_int32 allocNextId(cellEntry)
+     struct prentry *cellEntry;
+{
+       /* Id's for foreign cell entries are constructed as follows:
+          The 16 low order bits are the group id of the cell and the
+          top 16 bits identify the particular users in that cell */
+
+       afs_int32 id;
+
+
+       id = (ntohl(cellEntry -> nusers) +1); 
+       cellEntry->nusers = htonl(id);
+                                     /* use the field nusers to keep 
+                                        the next available id in that
+                                        foreign cell's group. Note :
+                                        It would seem more appropriate
+                                        to use ngroup for that and nusers
+                                        to enforce the quota, however pts
+                                        does not have an option to change 
+                                        foreign users quota yet  */
+
+       id = (id << 16) | ((ntohl(cellEntry-> id)) & 0x0000ffff);
+       return id;
+}
+
+int inRange(cellEntry,aid)
+struct prentry *cellEntry;
+afs_int32 aid;
+{
+       afs_uint32 id,cellid,groupid;
+
+
+       /*
+         The only thing that we want to make sure here is that
+         the id is in the legal range of this group. If it is
+         a duplicate we don't care since it will get caught 
+         in a different check.
+       */
+
+       cellid = aid & 0x0000ffff;
+       groupid =  (ntohl(cellEntry-> id)) & 0x0000ffff;
+       if (cellid != groupid) return 0; /* not in range */
+
+       /* 
+          if we got here we're ok but we need to update the nusers
+          field in order to get the id correct the next time that 
+          we try to allocate it automatically
+       */
+
+       id = aid >> 16;
+       if (id > ntohl(cellEntry -> nusers))
+               cellEntry -> nusers = htonl(id);
+       return 1;
+
+}
+
+AddAuthGroup(tentry, alist, size)
+  struct prentry *tentry;
+  prlist *alist;
+  afs_int32 *size;
+{
+       if (!(strchr(tentry->name, '@'))) 
+             return (AddToPRList (alist, size, AUTHUSERID));
+       else 
+            return PRSUCCESS;
+}
This page took 0.118513 seconds and 4 git commands to generate.