From 8ab7a909371f47ddb4f2adc8104b64dfc4c610bd Mon Sep 17 00:00:00 2001 From: Kevin Coffman Date: Wed, 15 Jan 2003 17:36:07 +0000 Subject: [PATCH] pts-supergroups-20030114 thanks to nneul@umr.edu add configure switch and support code for groups in groups --- acinclude.m4 | 6 + src/ptserver/Makefile.in | 12 +- src/ptserver/db_verify.c | 319 ++++++++++++++- src/ptserver/display.c | 12 + src/ptserver/map.c | 860 +++++++++++++++++++++++++++++++++++++++ src/ptserver/map.h | 50 +++ src/ptserver/ptclient.c | 102 +++++ src/ptserver/ptclient.h | 3 + src/ptserver/ptint.xg | 40 ++ src/ptserver/ptopcodes.h | 4 +- src/ptserver/ptprocs.c | 179 ++++++++ src/ptserver/pts.c | 185 +++++++++ src/ptserver/ptserver.c | 153 +++++++ src/ptserver/ptserver.h | 32 ++ src/ptserver/ptuser.c | 3 + src/ptserver/ptutils.c | 661 ++++++++++++++++++++++++++++++ src/ptserver/utils.c | 71 ++++ 17 files changed, 2684 insertions(+), 8 deletions(-) create mode 100644 src/ptserver/map.c create mode 100644 src/ptserver/map.h diff --git a/acinclude.m4 b/acinclude.m4 index 5562757c6..8f546082d 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -27,6 +27,8 @@ AC_ARG_ENABLE( largefile-fileserver, [ --enable-largefile-filesever enable large file support in fileserver],, enable_largefile_fileserver="no") AC_ARG_ENABLE( namei-fileserver, [ --enable-namei-fileserver force compilation of namei fileserver in preference to inode fileserver],, enable_namei_fileserver="no") +AC_ARG_ENABLE( supergroups, +[ --enable-supergroups enable support for nested pts groups],, enable_supergroups="no") AC_ARG_ENABLE( fast-restart, [ --enable-fast-restart enable fast startup of file server without salvaging],, enable_fast_restart="no") AC_ARG_ENABLE( bitmap-later, @@ -606,6 +608,10 @@ if test "$enable_insecure" = "yes"; then fi # Fast restart +if test "$enable_supergroups" = "yes"; then + AC_DEFINE(SUPERGROUPS, 1, [define if you want to have support for nested pts groups]) +fi + if test "$enable_fast_restart" = "yes"; then AC_DEFINE(FAST_RESTART, 1, [define if you want to have fast restart]) fi diff --git a/src/ptserver/Makefile.in b/src/ptserver/Makefile.in index 4f5233811..18434c4d0 100644 --- a/src/ptserver/Makefile.in +++ b/src/ptserver/Makefile.in @@ -14,7 +14,7 @@ INCLS=${TOP_INCDIR}/ubik.h \ ${TOP_INCDIR}/rx/xdr.h \ ${TOP_INCDIR}/afs/keys.h \ ${TOP_INCDIR}/afs/cellconfig.h \ - ptserver.h ptclient.h ptint.h ptopcodes.h pterror.h + ptserver.h ptclient.h ptint.h ptopcodes.h pterror.h map.h LINCLS=${TOP_INCDIR}/ubik.h \ ${TOP_INCDIR}/lock.h \ @@ -56,8 +56,8 @@ depinstall: \ # # Build targets # -ptserver: ptserver.o ptutils.o ptprocs.o ptint.ss.o ptint.xdr.o utils.o $(LIBS) ${TOP_LIBDIR}/libaudit.a - $(CC) ${CFLAGS} -o ptserver ptserver.o ptutils.o ptprocs.o ptint.ss.o ptint.xdr.o utils.o $(LIBS) ${XLIBS} ${TOP_LIBDIR}/libaudit.a +ptserver: ptserver.o ptutils.o ptprocs.o ptint.ss.o ptint.xdr.o utils.o $(LIBS) ${TOP_LIBDIR}/libaudit.a map.o + $(CC) ${CFLAGS} -o ptserver ptserver.o ptutils.o ptprocs.o ptint.ss.o ptint.xdr.o utils.o map.o $(LIBS) ${XLIBS} ${TOP_LIBDIR}/libaudit.a ptserver.o: ptserver.c ${INCLS} AFS_component_version_number.c @@ -67,6 +67,8 @@ ptprocs.o: ptprocs.c ${INCLS} utils.o: utils.c ${INCLS} +map.o: map.c ${INCLS} + ptint.ss.o: ptint.ss.c ptint.xdr.c ptint.xg ptint.cs.o: ptint.cs.c ptint.xdr.c ptint.xg ptint.xdr.o: ptint.xdr.c ptint.h ptint.xg @@ -144,8 +146,8 @@ testpt: testpt.o libprot.a ${TOP_LIBDIR}/libcmd.a $(LIBS) testpt.o: testpt.c ${INCLS} ${TOP_INCDIR}/afs/cmd.h AFS_component_version_number.c -pt_util: pt_util.o ptutils.o ubik.o utils.o libprot.a $(LIBS) - $(CC) ${CFLAGS} -o pt_util pt_util.o ptutils.o ubik.o utils.o libprot.a $(LIBS) ${XLIBS} +pt_util: pt_util.o ptutils.o ubik.o utils.o map.o libprot.a $(LIBS) + $(CC) ${CFLAGS} -o pt_util pt_util.o ptutils.o ubik.o utils.o map.o libprot.a $(LIBS) ${XLIBS} ubik.o: ubik.c ${INCLS} diff --git a/src/ptserver/db_verify.c b/src/ptserver/db_verify.c index 908147552..a4259c1c5 100644 --- a/src/ptserver/db_verify.c +++ b/src/ptserver/db_verify.c @@ -13,6 +13,24 @@ RCSID("$Header$"); +/* + * (3) Define a structure, idused, instead of an + * array of long integers, idmap, to count group + * memberships. These structures are on a linked + * list, with each structure containing IDCOUNT + * slots for id's. + * (4) Add new functions to processs the structure + * described above: + * zeromap(), idcount(), inccount(). + * (5) Add code, primarily in WalkNextChain(): + * 1. Test id's, allowing groups within groups. + * 2. Count the membership list for supergroups, + * and follow the continuation chain for + * supergroups. + * (6) Add fprintf statements for various error + * conditions. + */ + #include #include #ifdef AFS_NT40_ENV @@ -49,7 +67,6 @@ char *pr_dbaseName; char *whoami = "db_verify"; #define UBIK_HEADERSIZE 64 - afs_int32 printheader(h) struct prheader *h; { @@ -146,8 +163,17 @@ struct misc_data { afs_int32 maxId; /* user */ afs_int32 minId; /* group */ afs_int32 maxForId; /* foreign user id */ +#if defined(SUPERGROUPS) +#define IDCOUNT 512 + struct idused { + int idstart; + afs_int32 idcount[IDCOUNT]; + struct idused *idnext; + } *idmap; +#else int idRange; /* number of ids in map */ afs_int32 *idmap; /* map of all id's: midId is origin */ +#endif /* SUPERGROUPS */ int nusers; /* counts of each type */ int ngroups; int nforeigns; @@ -164,6 +190,12 @@ struct misc_data { FILE *recreate; /* stream for recreate instructions */ }; +#if defined(SUPERGROUPS) +void zeromap(struct idused *idmap); +void inccount(struct idused **idmapp, int id); +int idcount(struct idused **idmapp, int id); +#endif + int readUbikHeader(misc) struct misc_data *misc; { @@ -360,12 +392,21 @@ afs_int32 WalkNextChain (map, misc, ea, e) int i; int noErrors = 1; int length; /* length of chain */ +#if defined(SUPERGROUPS) + int sgcount; /* number of sgentrys */ + afs_int32 sghead; +#define g (((struct prentryg *)e)) +#endif if (e) { head = ntohl(e->next); eid = ntohl(e->id); bit = MAP_CONT; count = 0; /* set to >9999 if list ends early */ +#if defined(SUPERGROUPS) + sgcount = 0; + sghead = ntohl(g->next); +#endif for (i=0; ientries[i]); if (id == PRBADID) continue; @@ -375,26 +416,124 @@ afs_int32 WalkNextChain (map, misc, ea, e) /* in case the ids are large, convert to pure sign. */ if (id > 0) id_s = 1; else id_s = -1; if (eid > 0) eid_s = 1; else eid_s = -1; +#if defined(SUPERGROUPS) + if (id_s > 0 && eid_s > 0) { + fprintf (stderr, + "User can't be member of user in membership list\n"); + if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD; + noErrors = 0; + } +#else if (id_s * eid_s > 0) { /* sign should be different */ fprintf (stderr, "Bad user/group dicotomy in membership list\n"); if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD; noErrors = 0; } +#endif /* SUPERGROUPS */ /* count each user as a group, and each group a user is in */ +#if defined(SUPERGROUPS) + if (!(id < 0 && eid < 0) && + (id != ANONYMOUSID)) + inccount(&misc->idmap,id); +#else if ((id >= misc->minId) && (id <= misc->maxId) && (id != ANONYMOUSID)) misc->idmap[id - misc->minId]++; +#endif /* SUPERGROUPS */ } else if (head) count=9999; else break; } +#if defined(SUPERGROUPS) + sghead = g->nextsg; + if ((e->flags & PRGRP)) { + for (i = 0; isupergroup[i]); + if (id == PRBADID) continue; + else if (id) { + if (id > 0) { + fprintf (stderr, + "User can't be member of supergroup list\n"); + if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD; + noErrors = 0; + } + sgcount++; + inccount(&misc->idmap, id); + } + } + } +#endif /* SUPERGROUPS */ } else { head = ntohl(cheader.freePtr); +#if defined(SUPERGROUPS) + sghead = 0; +#endif bit = MAP_FREE; } +#if defined(SUPERGROUPS) + length = 0; + for (na=sghead; na; na=ntohl(c.next)) { + code = ConvertDiskAddress (na, &ni); + if (code) { + fprintf (stderr, "Bad continuation ptr %d", na); + if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD; + if (na != sghead) { + fprintf (stderr, "last block: \n"); + if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD; + } + return 0; + } + code = pr_Read (na, (char *)&c, sizeof(c)); + if (code) return code; + length++; + + if (map[ni]) { + fprintf (stderr, "Continuation entry reused\n"); + if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD; + if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD; + noErrors = 0; + break; + } + map[ni] |= bit; + if ((ntohl(c.id) != eid)) { + fprintf (stderr, "Continuation id mismatch\n"); + if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD; + if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD; + noErrors = 0; + continue; + } + + /* update membership count */ + for (i=0; i 0) id_s = 1; else id_s = -1; + if (eid > 0) eid_s = 1; else eid_s = -1; + if (id_s > 0) { + fprintf (stderr, + "User can't be member of supergroup list\n"); + if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD; + if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD; + noErrors = 0; + } + /* count each user as a group, and each group a user is in */ + if ( + (id != ANONYMOUSID)) + inccount(&misc->idmap, id); + } + else if (c.next) count = 9999; + else break; + } + } + if (length > misc->maxContLength) misc->maxContLength = length; +#endif /* SUPERGROUPS */ length = 0; for (na=head; na; na=ntohl(c.next)) { code = ConvertDiskAddress (na, &ni); @@ -440,6 +579,16 @@ afs_int32 WalkNextChain (map, misc, ea, e) /* in case the ids are large, convert to pure sign. */ if (id > 0) id_s = 1; else id_s = -1; if (eid > 0) eid_s = 1; else eid_s = -1; +#if defined(SUPERGROUPS) + if (id_s > 0 && eid_s > 0) { + fprintf (stderr, + "User can't be member of user in membership list\n" +); + if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD; + if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD; + noErrors = 0; + } +#else if (id_s * eid_s > 0) { /* sign should be different */ fprintf (stderr, "Bad user/group dicotomy in membership list\n"); @@ -447,20 +596,39 @@ afs_int32 WalkNextChain (map, misc, ea, e) if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD; noErrors = 0; } +#endif /* SUPERGROUPS */ /* count each user as a group, and each group a user is in */ +#if defined(SUPERGROUPS) + if (!(id < 0 && eid < 0) && + (id != ANONYMOUSID)) + inccount(&misc->idmap, id); +#else if ((id >= misc->minId) && (id <= misc->maxId) && (id != ANONYMOUSID)) misc->idmap[id - misc->minId]++; +#endif /* SUPERGROUPS */ } else if (c.next) count = 9999; else break; } } if (e && noErrors && (count != ntohl(e->count))) { +#if defined(SUPERGROUPS) + if (count >= 9999) fprintf (stderr, "Membership list ends early\n"); +#else if (count > 9999) fprintf (stderr, "Membership list ends early\n"); +#endif /* SUPERGROUPS */ fprintf (stderr, "Count was %d should be %d\n", count, ntohl(e->count)); if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD; +#if defined(SUPERGROUPS) + noErrors = 0; + } + if (e && (e->flags & PRGRP) && (sgcount != ntohl(g->countsg))) { + fprintf (stderr, "SGCount was %d should be %d\n", + sgcount, ntohl(g->countsg)); + if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD; +#endif } if (e) { @@ -469,6 +637,9 @@ afs_int32 WalkNextChain (map, misc, ea, e) else misc->freeLength = length; return 0; +#if defined(SUPERGROUPS) +#undef g +#endif } afs_int32 WalkOwnedChain (map, misc, ea, e) @@ -598,7 +769,11 @@ afs_int32 WalkChains (map, misc) break; case PRUSER: if (id <= 0) { +#if defined(SUPERGROUPS) + fprintf (stderr, "User id not positive\n"); +#else fprintf (stderr, "User id negative\n"); +#endif goto abort; } @@ -673,10 +848,16 @@ afs_int32 GC (map, misc) if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD; } id = ntohl(e.id); +#if defined(SUPERGROUPS) + if ((id != ANONYMOUSID) && + ((refCount = idcount(&misc->idmap, id)) != + ntohl(e.count))) { +#else if ((id >= misc->minId) && (id <= misc->maxId) && (id != ANONYMOUSID) && ((refCount = misc->idmap[id - misc->minId]) != ntohl(e.count))) { +#endif /* SUPERGROUPS */ afs_int32 na; fprintf (stderr, "Entry membership count is inconsistent: %d entries refer to this one\n", refCount); if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD; @@ -723,13 +904,21 @@ afs_int32 DumpRecreate (map, misc) char *name; int builtinUsers = 0; int createLow = 0; /* users uncreate from here */ +#if defined(SUPERGROUPS) + struct idused *idmap; /* map of all id's */ +#else afs_int32 *idmap; /* map of all id's */ +#endif int found; FILE *rc; rc = misc->recreate; idmap = misc->idmap; +#if defined(SUPERGROUPS) + zeromap(idmap); +#else memset(idmap, 0, misc->idRange*sizeof(misc->idmap[0])); +#endif do { found = 0; for (ei=createLow; einEntries; ei++) { @@ -762,7 +951,11 @@ afs_int32 DumpRecreate (map, misc) /* check for duplicate id. This may still lead to duplicate * names. */ +#if defined(SUPERGROUPS) + if (idcount(&idmap, id)) { +#else if (idmap[id-misc->minId]) { +#endif fprintf (stderr, "Skipping entry with duplicate id %di\n", id); goto user_done; @@ -786,7 +979,11 @@ afs_int32 DumpRecreate (map, misc) fprintf (stderr, "Warning: orphan group %s will become self owning.\n", name); owner = id; } +#if defined(SUPERGROUPS) + else if (!idcount(&idmap, owner)) goto user_skip; +#else else if (idmap[owner-misc->minId] == 0) goto user_skip; +#endif if (rc) fprintf (rc, "cr %s %d %d\n", name, id, owner); @@ -806,7 +1003,11 @@ afs_int32 DumpRecreate (map, misc) } user_done: map[ei] |= MAP_RECREATE; +#if defined(SUPERGROUPS) + if (id != ANONYMOUSID) inccount(&idmap, id); +#else if (id != ANONYMOUSID) idmap[id-misc->minId]++; +#endif found++; } /* bump low water mark if possible */ @@ -830,7 +1031,11 @@ user_skip:; name = QuoteName(e.name); fprintf (stderr, "Warning: group %s in self owning cycle\n", name); if (rc) fprintf (rc, "cr %s %d %d\n", name, id, id); +#if defined(SUPERGROUPS) + inccount(&idmap, id); +#else idmap[id-misc->minId]++; +#endif } for (ei=0; einEntries; ei++) if (((map[ei] & MAP_HASHES) == MAP_HASHES) && @@ -840,7 +1045,11 @@ user_skip:; if (code) return code; owner = ntohl(e.owner); +#if defined(SUPERGROUPS) + if (!idcount(&idmap, owner)) { +#else if (idmap[owner-misc->minId] == 0) { +#endif fprintf (stderr, "Skipping chown of '%s' to non-existant owner %di\n", e.name, owner); @@ -864,17 +1073,56 @@ user_skip:; if ((id < 0) && (flags & PRGRP)) { int count = 0; afs_int32 na; +#if defined(SUPERGROUPS) + afs_int32 ng; +#endif int i; for (i=0; i 0) { +#endif fprintf (rc, "au %d %d\n", uid, id); count++; +#if !defined(SUPERGROUPS) } else fprintf (stderr, "Skipping %di in group %di\n", uid, id); +#endif + } +#if defined(SUPERGROUPS) +#define g (*((struct prentryg *)&e)) + ng = ntohl(g.nextsg); + for (i=0; i 0) { +#endif fprintf (rc, "au %d %d\n", uid, id); count++; +#if !defined(SUPERGROUPS) } else fprintf (stderr, "Skipping %di in group %di\n", uid, id); +#endif } } else { fprintf (stderr, @@ -955,6 +1207,9 @@ afs_int32 CheckPrDatabase (misc) } /* hash walk calculates min and max id */ +#if defined(SUPERGROUPS) + misc->idmap = 0; +#else n = ((misc->maxId > misc->maxForId) ? misc->maxId : misc->maxForId); misc->idRange = n - misc->minId + 1; misc->idmap = (afs_int32 *)malloc (misc->idRange * sizeof(afs_int32)); @@ -965,6 +1220,7 @@ afs_int32 CheckPrDatabase (misc) goto abort; } memset(misc->idmap, 0, misc->idRange*sizeof(misc->idmap[0])); +#endif /* SUPERGROUPS */ if (misc->verbose) { printf ("\nChecking entry chains\n"); @@ -1114,3 +1370,64 @@ main (argc, argv) return cmd_Dispatch(argc, argv); } + + +#if defined(SUPERGROUPS) + +/* new routines to deal with very large ID numbers */ + +void zeromap(idmap) + struct idused *idmap; +{ + while (idmap) { + bzero((char*) idmap->idcount, sizeof idmap->idcount); + idmap = idmap->idnext; + } +} + +void inccount(struct idused **idmapp, int id) +{ + struct idused *idmap; + + if (IDCOUNT & (IDCOUNT-1)) { + fprintf(stderr,"IDCOUNT must be power of 2!\n"); + exit(1); + } + while (idmap = *idmapp) { + if (idmap->idstart == (id & ~(IDCOUNT-1))) + break; + idmapp = &idmap->idnext; + } + if (!idmap) { + idmap = (struct idused *) malloc(sizeof *idmap); + if (!idmap) { + perror("idmap"); + exit(1); + } + bzero((char*) idmap, sizeof idmap); + idmap->idstart = id & ~(IDCOUNT-1); + idmap->idnext = *idmapp; + *idmapp = idmap; + } + ++idmap->idcount[id & (IDCOUNT-1)]; +} + +int idcount(idmapp, id) + struct idused **idmapp; +{ + struct idused *idmap; + + if (IDCOUNT & (IDCOUNT-1)) { + fprintf(stderr,"IDCOUNT must be power of 2!\n"); + exit(1); + } + while (idmap = *idmapp) { + if (idmap->idstart == (id & ~(IDCOUNT-1))) { + return idmap->idcount[id & (IDCOUNT-1)]; + } + idmapp = &idmap->idnext; + } + return 0; +} + +#endif /* SUPERGROUPS */ diff --git a/src/ptserver/display.c b/src/ptserver/display.c index 8b66a6934..38f483392 100644 --- a/src/ptserver/display.c +++ b/src/ptserver/display.c @@ -120,13 +120,25 @@ int pr_PrintEntry (f, hostOrder, ea, e, indent) host(e->nextID), host(e->nextName), host(e->owner), host(e->creator)); fprintf (f, "%*s", indent, ""); +#if defined(SUPERGROUPS) + fprintf (f, "quota groups %d, foreign users %d. Mem: %d, cntsg: %d\n", + host(e->ngroups), host(e->nusers), + host(e->count), host(e->instance)); +#else fprintf (f, "quota groups %d, foreign users %d. Mem: %d, inst: %d\n", host(e->ngroups), host(e->nusers), host(e->count), host(e->instance)); +#endif fprintf (f, "%*s", indent, ""); +#if defined(SUPERGROUPS) + fprintf (f, "Owned chain %d, next owned %d, nextsg %d, sg (%d %d).\n", + host(e->owned), host(e->nextOwned), + host(e->parent), host(e->sibling), host(e->child)); +#else fprintf (f, "Owned chain %d, next owned %d, inst ptrs(%d %d %d).\n", host(e->owned), host(e->nextOwned), host(e->parent), host(e->sibling), host(e->child)); +#endif fprintf (f, "%*s", indent, ""); if (strlen (e->name) >= PR_MAXNAMELEN) fprintf (f, "NAME TOO LONG: "); diff --git a/src/ptserver/map.c b/src/ptserver/map.c new file mode 100644 index 000000000..a611eebcb --- /dev/null +++ b/src/ptserver/map.c @@ -0,0 +1,860 @@ +/* + * bit map routines (in-core). + */ +/* + * Copyright (c) 1995, 1996 Marcus D. Watts All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Marcus D. Watts. + * 4. The name of the developer may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * MARCUS D. WATTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +RCSID("$Header$"); + +#ifdef SUPERGROUPS +#include +#include "map.h" +char *malloc(); + +#undef PRINT_MAP_ERROR +/* #define MAP_DEBUG /**/ +/* #define NEED_READ_WRITE /**/ + +#define LSHIFT 5 +#define MSHIFT 8 /* XXX make this 8 in the production version... */ +#define MDATA (1<>LSHIFT) & ((1<>(LSHIFT+MSHIFT))) +#define TONUMBER(p,x,b) ((b) + ((x)< p=%d x=%d b=%d -> %ld, %ld, %ld = %ld\n", +node, +page, +x, +bit, +TONUMBER(page,0,0), +TONUMBER(0,x,0), +TONUMBER(0,0,bit), +TONUMBER(page,x,bit)); +} +#endif + bit = 1L<m_next) + if (map->m_page == page) + return NEGMAP(parm) ^ (!!(map->m_data[x] & bit)); + result = !POSMAP(parm); +#ifdef MAP_DEBUG +if (Aflag) +printf (" -> %s\n", result ? "yes" : "no"); +#endif + return result; +} + +void +free_map(parm) + struct map *parm; +{ + struct bitmap *map, *next; +#ifdef MAP_DEBUG +if (Aflag) +{ +printf ("Freeing map"); +print_map(parm); +printf ("\n"); +} +#endif + map = MAP(parm); + while (map) { + next = map->m_next; + free(map); + map = next; + } +} + +struct map *add_map(parm, node) + struct map *parm; + long node; +{ + struct bitmap *map; + long bit; + int x, page; + +#ifdef MAP_DEBUG +if (Aflag) +{ +printf ("add_map: adding %d to [", node); +print_map(parm); +printf (" ] "); +} +#endif + bit = NUMBERTOBIT(node); + x = NUMBERTOINDEX(node); + page = NUMBERTOPAGE(node); + + bit = 1L<m_next) + if (map->m_page == page) + break; + if (!map) { + map = (struct bitmap *) malloc(sizeof *map); + if (!map) { +#ifdef PRINT_MAP_ERROR +printf ("No memory!\n"); +#endif + free_map((struct map *) map); + return 0; + } + map->m_page = page; + bzero((char*) map->m_data, sizeof map->m_data); + if (NEGMAP(parm)) + { + int i; + for (i = 0; i < MDATA; ++i) + map->m_data[i] = ~0; + } + map->m_next = MAP(parm); + if (POSMAP(parm)) + parm = (struct map *) map; + else + parm = NOT_MAP(map); + } + if (POSMAP(parm)) + map->m_data[x] |= bit; + else + map->m_data[x] &= ~bit; +#ifdef MAP_DEBUG +if (Aflag) +{ +printf (" ->"); +print_map(parm); +printf ("\n"); +} +#endif + return (struct map *) parm; +} + +struct bitmap * +simplify_bitmap(map) + struct bitmap *map; +{ + struct bitmap **mpp, *mp2; + int i; + for (mpp = ↦ mp2 = *mpp; ) + { + for (i = 0; i < MDATA; ++i) + if (map->m_data[i]) + break; + if (i == MDATA) { +#ifdef PRINT_MAP_ERROR +printf ("simplify_bitmap: failed to eliminate zero page %d\n", mp2->m_page); +#endif + *mpp = mp2->m_next; + free((char*)mp2); + } + else mpp = &mp2->m_next; + } + return map; +} + +struct bitmap *or_bitmap(left, right) + struct bitmap *left, *right; +{ + struct bitmap **rightmp, *lmap, *rmap; + int i; + for (lmap = left; lmap; lmap = lmap->m_next) + { + for (rightmp = &right; rmap = *rightmp; rightmp = &rmap->m_next) + if (rmap->m_page == lmap->m_page) + { + for (i = 0; i < MDATA; ++i) + lmap->m_data[i] |= rmap->m_data[i]; + *rightmp = rmap->m_next; + free((char*)rmap); + break; + } + } + for (rightmp = &left; *rightmp; rightmp = &(*rightmp)->m_next) + ; + *rightmp = right; + return left; +} + +struct bitmap *and_bitmap(left, right) + struct bitmap *left, *right; +{ + struct bitmap **rightmp, *lmap, *rmap, **leftmp; + int i; + long sig; + for (leftmp = &left; lmap = *leftmp; ) + { + sig = 0; + for (rightmp = &right; rmap = *rightmp; rightmp = &rmap->m_next) + if (rmap->m_page == lmap->m_page) + { + for (i = 0; i < MDATA; ++i) + sig |= (lmap->m_data[i] &= rmap->m_data[i]); + *rightmp = rmap->m_next; + free((char*)rmap); + break; + } + if (rmap && sig) + { + leftmp = &lmap->m_next; + } else { + *leftmp = lmap->m_next; + free((char*)lmap); + } + } + free_map((struct map *) right); + return simplify_bitmap(left); +} + +/* bit set in left, but not in right */ +struct bitmap *bic_bitmap(left, right) + struct bitmap *left, *right; +{ + struct bitmap **rightmp, *lmap, *rmap, **leftmp; + int i; + long sig; +#ifdef MAP_DEBUG +if (Mflag) +{ +printf ("bic_bitmap: left=%#lx right=%#lx\n", left, right); +} +#endif + for (leftmp = &left; lmap = *leftmp; ) + { + sig = 0; + for (rightmp = &right; rmap = *rightmp; rightmp = &rmap->m_next) + if (rmap->m_page == lmap->m_page) + { + for (i = 0; i < MDATA; ++i) + sig |= (lmap->m_data[i] &= ~rmap->m_data[i]); + *rightmp = rmap->m_next; + free((char*)rmap); + break; + } + if (!rmap || sig) + { + leftmp = &lmap->m_next; + } else { + *leftmp = lmap->m_next; + free((char*)lmap); + } + } + free_map((struct map *) right); + left = simplify_bitmap(left); +#ifdef MAP_DEBUG +if (Mflag) +{ +printf ("bic_bitmap: result=%#lx\n", left); +} +#endif + return left; +} + +struct map *and_map(mp1, mp2) + struct map *mp1, *mp2; +{ +#ifdef MAP_DEBUG +if (Mflag) +{ +printf ("Anding maps"); +print_map(mp1); +printf (" and"); +print_map(mp2); +} +#endif + if (POSMAP(mp1)) + if (POSMAP(mp2)) + mp1 = (struct map *) and_bitmap(mp1, mp2); + else + mp1 = (struct map *) bic_bitmap(mp1, MAP(mp2)); + else + if (POSMAP(mp2)) + mp1 = (struct map *) bic_bitmap(mp2, MAP(mp1)); + else + mp1 = NOT_MAP(or_bitmap(MAP(mp1), MAP(mp2))); +#ifdef MAP_DEBUG +if (Mflag) +{ +printf (" ->"); +print_map(mp1); +printf ("\n"); +} +#endif + return mp1; +} + +struct map *or_map(mp1, mp2) + struct map *mp1, *mp2; +{ +#ifdef MAP_DEBUG +if (Mflag) +{ +printf ("Oring maps"); +print_map(mp1); +printf (" and"); +print_map(mp2); +} +#endif + if (POSMAP(mp1)) + if (POSMAP(mp2)) + mp1 = (struct map *) or_bitmap(mp1, mp2); + else + mp1 = NOT_MAP(bic_bitmap(MAP(mp2), mp1)); + else + if (POSMAP(mp2)) + mp1 = NOT_MAP(bic_bitmap(MAP(mp1), mp2)); + else + mp1 = NOT_MAP(and_bitmap(MAP(mp1), MAP(mp2))); +#ifdef MAP_DEBUG +if (Mflag) +{ +printf (" ->"); +print_map(mp1); +printf ("\n"); +} +#endif + return mp1; +} + +struct map *not_map(map) + struct map *map; +{ +#ifdef MAP_DEBUG +if (Mflag) +{ +printf ("Notting map"); +print_map(map); +printf ("\n"); +} +#endif + return NOT_MAP(map); +} + +struct map *copy_map(parm) + struct map *parm; +{ + struct bitmap *result, **mpp, *map; +#ifdef MAP_DEBUG +if (Mflag) +{ +printf ("copymap:"); +print_map(parm); +printf ("\n"); +} +#endif + map = MAP(parm); + for (mpp = &result; *mpp = 0, map; map = map->m_next) { + *mpp = (struct bitmap *) malloc(sizeof **mpp); + if (!*mpp) { +#ifdef MAP_DEBUG +if (Mflag) +printf ("copy_map: out of memory\n"); +#endif + free_map((struct map *) result); + result = 0; + break; + } + **mpp = *map; + mpp = &(*mpp)->m_next; + } + if (NEGMAP(parm)) + return NOT_MAP(result); + else + return (struct map*) result; +} + +long +count_map(parm) + struct map *parm; +{ + long nf; + struct bitmap *map; + register i, j; + + nf = 0; + for (map = MAP(parm); map; map = map->m_next) + { + for (i = 0; i < MDATA; ++i) + { + if (!map->m_data[i]) + ; + else if (!~map->m_data[i]) + nf += (1<m_data[i] & (1L< %d\n", nf); +} +#endif + return nf; +} + +long +next_map(parm, node) + struct map *parm; + long node; +{ + struct bitmap *map, *lowest; + long bit, mask; + int x, page; + int best; + int i; + int bn; + +#ifdef MAP_DEBUG +if (Aflag) +{ +printf ("next_map: selecting next after %d from", node); +print_map(parm); +} +#endif + if (NEGMAP(parm)) { +#ifdef MAP_DEBUG +if (Aflag) +printf ("next_map failed; negative map\n"); +#endif + return -1; + } + + ++node; + bit = NUMBERTOBIT(node); + x = NUMBERTOINDEX(node); + page = NUMBERTOPAGE(node); + bit = 1L<m_next) + if (map->m_page >= page && (!lowest || lowest->m_page > map->m_page)) + { + i = 0; mask = ~0; + if (page == map->m_page) i = x, mask = -bit; + for (; i < MDATA; ++i, mask = ~0) + if (map->m_data[i] & mask) break; + if (i < MDATA) { + for (bn = 0; bn < (1<m_data[i]&mask&(1L<m_page, +i, +map->m_data[i], +mask, +x,bit); +continue; +} +} +#endif + best = bn + ((i+((map->m_page)< %d\n", best); +if (best >= 0 && !in_map((struct map *) parm, best)) { +printf ("next_map: botch; %d not in map\n", best); +return -1; +} +} +#endif + return best; +} + +long +first_map(parm) + struct map *parm; +{ + return next_map(parm, -9999); +} + +long +prev_map(parm, node) + struct map *parm; + long node; +{ + struct bitmap *map, *lowest; + long bit, mask; + int x, page; + int best; + int i; + int bn; + +#ifdef MAP_DEBUG +if (Aflag) +{ +printf ("prev_map: selecting previous before %d from", node); +print_map(parm); +} +#endif + if (NEGMAP(parm)) { +#ifdef MAP_DEBUG +if (Aflag) +printf ("prev_map failed; negative map\n"); +#endif + return -1; + } + + if (node < 0) + node = ((unsigned long)~0)>>1; + + --node; + bit = NUMBERTOBIT(node); + x = NUMBERTOINDEX(node); + page = NUMBERTOPAGE(node); + bit = 1L<m_next) + if (map->m_page <= page && (!lowest || lowest->m_page < map->m_page)) + { + i = MDATA-1; mask = ~0; + if (page == map->m_page) i = x, mask = (bit<<1)-1; + for (; i >= 0; --i, mask = ~0) + if (map->m_data[i] & mask) break; + if (i >= 0) { + for (bn = (1<= 0; --bn) + if (map->m_data[i]&mask&(1L<m_page, +i, +map->m_data[i], +mask, +x,bit); +continue; +} +} +#endif + best = bn + ((i+((map->m_page)< %d\n", best); +if (best >= 0 && !in_map(parm, best)) { +printf ("prev_map: botch; %d not in map\n", best); +return -1; +} +} +#endif + return best; +} + +long +last_map(parm) + struct map *parm; +{ + return prev_map(parm, 0x7fffffff); +} + +struct map *negative_map(map) + struct map *map; +{ + return (struct map *) NEGMAP(map); +} + +struct map *bic_map(mp1, mp2) + struct map *mp1, *mp2; +{ +#ifdef MAP_DEBUG +if (Mflag) +{ +printf ("Bic maps"); +print_map(mp1); +printf (" minus"); +print_map(mp2); +} +#endif + mp1 = and_map(mp1, NOT_MAP(mp2)); +#ifdef MAP_DEBUG +if (Mflag) +{ +printf (" ->"); +print_map(mp1); +printf ("\n"); +} +#endif + return mp1; +} + +#ifdef PRINT_MAP_ERROR +print_map(parm) + struct map *parm; +{ + struct bitmap *map; + int i, j; + int bitno, firstbitno, lastbitno; + if (NEGMAP(parm)) { + printf (" NOT"); + } + map = MAP(parm); + if (!map) + printf (" nil(%lx)", parm); +else printf (" %lx", parm); + lastbitno = -100; + firstbitno = -100; + for (; map; map = map->m_next) + for (i = 0; i < MDATA; ++i) + if (map->m_data[i]) + for (j = 0; j < (1<m_page)<<(LSHIFT+MSHIFT)); + if (map->m_data[i] & (1<= 0 + && firstbitno != lastbitno) + printf ("-%d", lastbitno); + firstbitno = -100; + } + printf (" %d", + bitno); + firstbitno = lastbitno = bitno; + } else { + if (firstbitno >= 0 && firstbitno != lastbitno) + printf ("-%d", lastbitno); + firstbitno = -100; + } + } + if (firstbitno >= 0 && firstbitno != lastbitno) + printf ("-%d", lastbitno); +} +#endif + +#ifdef NEED_READ_WRITE +struct map * +read_map(f, arg) + int (*f)(); + char *arg; +{ + struct bitmap *map, *result, **mp; + int page; + int bitno, lastno, thisno, prevno; + int i, j; + int data; + +/* count, then startbitno, then bits. */ + lastno = ((*f)(arg)); + if (lastno == -1) + return 0; + if (lastno & ((1<m_page != page) + for (mp = &result; map = *mp; mp = &map->m_next) + if (map->m_page == page) + break; + if (!map) + { + map = (struct bitmap *) malloc(sizeof *map); + if (!map) { +#ifdef PRINT_MAP_ERROR +printf ("No memory!\n"); +#endif + if (result) + free_map((struct map *) result); + return 0; + } + bzero((char*) map->m_data, sizeof map->m_data); + map->m_page = page; + map->m_next = 0; + *mp = map; + } + map->m_data[NUMBERTOINDEX(bitno)] = data; + } + return (struct map *) result; +} + +write_map(parm, f, arg) + struct map *parm; + int (*f)(); + char *arg; +{ + struct bitmap *map; + int page; + int bitno, lastno, thisno, prevno; + int i, j; + + bitno = first_map(parm); + bitno &= ~((1<= 0; bitno = next_map(parm, bitno)) + { + page = NUMBERTOPAGE(bitno); + for (map = MAP(parm); map; map = map->m_next) + if (map->m_page == page) + break; + if (!map) + { +#ifdef PRINT_MAP_ERROR +printf ("write_map: botch #1: can't find page %d\n", page); +#endif +continue; + } + for (i = 0; i < MDATA; ++i) + { + if (!map->m_data[i]) + continue; + thisno = TONUMBER(page, i, 0); + for (j = thisno - prevno; j > 0; j -= (1<m_data[i]) == -1) + return -1; + prevno += (1<= MDATA || !map->m_data[i]) + break; + } + --i; + } + bitno = TONUMBER(page, i, 0)-1; + } +#ifdef PRINT_MAP_ERROR +if (prevno != lastno) +printf ("write_map: botch #2: bitno=%d prevno=%d lastno=%d\n", bitno, prevno, lastno); +#endif + return 0; +} +#endif + +#endif diff --git a/src/ptserver/map.h b/src/ptserver/map.h new file mode 100644 index 000000000..92f2fa49d --- /dev/null +++ b/src/ptserver/map.h @@ -0,0 +1,50 @@ +/* + * map.h - header routines for in-core bitmap routines. + */ +/* + * Copyright (c) 1995 Marcus D. Watts All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Marcus D. Watts. + * 4. The name of the developer may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * MARCUS D. WATTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +struct map; + +int in_map(struct map *, long); +void free_map(struct map *); +struct map *add_map(struct map *, long); +struct map *and_map(struct map *, struct map *); +struct map *or_map(struct map *, struct map *); +struct map *not_map(struct map *); +struct map *copy_map(struct map *); +long count_map(struct map *); +long next_map(struct map *, long); +long first_map(struct map *); +long prev_map(struct map *, long); +long last_map(struct map *); +struct map *negative_map(struct map *); +struct map *bic_map(struct map *, struct map *); +int print_map(struct map *); diff --git a/src/ptserver/ptclient.c b/src/ptserver/ptclient.c index 92a49ecf0..9f6364ce1 100644 --- a/src/ptserver/ptclient.c +++ b/src/ptserver/ptclient.c @@ -387,6 +387,28 @@ char **argv; else code = ubik_Call(PR_RemoveFromGroup,pruclient,0,id,gid); if (CodeOk(code)) printf("%s\n",pr_ErrorMsg(code)); } +#if defined(SUPERGROUPS) + else if (!strcmp(op,"lsg")) { + alist.prlist_len = 0; + alist.prlist_val = 0; + /* scanf("%d",&id); */ + if (GetInt32 (&id)) code = PRBADARG; + else code = ubik_Call(PR_ListSuperGroups,pruclient,0,id, &alist, &over); + if (CodeOk(code)) printf("%s\n",pr_ErrorMsg(code)); + if (code == PRSUCCESS) { + ptr = alist.prlist_val; + if (over) { + printf("Number of groups greater than PR_MAXGROUPS!\n"); + printf("Excess of %d.\n",over); + } + for (i=0;i #include @@ -54,6 +94,10 @@ afs_int32 getCPS(), getCPS2(), getHostCPS(), listMax(), setMax(), listEntry(); afs_int32 listEntries(), changeEntry(), setFieldsEntry(), put_prentries(); afs_int32 listElements(), listOwned(), isAMemberOf(), idToName(); +#if defined(SUPERGROUPS) +afs_int32 listSuperGroups(); +#endif + static stolower(); extern int IDCmp(); @@ -419,8 +463,12 @@ afs_int32 gid; memset(&uentry, 0, sizeof(uentry)); code = pr_ReadEntry(tt,0,tempu,&uentry); if (code != 0) ABORT_WITH(tt,code); + +#if !defined(SUPERGROUPS) /* we don't allow groups as members of groups at present */ if (uentry.flags & PRGRP) ABORT_WITH(tt,PRNOTUSER); +#endif + tempg = FindByID(tt,gid); if (!tempg) ABORT_WITH(tt,PRNOENT); code = pr_ReadEntry(tt,0,tempg,&tentry); @@ -431,6 +479,12 @@ afs_int32 gid; code = AddToEntry (tt, &tentry, tempg, aid); if (code != PRSUCCESS) ABORT_WITH(tt,code); + +#if defined(SUPERGROUPS) + if (uentry.flags & PRGRP) + code = AddToSGEntry (tt, &uentry, tempu, gid); /* mod group to be in sg */ + else +#endif /* now, modify the user's entry as well */ code = AddToEntry (tt, &uentry, tempu, gid); if (code != PRSUCCESS) ABORT_WITH(tt,code); @@ -615,6 +669,11 @@ afs_int32 Delete (call, aid) for (i=0;inextsg; + while (nptr != NULL) { + struct contentry centry; + int i; + + code = pr_ReadCoEntry(tt, 0, nptr, ¢ry); + if (code != 0) ABORT_WITH(tt,PRDBFAIL); + for (i=0;icountsg--; /* maintain count */ + if ((i&3) == 0) IOMGR_Poll(); + } + tentryg->nextsg = centry.next; /* thread out this block */ + code = FreeBlock (tt, nptr); /* free continuation block */ + if (code) ABORT_WITH(tt,code); + code = pr_WriteEntry (tt, 0, loc, &tentry); /* update main entry */ + if (code) ABORT_WITH(tt,code); + + /* end this trans and start a new one */ + code = ubik_EndTrans(tt); + if (code) return code; + IOMGR_Poll(); /* just to keep the connection alive */ + + code = ubik_BeginTrans(dbase,UBIK_WRITETRANS,&tt); + if (code) return code; + code = ubik_SetLock(tt,1,1,LOCKWRITE); + if (code) ABORT_WITH(tt,code); + + /* re-read entry to get consistent uptodate info */ + loc = FindByID (tt, aid); + if (loc == 0) ABORT_WITH(tt,PRNOENT); + code = pr_ReadEntry (tt, 0, loc, &tentry); + if (code) ABORT_WITH(tt,PRDBFAIL); + + nptr = tentryg->nextsg; + } + } + +#endif /* SUPERGROUPS */ + /* Then move the owned chain, except possibly ourself to the orphan list. * Because this list can be very long and so exceed the size of a ubik * transaction, we start a new transaction every 50 entries. */ @@ -805,11 +912,20 @@ afs_int32 gid; code = pr_ReadEntry(tt,0,tempg,&gentry); if (code != 0) ABORT_WITH(tt,code); if (!(gentry.flags & PRGRP)) ABORT_WITH(tt,PRNOTGROUP); +#if !defined(SUPERGROUPS) if (uentry.flags & PRGRP) ABORT_WITH(tt,PRNOTUSER); +#endif if (!AccessOK (tt, cid, &gentry, PRP_REMOVE_MEM, 0)) ABORT_WITH(tt,PRPERM); code = RemoveFromEntry(tt,aid,gid); if (code != PRSUCCESS) ABORT_WITH(tt,code); +#if defined(SUPERGROUPS) + if (!(uentry.flags & PRGRP)) +#endif code = RemoveFromEntry(tt,gid,aid); +#if defined(SUPERGROUPS) + else + code = RemoveFromSGEntry(tt,gid,aid); +#endif if (code != PRSUCCESS) ABORT_WITH(tt,code); code = ubik_EndTrans(tt); @@ -1501,6 +1617,65 @@ afs_int32 listElements (call, aid, alist, over) return code; } +#if defined(SUPERGROUPS) + +afs_int32 SPR_ListSuperGroups (call, aid, alist, over) + struct rx_call *call; + afs_int32 aid; + prlist *alist; + afs_int32 *over; +{ + afs_int32 code; + + code = listSuperGroups (call, aid, alist, over); + osi_auditU (call, "PTS_LstSGrps", code, AUD_LONG, aid, AUD_END); + return code; +} + +afs_int32 listSuperGroups (call, aid, alist, over) + struct rx_call *call; + afs_int32 aid; + prlist *alist; + afs_int32 *over; +{ + register afs_int32 code; + struct ubik_trans *tt; + afs_int32 cid; + afs_int32 temp; + struct prentry tentry; + + alist->prlist_len = 0; + alist->prlist_val = (afs_int32 *) 0; + + code = Initdb(); + if (code != PRSUCCESS) goto done; + code = ubik_BeginTransReadAny(dbase,UBIK_READTRANS,&tt); + if (code) goto done; + code = ubik_SetLock(tt,1,1,LOCKREAD); + if (code) ABORT_WITH(tt,code); + code = WhoIsThis(call,tt,&cid); + if (code) ABORT_WITH(tt,PRPERM); + + temp = FindByID(tt,aid); + if (!temp) ABORT_WITH(tt,PRNOENT); + code = pr_ReadEntry (tt, 0, temp, &tentry); + if (code) ABORT_WITH(tt,code); + if (!AccessOK (tt, cid, &tentry, PRP_MEMBER_MEM, PRP_MEMBER_ANY)) + ABORT_WITH(tt,PRPERM); + + code = GetSGList (tt, &tentry, alist); + *over = 0; + if (code == PRTOOMANY) *over = 1; + else if (code != PRSUCCESS) ABORT_WITH(tt,code); + + code = ubik_EndTrans(tt); + +done: + return code; +} + +#endif /* SUPERGROUPS */ + /* * SPR_ListOwned * List the entries owned by this id. If the id is zero, @@ -1628,7 +1803,11 @@ afs_int32 *flag; if (code) ABORT_WITH(tt,code); code = pr_ReadEntry (tt, 0, gloc, &gentry); if (code) ABORT_WITH(tt,code); +#if !defined(SUPERGROUPS) if ((uentry.flags & PRGRP) || !(gentry.flags & PRGRP)) ABORT_WITH(tt,PRBADARG); +#else + if (!(gentry.flags & PRGRP)) ABORT_WITH(tt,PRBADARG); +#endif if (!AccessOK (tt, cid, &uentry, 0, PRP_MEMBER_ANY) && !AccessOK (tt, cid, &gentry, PRP_MEMBER_MEM, PRP_MEMBER_ANY)) ABORT_WITH(tt,PRPERM); diff --git a/src/ptserver/pts.c b/src/ptserver/pts.c index 8ef3fe2d7..18e5e23e6 100644 --- a/src/ptserver/pts.c +++ b/src/ptserver/pts.c @@ -7,6 +7,18 @@ * directory or online at http://www.openafs.org/dl/license10.html */ +/* + * (3) add new pts commands: + * + * Interactive - allow the pts command + * to be run interactively. + * Quit - quit interactive mode. + * Source - allow input to come from a file(s). + * Sleep - pause for a specified number + * of seconds. + * + */ + #include #include @@ -39,6 +51,93 @@ RCSID("$Header$"); char *whoami; int force = 0; +#if defined(SUPERGROUPS) + +/* + * Add new pts commands: + * + * Interactive - allow the pts command to be run interactively. + * Quit - quit interactive mode. + * Source - allow input to come from a file(s). + * Sleep - pause for a specified number of seconds. + */ + +static int finished; +static FILE *source; +extern struct ubik_client *pruclient; + +struct sourcestack { + struct sourcestack *s_next; + FILE *s_file; +} *shead; + +int Interactive (as) + register struct cmd_syndesc *as; +{ + finished = 0; + return 0; +} + +int Quit (as) + register struct cmd_syndesc *as; +{ + finished = 1; + return 0; +} + +int Source (as) + register struct cmd_syndesc *as; +{ + FILE *fd; + struct sourcestack *sp; + + finished = 0; + if (!as->parms[0].items) { +/* can this happen? */ + return 1; + } + fd = fopen(as->parms[0].items->data, "r"); + if (!fd) { +perror(as->parms[0].items->data); + return errno; + } + sp = (struct sourcestack *) malloc(sizeof *sp); + if (!sp) { + return errno ? errno : ENOMEM; + } else { + sp->s_next = shead; + sp->s_file = source; + shead = sp; + source = fd; + } + return 0; +} + +int Sleep (as) + register struct cmd_syndesc *as; +{ + int delay; + if (!as->parms[0].items) { +/* can this happen? */ + return 1; + } + delay = atoi(as->parms[0].items->data); + IOMGR_Sleep(delay); +} + +int +popsource() +{ + register struct sourcestack *sp; + if (!(sp = shead)) return 0; + if (source != stdin) fclose(source); + source = sp->s_file; + shead = sp->s_next; + free((char*) sp); + return 1; +} + +#endif /* SUPERGROUPS */ int osi_audit() { @@ -83,10 +182,19 @@ int GetGlobals (as) int CleanUp (as) register struct cmd_syndesc *as; { +#if defined(SUPERGROUPS) + if (as && !strcmp(as->name,"help")) return; + if (pruclient) { + /* Need to shutdown the ubik_client & other connections */ + pr_End(); + rx_Finalize(); + } +#else if (!strcmp(as->name,"help")) return; /* Need to shutdown the ubik_client & other connections */ pr_End(); rx_Finalize(); +#endif /* SUPERGROUPS */ return 0; } @@ -120,6 +228,12 @@ CreateGroup (as) "because group id %d was not negative", id); return code; } +#if defined(SUPERGROUPS) + if (id == 0) { + printf ("0 isn't a valid user id; aborting\n"); + return EINVAL; + } +#endif idi = idi->next; } else id = 0; @@ -833,6 +947,13 @@ int main (argc, argv) { register afs_int32 code; register struct cmd_syndesc *ts; +#if defined(SUPERGROUPS) + char line[2048]; + char *cp, *lastp; + int parsec; + char *parsev[CMD_MAXPARMS]; + char *savec; +#endif #ifdef WIN32 WSADATA WSAjunk; #endif @@ -940,9 +1061,73 @@ int main (argc, argv) cmd_AddParm(ts, "-groups", CMD_FLAG, CMD_OPTIONAL, "list group entries"); add_std_args (ts); +#if defined(SUPERGROUPS) + + ts = cmd_CreateSyntax("interactive",Interactive,0, + "enter interactive mode"); + add_std_args (ts); + cmd_CreateAlias (ts, "in"); + + ts = cmd_CreateSyntax("quit",Quit,0, + "exit program"); + add_std_args (ts); + + ts = cmd_CreateSyntax("source",Source,0, + "read commands from file"); + cmd_AddParm(ts,"-file",CMD_SINGLE,0,"filename"); + add_std_args (ts); + + ts = cmd_CreateSyntax("sleep",Sleep,0, + "pause for a bit"); + cmd_AddParm(ts,"-delay",CMD_SINGLE,0,"seconds"); + add_std_args (ts); + +#endif /* SUPERGROUPS */ + cmd_SetBeforeProc(GetGlobals,0); + +#if defined(SUPERGROUPS) + finished = 1; + if (code = cmd_Dispatch(argc,argv)) { + CleanUp(0); + exit(1); + } + source = stdin; + while (!finished) { + if (isatty(fileno(source))) + fprintf(stderr,"pts> "); + if (!fgets(line, sizeof line, source)) { + if (!popsource()) break; + continue; + } + lastp = 0; + for (cp = line; *cp; ++cp) + if (!isspace(*cp)) + lastp = 0; + else if (!lastp) + lastp = cp; + if (lastp) *lastp = 0; + if (!*line) continue; + code = cmd_ParseLine(line, parsev, &parsec, + sizeof(parsev)/sizeof(*parsev)); + if (code) { + com_err(whoami, code, "parsing line: <%s>", line); + exit(2); + } + savec = parsev[0]; + parsev[0] = argv[0]; + code = cmd_Dispatch(parsec, parsev); + parsev[0] = savec; + cmd_FreeArgv(parsev); + } + CleanUp(0); + exit(0); + +#else /* SUPERGROUPS */ + cmd_SetAfterProc(CleanUp,0); code = cmd_Dispatch(argc,argv); exit (code != 0); +#endif /* SUPERGROUPS */ } diff --git a/src/ptserver/ptserver.c b/src/ptserver/ptserver.c index 9047d2bd0..8ab574a10 100644 --- a/src/ptserver/ptserver.c +++ b/src/ptserver/ptserver.c @@ -7,6 +7,107 @@ * directory or online at http://www.openafs.org/dl/license10.html */ +/* + * A general description of the supergroup changes + * to ptserver: + * + * In AFS users can be members of groups. When you add + * a user, u1, to a group, g1, you add the user id for u1 + * to an entries list in g1. This is a list of all the + * members of g1. + * You also add the id for g1 to an entries list in u1. + * This is a list of all the groups this user is a + * member of. + * The list has room for 10 entries. If more are required, + * a continuation record is created. + * + * With UMICH mods, u1 can be a group. When u1 is a group + * a new field is required to list the groups this group + * is a member of (since the entries field is used to + * list it's members). This new field is supergroups and + * has two entries. If more are required, a continuation + * record is formed. + * There are two additional fields required, nextsg is + * an address of the next continuation record for this + * group, and countsg is the count for the number of + * groups this group is a member of. + * + * + * + * 09/18/95 jjm Add mdw's changes to afs-3.3a Changes: + * (1) Add the parameter -groupdepth or -depth to + * define the maximum search depth for supergroups. + * Define the variable depthsg to be the value of + * the parameter. The default value is set to 5. + * + * (3) Make sure the sizes of the struct prentry and + * struct prentryg are equal. If they aren't equal + * the pt database will be corrupted. + * The error is reported with an fprintf statement, + * but this doesn't print when ptserver is started by + * bos, so all you see is an error message in the + * /usr/afs/logs/BosLog file. If you start the + * ptserver without bos the fprintf will print + * on stdout. + * The program will terminate with a PT_EXIT(1). + * + * + * Transarc does not currently use opcodes past 520, but + * they *could* decide at any time to use more opcodes. + * If they did, then one part of our local mods, + * ListSupergroups, would break. I've therefore + * renumbered it to 530, and put logic in to enable the + * old opcode to work (for now). + * + * 2/1/98 jjm Add mdw's changes for bit mapping for supergroups + * Overview: + * Before fetching a supergroup, this version of ptserver + * checks to see if it was marked "found" and "not a + * member". If and only if so, it doesn't fetch the group. + * Since this should be the case with most groups, this + * should save a significant amount of CPU in redundant + * fetches of the same group. After fetching the group, + * it sets "found", and either sets or clears "not a + * member", depending on if the group was a member of + * other groups. When it writes group entries to the + * database, it clears the "found" flag. + */ + +#if defined(SUPERGROUPS) +/* + * A general description of the supergroup changes + * to ptserver: + * + * In AFS users can be members of groups. When you add a user, u1, + * to a group, g1, you add the user id for u1 to an entries list + * in g1. This is a list of all the members of g1. You also add + * the id for g1 to an entries list in u1. This is a list of all + * the groups this user is a member of. The list has room for 10 + * entries. If more are required, a continuation record is created. + * + * With UMICH mods, u1 can be a group. When u1 is a group a new + * field is required to list the groups this group is a member of + * (since the entries field is used to list it's members). This + * new field is supergroups and has two entries. If more are + * required, a continuation record is formed. + * + * There are two additional fields required, nextsg is an address + * of the next continuation record for this group, and countsg is + * the count for the number of groups this group is a member of. + * + * Bit mapping support for supergroups: + * + * Before fetching a supergroup, this version of ptserver checks to + * see if it was marked "found" and "not a member". If and only if + * so, it doesn't fetch the group. Since this should be the case + * with most groups, this should save a significant amount of CPU in + * redundant fetches of the same group. After fetching the group, it + * sets "found", and either sets or clears "not a member", depending + * on if the group was a member of other groups. When it writes + * group entries to the database, it clears the "found" flag. + */ +#endif + #include #include @@ -51,6 +152,10 @@ struct prheader cheader; struct ubik_dbase *dbase; struct afsconf_dir *prdir; +#if defined(SUPERGROUPS) +extern afs_int32 depthsg; +#endif + extern afs_int32 ubik_lastYesTime; extern afs_int32 ubik_nBuffers; @@ -123,6 +228,21 @@ void main (argc, argv) pr_dbaseName = AFSDIR_SERVER_PRDB_FILEPATH; +#if defined(SUPERGROUPS) + /* make sure the structures for database records are the same size */ + if((sizeof(struct prentry) != ENTRYSIZE) || + (sizeof(struct prentryg) != ENTRYSIZE)) { + fprintf(stderr,"The structures for the database records are different" + " sizes\n" + "struct prentry = %d\n" + "struct prentryg = %d\n" + "ENTRYSIZE = %d\n", + sizeof(struct prentry), sizeof(struct prentryg), + ENTRYSIZE); + PT_EXIT(1); + } +#endif + for (a=1; a] " "[-syslog[=FACILITY]] " "[-p ] [-rebuild] " + "[-groupdepth ] " "[-enable_peer_stats] [-enable_process_stats] " "[-help]\n"); +#else /* AFS_NT40_ENV */ + printf ("Usage: ptserver [-database ] " + "[-p ] [-rebuild] " + "[-groupdepth ] " + "[-help]\n"); +#endif #else +#ifndef AFS_NT40_ENV printf ("Usage: ptserver [-database ] " + "[-syslog[=FACILITY]] " "[-p ] [-rebuild] " + "[-enable_peer_stats] [-enable_process_stats] " "[-help]\n"); +#else /* AFS_NT40_ENV */ + printf ("Usage: ptserver [-database ] " + "[-p ] [-rebuild] " + "[-help]\n"); +#endif #endif fflush(stdout); PT_EXIT(1); } +#if defined(SUPERGROUPS) + else { + fprintf (stderr, "Unrecognized arg: '%s' ignored!\n", arg); + } +#endif } OpenLog(AFSDIR_SERVER_PTLOG_FILEPATH); /* set up logging */ @@ -258,6 +405,11 @@ void main (argc, argv) com_err (whoami, code, "Ubik init failed"); PT_EXIT(2); } + +#if defined(SUPERGROUPS) + pt_hook_write(); +#endif + sc[0] = rxnull_NewServerSecurityObject(); sc[1] = 0; if (kerberosKeys) { @@ -290,4 +442,5 @@ void main (argc, argv) rx_StartServer(1); osi_audit (PTS_FinishEvent, -1, AUD_END); + exit(0); } diff --git a/src/ptserver/ptserver.h b/src/ptserver/ptserver.h index 4dc03873f..e2cd41a40 100644 --- a/src/ptserver/ptserver.h +++ b/src/ptserver/ptserver.h @@ -125,6 +125,38 @@ struct prentry { char name[PR_MAXNAMELEN]; /* user or group name */ }; +#if defined(SUPERGROUPS) + +struct prentryg { + afs_int32 flags; /* random flags */ + afs_int32 id; /* user or group id */ + afs_int32 cellid; /* reserved for cellID */ + afs_int32 next; /* next block same entry (or freelist) */ +#ifdef PR_REMEMBER_TIMES + afs_uint32 createTime, addTime, removeTime, changeTime; + afs_int32 reserved[1]; +#else + afs_int32 reserved[5]; +#endif + afs_int32 entries[PRSIZE]; /* groups a user is a member of (or list of members */ + afs_int32 nextID; /* id hash table next pointer */ + afs_int32 nextName; /* name has table next ptr */ + afs_int32 owner; /* id of owner of entry */ + afs_int32 creator; /* may differ from owner */ + afs_int32 ngroups; /* number of groups this user has created - 0 for group entries */ + afs_int32 nusers; /* number of foreign user entries this user has created - 0 for group entries NYI */ + afs_int32 count; /* number of members/groups for this group/user */ + afs_int32 countsg; /* number of supergroups for this group */ + afs_int32 owned; /* chain of groups owned by this entry */ + afs_int32 nextOwned; /* chain of groups for owner of this entry */ + afs_int32 nextsg; /* next block same entry for supergroups */ +#define SGSIZE 2 /* number of supergroup entries */ + afs_int32 supergroup[SGSIZE]; /* supergroups this group belongs to */ + char name[PR_MAXNAMELEN]; /* user or group name */ +}; + +#endif /* SUPERGROUPS */ + struct contentry { /* continuation of entry */ afs_int32 flags; afs_int32 id; diff --git a/src/ptserver/ptuser.c b/src/ptserver/ptuser.c index 45a88a2cc..ebff0bda1 100644 --- a/src/ptserver/ptuser.c +++ b/src/ptserver/ptuser.c @@ -150,6 +150,9 @@ afs_int32 pr_Initialize (secLevel, confDir, cell) /* If secLevel is two assume we're on a file server and use * ClientAuthSecure if possible. */ code = afsconf_ClientAuthSecure (tdir, &sc[2], &scIndex); + if (code) + fprintf(stderr,"libprot: clientauthsecure returns %d %s" + " (so trying noauth)\n",code, error_message(code)); if (code) scIndex = 0; /* use noauth */ if (scIndex != 2) /* if there was a problem, an unauthenticated conn is returned */ diff --git a/src/ptserver/ptutils.c b/src/ptserver/ptutils.c index c74286794..da2b59962 100644 --- a/src/ptserver/ptutils.c +++ b/src/ptserver/ptutils.c @@ -7,6 +7,19 @@ * directory or online at http://www.openafs.org/dl/license10.html */ +/* + * (5) Add functions to process supergroups: + * ChangeIDEntry(), RemoveFromSGEntry(), + * AddToSGEntry(), GetListSG2(). + * (6) Add code to existing functions to process + * supergroups. + * 2/1/98 jjm Add mdw's changes for bit mapping for supergroups + * + * 09/26/02 kwc Move depthsg definition here from ptserver.c since + * pt_util needs it defined also, and this file is + * common between the two programs. + */ + #include #include @@ -48,6 +61,130 @@ extern int IDCmp(); extern afs_int32 AddToEntry(); static char *whoami = "ptserver"; +#if defined(SUPERGROUPS) + +#include "map.h" + +afs_int32 depthsg = 5; /* Maximum iterations used during IsAMemberOF */ +extern int IDCmp(); +afs_int32 GetListSG2 (struct ubik_trans *at, afs_int32 gid, prlist *alist, + afs_int32 *sizeP, afs_int32 depth); + +struct map *sg_flagged; +struct map *sg_found; + +#define NIL_MAP ((struct map *) 0) + +/* pt_mywrite hooks into the logic that writes ubik records to disk + * at a very low level. It invalidates mappings in sg_flagged/sg_found. + * By hoooking in at this level, we ensure that a ubik file reload + * invalidates our incore cache. + * + * We assert records, cheaders and everything else are 0 mod 64. + * So, we can always see the first 64 bytes of any record written. + * The stuff we're interested in (flags, id) are in the first 8 bytes. + * so we can always tell if we're writing a group record. + */ + +int (*pt_save_dbase_write)(); + +int pt_mywrite(tdb, fno, bp, pos, count) + struct ubik_dbase *tdb; + afs_int32 fno, pos, count; + char *bp; +{ + afs_uint32 headersize = ntohl(cheader.headerSize); + + if (fno == 0 && pos+count > headersize) + { + afs_int32 p, l, c, o; + char *cp; + p = pos-headersize; + cp = bp; + l = count; + if (p < 0) { + l += p; + p = 0; + } + while (l > 0) + { + o = p%ENTRYSIZE; + c = ENTRYSIZE-o; + if (c > l) + c = l; +#if DEBUG_SG_MAP + if (o) + fprintf (stderr,"Writing %d bytes of entry @ %#lx(+%d)\n", + c, p-o, o); + else if (c == ENTRYSIZE) + fprintf (stderr,"Writing %d bytes of entry @ %#lx (%d<%s>,%d)\n", + c, p, + ((struct prentry *)cp)->flags, +(((struct prentry *)cp)->flags&PRTYPE)==PRUSER ? "user" : +(((struct prentry *)cp)->flags&PRTYPE)==PRFREE ? "free" : +(((struct prentry *)cp)->flags&PRTYPE)==PRGRP ? "group" : +(((struct prentry *)cp)->flags&PRTYPE)==PRCONT ? "cont" : +(((struct prentry *)cp)->flags&PRTYPE)==PRCELL ? "cell" : +(((struct prentry *)cp)->flags&PRTYPE)==PRFOREIGN ? "foreign" : +(((struct prentry *)cp)->flags&PRTYPE)==PRINST ? "sub/super instance" : +"?", + ((struct prentry *)cp)->id); + else if (c >= 8) + fprintf (stderr,"Writing first %d bytes of entry @ %#lx (%d<%s>,%d)\n", + c, p, + ((struct prentry *)cp)->flags, +(((struct prentry *)cp)->flags&PRTYPE)==PRUSER ? "user" : +(((struct prentry *)cp)->flags&PRTYPE)==PRFREE ? "free" : +(((struct prentry *)cp)->flags&PRTYPE)==PRGRP ? "group" : +(((struct prentry *)cp)->flags&PRTYPE)==PRCONT ? "cont" : +(((struct prentry *)cp)->flags&PRTYPE)==PRCELL ? "cell" : +(((struct prentry *)cp)->flags&PRTYPE)==PRFOREIGN ? "foreign" : +(((struct prentry *)cp)->flags&PRTYPE)==PRINST ? "sub/super instance" : +"?", + ((struct prentry *)cp)->id); + else + fprintf (stderr,"Writing %d bytes of entry @ %#lx\n", + c, p); +#endif + if (!o && c >= 8 && + (((struct prentry *)cp)->flags&PRTYPE)==PRGRP) + { +#if DEBUG_SG_MAP +if (in_map(sg_found, -((struct prentry *)cp)->id))fprintf(stderr,"Unfound: Removing group %d\n", +((struct prentry *)cp)->id); +if (in_map(sg_flagged, -((struct prentry *)cp)->id))fprintf(stderr,"Unflag: Removing group %d\n", +((struct prentry *)cp)->id); +#endif + sg_found = bic_map(sg_found, add_map(NIL_MAP, + -((struct prentry *)cp)->id)); + sg_flagged = bic_map(sg_flagged, add_map(NIL_MAP, + -((struct prentry *)cp)->id)); + } + cp += c; + p += c; + l -= c; + } + } + return (*pt_save_dbase_write)(tdb, fno, bp, pos, count); +} + +/* + * this function attaches pt_mywrite. It's called once, + * just after ubik_ServerInit. + */ + +pt_hook_write() +{ + extern struct ubik_dbase *ubik_dbase; + if (ubik_dbase->write != pt_mywrite) + { + pt_save_dbase_write = ubik_dbase->write; + ubik_dbase->write = pt_mywrite; + } +} + +#endif /* SUPERGROUPS */ + /* CorrectUserName - Check to make sure a user name is OK. It must not include * either a colon (or it would look like a group) or an atsign (or it would * look like a foreign user). The length is checked as well to make sure @@ -501,6 +638,163 @@ afs_int32 RemoveFromEntry (at, aid, bid) return PRNOENT; } +#if defined(SUPERGROUPS) +/* ChangeIDEntry - remove aid from bid's entries list, freeing a continuation + * entry if appropriate */ + +afs_int32 ChangeIDEntry (at, aid, newid, bid) + register struct ubik_trans *at; + register afs_int32 aid; + register afs_int32 bid; + afs_int32 newid; +{ + register afs_int32 code; + struct prentry tentry; + struct contentry centry; + afs_int32 temp; + afs_int32 i,j; + afs_int32 nptr; + + if (aid == bid) return PRINCONSISTENT; + temp = FindByID(at,bid); + if (temp == 0) { + return PRNOENT; + } + code = pr_ReadEntry(at, 0, temp, &tentry); + if (code != 0) return code; + for (i=0;isupergroup[i] == aid) { + tentryg->supergroup[i] = PRBADID; + tentryg->countsg--; + code = pr_WriteEntry(at,0,temp,&tentry); + if (code != 0) return code; + return PRSUCCESS; + } + if (tentryg->supergroup[i] == 0) { /* found end of list */ + return PRNOENT; + } + } + hloc = 0; + nptr = tentryg->nextsg; + while (nptr != NULL) { + code = pr_ReadCoEntry(at,0,nptr,¢ry); + if (code != 0) return code; + if ((centry.id != bid) || !(centry.flags & PRCONT)) { + fprintf(stderr,"ChangeIDEntry: bad database bid=%d centry.id=%d .flags=%d\n", + bid, centry.id, centry.flags); + return PRDBBAD; + } + for (i=0;inextsg = centry.next; + } + else { + hentry.next = centry.next; + code = pr_WriteCoEntry (at, 0, hloc, &hentry); + if (code != 0) return code; + } + code = FreeBlock (at, nptr); + if (code) return code; + } + else { /* can't free it yet */ + code = pr_WriteCoEntry(at,0,nptr,¢ry); + if (code != 0) return code; + } + tentryg->countsg--; + code = pr_WriteEntry(at,0,temp,&tentry); + if (code) return PRDBFAIL; + return 0; + } + if (centry.entries[i] == 0) { + return PRNOENT; + } + } /* for all coentry slots */ + hloc = nptr; + nptr = centry.next; + bcopy((char*)¢ry,(char*)&hentry,sizeof(centry)); + } /* while there are coentries */ + return PRNOENT; +} + +#endif /* SUPERGROUPS */ + /* DeleteEntry - delete the entry in tentry at loc, removing it from all * groups, putting groups owned by it on orphan chain, and freeing the space */ @@ -539,9 +833,27 @@ afs_int32 DeleteEntry (at, tentry, loc) for (i=0;ientries[i] == PRBADID) continue; if (tentry->entries[i] == 0) break; +#if defined(SUPERGROUPS) + if ((tentry->flags & PRGRP) && tentry->entries[i] < 0) /* Supergroup */ + code = RemoveFromSGEntry (at, tentry->id, tentry->entries[i]); + else +#endif code = RemoveFromEntry (at, tentry->id, tentry->entries[i]); if (code) return code; } +#if defined(SUPERGROUPS) + { + struct prentryg *tentryg = (struct prentryg *)tentry; + + /* Then remove the entire supergroup list */ + for (i=0;isupergroup[i] == PRBADID) continue; + if (tentryg->supergroup[i] == 0) break; + code = RemoveFromEntry (at, tentry->id, tentryg->supergroup[i]); + if (code) return code; + } + } +#endif /* SUPERGROUPS */ nptr = tentry->next; while (nptr != (afs_int32)NULL) { code = pr_ReadCoEntry(at,0,nptr,¢ry); @@ -721,6 +1033,119 @@ afs_int32 AddToEntry (tt, entry, loc, aid) } +#if defined(SUPERGROUPS) + +/* AddToSGEntry - add aid to entry's supergroup list, alloc'ing a + * continuation block if needed. + * + * Note the entry is written out by this routine. */ + +afs_int32 AddToSGEntry (tt, entry, loc, aid) + struct ubik_trans *tt; + struct prentry *entry; + afs_int32 loc; + afs_int32 aid; +{ + register afs_int32 code; + afs_int32 i; + struct contentry nentry; + struct contentry aentry; + struct prentryg *entryg; + afs_int32 nptr; + afs_int32 last; /* addr of last cont. block */ + afs_int32 first = 0; + afs_int32 cloc; + afs_int32 slot = -1; + + if (entry->id == aid) return PRINCONSISTENT; +#ifdef PR_REMEMBER_TIMES + entry->addTime = time((afs_int32*)0); +#endif + entryg = (struct prentryg *)entry; + for (i=0;isupergroup[i] == aid) + return PRIDEXIST; + if (entryg->supergroup[i] == PRBADID) { /* remember this spot */ + first = 1; + slot = i; + } + else if (entryg->supergroup[i] == 0) { /* end of the line */ + if (slot == -1) { + first = 1; + slot = i; + } + break; + } + } + last = 0; + nptr = entryg->nextsg; + while (nptr != NULL) { + code = pr_ReadCoEntry(tt,0,nptr,&nentry); + if (code != 0) return code; + last = nptr; + if (!(nentry.flags & PRCONT)) return PRDBFAIL; + for (i=0;icountsg++; + if (first) { /* place is in first block */ + entryg->supergroup[slot] = aid; + code = pr_WriteEntry (tt, 0, loc, entry); + if (code != 0) return code; + return PRSUCCESS; + } + code = pr_WriteEntry (tt, 0, loc, entry); + if (code) return code; + code = pr_ReadCoEntry(tt,0,cloc,&aentry); + if (code != 0) return code; + aentry.entries[slot] = aid; + code = pr_WriteCoEntry(tt,0,cloc,&aentry); + if (code != 0) return code; + return PRSUCCESS; + } + /* have to allocate a continuation block if we got here */ + nptr = AllocBlock(tt); + if (last) { + /* then we should tack new block after last block in cont. chain */ + nentry.next = nptr; + code = pr_WriteCoEntry(tt,0,last,&nentry); + if (code != 0) return code; + } + else { + entryg->nextsg = nptr; + } + memset(&aentry, 0, sizeof(aentry)); + aentry.flags |= PRCONT; + aentry.id = entry->id; + aentry.next = NULL; + aentry.entries[0] = aid; + code = pr_WriteCoEntry(tt,0,nptr,&aentry); + if (code != 0) return code; + /* don't forget to update count, here! */ + entryg->countsg++; + code = pr_WriteEntry (tt, 0, loc, entry); + return code; + +} +#endif /* SUPERGROUPS */ + afs_int32 AddToPRList (alist, sizeP, id) prlist *alist; int *sizeP; @@ -766,6 +1191,11 @@ afs_int32 GetList (at, tentry, alist, add) if (tentry->entries[i] == 0) break; code = AddToPRList (alist, &size, tentry->entries[i]); if (code) return code; +#if defined(SUPERGROUPS) + if (!add) continue; + code = GetListSG2 (at, tentry->entries[i], alist, &size, depthsg); + if (code) return code; +#endif } for (nptr = tentry->next; nptr != 0; nptr = centry.next) { @@ -777,6 +1207,11 @@ afs_int32 GetList (at, tentry, alist, add) if (centry.entries[i] == 0) break; code = AddToPRList (alist, &size, centry.entries[i]); if (code) return code; +#if defined(SUPERGROUPS) + if (!add) continue; + code = GetListSG2 (at, centry.entries[i], alist, &size, depthsg); + if (code) return code; +#endif } if (count++ > 50) IOMGR_Poll(), count = 0; } @@ -820,6 +1255,11 @@ afs_int32 GetList2 (at, tentry, tentry2 , alist, add) if (tentry->entries[i] == 0) break; code = AddToPRList (alist, &size, tentry->entries[i]); if (code) return code; +#if defined(SUPERGROUPS) + if (!add) continue; + code = GetListSG2 (at, tentry->entries[i], alist, &size, depthsg); + if (code) return code; +#endif } nptr = tentry->next; @@ -832,6 +1272,11 @@ afs_int32 GetList2 (at, tentry, tentry2 , alist, add) if (centry.entries[i] == 0) break; code = AddToPRList (alist, &size, centry.entries[i]); if (code) return code; +#if defined(SUPERGROUPS) + if (!add) continue; + code = GetListSG2 (at, centry.entries[i], alist, &size, depthsg); + if (code) return code; +#endif } nptr = centry.next; if (count++ > 50) IOMGR_Poll(), count = 0; @@ -876,6 +1321,158 @@ afs_int32 GetList2 (at, tentry, tentry2 , alist, add) return PRSUCCESS; } +#if defined(SUPERGROUPS) + +afs_int32 GetListSG2 (at, gid, alist, sizeP, depth) + struct ubik_trans *at; + afs_int32 gid; + prlist *alist; + afs_int32 depth; + afs_int32 *sizeP; +{ + register afs_int32 code; + struct prentry tentry; + struct prentryg *tentryg = (struct prentryg *)&tentry; + afs_int32 i; + struct contentry centry; + afs_int32 nptr; + int count = 0; + afs_int32 temp; + int didsomething; +#if DEBUG_SG_MAP + int predictfound, predictflagged; +#endif + +#if DEBUG_SG_MAP + predictfound = 0; + if (!in_map(sg_flagged, -gid)) + { + predictflagged = 0; + fprintf(stderr,"GetListSG2: I have not yet searched for gid=%d\n", gid); + } + else if (predictflagged = 1, in_map(sg_found, -gid)) { + predictfound = 1; + fprintf (stderr, + "GetListSG2: I have already searched for gid=%d, and predict success.\n", + gid); + } +#endif + + if (in_map(sg_flagged, -gid) && !in_map(sg_found, -gid)) { +#if DEBUG_SG_MAP + fprintf (stderr, + "GetListSG2: I have already searched for gid=%d, and predict failure.\n", + gid); +#else + return 0; +#endif + } + + if (depth < 1) return 0; + temp = FindByID (at, gid); + if (!temp) { + code = PRNOENT; + return code; + } + code = pr_ReadEntry (at, 0, temp, &tentry); + if (code) return code; +#if DEBUG_SG_MAP + fprintf (stderr,"GetListSG2: lookup for gid=%d [\n", gid); +#endif + didsomething = 0; + + for (i=0;isupergroup[i] == PRBADID) continue; + if (tentryg->supergroup[i] == 0) break; + didsomething = 1; +#if DEBUG_SG_MAP + fprintf (stderr,"via gid=%d, added %d\n", gid, e.tentryg.supergroup[i]); +#endif + code = AddToPRList (alist, sizeP, tentryg->supergroup[i]); + if (code) return code; + code = GetListSG2 (at, tentryg->supergroup[i], alist, sizeP, depth-1); + if (code) return code; + } + + nptr = tentryg->nextsg; + while (nptr != NULL) { + didsomething = 1; + /* look through cont entries */ + code = pr_ReadCoEntry(at,0,nptr,¢ry); + if (code != 0) return code; + for (i=0;i 50) IOMGR_Poll(), count = 0; + } +#if DEBUG_SG_MAP + fprintf (stderr,"] for gid %d, done [flag=%s]\n", gid, didsomething ? "TRUE" : "FALSE"); + if (predictflagged && didsomething != predictfound) + fprintf (stderr,"**** for gid=%d, didsomething=%d predictfound=%d\n", + didsomething, predictfound); +#endif + if (didsomething) + sg_found = add_map(sg_found, -gid); + else sg_found = bic_map(sg_found, add_map(NIL_MAP, -gid)); + sg_flagged = add_map(sg_flagged, -gid); + return 0; +} + +afs_int32 GetSGList (at, tentry, alist) + struct ubik_trans *at; + struct prentry *tentry; + prlist *alist; +{ + register afs_int32 code; + afs_int32 i; + struct contentry centry; + struct prentryg *tentryg; + afs_int32 nptr; + int size; + int count = 0; + + size = 0; + alist->prlist_val = 0; + alist->prlist_len = 0; + + tentryg = (struct prentryg *)tentry; + for (i=0;isupergroup[i] == PRBADID) continue; + if (tentryg->supergroup[i] == 0) break; + code = AddToPRList (alist, &size, tentryg->supergroup[i]); + if (code) return code; + } + + nptr = tentryg->nextsg; + while (nptr != NULL) { + /* look through cont entries */ + code = pr_ReadCoEntry(at,0,nptr,¢ry); + if (code != 0) return code; + for (i=0;i 50) IOMGR_Poll(), count = 0; + } + + if (alist->prlist_len > 100) IOMGR_Poll(); + qsort((char*)alist->prlist_val,(int)alist->prlist_len,sizeof(afs_int32),IDCmp); + return PRSUCCESS; +} +#endif /* SUPERGROUPS */ + afs_int32 GetOwnedChain (ut, next, alist) struct ubik_trans *ut; afs_int32 *next; @@ -1091,6 +1688,9 @@ afs_int32 ChangeEntry (at, aid, cid, name, oid, newid) { afs_int32 code; afs_int32 i, nptr, pos; +#if defined(SUPERGROUPS) + afs_int32 nextpos; +#endif struct contentry centry; struct prentry tentry, tent; afs_int32 loc; @@ -1137,6 +1737,66 @@ afs_int32 ChangeEntry (at, aid, cid, name, oid, newid) code = pr_ReadEntry(at, 0, loc, &tentry); if (code) return PRDBFAIL; +#if defined(SUPERGROUPS) + if (tentry.id > (afs_int32)ntohl(cheader.maxID)) + code = set_header_word (at, maxID, htonl(tentry.id)); + if (code) return PRDBFAIL; + + /* need to fix up: membership + * (supergroups?) + * ownership + */ + + for (i=0;i