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