Fix scanf buffer overflows
[openafs.git] / src / ptserver / ptclient.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12 #include <afs/stds.h>
13
14 #include <roken.h>
15 #include <afs/opr.h>
16
17 #ifdef AFS_NT40_ENV
18 #include <WINNT/afsevent.h>
19 #endif
20
21 #include <rx/xdr.h>
22 #include <rx/rx.h>
23 #include <afs/com_err.h>
24 #include <afs/cellconfig.h>
25 #include <afs/afsutil.h>
26
27 #include "ptclient.h"
28 #include "ptuser.h"
29 #include "pterror.h"
30 #include "display.h"
31
32 afs_int32 security = 0;
33 char confdir[AFSDIR_PATH_MAX];
34
35 char *whoami;
36
37 #ifndef AFS_PTHREAD_ENV
38 extern struct ubik_client *pruclient;
39 static void skip(char **);
40 static void PrintHelp(void);
41 #endif
42
43 static int ignoreExist = 0;
44 static char line[256];
45 static char *lineProgress;
46
47 #define WHITESPACE " \t\n"
48
49 #ifndef AFS_PTHREAD_ENV
50 int
51 osi_audit(void)
52 {
53 /* OK, this REALLY sucks bigtime, but I can't tell who is calling
54  * afsconf_CheckAuth easily, and only *SERVERS* should be calling osi_audit
55  * anyway.  It's gonna give somebody fits to debug, I know, I know.
56  */
57     return 0;
58 }
59 #endif /* !AFS_PTHREAD_ENV */
60
61 int
62 GetToken(char *format, afs_int32 *l)
63 {
64     int c;
65
66     *l = 0;
67     if (lineProgress == 0)
68         lineProgress = line;
69     c = sscanf(lineProgress, format, l);
70     if (c != 1)
71         return -1;
72     /* skip the white space */
73     lineProgress += strspn(lineProgress, WHITESPACE);
74     /* skip to end of token */
75     lineProgress = strpbrk(lineProgress, WHITESPACE);
76     return 0;
77 }
78
79 #define GetInt32(l) GetToken ("%d", l)
80 #define GetXInt32(l) GetToken ("%x", l)
81
82 int
83 GetString(char *s, int slen)
84 {
85     char *beg;
86     int l;
87     int code;
88
89     if (lineProgress == 0)
90         lineProgress = line;
91     /* skip the white space */
92     lineProgress += strspn(lineProgress, WHITESPACE);
93
94     /* check for quoted string and find end */
95     beg = lineProgress;
96     if (*beg == '"') {
97         l = strcspn(++beg, "\"");
98         if (l == strlen(beg))
99             return -1;          /* unbalanced quotes */
100         lineProgress = beg + l + 1;
101     } else {
102         l = strcspn(beg, WHITESPACE);
103         lineProgress += l;
104     }
105     if (l >= slen) {            /* don't return too much */
106         code = -1;
107         l = slen - 1;
108     } else
109         code = 0;
110
111     strncpy(s, beg, l);
112     s[l] = 0;                   /* null termination */
113     return code;
114 }
115
116 int
117 CodeOk(afs_int32 code)
118 {
119     if (!ignoreExist)
120         return code;
121     return code && (code != PREXIST) && (code != PRIDEXIST);
122 }
123
124 int
125 PrintEntry(afs_int32 ea, struct prentry *e, int indent)
126 {
127     /* handle screwed up versions of DumpEntry */
128     if (e->flags & PRCONT) {
129         afs_int32 id;
130
131         memcpy(&id, e->name, sizeof(id));
132         if ((id != PRBADID) && ((id > (1 << 24)) || (id < -(1 << 24)))) {
133             /* assume server incorrectly swapped these bytes... */
134             int i = 0;
135             while (i < sizeof(e->name)) {
136                 char temp;
137                 temp = e->name[i];
138                 e->name[i] = e->name[i + 3];
139                 e->name[i + 3] = temp;
140                 temp = e->name[i + 1];
141                 e->name[i + 1] = e->name[i + 2];
142                 e->name[i + 2] = temp;
143                 i += 4;
144             }
145         }
146     }
147     return pr_PrintEntry(stdout, /*host order */ 1, ea, e, indent);
148 }
149
150 #ifndef AFS_PTHREAD_ENV
151
152 /* main program */
153
154 #include "AFS_component_version_number.c"
155
156 int
157 main(int argc, char **argv)
158 {
159     afs_int32 code;
160     char op[8];
161     char name[PR_MAXNAMELEN];
162     afs_int32 id, oid = ANONYMOUSID, gid;
163     afs_int32 pos;
164     unsigned int i;
165     int n;
166     struct prentry entry;
167     prlist alist;
168     idlist lid;
169     namelist lnames;
170     struct hostent *hostinfo;
171     struct in_addr *hostaddr;
172     afs_int32 *ptr;
173     char *foo;
174     afs_int32 over;
175     char *cell;
176
177 #ifdef  AFS_AIX32_ENV
178     /*
179      * The following signal action for AIX is necessary so that in case of a
180      * crash (i.e. core is generated) we can include the user's data section
181      * in the core dump. Unfortunately, by default, only a partial core is
182      * generated which, in many cases, isn't too useful.
183      */
184     struct sigaction nsa;
185
186     sigemptyset(&nsa.sa_mask);
187     nsa.sa_handler = SIG_DFL;
188     nsa.sa_flags = SA_FULLDUMP;
189     sigaction(SIGSEGV, &nsa, NULL);
190 #endif
191     whoami = argv[0];
192
193     initialize_PT_error_table();
194
195     strcpy(confdir, AFSDIR_CLIENT_ETC_DIRPATH);
196     cell = 0;
197     n = 1;
198     while (n < argc) {
199         int arglen = strlen(argv[n]);
200         char arg[256];
201         lcstring(arg, argv[n], sizeof(arg));
202 #define IsArg(a) (strncmp (arg,a, arglen) == 0)
203         if (IsArg("-testconfdir"))
204             strncpy(confdir, argv[++n], sizeof(confdir));
205         else if (IsArg("client"))
206             strncpy(confdir, AFSDIR_CLIENT_ETC_DIRPATH, sizeof(confdir));
207         else if (IsArg("server"))
208             strncpy(confdir, AFSDIR_SERVER_ETC_DIRPATH, sizeof(confdir));
209         else if (IsArg("0") || IsArg("1") || IsArg("2"))
210             security = atoi(argv[n]);
211         else if (IsArg("-ignoreexist"))
212             ignoreExist++;
213         else if (IsArg("-cell"))
214             cell = argv[++n];
215         else {
216             printf
217                 ("Usage is: 'prclient [-testconfdir <dir> | server | client] [0 | 1 | 2] [-ignoreExist] [-cell <cellname>]\n");
218             exit(1);
219         }
220         n++;
221     }
222
223     printf("Using CellServDB file in %s\n", confdir);
224     if (security == 0)
225         printf("Making unauthenticated connection to prserver\n");
226
227     code = pr_Initialize(security, confdir, cell);
228     if (code) {
229         afs_com_err(whoami, code, "Couldn't initialize protection library");
230         exit(1);
231     }
232
233     while (1) {
234         char *s;
235
236         printf("pr> ");
237         s = fgets(line, sizeof(line), stdin);
238         if (s == NULL)
239             break;
240         lineProgress = 0;
241
242         code = GetString(op, sizeof(op));
243         if (code) {
244             afs_com_err(whoami, PRBADARG,
245                     "error reading opcode in line '%s', got '%.*s'", line,
246                     (int) sizeof(op), op);
247             exit(1);
248         }
249         if (strlen(op) == 0)
250             continue;           /* no input */
251
252         if (!strcmp(op, "cr")) {
253             if (GetString(name, sizeof(name)) || GetInt32(&id)
254                 || GetInt32(&oid))
255                 code = PRBADARG;
256             /* use ubik_Call to do the work, finding an up server and handling
257              * the job of finding a sync site, if need be */
258             else
259                 code = ubik_PR_INewEntry(pruclient, 0, name, id, oid);
260             if (CodeOk(code))
261                 afs_com_err(whoami, code, "on %s %s %d %d", op, name, id, oid);
262         } else if (!strcmp(op, "sf")) {
263             afs_int32 mask, access, gq, uq;
264             if (GetInt32(&id) || GetXInt32(&mask) || GetXInt32(&access)
265                 || GetInt32(&gq) || GetInt32(&uq))
266                 code = PRBADARG;
267             else
268                 code =
269                     ubik_PR_SetFieldsEntry(pruclient, 0, id, mask,
270                               access, gq, uq, 0, 0);
271             if (CodeOk(code))
272                 afs_com_err(whoami, code, "on %s %d %x %x %d %d", op, id, mask,
273                         access, gq, uq);
274         } else if (!strcmp(op, "ce")) {
275             char newname[PR_MAXNAMELEN];
276             afs_int32 newid;
277             if (GetInt32(&id) || GetString(newname, sizeof(newname))
278                 || GetInt32(&oid) || GetInt32(&newid))
279                 code = PRBADARG;
280             else
281                 code =
282                     ubik_PR_ChangeEntry(pruclient, 0, id, newname, oid,
283                               newid);
284             if (CodeOk(code))
285                 afs_com_err(whoami, code, "on %s %d %s %d %d", op, id, newname,
286                         oid, newid);
287         } else if (!strcmp(op, "wh")) {
288             /* scanf("%d",&id); */
289             if (GetInt32(&id))
290                 code = PRBADARG;
291             else
292                 code = ubik_PR_WhereIsIt(pruclient, 0, id, &pos);
293             if (CodeOk(code))
294                 printf("%s\n", pr_ErrorMsg(code));
295             else
296                 printf("location %d\n", pos);
297         } else if (!strcmp(op, "du")) {
298             memset(&entry, 0, sizeof(entry));
299             /* scanf("%d",&pos); */
300             if (GetInt32(&pos))
301                 code = PRBADARG;
302             else
303                 code = ubik_PR_DumpEntry(pruclient, 0, pos, (struct prdebugentry *)&entry);
304             if (CodeOk(code))
305                 printf("%s\n", pr_ErrorMsg(code));
306             if (code == PRSUCCESS) {
307                 PrintEntry(pos, &entry, /*indent */ 0);
308 #if 0
309                 printf("The contents of the entry for %d are:\n", entry.id);
310                 printf("flags %d next %d\n", entry.flags, entry.next);
311                 printf("Groups (or members) \n");
312                 for (i = 0; i < PRSIZE; i++)
313                     printf("%d\n", entry.entries[i]);
314                 printf("nextID %d nextname %d name %s\n", entry.nextID,
315                        entry.nextName, entry.name);
316                 printf("owner %d creator %d\n", entry.owner, entry.creator);
317 #endif
318             }
319         } else if (!strcmp(op, "add") || !strcmp(op, "au")) {
320             /* scanf("%d %d",&id,&gid); */
321             if (GetInt32(&id) || GetInt32(&gid))
322                 code = PRBADARG;
323             else
324                 code = ubik_PR_AddToGroup(pruclient, 0, id, gid);
325             if (CodeOk(code))
326                 afs_com_err(whoami, code, "on %s %d %d", op, id, gid);
327         } else if (!strcmp(op, "iton")) {
328             lid.idlist_val = malloc(20 * sizeof(afs_int32));
329             ptr = lid.idlist_val;
330             lid.idlist_len = 0;
331             foo = line;
332             skip(&foo);
333             while ((lid.idlist_len < 20) && (sscanf(foo, "%d", ptr) != EOF)) {
334                 lid.idlist_len++;
335                 skip(&foo);
336                 ptr++;
337             }
338             if (*foo) {
339                 fprintf(stderr, "too many values specified; max is %d\n", 20);
340             }
341             lnames.namelist_val = 0;
342             lnames.namelist_len = 0;
343             code = ubik_PR_IDToName(pruclient, 0, &lid, &lnames);
344             if (CodeOk(code))
345                 printf("%s\n", pr_ErrorMsg(code));
346             if (code == PRSUCCESS) {
347                 for (i = 0; i < lnames.namelist_len; i++) {
348                     printf("id %d name %s\n", lid.idlist_val[i],
349                            lnames.namelist_val[i]);
350                 }
351                 free(lnames.namelist_val);
352             }
353             free(lid.idlist_val);
354             lid.idlist_val = 0;
355             lid.idlist_len = 0;
356         } else if (!strcmp(op, "ntoi")) {
357             lnames.namelist_val = malloc(PR_MAXLIST * PR_MAXNAMELEN);
358             lnames.namelist_len = 0;
359             foo = line;
360             skip(&foo);
361             for (i = 0; ((lnames.namelist_len < PR_MAXLIST)
362                          && (sscanf(foo, "%63s", lnames.namelist_val[i]) !=
363                              EOF)); i++) {
364                 lnames.namelist_len++;
365                 skip(&foo);
366             }
367             if (*foo) {
368                 fprintf(stderr, "too many values specified; max is %d\n",
369                         PR_MAXLIST);
370             }
371             lid.idlist_val = 0;
372             lid.idlist_len = 0;
373             code = ubik_PR_NameToID(pruclient, 0, &lnames, &lid);
374             if (CodeOk(code))
375                 printf("%s\n", pr_ErrorMsg(code));
376             if (code == PRSUCCESS) {
377                 for (i = 0; i < lid.idlist_len; i++)
378                     printf("name %s id %d\n", lnames.namelist_val[i],
379                            lid.idlist_val[i]);
380                 free(lid.idlist_val);
381             }
382             free(lnames.namelist_val);
383             lnames.namelist_val = 0;
384             lnames.namelist_len = 0;
385         } else if (!strcmp(op, "del")) {
386             /* scanf("%d",&id); */
387             if (GetInt32(&id))
388                 code = PRBADARG;
389             else
390                 code = ubik_PR_Delete(pruclient, 0, id);
391             if (CodeOk(code))
392                 printf("%s\n", pr_ErrorMsg(code));
393         } else if (!strcmp(op, "dg")) {
394             /* scanf("%d",&id); */
395             if (GetInt32(&id))
396                 code = PRBADARG;
397             else
398                 code = ubik_PR_Delete(pruclient, 0, id);
399             if (CodeOk(code))
400                 printf("%s\n", pr_ErrorMsg(code));
401         } else if (!strcmp(op, "rm")) {
402             /* scanf("%d %d",&id,&gid); */
403             if (GetInt32(&id) || GetInt32(&gid))
404                 code = PRBADARG;
405             else
406                 code = ubik_PR_RemoveFromGroup(pruclient, 0, id, gid);
407             if (CodeOk(code))
408                 printf("%s\n", pr_ErrorMsg(code));
409         }
410 #if defined(SUPERGROUPS)
411         else if (!strcmp(op, "lsg")) {
412             alist.prlist_len = 0;
413             alist.prlist_val = 0;
414             /* scanf("%d",&id); */
415             if (GetInt32(&id))
416                 code = PRBADARG;
417             else
418                 code =
419                     ubik_PR_ListSuperGroups(pruclient, 0, id, &alist,
420                               &over);
421             if (CodeOk(code))
422                 printf("%s\n", pr_ErrorMsg(code));
423             if (code == PRSUCCESS) {
424                 ptr = alist.prlist_val;
425                 if (over) {
426                     printf("Number of groups greater than PR_MAXGROUPS!\n");
427                     printf("Excess of %d.\n", over);
428                 }
429                 for (i = 0; i < alist.prlist_len; i++, ptr++)
430                     printf("%d\n", *ptr);
431                 free(alist.prlist_val);
432                 alist.prlist_len = 0;
433                 alist.prlist_val = 0;
434             }
435         }
436 #endif /* SUPERGROUPS */
437         else if (!strcmp(op, "l")) {
438             alist.prlist_len = 0;
439             alist.prlist_val = 0;
440             /* scanf("%d",&id); */
441             if (GetInt32(&id))
442                 code = PRBADARG;
443             else
444                 code = ubik_PR_GetCPS(pruclient, 0, id, &alist, &over);
445             if (CodeOk(code))
446                 printf("%s\n", pr_ErrorMsg(code));
447             if (code == PRSUCCESS) {
448                 ptr = alist.prlist_val;
449                 if (over) {
450                     printf("Number of groups greater than PR_MAXGROUPS!\n");
451                     printf("Excess of %d.\n", over);
452                 }
453                 for (i = 0; i < alist.prlist_len; i++, ptr++)
454                     printf("%d\n", *ptr);
455                 free(alist.prlist_val);
456                 alist.prlist_len = 0;
457                 alist.prlist_val = 0;
458             }
459         } else if (!strcmp(op, "lh")) {
460             alist.prlist_len = 0;
461             alist.prlist_val = 0;
462             /* scanf("%d",&id); */
463             if (GetString(name, sizeof(name)))
464                 code = PRBADARG;
465             else if (!(hostinfo = gethostbyname(name)))
466                 code = PRBADARG;
467             else {
468                 hostaddr = (struct in_addr *)hostinfo->h_addr_list[0];
469                 id = ntohl(hostaddr->s_addr);
470                 code =
471                     ubik_PR_GetHostCPS(pruclient, 0, id, &alist, &over);
472             }
473             if (CodeOk(code))
474                 printf("%s\n", pr_ErrorMsg(code));
475             if (code == PRSUCCESS) {
476                 ptr = alist.prlist_val;
477                 if (over) {
478                     printf("Number of groups greater than PR_MAXGROUPS!\n");
479                     printf("Excess of %d.\n", over);
480                 }
481                 for (i = 0; i < alist.prlist_len; i++, ptr++)
482                     printf("%d\n", *ptr);
483                 free(alist.prlist_val);
484                 alist.prlist_len = 0;
485                 alist.prlist_val = 0;
486             }
487         }
488 #if defined(SUPERGROUPS)
489         else if (!strcmp(op, "m")) {
490             alist.prlist_len = 0;
491             alist.prlist_val = 0;
492             /* scanf("%d",&id); */
493             if (GetInt32(&id))
494                 code = PRBADARG;
495             else
496                 code =
497                     ubik_PR_ListElements(pruclient, 0, id, &alist,
498                               &over);
499             if (CodeOk(code))
500                 printf("%s\n", pr_ErrorMsg(code));
501             if (code == PRSUCCESS) {
502                 ptr = alist.prlist_val;
503                 if (over) {
504                     printf("Number of groups greater than PR_MAXGROUPS!\n");
505                     printf("Excess of %d.\n", over);
506                 }
507                 for (i = 0; i < alist.prlist_len; i++, ptr++)
508                     printf("%d\n", *ptr);
509                 free(alist.prlist_val);
510                 alist.prlist_len = 0;
511                 alist.prlist_val = 0;
512             }
513         }
514 #endif /* SUPERGROUPS */
515         else if (!strcmp(op, "nu")) {
516             /* scanf("%s",name); */
517             if (GetString(name, sizeof(name)))
518                 code = PRBADARG;
519             else
520                 code = pr_CreateUser(name, &id);
521             if (CodeOk(code))
522                 printf("%s\n", pr_ErrorMsg(code));
523             if (code == PRSUCCESS)
524                 printf("Id is %d.\n", id);
525         } else if (!strcmp(op, "ng")) {
526             /* scanf("%s",name); */
527             if (GetString(name, sizeof(name)))
528                 code = PRBADARG;
529             else
530                 code = ubik_PR_NewEntry(pruclient, 0, name, 1, oid, &id);
531             if (CodeOk(code))
532                 printf("%s\n", pr_ErrorMsg(code));
533             if (code == PRSUCCESS)
534                 printf("Id is %d.\n", id);
535         } else if (!strcmp(op, "lm")) {
536             code = ubik_PR_ListMax(pruclient, 0, &id, &gid);
537             if (CodeOk(code))
538                 printf("%s\n", pr_ErrorMsg(code));
539             if (code == PRSUCCESS)
540                 printf("Max user id is %d, max (really min) group is %d.\n",
541                        id, gid);
542         } else if (!strcmp(op, "smu")) {
543             /* scanf("%d",&id); */
544             if (GetInt32(&id))
545                 code = PRBADARG;
546             else
547                 code = ubik_PR_SetMax(pruclient, 0, id, 0);
548             if (CodeOk(code))
549                 printf("%s\n", pr_ErrorMsg(code));
550         } else if (!strcmp(op, "smg")) {
551             /* scanf("%d",&id); */
552             if (GetInt32(&id))
553                 code = PRBADARG;
554             else
555                 code = ubik_PR_SetMax(pruclient, 0, id, 1);
556             if (CodeOk(code))
557                 printf("%s\n", pr_ErrorMsg(code));
558         } else if (!strcmp(op, "sin")) {
559             /* scanf("%d",&id); */
560             if (GetInt32(&id))
561                 code = PRBADARG;
562             else
563                 code = pr_SIdToName(id, name);
564             if (CodeOk(code))
565                 printf("%s\n", pr_ErrorMsg(code));
566             if (code == PRSUCCESS)
567                 printf("id %d name %s\n", id, name);
568         } else if (!strcmp(op, "sni")) {
569             /* scanf("%s",name); */
570             if (GetString(name, sizeof(name)))
571                 code = PRBADARG;
572             else
573                 code = pr_SNameToId(name, &id);
574             if (CodeOk(code))
575                 printf("%s\n", pr_ErrorMsg(code));
576             if (code == PRSUCCESS)
577                 printf("name %s id %d\n", name, id);
578         } else if (!strcmp(op, "fih")) {
579             char tname[128];
580             struct PrUpdateEntry uentry;
581             memset(&uentry, 0, sizeof(uentry));
582             /* scanf("%s",name); */
583             if (GetString(name, sizeof(name))) {
584                 code = PRBADARG;
585                 continue;
586             }
587             code = pr_SNameToId(name, &id);
588             if (CodeOk(code)) {
589                 printf("%s\n", pr_ErrorMsg(code));
590                 continue;
591             }
592             code = pr_SIdToName(id, tname);
593             if (code == PRSUCCESS) {
594                 printf
595                     ("Warning: Id hash for %s (id %d) seems correct at the db; rehashing it anyway\n",
596                      name, id);
597 /*              continue;*/
598             }
599             uentry.Mask = PRUPDATE_IDHASH;
600             code = ubik_PR_UpdateEntry(pruclient, 0, 0, name, &uentry);
601             if (code) {
602                 printf("Failed to update entry %s (err=%d)\n", name, code);
603                 continue;
604             }
605         } else if (!strcmp(op, "fnh")) {
606             int tid;
607             struct PrUpdateEntry uentry;
608             memset(&uentry, 0, sizeof(uentry));
609             /* scanf("%d", &id); */
610             if (GetInt32(&id)) {
611                 code = PRBADARG;
612                 continue;
613             }
614             code = pr_SIdToName(id, name);
615             if (CodeOk(code)) {
616                 printf("%s\n", pr_ErrorMsg(code));
617                 continue;
618             }
619             code = pr_SNameToId(name, &tid);
620             if (code == PRSUCCESS) {
621                 printf
622                     ("Name hash for %d (name is %s) seems correct at the db; rehashing it anyway\n",
623                      id, name);
624 /*              continue;*/
625             }
626             uentry.Mask = PRUPDATE_NAMEHASH;
627             code =
628                 ubik_PR_UpdateEntry(pruclient, 0, id, "_foo_", &uentry);
629             if (code) {
630                 printf("Failed to update entry with id %d (err=%d)\n", id,
631                        code);
632                 continue;
633             }
634         }
635 #if defined(SUPERGROUPS)
636         else if (!strcmp(op, "fih")) {
637             char tname[128];
638             struct PrUpdateEntry uentry;
639             memset(&uentry, 0, sizeof(uentry));
640             /* scanf("%s",name); */
641             if (GetString(name, sizeof(name))) {
642                 code = PRBADARG;
643                 continue;
644             }
645             code = pr_SNameToId(name, &id);
646             if (CodeOk(code)) {
647                 printf("%s\n", pr_ErrorMsg(code));
648                 continue;
649             }
650             code = pr_SIdToName(id, tname);
651             if (code == PRSUCCESS) {
652                 printf
653                     ("Warning: Id hash for %s (id %d) seems correct at the db; rehashing it anyway\n",
654                      name, id);
655 /*              continue;*/
656             }
657             uentry.Mask = PRUPDATE_IDHASH;
658             code = ubik_PR_UpdateEntry(pruclient, 0, 0, name, &uentry);
659             if (code) {
660                 printf("Failed to update entry %s (err=%d)\n", name, code);
661                 continue;
662             }
663         } else if (!strcmp(op, "fnh")) {
664             int tid;
665             struct PrUpdateEntry uentry;
666             memset(&uentry, 0, sizeof(uentry));
667             /* scanf("%d", &id); */
668             if (GetInt32(&id)) {
669                 code = PRBADARG;
670                 continue;
671             }
672             code = pr_SIdToName(id, name);
673             if (CodeOk(code)) {
674                 printf("%s\n", pr_ErrorMsg(code));
675                 continue;
676             }
677             code = pr_SNameToId(name, &tid);
678             if (code == PRSUCCESS) {
679                 printf
680                     ("Name hash for %d (name is %s) seems correct at the db; rehashing it anyway\n",
681                      id, name);
682 /*              continue;*/
683             }
684             uentry.Mask = PRUPDATE_NAMEHASH;
685             code =
686                 ubik_PR_UpdateEntry(pruclient, 0, id, "_foo_", &uentry);
687             if (code) {
688                 printf("Failed to update entry with id %d (err=%d)\n", id,
689                        code);
690                 continue;
691             }
692         }
693 #endif /* SUPERGROUPS */
694         else if (!strcmp(op, "?"))
695             PrintHelp();
696         else if (!strcmp(op, "q"))
697             exit(0);
698         else
699             printf("Unknown op: '%s'! ? for help\n", op);
700     }
701     return 0;
702 }
703
704
705 static void
706 PrintHelp(void)
707 {
708     printf("cr name id owner - create entry with name and id.\n");
709     printf("wh id  - what is the offset into database for id?\n");
710     printf("du offset - dump the contents of the entry at offset.\n");
711     printf("add uid gid - add user uid to group gid.\n");
712     printf("iton id* - translate the list of id's to names.\n");
713     printf("ntoi name* - translate the list of names to ids.\n");
714     printf("del id - delete the entry for id.\n");
715     printf("dg gid - delete the entry for group gid.\n");
716     printf("rm id gid - remove user id from group gid.\n");
717     printf("l id - get the CPS for id.\n");
718     printf("lh host - get the host CPS for host.\n");
719 #if defined(SUPERGROUPS)
720     printf("lsg id - get the supergroups for id.\n");
721     printf("m id - list elements for id.\n");
722 #endif
723     printf("nu name - create new user with name - returns an id.\n");
724     printf("ng name - create new group with name - returns an id.\n");
725     printf("lm  - list max user id and max (really min) group id.\n");
726     printf("smu - set max user id.\n");
727     printf("smg - set max group id.\n");
728     printf("sin id - single iton.\n");
729     printf("sni name - single ntoi.\n");
730     printf("fih name - fix id hash for <name>.\n");
731     printf("fnh id - fix name hash for <id>.\n");
732     printf("q - quit.\n?- this message.\n");
733 }
734
735 static void
736 skip(char **s)
737 {
738     while (**s != ' ' && **s != '\0')
739         (*s)++;
740     while (**s == ' ')
741         (*s)++;
742 }
743 #endif /* !AFS_PTHREAD_ENV */