prdb_check: fix out of bounds array access in continuation entries
[openafs.git] / src / ptserver / db_verify.c
index 144623f..a8e4916 100644 (file)
@@ -1,18 +1,17 @@
 /*
  * Copyright 2000, International Business Machines Corporation and others.
  * All Rights Reserved.
- * 
+ *
  * This software has been released under the terms of the IBM Public
  * License.  For details, see the LICENSE file in the top-level source
  * directory or online at http://www.openafs.org/dl/license10.html
  */
 
-
 #include <afsconfig.h>
 #include <afs/param.h>
+#include <afs/stds.h>
 
-RCSID
-    ("$Header$");
+#include <roken.h>
 
 /*
  *                      (3) Define a structure, idused, instead of an
@@ -32,27 +31,13 @@ RCSID
  *                          conditions.
  */
 
-#include <afs/stds.h>
-#include <sys/types.h>
+
 #ifdef AFS_NT40_ENV
-#include <winsock2.h>
 #include <WINNT/afsevent.h>
-#include <io.h>
 #else
-#include <netdb.h>
-#include <netinet/in.h>
 #include <sys/file.h>
 #endif
-#include <stdio.h>
-#ifdef HAVE_STRING_H
-#include <string.h>
-#else
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
-#endif
-#include <errno.h>
-#include <fcntl.h>
+
 #include <afs/cellconfig.h>
 #include <afs/afsutil.h>
 #include <ubik.h>
@@ -62,10 +47,12 @@ RCSID
 #include "ptint.h"
 #include "pterror.h"
 #include "ptserver.h"
+#include "ptuser.h"
+#include "display.h"
 
 struct prheader cheader;
 int fd;
-char *pr_dbaseName;
+const char *pr_dbaseName;
 char *whoami = "db_verify";
 #define UBIK_HEADERSIZE 64
 
@@ -91,7 +78,7 @@ printheader(struct prheader *h)
 }
 
 static afs_int32
-pr_Read(afs_int32 pos, char *buff, afs_int32 len)
+pr_Read(afs_int32 pos, void *buff, afs_int32 len)
 {
     afs_int32 code;
 
@@ -116,7 +103,7 @@ pr_Read(afs_int32 pos, char *buff, afs_int32 len)
  */
 
 afs_int32
-ReadHeader()
+ReadHeader(void)
 {
     afs_int32 code;
 
@@ -144,14 +131,14 @@ IDHash(afs_int32 x)
 }
 
 static afs_int32
-NameHash(register unsigned char *aname)
+NameHash(char *aname)
 {
     /* returns hash bucket for aname */
-    register unsigned int hash = 0;
-    register int i;
+    unsigned int hash = 0;
+    int i;
 /* stolen directly from the HashString function in the vol package */
     for (i = strlen(aname), aname += i - 1; i--; aname--)
-       hash = (hash * 31) + (*aname - 31);
+       hash = (hash * 31) + (*(unsigned char *)aname - 31);
     return (hash % HASHSIZE);
 }
 
@@ -217,13 +204,13 @@ readUbikHeader(struct misc_data *misc)
     /* now read the info */
     r = read(fd, &uheader, sizeof(uheader));
     if (r != sizeof(uheader)) {
-       printf("error: read of %d bytes failed: %d %d\n", sizeof(uheader), r,
-              errno);
+       printf("error: read of %" AFS_SIZET_FMT " bytes failed: %d %d\n",
+              sizeof(uheader), r, errno);
        return (-1);
     }
 
     uheader.magic = ntohl(uheader.magic);
-    uheader.size = ntohl(uheader.size);
+    uheader.size = ntohs(uheader.size);
     uheader.version.epoch = ntohl(uheader.version.epoch);
     uheader.version.counter = ntohl(uheader.version.counter);
 
@@ -273,6 +260,13 @@ PrintEntryError(struct misc_data *misc, afs_int32 ea, struct prentry *e, int ind
     return 0;
 }
 
+int
+PrintContError(struct misc_data *misc, afs_int32 ea, struct contentry *c, int indent)
+{
+    pr_PrintContEntry(stderr, /*net order */ 0, ea, c, indent);
+    return 0;
+}
+
 afs_int32
 WalkHashTable(afs_int32 hashtable[],   /* hash table to walk */
              int hashType,             /* hash function to use */
@@ -398,16 +392,17 @@ WalkNextChain(char map[],         /* one byte per db entry */
     afs_int32 head;
     int bit;
     afs_int32 code;
-    struct prentry c;          /* continuation entry */
+    struct contentry c;                /* continuation entry */
     afs_int32 na;              /* next thread */
     int ni;
-    afs_int32 eid;
-    int count;                 /* number of members */
+    afs_int32 eid = 0;
+    int count = 0;             /* number of members, set to > 9999 if */
+                               /* list ends early */
     int i;
     int noErrors = 1;
     int length;                        /* length of chain */
 #if defined(SUPERGROUPS)
-    int sgcount;               /* number of sgentrys */
+    int sgcount = 0;           /* number of sgentrys */
     afs_int32 sghead;
 #define g (((struct prentryg *)e))
 #endif
@@ -416,9 +411,7 @@ WalkNextChain(char map[],           /* one byte per db entry */
        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; i < PRSIZE; i++) {
@@ -507,7 +500,7 @@ WalkNextChain(char map[],           /* one byte per db entry */
                return PRDBBAD;
            if (na != sghead) {
                fprintf(stderr, "last block: \n");
-               if (PrintEntryError(misc, na, &c, 4))
+               if (PrintContError(misc, na, &c, 4))
                    return PRDBBAD;
            }
            return 0;
@@ -521,7 +514,7 @@ WalkNextChain(char map[],           /* one byte per db entry */
            fprintf(stderr, "Continuation entry reused\n");
            if (PrintEntryError(misc, ea, e, 2))
                return PRDBBAD;
-           if (PrintEntryError(misc, na, &c, 4))
+           if (PrintContError(misc, na, &c, 4))
                return PRDBBAD;
            noErrors = 0;
            break;
@@ -531,7 +524,7 @@ WalkNextChain(char map[],           /* one byte per db entry */
            fprintf(stderr, "Continuation id mismatch\n");
            if (PrintEntryError(misc, ea, e, 2))
                return PRDBBAD;
-           if (PrintEntryError(misc, na, &c, 4))
+           if (PrintContError(misc, na, &c, 4))
                return PRDBBAD;
            noErrors = 0;
            continue;
@@ -543,23 +536,19 @@ WalkNextChain(char map[],         /* one byte per db entry */
            if (id == PRBADID)
                continue;
            else if (id) {
-               int eid_s, id_s;
+               int id_s;
                sgcount++;
                /* 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 (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))
+                   if (PrintContError(misc, na, &c, 4))
                        return PRDBBAD;
                    noErrors = 0;
                }
@@ -586,7 +575,7 @@ WalkNextChain(char map[],           /* one byte per db entry */
                return PRDBBAD;
            if (na != head) {
                fprintf(stderr, "last block: \n");
-               if (PrintEntryError(misc, na, &c, 4))
+               if (PrintContError(misc, na, &c, 4))
                    return PRDBBAD;
            }
            return 0;
@@ -602,7 +591,7 @@ WalkNextChain(char map[],           /* one byte per db entry */
                fprintf(stderr, "walking free list");
            else if (PrintEntryError(misc, ea, e, 2))
                return PRDBBAD;
-           if (PrintEntryError(misc, na, &c, 4))
+           if (PrintContError(misc, na, &c, 4))
                return PRDBBAD;
            noErrors = 0;
            break;
@@ -614,7 +603,7 @@ WalkNextChain(char map[],           /* one byte per db entry */
                fprintf(stderr, "walking free list");
            else if (PrintEntryError(misc, ea, e, 2))
                return PRDBBAD;
-           if (PrintEntryError(misc, na, &c, 4))
+           if (PrintContError(misc, na, &c, 4))
                return PRDBBAD;
            noErrors = 0;
            continue;
@@ -644,7 +633,7 @@ WalkNextChain(char map[],           /* one byte per db entry */
                                "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))
+                       if (PrintContError(misc, na, &c, 4))
                            return PRDBBAD;
                        noErrors = 0;
                    }
@@ -654,7 +643,7 @@ WalkNextChain(char map[],           /* one byte per db entry */
                                "Bad user/group dicotomy in membership list\n");
                        if (PrintEntryError(misc, ea, e, 2))
                            return PRDBBAD;
-                       if (PrintEntryError(misc, na, &c, 4))
+                       if (PrintContError(misc, na, &c, 4))
                            return PRDBBAD;
                        noErrors = 0;
                    }
@@ -716,10 +705,10 @@ WalkOwnedChain(char map[],                /* one byte per db entry */
 {
     afs_int32 head;
     afs_int32 code;
-    struct prentry c;          /* continuation entry */
+    struct prentry te;         /* next entry in owner chain */
     afs_int32 na;              /* next thread */
     int ni;
-    afs_int32 eid;
+    afs_int32 eid = 0;
     int length;                        /* length of chain */
 
     if (e) {
@@ -729,7 +718,7 @@ WalkOwnedChain(char map[],          /* one byte per db entry */
        head = ntohl(cheader.orphan);
 
     length = 0;
-    for (na = head; na; na = ntohl(c.nextOwned)) {
+    for (na = head; na; na = ntohl(te.nextOwned)) {
        code = ConvertDiskAddress(na, &ni);
        if (code) {
            fprintf(stderr, "Bad owned list ptr %d", na);
@@ -739,23 +728,33 @@ WalkOwnedChain(char map[],                /* one byte per db entry */
                return PRDBBAD;
            if (na != head) {
                fprintf(stderr, "last block: \n");
-               if (PrintEntryError(misc, na, &c, 4))
+               if (PrintEntryError(misc, na, &te, 4))
                    return PRDBBAD;
            }
            return 0;
        }
-       code = pr_Read(na, (char *)&c, sizeof(c));
+       code = pr_Read(na, (char *)&te, sizeof(te));
        if (code)
            return code;
        length++;
 
+       if ((ntohl(te.flags) & PRTYPE) == PRCONT) {
+           fprintf(stderr, "Continuation entry found on owner chain\n");
+           if (e == 0)
+               fprintf(stderr, "walking orphan list");
+           else if (PrintEntryError(misc, ea, e, 2))
+               return PRDBBAD;
+           if (PrintEntryError(misc, na, &te, 4))
+               return PRDBBAD;
+           break;
+       }
        if (map[ni] & MAP_OWNED) {
            fprintf(stderr, "Entry on multiple owner chains\n");
            if (e == 0)
                fprintf(stderr, "walking orphan list");
            else if (PrintEntryError(misc, ea, e, 2))
                return PRDBBAD;
-           if (PrintEntryError(misc, na, &c, 4))
+           if (PrintEntryError(misc, na, &te, 4))
                return PRDBBAD;
            break;
        }
@@ -767,16 +766,16 @@ WalkOwnedChain(char map[],                /* one byte per db entry */
                fprintf(stderr, "walking orphan list");
            else if (PrintEntryError(misc, ea, e, 2))
                return PRDBBAD;
-           if (PrintEntryError(misc, na, &c, 4))
+           if (PrintEntryError(misc, na, &te, 4))
                return PRDBBAD;
            continue;
        }
        if (e) {
-           if (ntohl(c.owner) != eid) {
+           if (ntohl(te.owner) != eid) {
                fprintf(stderr, "Owner id mismatch\n");
                goto abort;
            }
-       } else /* orphan */ if (c.owner) {
+       } else /* orphan */ if (te.owner) {
            fprintf(stderr, "Orphan group owner not zero\n");
            goto abort;
        }
@@ -938,12 +937,12 @@ GC(char map[], struct misc_data *misc)
            id = ntohl(e.id);
 #if defined(SUPERGROUPS)
            if ((id != ANONYMOUSID)
-               && ((refCount = idcount(&misc->idmap, id)) != ntohl(e.count))) 
+               && ((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))) 
+                   ntohl(e.count)))
 #endif /* SUPERGROUPS */
              {
                afs_int32 na;
@@ -976,10 +975,8 @@ QuoteName(char *s)
 {
     char *qs;
     if (strpbrk(s, " \t")) {
-       qs = (char *)malloc(strlen(s) + 3);
-       strcpy(qs, "\"");
-       strcat(qs, s);
-       strcat(qs, "\"");
+       if (asprintf(&qs, "\"%s\"", s) < 0)
+           qs = "<<-OUT-OF-MEMORY->>";
     } else
        qs = s;
     return qs;
@@ -1047,9 +1044,9 @@ DumpRecreate(char map[], struct misc_data *misc)
                /* check for duplicate id.  This may still lead to duplicate
                 * names. */
 #if defined(SUPERGROUPS)
-               if (idcount(&idmap, id)) 
+               if (idcount(&idmap, id))
 #else
-               if (idmap[id - misc->minId]) 
+               if (idmap[id - misc->minId])
 #endif
                  {
                    fprintf(stderr, "Skipping entry with duplicate id %di\n",
@@ -1158,9 +1155,9 @@ DumpRecreate(char map[], struct misc_data *misc)
 
            owner = ntohl(e.owner);
 #if defined(SUPERGROUPS)
-           if (!idcount(&idmap, owner)) 
+           if (!idcount(&idmap, owner))
 #else
-           if (idmap[owner - misc->minId] == 0) 
+           if (idmap[owner - misc->minId] == 0)
 #endif
              {
                fprintf(stderr,
@@ -1187,9 +1184,6 @@ DumpRecreate(char map[], struct misc_data *misc)
            if ((id < 0) && (flags & PRGRP)) {
                int count = 0;
                afs_int32 na;
-#if defined(SUPERGROUPS)
-               afs_int32 ng;
-#endif
                int i;
                for (i = 0; i < PRSIZE; i++) {
                    afs_int32 uid = ntohl(e.entries[i]);
@@ -1208,46 +1202,9 @@ DumpRecreate(char map[], struct misc_data *misc)
                                id);
 #endif
                }
-#if defined(SUPERGROUPS)
-#define g      (*((struct prentryg *)&e))
-               ng = ntohl(g.nextsg);
-               for (i = 0; i < SGSIZE; i++) {
-                   afs_int32 uid = ntohl(g.supergroup[i]);
-                   if (uid == 0)
-                       break;
-                   if (uid == PRBADID)
-                       continue;
-                   fprintf(rc, "au %d %d\n", uid, id);
-                   count++;
-               }
-               while (ng) {
-                   struct prentry c;
-                   code = pr_Read(ng, (char *)&c, sizeof(c));
-                   if (code)
-                       return code;
-
-                   if ((id == ntohl(c.id)) && (c.flags & htonl(PRCONT))) {
-                       for (i = 0; i < COSIZE; i++) {
-                           afs_int32 uid = ntohl(c.entries[i]);
-                           if (uid == 0)
-                               break;
-                           if (uid == PRBADID)
-                               continue;
-                           fprintf(rc, "au %d %d\n", uid, id);
-                           count++;
-                       }
-                   } else {
-                       fprintf(stderr, "Skipping continuation block at %d\n",
-                               ng);
-                       break;
-                   }
-                   ng = ntohl(c.next);
-               }
-#undef g
-#endif /* SUPERGROUPS */
                na = ntohl(e.next);
                while (na) {
-                   struct prentry c;
+                   struct contentry c;
                    code = pr_Read(na, (char *)&c, sizeof(c));
                    if (code)
                        return code;
@@ -1302,15 +1259,15 @@ CheckPrDatabase(struct misc_data *misc) /* info & statistics */
     n = eof / sizeof(struct prentry);
     if ((eof < 0) || (n * sizeof(struct prentry) != eof)) {
        code = PRDBBAD;
-       afs_com_err(whoami, code, "eof ptr no good: eof=%d, sizeof(prentry)=%d",
+       afs_com_err(whoami, code,
+                   "eof ptr no good: eof=%d, sizeof(prentry)=%" AFS_SIZET_FMT,
                eof, sizeof(struct prentry));
       abort:
        return code;
     }
     if (misc->verbose)
        printf("Database has %d entries\n", n);
-    map = (char *)malloc(n);
-    memset(map, 0, n);
+    map = calloc(1, n);
     misc->nEntries = n;
 
     if (misc->verbose) {
@@ -1338,14 +1295,13 @@ CheckPrDatabase(struct misc_data *misc) /* info & statistics */
 #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));
+    misc->idmap = calloc(misc->idRange, sizeof(afs_int32));
     if (!misc->idmap) {
        afs_com_err(whoami, 0, "Unable to malloc space for max ids of %d",
                misc->idRange);
        code = -1;
        goto abort;
     }
-    memset(misc->idmap, 0, misc->idRange * sizeof(misc->idmap[0]));
 #endif /* SUPERGROUPS */
 
     if (misc->verbose) {
@@ -1429,11 +1385,11 @@ CheckPrDatabase(struct misc_data *misc) /* info & statistics */
     free(map);
     return code;
 }
-    
+
 #include "AFS_component_version_number.c"
 
 int
-WorkerBee(struct cmd_syndesc *as, char *arock)
+WorkerBee(struct cmd_syndesc *as, void *arock)
 {
     afs_int32 code;
     char *recreateFile;
@@ -1493,7 +1449,7 @@ main(int argc, char *argv[])
 
     setlinebuf(stdout);
 
-    ts = cmd_CreateSyntax(NULL, WorkerBee, NULL, "PRDB check");
+    ts = cmd_CreateSyntax(NULL, WorkerBee, NULL, 0, "PRDB check");
     cmd_AddParm(ts, "-database", CMD_SINGLE, CMD_REQUIRED, "ptdb_file");
     cmd_AddParm(ts, "-uheader", CMD_FLAG, CMD_OPTIONAL,
                "Display UBIK header");
@@ -1516,7 +1472,7 @@ void
 zeromap(struct idused *idmap)
 {
     while (idmap) {
-       bzero((char *)idmap->idcount, sizeof idmap->idcount);
+       memset(idmap->idcount, 0, sizeof idmap->idcount);
        idmap = idmap->idnext;
     }
 }
@@ -1530,18 +1486,17 @@ inccount(struct idused **idmapp, int id)
        fprintf(stderr, "IDCOUNT must be power of 2!\n");
        exit(1);
     }
-    while (idmap = *idmapp) {
+    while ((idmap = *idmapp) != NULL) {
        if (idmap->idstart == (id & ~(IDCOUNT - 1)))
            break;
        idmapp = &idmap->idnext;
     }
     if (!idmap) {
-       idmap = (struct idused *)malloc(sizeof *idmap);
+       idmap = calloc(1, sizeof *idmap);
        if (!idmap) {
            perror("idmap");
            exit(1);
        }
-       bzero((char *)idmap, sizeof idmap);
        idmap->idstart = id & ~(IDCOUNT - 1);
        idmap->idnext = *idmapp;
        *idmapp = idmap;
@@ -1558,7 +1513,7 @@ idcount(struct idused **idmapp, int id)
        fprintf(stderr, "IDCOUNT must be power of 2!\n");
        exit(1);
     }
-    while (idmap = *idmapp) {
+    while ((idmap = *idmapp) != NULL) {
        if (idmap->idstart == (id & ~(IDCOUNT - 1))) {
            return idmap->idcount[id & (IDCOUNT - 1)];
        }