On Fri, May 25, 2001 at 07:46:24AM -0400, Jan Harkes wrote:
> > Also, I'm trying to change the user id for the administrative user in 
> > pdbtool, but not all references to that id are changed.  I want to free 
> > up that id so I can match my current system user ids for consistency 
> > across the system.  If I change the id and do a 'list', the 
> > System:Administrators owner id still shows the old value and now I can't 
> > do anything as the coda admin until I change it back.  Same with any 
> > groups that are owned by the user whose id I'm trying to change.  Is 
> > this a bug in pdbtool?
> 
> I guess the pdbtools isn't exhaustive enough in hunting down all id's
> that need to be renumbered. It will work when the changing userid is
> only a member of a group, so yes, this is a bug. I'll look into it.

I found several bugs in the implementation of 'pdbtool ci' that result
in inconsistencies in the pdb databases.

- Group owner id wasn't updated.
- Traversal of the groups_or_members array was broken. As a result users
  who's uid changed and that were a member of a group, are not listed as
  group members in the group information.
- Member of information was updated in such a way that a group would
  be listed as a member of a user (shouldn't be possible).

I just committed a version into CVS that fixes these bugs and also has
added the functionality to 'pdbtool cm' to fix inconsistencies that
occur as a result of these bugs (same patch follows here).

Jan

Index: pdb.c
===================================================================
RCS file: /afs/cs/project/coda-src/cvs/coda/coda-src/al/pdb.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -u -r1.9 -r1.10
--- pdb.c       1999/09/14 19:00:40     1.9
+++ pdb.c       2001/05/25 16:29:57     1.10
@@ -425,6 +425,99 @@
 }
 
 
+void PDB_bugfixes(void)
+{
+    PDB_HANDLE h;
+    /* fixups for old bugs */
+    int32_t id, id2;
+    pdb_array_off off, off2;
+    int rc;
+    PDB_profile p, r;
+
+    h = PDB_db_open(O_RDWR);
+
+    while ( (rc = PDB_db_nextkey(h, &id)) ) {
+       if ( rc == -1 ) continue; 
+       PDB_readProfile(h, id, &p);
+
+       if (PDB_ISGROUP(p.id)) {
+           /* BUG: forgot to update owner_id when changing a user's uid */
+           PDB_lookupByName(p.owner_name, &id);
+           if (p.owner_id != id) {
+               fprintf(stderr, "Group %d owner name %s didn't match owner id %d, 
+FIXED\n", p.id, p.owner_name, p.owner_id);
+               p.owner_id = id;
+               PDB_writeProfile(h, &p);
+           }
+
+           /* BUG: we added userid's to a group's member_of list */
+again:
+           id = pdb_array_head(&p.member_of, &off);
+           while(id != 0) {
+               if (PDB_ISUSER(id)) {
+                   fprintf(stderr, "Group %d was listed as a member of userid %d, 
+FIXED\n", p.id, id);
+                   pdb_array_del(&p.member_of, id);
+                   PDB_updateCps(h, &p);
+                   PDB_writeProfile(h, &p);
+                   goto again;
+               }
+               id = pdb_array_next(&p.member_of, &off);
+           }
+
+           /* BUG: we forgot to change userid's in a group's groups_or_members
+            *      list (fix part 1, removes non-existing or non-member
+            *      userids) */
+again2:
+           id = pdb_array_head(&p.groups_or_members, &off);
+           while(id != 0) {
+               if (PDB_ISUSER(id)) {
+                   PDB_readProfile(h, id, &r);
+                   id2 = pdb_array_head(&r.member_of, &off2);
+                   while (id2 != 0) {
+                       if (id2 == p.id) break;
+                       id2 = pdb_array_next(&r.member_of, &off2);
+                   }
+                   if (id2 == 0) {
+                       pdb_array_del(&p.groups_or_members, id);
+                       PDB_updateCps(h, &p);
+                       PDB_writeProfile(h, &p);
+                       fprintf(stderr, "Group %d had nonexisting member %d, FIXED\n", 
+p.id, id);
+                       PDB_freeProfile(&r);
+                       goto again2;
+                   }
+                   PDB_freeProfile(&r);
+               }
+               id = pdb_array_next(&p.groups_or_members, &off);
+           }
+       }
+       else /* PDB_ISUSER(p.id) */
+       {
+           /* BUG: we forgot to change userid's in a group's groups_or_members
+            *      list (fix part 2, adds missing members to groups)*/
+           id = pdb_array_head(&p.member_of, &off);
+           while (id != 0) {
+               if (PDB_ISGROUP(id)) {
+                   PDB_readProfile(h, id, &r);
+                   id2 = pdb_array_head(&r.groups_or_members, &off2);
+                   while (id2 != 0) {
+                       if (id2 == p.id) break;
+                       id2 = pdb_array_next(&r.groups_or_members, &off2);
+                   }
+                   if (id2 == 0) {
+                       fprintf(stderr, "Group %d was missing member %d, FIXED\n", id, 
+p.id);
+                       pdb_array_add(&r.groups_or_members, p.id);
+                       PDB_updateCps(h, &r);
+                       PDB_writeProfile(h, &r);
+                   }
+                   PDB_freeProfile(&r);
+               }
+               id = pdb_array_next(&p.member_of, &off);
+           }
+       }
+       PDB_freeProfile(&p);
+    }
+    PDB_db_close(h);
+}
+
 void PDB_changeId(int32_t oldId, int32_t newId)
 {
        PDB_HANDLE h;
@@ -466,35 +559,44 @@
        else
                PDB_db_update_maxids(h, newId, 0, PDB_MAXID_SET);
 
-       /* update groups is member of */
+       /* update groups we are a member of */
        nextid = pdb_array_head(&(r.member_of), &off);
        while(nextid != 0){
                PDB_readProfile(h, nextid, &p);
                CODA_ASSERT(p.id != 0);
                pdb_array_del(&(p.groups_or_members), oldId);
                pdb_array_add(&(p.groups_or_members), newId);
+
                /* Don't need CPS updates */
                PDB_writeProfile(h, &p);
                PDB_freeProfile(&p);
-               nextid = pdb_array_next(&(r.groups_or_members), &off);
+               nextid = pdb_array_next(&(r.member_of), &off);
        }
 
-       /* update members */
+       /* update members or ownership */
        nextid = pdb_array_head(&(r.groups_or_members), &off);
-       while(nextid != 0){
-               PDB_readProfile(h, nextid, &p);
-               CODA_ASSERT(p.id != 0);
+       while(nextid != 0) {
+           PDB_readProfile(h, nextid, &p);
+           CODA_ASSERT(p.id != 0);
+
+           if (PDB_ISGROUP(oldId)) {
                pdb_array_del(&(p.member_of), oldId);
                pdb_array_add(&(p.member_of), newId);
-               if(PDB_ISGROUP(oldId)){
-                       if(PDB_ISGROUP(p.id))
-                               PDB_updateCps(h, &p);
-                       else
-                               PDB_updateCpsSelf(h, &p);
+           } else {
+               if (PDB_ISGROUP(p.id)) {
+                   if(p.owner_id == oldId)
+                       p.owner_id = newId;
                }
-               PDB_writeProfile(h, &p);
-               PDB_freeProfile(&p);
-               nextid = pdb_array_next(&(r.groups_or_members), &off);
+           }
+
+           if(PDB_ISGROUP(p.id))
+               PDB_updateCps(h, &p);
+           else
+               PDB_updateCpsSelf(h, &p);
+
+           PDB_writeProfile(h, &p);
+           PDB_freeProfile(&p);
+           nextid = pdb_array_next(&(r.groups_or_members), &off);
        }
 
        PDB_db_close(h);
Index: pdb.h
===================================================================
RCS file: /afs/cs/project/coda-src/cvs/coda/coda-src/al/pdb.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -u -r1.2 -r1.3
--- pdb.h       1999/05/07 04:04:19     1.2
+++ pdb.h       2001/05/25 16:29:57     1.3
@@ -70,6 +70,9 @@
 int PDB_nameInUse(char *name);
 void PDB_changeId(int32_t oldid, int32_t newid);
 
+/* fix known problems in PDB profiles created by older versions of pdbtool */
+void PDB_bugfixes(void);
+
 /* internal packing functions */
 void pdb_pack(PDB_profile *r, void **data, size_t *size);
 void pdb_unpack(PDB_profile *r, void *data, size_t size);
Index: pdbtool.c
===================================================================
RCS file: /afs/cs/project/coda-src/cvs/coda/coda-src/al/pdbtool.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -u -r1.13 -r1.14
--- pdbtool.c   2001/01/19 12:58:02     1.13
+++ pdbtool.c   2001/05/25 16:29:57     1.14
@@ -362,12 +362,17 @@
 }
 
 /* COMPACT DATABASES */
-void tool_compact(int argc,char *argv[]){
+void tool_compact(int argc,char *argv[])
+{
        PDB_HANDLE h;
+
        if(check_args_num(argc,1)){
                printf("Usage: cm\n");
                return;
        }
+       /* fix database consistency bugs */
+       PDB_bugfixes();
+
        h = PDB_db_open(O_RDWR);
        PDB_db_compact(h);
        PDB_db_close(h);
@@ -757,7 +762,7 @@
        printf("cu <newusername> <userid>\tclone a user\n");
        printf("ag <groupid/name> <id/name>\tadd a group or user to a group\n");
        printf("rg <groupid/name> <id/name>\tremove a group or user from a group\n");
-       printf("d <id/name>\t\t\t\tdelete a user or a group\n");
+       printf("d <id/name>\t\t\tdelete a user or a group\n");
        printf("cm\t\t\t\tcompact the database (RARE)\n");
        printf("ci <name> <newid>\t\tchange the Id of a user or group\n");
        printf("cn <id> <newname>\t\tchange the Name of a user or group\n");

Reply via email to