]> andersk Git - moira.git/blob - afssync/ptutils.c
Attempt to preserve hidden status on all groups (not just those created)
[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 || 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 ( 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 long ChangeEntry (at, aid, cid, name, oid, newid)
1049   struct ubik_trans *at;
1050   long aid;
1051   long cid;
1052   char *name;
1053   long oid;
1054   long newid;
1055 {
1056     register long code;
1057     long pos;
1058     struct prentry tentry;
1059     long loc;
1060     long oldowner;
1061     char holder[PR_MAXNAMELEN];
1062     char temp[PR_MAXNAMELEN];
1063     char oldname[PR_MAXNAMELEN];
1064 #if CROSS_CELL
1065     char *atsign;
1066 #endif
1067
1068     bzero(holder,PR_MAXNAMELEN);
1069     bzero(temp,PR_MAXNAMELEN);
1070     loc = FindByID(at,aid);
1071     if (!loc) return PRNOENT;
1072     code = pr_ReadEntry(at,0,loc,&tentry);
1073     if (code) return PRDBFAIL;
1074     if (tentry.owner != cid &&
1075         !IsAMemberOf(at,cid,SYSADMINID) &&
1076         !IsAMemberOf(at,cid,tentry.owner) &&
1077         !pr_noAuth) return PRPERM;
1078 #ifdef PR_REMEMBER_TIMES
1079     tentry.changeTime = time(0);
1080 #endif
1081
1082     /* we're actually trying to change the id */
1083     if (aid != newid && newid != 0) {
1084         if (!IsAMemberOf(at,cid,SYSADMINID) && !pr_noAuth) return PRPERM;
1085         pos = FindByID(at,newid);
1086         if (pos) return PRIDEXIST;  /* new id already in use! */
1087         if ((aid < 0 && newid > 0) || (aid > 0 && newid < 0)) return PRPERM;
1088         /* if new id is not in use, rehash things */
1089         code = RemoveFromIDHash(at,aid,&loc);
1090         if (code != PRSUCCESS) return code;
1091         tentry.id = newid;
1092         code = pr_WriteEntry(at,0,loc,&tentry);
1093         if (code) return code;
1094         code = AddToIDHash(at,tentry.id,loc);
1095         if (code) return code;
1096         /* get current data */
1097         code = pr_ReadEntry(at,0,loc,&tentry);
1098         if (code) return PRDBFAIL;
1099     }
1100
1101 #ifdef CROSS_CELL
1102     atsign = index(tentry.name, '@'); /* check for foreign entry */
1103 #endif
1104
1105     /* Change the owner */
1106     if (tentry.owner != oid && oid) {
1107         /* only groups can have their owner's changed */
1108         if (!(tentry.flags & PRGRP)) return PRPERM;
1109 #ifdef CROSS_CELL
1110         /* don't allow modifications to foreign cell group owners */
1111         if (atsign) return PRPERM;
1112 #endif
1113         oldowner = tentry.owner;
1114         tentry.owner = oid;
1115         /* The entry must be written through first so Remove and Add routines
1116          * can operate on disk data */
1117         code = pr_WriteEntry(at,0,loc,(char *)&tentry);
1118         if (code) return PRDBFAIL;
1119         if (tentry.flags & PRGRP) {
1120             /* switch owner chains */
1121             if (oldowner)               /* if it has an owner */
1122                 code = RemoveFromOwnerChain(at,tentry.id,oldowner);
1123             else                        /* must be an orphan */
1124                 code = RemoveFromOrphan(at,tentry.id);
1125             if (code) return code;
1126             code = AddToOwnerChain(at,tentry.id,tentry.owner);
1127             if (code) return code;
1128         }
1129         /* fix up the name */
1130         if ((tentry.flags & PRGRP) && (strlen(name) == 0)) name = tentry.name;
1131         /* get current data */
1132         code = pr_ReadEntry(at,0,loc,&tentry);
1133         if (code) return PRDBFAIL;
1134     }
1135
1136     /* Change the name, if name is a ptr to tentry.name then this name change
1137      * is due to a chown, otherwise caller has specified a new name */
1138     if ((name == tentry.name) ||
1139         (*name && (strcmp (tentry.name, name) != 0))) {
1140         strncpy (oldname, tentry.name, PR_MAXNAMELEN);
1141         if (tentry.flags & PRGRP) {
1142 #ifdef CROSS_CELL
1143             if (atsign) return PRPERM;
1144 #endif
1145             code = CorrectGroupName (at, name, cid, tentry.owner, tentry.name);
1146             if (code) return code;
1147
1148             if (name == tentry.name) {  /* owner fixup */
1149                 if (strcmp (oldname, tentry.name) == 0) goto nameOK;
1150             } else {                    /* new name, caller must be correct */
1151                 if (strcmp (name, tentry.name) != 0) return PRBADNAM;
1152             }
1153         } else {
1154 #ifdef CROSS_CELL
1155             /* Allow a foreign name change only if the cellname part is
1156              * the same */
1157             char *newatsign;
1158
1159             newatsign = index (name, '@');
1160             if (newatsign != atsign){ /* if they are the same no problem*/
1161                 /* if the pointers are not equal the strings better be */
1162                 if ((atsign == 0) || (newatsign == 0) ||
1163                     strcmp (atsign,newatsign)) return PRPERM;
1164             }
1165 #endif
1166             if (!CorrectUserName(name)) return PRBADNAM;
1167         }
1168
1169         pos = FindByName(at,name);
1170         if (pos) return PREXIST;
1171         code = RemoveFromNameHash (at, oldname, &loc);
1172         if (code != PRSUCCESS) return code;
1173         strncpy (tentry.name, name, PR_MAXNAMELEN);
1174         code = pr_WriteEntry(at,0,loc,(char *)&tentry);
1175         if (code) return PRDBFAIL;
1176         code = AddToNameHash(at,tentry.name,loc);
1177         if (code != PRSUCCESS) return code;
1178 nameOK:;
1179     }
1180     return PRSUCCESS;
1181 }
1182
1183 #ifdef CROSS_CELL
1184 long allocNextId(cellEntry)
1185 struct prentry *cellEntry;
1186 {
1187     /* Id's for foreign cell entries are constructed as follows:
1188      * The 16 low order bits are the group id of the cell and the
1189      * top 16 bits identify the particular users in that cell */
1190
1191     long id;
1192
1193     id = (ntohl(cellEntry -> nusers) +1);
1194     cellEntry -> nusers = htonl(id);
1195     /* use the field nusers to keep the last used id in that
1196      * foreign cell's group.
1197      *
1198      * Note: It would seem more appropriate to use ngroup for
1199      * that and nusers to enforce the quota, however pts does not
1200      * have an option to change foreign users quota yet. */
1201     id = (id << 16) | ((ntohl(cellEntry-> id)) & 0x0000ffff);
1202     return id;
1203 }
1204
1205 int inRange(cellEntry,aid)
1206 struct prentry *cellEntry;
1207 long aid;
1208 {
1209     unsigned long id,cellid,groupid;
1210
1211     /* The only thing that we want to make sure here is that the id
1212      * is in the legal range of this group. If it is a duplicate we
1213      * don't care since it will get in a different check. */
1214     cellid = aid & 0x0000ffff;
1215     groupid =  (ntohl(cellEntry-> id)) & 0x0000ffff;
1216     if (cellid != groupid) return 0;            /* not in range */
1217
1218     /* if we got here we're ok but we need to update the nusers field
1219      * in order to get the id correct the next time that we try to
1220      * allocate it automatically. */
1221     id = aid >> 16;
1222     if (id > ntohl(cellEntry -> nusers))
1223         cellEntry -> nusers = htonl(id);
1224     return 1;
1225 }
1226
1227 AddAuthGroup(tentry, alist, size)
1228     struct prentry *tentry;
1229     prlist *alist;
1230     long *size;
1231 {
1232     if (!(index(tentry->name, '@')))
1233         return (AddToPRList (alist, size, AUTHUSERID));
1234 #if ADD_TO_AUTHUSER_GROUP
1235     return PRSUCCESS;
1236 #else
1237     return (AddToPRList (alist, size, tentry->cellid));
1238 #endif
1239 }
1240 #endif  /* CROSS_CELL */
This page took 1.656321 seconds and 5 git commands to generate.