source: trunk/third/moira/afssync/ptutils.c @ 23095

Revision 23095, 37.1 KB checked in by ghudson, 16 years ago (diff)
Import the moira package from SIPB Debathena.
Line 
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
34extern struct ubik_dbase *dbase;
35extern struct afsconf_dir *prdir;
36extern int pr_noAuth;
37extern int IDCmp();
38
39extern afs_int32 AddToEntry();
40static 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
50static 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
66static 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
137int 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
179afs_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
417afs_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
496afs_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
610afs_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
713afs_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
736afs_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
790afs_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
868afs_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
896afs_int32 GetMax(at,uid,gid)
897struct ubik_trans *at;
898afs_int32 *uid;
899afs_int32 *gid;
900{
901    *uid = ntohl(cheader.maxID);
902    *gid = ntohl(cheader.maxGroup);
903    return PRSUCCESS;
904}
905
906afs_int32 SetMax(at,id,flag)
907struct ubik_trans *at;
908afs_int32 id;
909afs_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
925afs_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
939int pr_noAuth;
940afs_int32 initd=0;
941
942afs_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
1073afs_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;
1235nameOK:;
1236    }
1237    return PRSUCCESS;
1238}
1239
1240
1241afs_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
1266int inRange(cellEntry,aid)
1267struct prentry *cellEntry;
1268afs_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
1297AddAuthGroup(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}
Note: See TracBrowser for help on using the repository browser.