]> andersk Git - moira.git/blob - afssync/ptutils.c
Removed ID hashing code (it doesn't really help)
[moira.git] / afssync / ptutils.c
1 /* Copyright (C) 1990, 1989 Transarc Corporation - All rights reserved */
2 /*
3  * P_R_P_Q_# (C) COPYRIGHT IBM CORPORATION 1988
4  * LICENSED MATERIALS - PROPERTY OF IBM
5  * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
6  */
7
8
9 /*      
10              Sherri Nichols
11              Information Technology Center
12        November, 1988
13
14        Modified May, 1989 by Jeff Schiller to keep disk file in
15        network byte order
16
17 */
18
19 #include <afs/param.h>
20 #include <afs/stds.h>
21 #include <sys/types.h>
22 #include <stdio.h>
23 #ifdef AFS_HPUX_ENV
24 #include <string.h>
25 #else
26 #include <strings.h>
27 #endif
28 #include <lock.h>
29 #include <netinet/in.h>
30 #include <ubik.h>
31 #include <rx/xdr.h>
32 #include <afs/com_err.h>
33 #include "ptserver.h"
34 #include "pterror.h"
35
36 RCSID ("$Header$")
37
38 extern struct ubik_dbase *dbase;
39 extern struct afsconf_dir *prdir;
40 extern int pr_noAuth;
41
42 static char *whoami = "ptserver";
43
44 /* CorrectUserName - Check to make sure a user name is OK.  It must not include
45  *   either a colon (or it would look like a group) or an atsign (or it would
46  *   look like a foreign user).  The length is checked as well to make sure
47  *   that the user name, an atsign, and the local cell name will fit in
48  *   PR_MAXNAMELEN.  This is so this user can fit in another cells database as
49  *   a foreign user with our cell name tacked on.  This is a predicate, so it
50  *   return one if name is OK and zero if name is bogus. */
51
52 static int CorrectUserName (name)
53   char *name;
54 {
55     extern int pr_realmNameLen;
56
57 #ifdef CROSS_CELL
58     if (index (name, ':') || index(name, '\n')) return 0;
59 #else
60     if (index (name, ':') || index(name, '@') || index(name, '\n')) return 0;
61 #endif
62     if (strlen (name) >= PR_MAXNAMELEN - pr_realmNameLen - 1) return 0; 
63     return 1;
64 }
65
66 /* CorrectGroupName - Like the above but handles more complicated cases caused
67  * by including the ownership in the name.  The interface works by calculating
68  * the correct name based on a given name and owner.  This allows easy use by
69  * rename, which then compares the correct name with the requested new name. */
70
71 static long CorrectGroupName (ut, aname, cid, oid, cname)
72   struct ubik_trans *ut;
73   char aname[PR_MAXNAMELEN];            /* name for group */
74   long cid;                             /* caller id */
75   long oid;                             /* owner of group */
76   char cname[PR_MAXNAMELEN];            /* correct name for group */
77 {
78     long  code;
79     int   admin;
80     char *prefix;                       /* ptr to group owner part */
81     char *suffix;                       /* ptr to group name part */
82     char  name[PR_MAXNAMELEN];          /* correct name for group */
83     struct prentry tentry;
84
85     if (strlen (aname) >= PR_MAXNAMELEN) return PRBADNAM;
86     admin = pr_noAuth || (cid==SYSADMINID) || IsAMemberOf(ut, cid, SYSADMINID);
87
88     if (oid == 0) oid = cid;
89
90     /* Determine the correct prefix for the name. */
91     if (oid == SYSADMINID) prefix = "system";
92     else {
93         long loc = FindByID (ut, oid);
94         if (loc == 0) {
95             /* let admin create groups owned by non-existent ids (probably
96              * setting a group to own itself).  Check that they look like
97              * groups (with a colon) or otherwise are good user names. */
98             if (admin) {
99                 strcpy (cname, aname);
100                 goto done;
101             }
102             return PRNOENT;
103         }
104         code = pr_Read (ut, 0, loc, &tentry, sizeof(tentry));
105         if (code) return code;
106         if (ntohl(tentry.flags) & PRGRP) {
107             if ((tentry.count == 0) && !admin) return PRGROUPEMPTY;
108             /* terminate prefix at colon if there is one */
109             if (prefix = index(tentry.name, ':')) *prefix = 0;
110         }
111         prefix = tentry.name;
112     }
113     /* only sysadmin allow to use 'system:' prefix */
114     if ((strcmp (prefix, "system") == 0) && !admin) return PRPERM;
115
116     strcpy (name, aname);               /* in case aname & cname are same */
117     suffix = index(name, ':');
118     if (suffix == 0) {
119         /* sysadmin can make groups w/o ':', but they must still look like
120          * legal user names. */
121         if (!admin) return PRBADNAM;
122         strcpy (cname, name);
123     }
124     else {
125         if (strlen(prefix)+strlen(suffix) >= PR_MAXNAMELEN) return PRBADNAM;
126         strcpy (cname, prefix);
127         strcat (cname, suffix);
128     }
129   done:
130     /* check for legal name with either group rules or user rules */
131     if (suffix = index(cname, ':')) {
132         /* check for confusing characters */
133 #ifdef CROSS_CELL
134         if (index(cname, '\n') ||       /* restrict so recreate can work */
135             index(suffix+1, ':'))       /* avoid multiple colons */
136             return PRBADNAM;
137 #else
138         if (index(cname, '@') ||        /* avoid confusion w/ foreign users */
139             index(cname, '\n') ||       /* restrict so recreate can work */
140             index(suffix+1, ':'))       /* avoid multiple colons */
141             return PRBADNAM;
142 #endif
143     } else {
144         if (!CorrectUserName (cname)) return PRBADNAM;
145     }
146     return 0;
147 }
148
149 int AccessOK (ut, cid, tentry, mem, any)
150   struct ubik_trans *ut;
151   long cid;                             /* caller id */
152   struct prentry *tentry;               /* object being accessed */
153   int mem;                              /* check membership in aid, if group */
154   int any;                              /* if set return true */
155 {   long flags;
156     long oid;
157     long aid;
158
159     if (pr_noAuth) return 1;
160     if (cid == SYSADMINID) return 1;    /* special case fileserver */
161     if (tentry) {
162         flags = tentry->flags;
163         oid = tentry->owner;
164         aid = tentry->id;
165     } else {
166         flags = oid = aid = 0;
167     }
168     if (!(flags & PRACCESS))            /* provide default access */
169         if (flags & PRGRP)
170             flags |= PRP_GROUP_DEFAULT;
171         else
172             flags |= PRP_USER_DEFAULT;
173
174     if (flags & any) return 1;
175     if (oid) {
176         if ((cid == oid) ||
177             IsAMemberOf (ut, cid, oid)) return 1;
178     }
179     if (aid > 0) {                      /* checking on a user */
180         if (aid == cid) return 1;
181     } else if (aid < 0) {               /* checking on group */
182         if ((flags & mem) && IsAMemberOf (ut, cid, aid)) return 1;
183     }
184     if (IsAMemberOf (ut, cid, SYSADMINID)) return 1;
185     return 0;                           /* no access */
186 }
187
188 long CreateEntry (at, aname, aid, idflag, flag, oid, creator)  
189   register struct ubik_trans *at;
190   char aname[PR_MAXNAMELEN];
191   long *aid;
192   long idflag;
193   long flag;
194   long oid;
195   long creator;
196 {
197     /* get and init a new entry */
198     register long code;
199     long newEntry;
200     struct prentry tentry;
201     
202     bzero(&tentry, sizeof(tentry));
203
204     if ((oid == 0) || (oid == ANONYMOUSID)) oid = creator;
205
206     if (flag & PRGRP) {
207         code = CorrectGroupName (at, aname, creator, oid, tentry.name);
208         if (code) return code;
209         if (strcmp (aname, tentry.name) != 0)  return PRBADNAM;
210     } else {                            /* non-group must not have colon */
211         if (!CorrectUserName(aname)) return PRBADNAM;
212         strcpy (tentry.name, aname);
213     }
214
215     if (FindByName(at,aname)) return PREXIST;
216
217     newEntry = AllocBlock(at);
218     if (!newEntry) return PRDBFAIL;
219 #ifdef PR_REMEMBER_TIMES
220     tentry.createTime = time(0);
221 #endif
222     if (flag & PRGRP) {
223         tentry.flags |= PRGRP;
224         tentry.owner = oid;
225     }
226     else if (flag & PRFOREIGN) {
227         tentry.flags |= PRFOREIGN;
228         tentry.owner = oid;
229     }
230     else tentry.owner = SYSADMINID;
231
232 #ifdef CROSS_CELL
233 #define ADD_TO_AUTHUSER_GROUP 1
234 #define AUTHUSER_GROUP "system:authuser"
235     {
236         char * atsign;
237
238         if (!(atsign= index(aname,'@'))) {      /* No @ so local cell*/
239             if (idflag)
240                 tentry.id = *aid;
241             else {
242                 code= AllocID(at,flag,&tentry.id);
243                 if (code != PRSUCCESS) return code;
244             }
245         } else {
246             /*foreign cells are represented by the group system:authuser@cell*/
247             if (flag & PRGRP) {
248                 /* it's a new foreign cell so the format
249                  * must be AUTHUSER_GROUP@cellname  */
250                 int badFormat;
251                 
252                 *atsign = '\0';
253                 badFormat = strcmp(AUTHUSER_GROUP, aname);
254                 *atsign = '@';
255                 if (badFormat) return PRBADNAM;
256                 if (idflag)
257                     tentry.id = *aid;
258                 else {
259                     code= AllocID(at,flag,&tentry.id);
260                     if (code != PRSUCCESS) return code;
261                 }
262             } else {
263                 /* it's a foreign cell entry */
264                 char *cellGroup;
265                 long pos;
266                 struct prentry centry;
267                 extern long allocNextId();
268                 extern long AddToEntry();
269                 
270                 cellGroup = (char *) malloc (strlen(AUTHUSER_GROUP) +
271                                              strlen(atsign) +1);
272                 strcpy(cellGroup, AUTHUSER_GROUP);
273                 strcat(cellGroup, atsign);
274                 pos = FindByName(at,cellGroup);
275                 
276                 /* if the group doesn't exist don't allow user creation */
277                 if (!pos) return PRBADNAM;
278                 
279                 code = pr_Read (at, 0, pos, &centry, sizeof(centry));
280                 if (code) return code;
281                 tentry.cellid = ntohl(centry.id);
282                 /* cellid is the id of the group representing the cell */
283                 
284                 if (idflag) {
285                     if (!inRange(&centry,*aid))
286                         return PRBADARG;        /* the id specified is not in
287                                                  * the id space of the group */
288                     tentry.id = *aid;
289                 } else
290                     /* allocNextID() will allocate the next id
291                      * in that cell's space */
292                     tentry.id = allocNextId(&centry);
293
294                 /* charge the cell group for the new user and test quota */
295                 if (!(ntohl(centry.flags) & PRQUOTA)) {
296                     /* quota uninitialized, so initialize it now */
297                     centry.flags = htonl (ntohl(centry.flags) | PRQUOTA);
298                     centry.ngroups = htonl(30);
299                 }
300
301                 centry.ngroups = htonl(ntohl(centry.ngroups) - 1);
302                 if (ntohl(centry.ngroups) < 0)
303                     if (!pr_noAuth) return PRNOMORE;
304                 
305 #if !ADD_TO_AUTHUSER_GROUP
306                 centry.count = htonl(ntohl(centry.ngroups) +1);
307                 /* keep count of how many people are in the group. */
308 #endif
309                 
310                 code = pr_Write (at, 0, pos, &centry, sizeof(centry));
311                 /* write updated entry for group */
312
313                 /* Now add the new user entry to the database */
314                 
315                 tentry.creator = creator;
316                 *aid = tentry.id;
317                 code = pr_WriteEntry(at, 0, newEntry, &tentry);
318                 if (code) return PRDBFAIL;
319                 code = AddToIDHash(at,*aid,newEntry);
320                 if (code != PRSUCCESS) return code;
321                 code = AddToNameHash(at,aname,newEntry);
322                 if (code != PRSUCCESS) return code;
323                 if (inc_header_word (at, foreigncount, 1)) return PRDBFAIL;
324                 
325 #if ADD_TO_AUTHUSER_GROUP
326                 
327                 /* Now add the entry to the authuser group for this cell.
328                  * We will reread the entries for the user and the group
329                  * instead of modifying them before writing them in the
330                  * previous steps. Although not very efficient, much simpler */
331
332                 /* First update the group entry */
333                 pos = FindByID(at,tentry.cellid);
334                 if (!pos) return PRBADNAM;
335                 code = pr_ReadEntry (at, 0, pos, &centry);
336                 if (code) return code;
337                 code = AddToEntry(at, &centry,pos,*aid);
338                 if (code) return code;
339                 /* and now the user entry */
340                 pos = FindByID(at,*aid);
341                 if (!pos) return PRBADNAM;
342                 code = pr_ReadEntry(at, 0, pos, &tentry);
343                 if (code) return code;
344                 code = AddToEntry(at, &tentry,pos,tentry.cellid);
345                 if (code) return code;
346                 
347 #endif
348                 
349                 /* Ok we're done */
350                 return PRSUCCESS;
351             }
352         }
353     }
354
355 #else   /* !CROSS_CELL */
356
357     if (idflag) 
358         tentry.id = *aid;
359     else {
360         code= AllocID(at,flag,&tentry.id);
361         if (code != PRSUCCESS) return code;
362     }
363 #endif  /* !CROSS_CELL */
364
365     if (flag & PRGRP) {
366         /* group ids are negative */
367         if (tentry.id < (long)ntohl(cheader.maxGroup)) {
368             code = set_header_word (at, maxGroup, htonl(tentry.id));
369             if (code) return PRDBFAIL;
370         }
371     }
372     else if (flag & PRFOREIGN) {
373         if (tentry.id > (long)ntohl(cheader.maxForeign)) {
374             code = set_header_word (at, maxForeign, htonl(tentry.id));
375             if (code) return PRDBFAIL;
376         }
377     }
378     else {
379         if (tentry.id > (long)ntohl(cheader.maxID)) {
380             code = set_header_word (at, maxID, htonl(tentry.id));
381             if (code) return PRDBFAIL;
382         }
383     }
384     /* PRACCESS is off until set, defaults provided in AccessOK */
385     if (flag == 0) {                    /* only normal users get quota */
386         tentry.flags |= PRQUOTA;
387         tentry.ngroups = tentry.nusers = 20;
388     }
389
390     if (flag & (PRGRP | PRFOREIGN)) {
391         long loc = FindByID (at, creator);
392         struct prentry centry;
393         long *nP;                       /* ptr to entry to be decremented */
394         long  n;                        /* quota to check */
395
396         if (loc) { /* this should only fail during initialization */
397             code = pr_Read (at, 0, loc, &centry, sizeof(centry));
398             if (code) return code;
399
400             if (flag & PRGRP) nP = &centry.ngroups;
401             else if (flag & PRFOREIGN) nP = &centry.nusers;
402             else nP = 0;
403             
404             if (nP) {
405                 if (!(ntohl(centry.flags) & PRQUOTA)) {
406                     /* quota uninitialized, so do it now */
407                     centry.flags = htonl (ntohl(centry.flags) | PRQUOTA);
408                     centry.ngroups = centry.nusers = htonl(20);
409                 }
410                 n = ntohl(*nP);
411                 if (n <= 0) {
412                     if (!pr_noAuth &&
413                         !IsAMemberOf (at, creator, SYSADMINID))
414                         return PRNOMORE;
415                 }
416                 else {                  /* don't use up admin user's quota */
417                     int admin = ((creator == SYSADMINID) ||
418                                  IsAMemberOf (at, creator, SYSADMINID));
419                     if (!admin) *nP = htonl(n-1);
420                 }
421             }
422             code = pr_Write (at, 0, loc, &centry, sizeof(centry));
423             if (code) return code;
424         } /* if (loc) */
425     } /* need to check creation quota */
426     tentry.creator = creator;
427     *aid = tentry.id;
428     code = pr_WriteEntry(at, 0, newEntry, &tentry);
429     if (code) return PRDBFAIL;
430     code = AddToIDHash(at,*aid,newEntry);
431     if (code != PRSUCCESS) return code;
432     code = AddToNameHash(at,aname,newEntry);
433     if (code != PRSUCCESS) return code;
434     if (tentry.flags & PRGRP) {
435         code = AddToOwnerChain(at,tentry.id,oid);
436         if (code) return code;
437     }
438     if (tentry.flags & PRGRP) {
439         if (inc_header_word (at, groupcount, 1)) return PRDBFAIL;
440     }
441     else if (tentry.flags & PRFOREIGN) {
442         if (inc_header_word (at, foreigncount, 1)) return PRDBFAIL;
443     }
444     else if (tentry.flags & PRINST) {
445         if (inc_header_word (at, instcount, 1)) return PRDBFAIL;
446     }
447     else {
448         if (inc_header_word (at, usercount, 1)) return PRDBFAIL;
449     }
450     return PRSUCCESS;
451 }
452     
453
454 /* RemoveFromEntry - remove aid from bid's entries list, freeing a continuation
455  * entry if appropriate */
456
457 long RemoveFromEntry (at, aid, bid)
458   register struct ubik_trans *at;
459   register long aid;
460   register long bid;
461 {
462     register long code;
463     struct prentry tentry;
464     struct contentry centry;
465     struct contentry hentry;
466     long temp;
467     long i,j;
468     long nptr;
469     long hloc;
470     
471     if (aid == bid) return PRINCONSISTENT;
472     bzero(&hentry,sizeof(hentry));
473     temp = FindByID(at,bid);
474     if (temp == 0) return PRNOENT;
475     code = pr_ReadEntry(at, 0, temp, &tentry);
476     if (code != 0) return code;
477 #ifdef PR_REMEMBER_TIMES
478     tentry.removeTime = time(0);
479 #endif
480     for (i=0;i<PRSIZE;i++) {
481         if (tentry.entries[i] == aid) {  
482             tentry.entries[i] = PRBADID;
483             tentry.count--;
484             code = pr_WriteEntry(at,0,temp,&tentry);
485             if (code != 0) return code;
486             return PRSUCCESS;
487         }
488         if (tentry.entries[i] == 0)   /* found end of list */
489             return PRNOENT;
490     }
491     hloc = 0;
492     nptr = tentry.next;
493     while (nptr != NULL) {
494         code = pr_ReadCoEntry(at,0,nptr,&centry);
495         if (code != 0) return code;
496         if ((centry.id != bid) || !(centry.flags & PRCONT)) return PRDBBAD;
497         for (i=0;i<COSIZE;i++) {
498             if (centry.entries[i] == aid) {
499                 centry.entries[i] = PRBADID;
500                 for (j=0;j<COSIZE;j++)
501                     if (centry.entries[j] != PRBADID &&
502                         centry.entries[j] != 0) break;
503                 if (j == COSIZE) {   /* can free this block */
504                     if (hloc == 0) {
505                         tentry.next = centry.next;
506                     }
507                     else {
508                         hentry.next = centry.next;
509                         code = pr_WriteCoEntry (at, 0, hloc, &hentry);
510                         if (code != 0) return code;
511                     }
512                     code = FreeBlock (at, nptr);
513                     if (code) return code;
514                 }
515                 else { /* can't free it yet */
516                     code = pr_WriteCoEntry(at,0,nptr,&centry);
517                     if (code != 0) return code;
518                 }
519                 tentry.count--;
520                 code = pr_WriteEntry(at,0,temp,&tentry);
521                 if (code) return PRDBFAIL;
522                 return 0;
523             }
524             if (centry.entries[i] == 0) return PRNOENT;
525         } /* for all coentry slots */
526         hloc = nptr;
527         nptr = centry.next;
528         bcopy(&centry,&hentry,sizeof(centry));
529     } /* while there are coentries */
530     return PRNOENT;
531 }
532
533 /* DeleteEntry - delete the entry in tentry at loc, removing it from all
534  * groups, putting groups owned by it on orphan chain, and freeing the space */
535
536 long DeleteEntry (at, tentry, loc)
537   register struct ubik_trans *at;
538   struct prentry *tentry;
539   long loc;
540 {
541     register long code;
542     struct contentry centry;
543     register long  i;
544     long nptr;
545
546 #ifdef CROSS_CELL
547     if (index(tentry->name,'@')) {
548         if (tentry->flags & PRGRP) {
549             /* If there are still foreign user accounts from that cell
550              * don't delete the group */
551             if (tentry->count) return PRBADARG;
552         } else {
553             /* It's a user adjust the group quota upwards */
554             long loc = FindByID (at, tentry->cellid);
555             struct prentry centry;
556             if (loc) {
557                 code = pr_Read (at, 0, loc, &centry, sizeof(centry));
558                 if (code) return code;
559                 if (ntohl(centry.flags) & PRQUOTA) {
560                     centry.ngroups = htonl(ntohl(centry.ngroups) + 1);
561                 }
562 #if !ADD_TO_AUTHUSER_GROUP
563                 /* if this is a foreign cell entry then decrement the number of
564                  * existing users in the prentry of the authuser group for that
565                  * cell
566                  */
567                 centry.count = htonl(ntohl(centry.count) - 1);
568 #endif
569                 code = pr_Write (at, 0, loc, &centry, sizeof(centry));
570                 if (code) return code;
571             }
572         }
573     }
574 #endif /* CROSS_CELL */
575     
576     /* First remove the entire membership list */
577     for (i=0;i<PRSIZE;i++) {
578         if (tentry->entries[i] == PRBADID) continue;
579         if (tentry->entries[i] == 0) break;
580         code = RemoveFromEntry (at, tentry->id, tentry->entries[i]);
581         if (code) return code;
582     }
583     nptr = tentry->next;
584     while (nptr != NULL) {
585         code = pr_ReadCoEntry(at,0,nptr,&centry);
586         if (code != 0) return PRDBFAIL;
587         for (i=0;i<COSIZE;i++) {
588             if (centry.entries[i] == PRBADID) continue;
589             if (centry.entries[i] == 0) break;
590             code = RemoveFromEntry (at, tentry->id, centry.entries[i]);
591             if (code) return code;
592         }
593         code = FreeBlock (at, nptr);    /* free continuation block */
594         if (code) return code;
595         nptr = centry.next;
596     }
597
598     /* Remove us from other's owned chain.  Note that this will zero our owned
599      * field (on disk) so this step must follow the above step in case we are
600      * on our own owned list. */
601     if (tentry->flags & PRGRP) {
602         if (tentry->owner) {
603             code = RemoveFromOwnerChain (at, tentry->id, tentry->owner);
604             if (code) return code;
605         }
606         else {
607             code = RemoveFromOrphan (at, tentry->id);
608             if (code) return code;
609         }
610     }
611
612     code = RemoveFromIDHash(at,tentry->id,&loc);
613     if (code != PRSUCCESS) return code;
614     code = RemoveFromNameHash(at,tentry->name,&loc);
615     if (code != PRSUCCESS) return code;
616
617     if (tentry->flags & (PRGRP | PRFOREIGN)) {
618         long loc = FindByID (at, tentry->creator);
619         struct prentry centry;
620         int admin;
621         if (loc) {
622             code = pr_Read (at, 0, loc, &centry, sizeof(centry));
623             if (code) return code;
624             admin = ((tentry->creator == SYSADMINID) ||
625                      IsAMemberOf (at, tentry->creator, SYSADMINID));
626             if (ntohl(centry.flags) & PRQUOTA) {
627                 if ((tentry->flags & PRGRP) &&
628                     !(admin && (ntohl(centry.ngroups) >= 20))) {
629                     centry.ngroups = htonl(ntohl(centry.ngroups) + 1);
630                 } else if ((tentry->flags & PRFOREIGN) &&
631                            !(admin && (ntohl(centry.nusers) >= 20))) {
632                     centry.nusers = htonl(ntohl(centry.nusers) + 1);
633                 }
634             }
635             code = pr_Write (at, 0, loc, &centry, sizeof(centry));
636             if (code) return code;
637         }
638     }
639
640     if (tentry->flags & PRGRP) {
641         if (inc_header_word (at, groupcount, -1)) return PRDBFAIL;
642     }
643     else if (tentry->flags & PRFOREIGN) {
644         if (inc_header_word (at, foreigncount, -1)) return PRDBFAIL;
645     }
646     else if (tentry->flags & PRINST) {
647         if (inc_header_word (at, instcount, -1)) return PRDBFAIL;
648     }
649     else {
650         if (inc_header_word (at, usercount, -1)) return PRDBFAIL;
651     }
652     code = FreeBlock(at, loc);
653     return code;
654 }
655
656 /* AddToEntry - add aid to entry's entries list, alloc'ing a continuation block
657  * if needed.
658  *
659  * Note the entry is written out by this routine. */
660
661 long AddToEntry (tt, entry, loc, aid)
662   struct ubik_trans *tt;
663   struct prentry *entry;
664   long loc;
665   long aid;
666 {
667     register long code;
668     long i;
669     struct contentry nentry;
670     struct contentry aentry;
671     long nptr;
672     long last;                          /* addr of last cont. block */
673     long first = 0;
674     long cloc;
675     long slot = -1;
676
677     if (entry->id == aid) return PRINCONSISTENT;
678 #ifdef PR_REMEMBER_TIMES
679     entry->addTime = time(0);
680 #endif
681     for (i=0;i<PRSIZE;i++) {
682         if (entry->entries[i] == aid)
683             return PRIDEXIST;
684         if (entry->entries[i] == PRBADID) { /* remember this spot */
685             first = 1;
686             slot = i;
687         }
688         else if (entry->entries[i] == 0) { /* end of the line */
689             if (slot == -1) {
690                 first = 1;
691                 slot = i;
692             }
693             break;
694         }
695     }
696     last = 0;
697     nptr = entry->next;
698     while (nptr != NULL) {
699         code = pr_ReadCoEntry(tt,0,nptr,&nentry);
700         if (code != 0) return code;
701         last = nptr;
702         if (!(nentry.flags & PRCONT)) return PRDBFAIL;
703         for (i=0;i<COSIZE;i++) {
704             if (nentry.entries[i] == aid)
705                 return PRIDEXIST;
706             if (nentry.entries[i] == PRBADID) {
707                 if (slot == -1) {
708                     slot = i;
709                     cloc = nptr;
710                 }
711             }
712             else if (nentry.entries[i] == 0) {
713                 if (slot == -1) {
714                     slot = i;
715                     cloc = nptr;
716                 }
717                 break;
718             }
719         }
720         nptr = nentry.next;
721     }
722     if (slot != -1) {                   /* we found a place */
723         entry->count++;
724         if (first) {  /* place is in first block */
725             entry->entries[slot] = aid;
726             code = pr_WriteEntry (tt, 0, loc, entry);
727             if (code != 0) return code;
728             return PRSUCCESS;
729         }
730         code = pr_WriteEntry (tt, 0, loc, entry);
731         if (code) return code;
732         code = pr_ReadCoEntry(tt,0,cloc,&aentry);
733         if (code != 0) return code;
734         aentry.entries[slot] = aid;
735         code = pr_WriteCoEntry(tt,0,cloc,&aentry);
736         if (code != 0) return code;
737         return PRSUCCESS;
738     }
739     /* have to allocate a continuation block if we got here */
740     nptr = AllocBlock(tt);
741     if (last) {
742         /* then we should tack new block after last block in cont. chain */
743         nentry.next = nptr;
744         code = pr_WriteCoEntry(tt,0,last,&nentry);
745         if (code != 0) return code;
746     }
747     else {
748         entry->next = nptr;
749     }
750     bzero(&aentry,sizeof(aentry));
751     aentry.flags |= PRCONT;
752     aentry.id = entry->id;
753     aentry.next = NULL;
754     aentry.entries[0] = aid;
755     code = pr_WriteCoEntry(tt,0,nptr,&aentry);
756     if (code != 0) return code;
757     /* don't forget to update count, here! */
758     entry->count++;
759     code = pr_WriteEntry (tt, 0, loc, entry);
760     return code;
761         
762 }
763
764 long AddToPRList (alist, sizeP, id)
765   prlist *alist;
766   int *sizeP;
767   long id;
768 {
769     if (alist->prlist_len >= PR_MAXGROUPS) return PRTOOMANY;
770     if (alist->prlist_len >= *sizeP) {
771         *sizeP = *sizeP + 100;
772         if (*sizeP > PR_MAXGROUPS) *sizeP = PR_MAXGROUPS;
773         alist->prlist_val =
774             (long *) ((alist->prlist_val) ?
775                       realloc (alist->prlist_val, (*sizeP)*sizeof(long)) :
776                       malloc ((*sizeP)*sizeof(long)));
777     }
778     alist->prlist_val[alist->prlist_len++] = id;
779     return 0;
780 }
781
782 long GetList (at, tentry, alist, add)
783   struct ubik_trans *at;
784   struct prentry *tentry;
785   prlist *alist;
786   long add;
787 {
788     register long code;
789     long i;
790     struct contentry centry;
791     long nptr;
792     int size;
793     int count = 0;
794     extern long IDCmp();
795
796     size = 0;
797     alist->prlist_val = 0;
798     alist->prlist_len = 0;
799
800     for (i=0;i<PRSIZE;i++) {
801         if (tentry->entries[i] == PRBADID) continue;
802         if (tentry->entries[i] == 0) break;
803         code = AddToPRList (alist, &size, tentry->entries[i]);
804         if (code) return code;
805     }
806
807     nptr = tentry->next;
808     while (nptr != NULL) {
809         /* look through cont entries */
810         code = pr_ReadCoEntry(at,0,nptr,&centry);
811         if (code != 0) return code;
812         for (i=0;i<COSIZE;i++) {
813             if (centry.entries[i] == PRBADID) continue;
814             if (centry.entries[i] == 0) break;
815             code = AddToPRList (alist, &size, centry.entries[i]);
816             if (code) return code;
817         }
818         nptr = centry.next;
819         if (count++ > 50) IOMGR_Poll(), count = 0;
820     }
821
822     if (add) { /* this is for a CPS, so tack on appropriate stuff */
823         if (tentry->id != ANONYMOUSID && tentry->id != ANYUSERID) {
824 #ifdef CROSS_CELL
825             if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
826                 (code = AddAuthGroup(tentry, alist, &size)) ||
827                 (code = AddToPRList (alist, &size, tentry->id))) return code;
828 #else
829             if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
830                 (code = AddToPRList (alist, &size, AUTHUSERID)) ||
831                 (code = AddToPRList (alist, &size, tentry->id))) return code;
832 #endif
833         }
834         else {
835             if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
836                 (code = AddToPRList (alist, &size, tentry->id))) return code;
837         }
838     }
839     if (alist->prlist_len > 100) IOMGR_Poll();
840     qsort(alist->prlist_val,alist->prlist_len,sizeof(long),IDCmp);
841     return PRSUCCESS;
842 }
843
844 long GetOwnedChain (ut, next, alist)
845   struct ubik_trans *ut;
846   long next;
847   prlist *alist;
848 {   register long code;
849     struct prentry tentry;
850     int size;
851     int count = 0;
852     extern long IDCmp();
853
854     size = 0;
855     alist->prlist_val = 0;
856     alist->prlist_len = 0;
857
858     while (next) {
859         code = pr_Read (ut, 0, next, &tentry, sizeof(tentry));
860         if (code) return code;
861         code = AddToPRList (alist, &size, ntohl(tentry.id));
862         if (code) return code;
863         next = ntohl(tentry.nextOwned);
864         if (count++ > 50) IOMGR_Poll(), count = 0;
865     }
866     if (alist->prlist_len > 100) IOMGR_Poll();
867     qsort(alist->prlist_val,alist->prlist_len,sizeof(long),IDCmp);
868     return PRSUCCESS;
869 }
870
871 long GetMax(at,uid,gid)
872 register struct ubik_trans *at;
873 long *uid;
874 long *gid;
875 {
876     *uid = ntohl(cheader.maxID);
877     *gid = ntohl(cheader.maxGroup);
878     return PRSUCCESS;
879 }
880
881 long SetMax(at,id,flag)
882 register struct ubik_trans *at;
883 long id;
884 long flag;
885 {
886     register long code;
887     if (flag & PRGRP) {
888         cheader.maxGroup = htonl(id);
889         code = pr_Write(at,0,16,(char *)&cheader.maxGroup,sizeof(cheader.maxGroup));
890         if (code != 0) return code;
891     }
892     else {
893         cheader.maxID = htonl(id);
894         code = pr_Write(at,0,20,(char *)&cheader.maxID,sizeof(cheader.maxID));
895         if (code != 0) return code;
896     }
897     return PRSUCCESS;
898 }
899
900 int pr_noAuth;
901
902 long Initdb()
903 {
904     long code;
905     struct ubik_trans *tt;
906     long len;
907     static long initd=0;
908 #if 0
909     static struct ubik_version curver;
910     struct ubik_version newver;
911 #endif
912
913     /* init the database.  We'll try reading it, but if we're starting from scratch, we'll have to do a write transaction. */
914
915     pr_noAuth = afsconf_GetNoAuthFlag(prdir);
916
917     code = ubik_BeginTransReadAny(dbase,UBIK_READTRANS, &tt);
918     if (code) return code;
919     code = ubik_SetLock(tt,1,1,LOCKREAD);
920     if (code) {
921         ubik_AbortTrans(tt);
922         return code;
923     }
924     if (!initd) {
925         initd = 1;
926 #if 0
927         bzero(&curver,sizeof(curver));
928 #endif
929     } else if (!ubik_CacheUpdate (tt)) {
930         code = ubik_EndTrans(tt);
931         return code;
932     }
933 #if 0
934     code = ubik_GetVersion(tt,&newver);
935     if (vcmp(curver,newver) == 0) {
936         /* same version */
937         code = ubik_EndTrans(tt);
938         if (code) return code;
939         return PRSUCCESS;
940     }
941     bcopy(&newver,&curver,sizeof(struct ubik_version));
942 #endif
943
944     len = sizeof(cheader);
945     code = pr_Read(tt, 0, 0, (char *) &cheader, len);
946     if (code != 0) {
947         com_err (whoami, code, "couldn't read header");
948         ubik_AbortTrans(tt);
949         return code;
950     }
951     if ((ntohl(cheader.version) == PRDBVERSION) &&
952         ntohl(cheader.headerSize) == sizeof(cheader) &&
953         ntohl(cheader.eofPtr) != NULL &&
954         FindByID(tt,ANONYMOUSID) != 0){
955         /* database exists, so we don't have to build it */
956         code = ubik_EndTrans(tt);
957         if (code) return code;
958         return PRSUCCESS;
959     }
960     /* else we need to build a database */
961     code = ubik_EndTrans(tt);
962     if (code) return code;
963
964     /* Only rebuild database if the db was deleted (the header is zero) and we
965        are running noAuth. */
966     {   char *bp = (char *)&cheader;
967         int i;
968         for (i=0; i<sizeof(cheader); i++)
969             if (bp[i])  {
970                 code = PRDBBAD;
971                 com_err (whoami, code,
972                          "Can't rebuild database because it is not empty");
973                 return code;
974             }
975     }
976     if (!pr_noAuth) {
977         code = PRDBBAD;
978         com_err (whoami, code,
979                  "Can't rebuild database because not running NoAuth");
980         return code;
981     }
982
983     code = ubik_BeginTrans(dbase,UBIK_WRITETRANS, &tt);
984     if (code) return code;
985
986     code = ubik_SetLock(tt,1,1,LOCKWRITE);
987     if (code) {
988         ubik_AbortTrans(tt);
989         return code;
990     }
991
992     /* before doing a rebuild, check again that the dbase looks bad, because
993      * the previous check was only under a ReadAny transaction, and there could
994      * actually have been a good database out there.  Now that we have a
995      * real write transaction, make sure things are still bad.
996      */
997     if ((ntohl(cheader.version) == PRDBVERSION) &&
998         ntohl(cheader.headerSize) == sizeof(cheader) &&
999         ntohl(cheader.eofPtr) != NULL &&
1000         FindByID(tt,ANONYMOUSID) != 0){
1001         /* database exists, so we don't have to build it */
1002         code = ubik_EndTrans(tt);
1003         if (code) return code;
1004         return PRSUCCESS;
1005     }
1006
1007     /* Initialize the database header */
1008     if ((code = set_header_word (tt, version, htonl(PRDBVERSION))) ||
1009         (code = set_header_word (tt, headerSize, htonl(sizeof(cheader)))) ||
1010         (code = set_header_word (tt, eofPtr, cheader.headerSize))) {
1011         com_err (whoami, code, "couldn't write header words");
1012         ubik_AbortTrans(tt);
1013         return code;
1014     }
1015
1016 #define InitialGroup(id,name) do {    \
1017     long temp = (id);                 \
1018     long flag = (id) < 0 ? PRGRP : 0; \
1019     code = CreateEntry                \
1020         (tt, (name), &temp, /*idflag*/1, flag, SYSADMINID, SYSADMINID); \
1021     if (code) {                       \
1022         com_err (whoami, code, "couldn't create %s with id %di.",       \
1023                  (name), (id));       \
1024         ubik_AbortTrans(tt);          \
1025         return code;                  \
1026     }                                 \
1027 } while (0)
1028
1029     InitialGroup (SYSADMINID, "system:administrators");
1030     InitialGroup (ANYUSERID, "system:anyuser");
1031     InitialGroup (AUTHUSERID, "system:authuser");
1032     InitialGroup (ANONYMOUSID, "anonymous");
1033
1034     /* Well, we don't really want the max id set to anonymousid, so we'll set
1035      * it back to 0 */
1036     code = set_header_word (tt, maxID, 0); /* correct in any byte order */
1037     if (code) {
1038         com_err (whoami, code, "couldn't reset max id");
1039         ubik_AbortTrans(tt);
1040         return code;
1041     }
1042
1043     code = ubik_EndTrans(tt);
1044     if (code) return code;
1045     return PRSUCCESS;
1046 }
1047
1048 /*
1049  * FUNCTION
1050  *      fixOwnerChain
1051  *
1052  * DESCRIPTION
1053  * This function follows the "owned" and "nextOwned" chains and verifies
1054  * that the data is consistent.  The chain is only traversed as far as is
1055  * necessary for efficiency reasons:
1056  * o Follow the "nextOwned" chain only if we had to adjust ourself
1057  *   (either renaming ourself or adjusting the owner id)
1058  * o Follow the "owned" chain if we had to adjust ourself (see above), or
1059  *   we are the parent that started this mess (tentry->id == oldid/newid)
1060  */
1061
1062 long fixOwnerChain(at,loc,tentry,oldid,newid)
1063     struct ubik_trans *at;
1064     struct prentry *tentry;
1065     long loc, oldid, newid;
1066 {
1067     char name[PR_MAXNAMELEN];
1068     struct prentry nentry;
1069     long pos;
1070     register long code;
1071     int nextOwn = 0;
1072
1073     if (newid && oldid != newid) {
1074         if (tentry->owner == oldid) tentry->owner = newid;
1075         if (tentry->creator == oldid) tentry->creator = newid;
1076
1077         /* If our owner has changed, continue along the nextOwned chain */
1078         if (tentry->owner == newid) nextOwn=1;
1079     }
1080     
1081     strcpy(name, tentry->name);
1082     code=CorrectGroupName(at,name,tentry->creator,tentry->owner,tentry->name);
1083     if (code) return code;
1084     if (strcmp(name, tentry->name)) {
1085
1086         /* If we had to rename ourself, there are probably others
1087          * along the nextOwned chain that have to do the same.  */
1088         nextOwn = 1;
1089
1090         pos = FindByName(at,tentry->name);
1091         if (pos) return PREXIST;
1092
1093         code = RemoveFromNameHash (at, name, &loc);
1094         if (code) return code;
1095         code = AddToNameHash(at,tentry->name,loc);
1096         if (code) return code;
1097     }
1098
1099     code = pr_WriteEntry(at, 0, loc, tentry);
1100     if (code) return code;
1101
1102     if ((loc = tentry->owned) &&
1103         (nextOwn || (newid && tentry->id == newid) || (tentry->id == oldid))) {
1104
1105         code = pr_ReadEntry(at,0,loc,&nentry);
1106         if (code) return code;
1107         code = fixOwnerChain(at, loc, &nentry, oldid, newid);
1108         if (code) return code;
1109     }
1110
1111     if (nextOwn && (loc = tentry->nextOwned)) {
1112
1113         code = pr_ReadEntry(at,0,loc,&nentry);
1114         if (code) return code;
1115         code = fixOwnerChain(at, loc, &nentry, oldid, newid);
1116         if (code) return code;
1117     }
1118     return PRSUCCESS;
1119 }
1120
1121 long ChangeEntry (at, aid, cid, name, oid, newid)
1122   struct ubik_trans *at;
1123   long aid;
1124   long cid;
1125   char *name;
1126   long oid;
1127   long newid;
1128 {
1129     register long code, nptr, i;
1130     long pos;
1131     struct prentry tentry, gentry;
1132     struct contentry centry;
1133     long loc;
1134     long oldowner;
1135     char holder[PR_MAXNAMELEN];
1136     char temp[PR_MAXNAMELEN];
1137     char oldname[PR_MAXNAMELEN];
1138 #if CROSS_CELL
1139     char *atsign;
1140 #endif
1141
1142     bzero(holder,PR_MAXNAMELEN);
1143     bzero(temp,PR_MAXNAMELEN);
1144     loc = FindByID(at,aid);
1145     if (!loc) return PRNOENT;
1146     code = pr_ReadEntry(at,0,loc,&tentry);
1147     if (code) return PRDBFAIL;
1148     if (tentry.owner != cid &&
1149         !IsAMemberOf(at,cid,SYSADMINID) &&
1150         !IsAMemberOf(at,cid,tentry.owner) &&
1151         !pr_noAuth) return PRPERM;
1152 #ifdef PR_REMEMBER_TIMES
1153     tentry.changeTime = time(0);
1154 #endif
1155
1156     /* we're actually trying to change the id */
1157     if (aid != newid && newid != 0) {
1158         if (!IsAMemberOf(at,cid,SYSADMINID) && !pr_noAuth) return PRPERM;
1159         pos = FindByID(at,newid);
1160         if (pos) return PRIDEXIST;  /* new id already in use! */
1161         if ((aid < 0 && newid > 0) || (aid > 0 && newid < 0)) return PRPERM;
1162         /* if new id is not in use, rehash things */
1163         code = RemoveFromIDHash(at,aid,&loc);
1164         if (code != PRSUCCESS) return code;
1165         tentry.id = newid;
1166         code = pr_WriteEntry(at,0,loc,&tentry);
1167         if (code) return code;
1168         code = AddToIDHash(at,tentry.id,loc);
1169         if (code) return code;
1170         /* get current data */
1171         code = pr_ReadEntry(at,0,loc,&tentry);
1172         if (code) return PRDBFAIL;
1173
1174         for (i=0;i<PRSIZE;i++) {
1175             if (tentry.entries[i] == PRBADID) continue;
1176             if (tentry.entries[i] == 0) break;
1177             if (pos = FindByID(at, tentry.entries[i])) {
1178                 code = pr_ReadEntry(at,0,pos,&gentry);
1179                 if (code) return PRDBFAIL;
1180                 code = AddToEntry(at,&gentry,pos,newid);
1181                 if (code) return PRDBFAIL;
1182                 code = RemoveFromEntry(at,aid,tentry.entries[i]);
1183                 if (code) return PRDBFAIL;
1184             } else {
1185                 fprintf(stderr, "ChangeEntry: %d: Couldn't locate group %d\n",
1186                     newid, tentry.entries[i]);
1187                 return PRDBFAIL;
1188             }
1189         }
1190         nptr = tentry.next;
1191         while (nptr) {
1192             /* look through cont entries */
1193             code = pr_ReadCoEntry(at,0,nptr,&centry);
1194             if (code != 0) return code;
1195             for (i=0;i<COSIZE;i++) {
1196                 if (centry.entries[i] == PRBADID) continue;
1197                 if (centry.entries[i] == 0) break;
1198                 if (pos = FindByID(at, centry.entries[i])) {
1199                     code = pr_ReadEntry(at,0,pos,&gentry);
1200                     if (code) return PRDBFAIL;
1201                     code = AddToEntry(at,&gentry,pos,newid);
1202                     if (code) return PRDBFAIL;
1203                     code = RemoveFromEntry(at,aid,centry.entries[i]);
1204                     if (code) return PRDBFAIL;
1205                 } else
1206                     return PRDBFAIL;
1207             }
1208             nptr = centry.next;
1209         }
1210     }
1211
1212 #ifdef CROSS_CELL
1213     atsign = index(tentry.name, '@'); /* check for foreign entry */
1214 #endif
1215
1216     /* Change the owner */
1217     if (tentry.owner != oid && oid) {
1218         /* only groups can have their owner's changed */
1219         if (!(tentry.flags & PRGRP)) return PRPERM;
1220 #ifdef CROSS_CELL
1221         /* don't allow modifications to foreign cell group owners */
1222         if (atsign) return PRPERM;
1223 #endif
1224         oldowner = tentry.owner;
1225         tentry.owner = oid;
1226         /* The entry must be written through first so Remove and Add routines
1227          * can operate on disk data */
1228         code = pr_WriteEntry(at,0,loc,(char *)&tentry);
1229         if (code) return PRDBFAIL;
1230         if (tentry.flags & PRGRP) {
1231             /* switch owner chains */
1232             if (oldowner)               /* if it has an owner */
1233                 code = RemoveFromOwnerChain(at,tentry.id,oldowner);
1234             else                        /* must be an orphan */
1235                 code = RemoveFromOrphan(at,tentry.id);
1236             if (code) return code;
1237             code = AddToOwnerChain(at,tentry.id,tentry.owner);
1238             if (code) return code;
1239         }
1240         /* fix up the name */
1241         if ((tentry.flags & PRGRP) && (strlen(name) == 0)) name = tentry.name;
1242         /* get current data */
1243         code = pr_ReadEntry(at,0,loc,&tentry);
1244         if (code) return PRDBFAIL;
1245     }
1246
1247     /* Change the name, if name is a ptr to tentry.name then this name change
1248      * is due to a chown, otherwise caller has specified a new name */
1249     if ((name == tentry.name) ||
1250         (*name && (strcmp (tentry.name, name) != 0))) {
1251         strncpy (oldname, tentry.name, PR_MAXNAMELEN);
1252         if (tentry.flags & PRGRP) {
1253 #ifdef CROSS_CELL
1254             if (atsign) return PRPERM;
1255 #endif
1256             code = CorrectGroupName (at, name, cid, tentry.owner, tentry.name);
1257             if (code) return code;
1258
1259             if (name == tentry.name) {  /* owner fixup */
1260                 if (strcmp (oldname, tentry.name) == 0) goto nameOK;
1261             } else {                    /* new name, caller must be correct */
1262                 if (strcmp (name, tentry.name) != 0) return PRBADNAM;
1263             }
1264         } else {
1265 #ifdef CROSS_CELL
1266             /* Allow a foreign name change only if the cellname part is
1267              * the same */
1268             char *newatsign;
1269
1270             newatsign = index (name, '@');
1271             if (newatsign != atsign){ /* if they are the same no problem*/
1272                 /* if the pointers are not equal the strings better be */
1273                 if ((atsign == 0) || (newatsign == 0) ||
1274                     strcmp (atsign,newatsign)) return PRPERM;
1275             }
1276 #endif
1277             if (!CorrectUserName(name)) return PRBADNAM;
1278         }
1279
1280         pos = FindByName(at,name);
1281         if (pos) return PREXIST;
1282         code = RemoveFromNameHash (at, oldname, &loc);
1283         if (code != PRSUCCESS) return code;
1284         strncpy (tentry.name, name, PR_MAXNAMELEN);
1285         code = pr_WriteEntry(at,0,loc,(char *)&tentry);
1286         if (code) return PRDBFAIL;
1287         code = AddToNameHash(at,tentry.name,loc);
1288         if (code != PRSUCCESS) return code;
1289 nameOK:;
1290     }
1291     return (fixOwnerChain(at, loc, &tentry, aid, newid));
1292 }
1293
1294 #ifdef CROSS_CELL
1295 long allocNextId(cellEntry)
1296 struct prentry *cellEntry;
1297 {
1298     /* Id's for foreign cell entries are constructed as follows:
1299      * The 16 low order bits are the group id of the cell and the
1300      * top 16 bits identify the particular users in that cell */
1301
1302     long id;
1303
1304     id = (ntohl(cellEntry -> nusers) +1);
1305     cellEntry -> nusers = htonl(id);
1306     /* use the field nusers to keep the last used id in that
1307      * foreign cell's group.
1308      *
1309      * Note: It would seem more appropriate to use ngroup for
1310      * that and nusers to enforce the quota, however pts does not
1311      * have an option to change foreign users quota yet. */
1312     id = (id << 16) | ((ntohl(cellEntry-> id)) & 0x0000ffff);
1313     return id;
1314 }
1315
1316 int inRange(cellEntry,aid)
1317 struct prentry *cellEntry;
1318 long aid;
1319 {
1320     unsigned long id,cellid,groupid;
1321
1322     /* The only thing that we want to make sure here is that the id
1323      * is in the legal range of this group. If it is a duplicate we
1324      * don't care since it will get in a different check. */
1325     cellid = aid & 0x0000ffff;
1326     groupid =  (ntohl(cellEntry-> id)) & 0x0000ffff;
1327     if (cellid != groupid) return 0;            /* not in range */
1328
1329     /* if we got here we're ok but we need to update the nusers field
1330      * in order to get the id correct the next time that we try to
1331      * allocate it automatically. */
1332     id = aid >> 16;
1333     if (id > ntohl(cellEntry -> nusers))
1334         cellEntry -> nusers = htonl(id);
1335     return 1;
1336 }
1337
1338 AddAuthGroup(tentry, alist, size)
1339     struct prentry *tentry;
1340     prlist *alist;
1341     long *size;
1342 {
1343     if (!(index(tentry->name, '@')))
1344         return (AddToPRList (alist, size, AUTHUSERID));
1345 #if ADD_TO_AUTHUSER_GROUP
1346     return PRSUCCESS;
1347 #else
1348     return (AddToPRList (alist, size, tentry->cellid));
1349 #endif
1350 }
1351 #endif  /* CROSS_CELL */
This page took 0.142189 seconds and 5 git commands to generate.