ptutil-use-libcmd-20030808
[openafs.git] / src / ptserver / pt_util.c
1 /* $Id$ */
2
3 /*
4  *
5  * pt_util: Program to dump the AFS protection server database
6  *         into an ascii file.
7  *
8  *      Assumptions: We *cheat* here and read the datafile directly, ie.
9  *                   not going through the ubik distributed data manager.
10  *                   therefore the database must be quiescent for the
11  *                   output of this program to be valid.
12  */
13
14 #include <sys/types.h>
15 #include <sys/time.h>
16 #include <stdio.h>
17 #include <ctype.h>
18 #include <string.h>
19 #include <errno.h>
20 #include <sys/file.h>
21
22 #include <afsconfig.h>
23 #include <afs/param.h>
24
25 RCSID
26     ("$Header$");
27
28 #include <afs/cmd.h>            /*Command line parsing */
29 #include <errno.h>
30 #include <lock.h>
31 #include <netinet/in.h>
32 #define UBIK_INTERNALS
33 #include <ubik.h>
34 #include <rx/xdr.h>
35 #include <rx/rx.h>
36 #include "ptint.h"
37 #include "ptserver.h"
38 #include "pterror.h"
39
40 #define IDHash(x) (abs(x) % HASHSIZE)
41 #define print_id(x) ( ((flags&DO_SYS)==0 && (x<-32767 || x>97536)) || \
42                       ((flags&DO_OTR)==0 && (x>-32768 && x<97537)))
43
44 extern char *optarg;
45 extern int optind;
46
47 int display_entry();
48 void add_group();
49 void display_groups();
50 void display_group();
51 void fix_pre();
52 char *checkin();
53 char *check_core();
54 char *id_to_name();
55 int CommandProc(struct cmd_syndesc *);
56
57 struct hash_entry {
58     char h_name[PR_MAXNAMELEN];
59     int h_id;
60     struct hash_entry *next;
61 };
62 struct hash_entry *hat[HASHSIZE];
63
64 static struct contentry prco;
65 static struct prentry pre;
66 static struct prheader prh;
67 static struct ubik_version uv;
68
69 struct grp_list {
70     struct grp_list *next;
71     long groups[1024];
72 };
73 static struct grp_list *grp_head = 0;
74 static long grp_count = 0;
75
76 struct usr_list {
77     struct usr_list *next;
78     char name[PR_MAXNAMELEN];
79     long uid;
80 };
81 static struct usr_list *usr_head = 0;
82
83 char buffer[1024];
84 int dbase_fd;
85 FILE *dfp;
86
87 #define FMT_BASE "%-10s %d/%d %d %d %d\n"
88 #define FMT_MEM  "   %-8s %d\n"
89
90 #define DO_USR 1
91 #define DO_GRP 2
92 #define DO_MEM 4
93 #define DO_SYS 8
94 #define DO_OTR 16
95
96 int nflag = 0;
97 int wflag = 0;
98 int flags = 0;
99
100 main(argc, argv)
101      int argc;
102      char **argv;
103 {
104
105     register struct cmd_syndesc *cs;    /*Command line syntax descriptor */
106     register afs_int32 code;    /*Return code */
107
108     cs = cmd_CreateSyntax((char *)0, CommandProc, 0,
109                           "access protection database");
110     cmd_AddParm(cs, "-w", CMD_FLAG, CMD_OPTIONAL,
111                 "update prdb with contents of data file");
112     cmd_AddParm(cs, "-user", CMD_FLAG, CMD_OPTIONAL, "display users");
113     cmd_AddParm(cs, "-group", CMD_FLAG, CMD_OPTIONAL, "display groups");
114     cmd_AddParm(cs, "-members", CMD_FLAG, CMD_OPTIONAL,
115                 "display group members");
116     cmd_AddParm(cs, "-name", CMD_FLAG, CMD_OPTIONAL,
117                 "follow name hash chains (not id hashes)");
118     cmd_AddParm(cs, "-system", CMD_FLAG, CMD_OPTIONAL,
119                 "display only system data");
120     cmd_AddParm(cs, "-xtra", CMD_FLAG, CMD_OPTIONAL,
121                 "display extra users/groups");
122     cmd_Seek(cs, 10);
123     cmd_AddParm(cs, "-prdb", CMD_SINGLE, CMD_OPTIONAL, "prdb file");
124     cmd_AddParm(cs, "-datafile", CMD_SINGLE, CMD_OPTIONAL, "data file");
125     code = cmd_Dispatch(argc, argv);
126
127     exit(code);
128
129 }
130
131 int
132 CommandProc(a_as)
133      register struct cmd_syndesc *a_as;
134 {
135     register int i;
136     register long code;
137     long cc, upos, gpos;
138     struct prentry uentry, gentry;
139     struct ubik_hdr *uh;
140     char *dfile = 0;
141     char *pfile = "/usr/afs/db/prdb.DB0";
142     struct cmd_parmdesc *tparm;
143
144     tparm = a_as->parms;
145
146     if (tparm[0].items) {
147         wflag++;
148     }
149     if (tparm[1].items) {
150         flags |= DO_USR;
151     }
152     if (tparm[2].items) {
153         flags |= DO_GRP;
154     }
155     if (tparm[3].items) {
156         flags |= (DO_GRP | DO_MEM);
157     }
158     if (tparm[4].items) {
159         nflag++;
160     }
161     if (tparm[5].items) {
162         flags |= DO_SYS;
163     }
164     if (tparm[6].items) {
165         flags |= DO_OTR;
166     }
167     if (tparm[7].items) {
168         pfile = tparm[7].items->data;
169     }
170     if (tparm[8].items) {
171         dfile = tparm[8].items->data;
172     }
173
174     if ((dbase_fd = open(pfile, (wflag ? O_RDWR : O_RDONLY) | O_CREAT, 0600))
175         < 0) {
176         fprintf(stderr, "pt_util: cannot open %s: %s\n", pfile,
177                 strerror(errno));
178         exit(1);
179     }
180     if (read(dbase_fd, buffer, HDRSIZE) < 0) {
181         fprintf(stderr, "pt_util: error reading %s: %s\n", pfile,
182                 strerror(errno));
183         exit(1);
184     }
185
186     if (dfile) {
187         if ((dfp = fopen(dfile, wflag ? "r" : "w")) == 0) {
188             fprintf(stderr, "pt_util: error opening %s: %s\n", dfile,
189                     strerror(errno));
190             exit(1);
191         }
192     } else
193         dfp = (wflag ? stdin : stdout);
194
195     uh = (struct ubik_hdr *)buffer;
196     if (ntohl(uh->magic) != UBIK_MAGIC)
197         fprintf(stderr, "pt_util: %s: Bad UBIK_MAGIC. Is %x should be %x\n",
198                 pfile, ntohl(uh->magic), UBIK_MAGIC);
199     memcpy(&uv, &uh->version, sizeof(struct ubik_version));
200     if (wflag && uv.epoch == 0 && uv.counter == 0) {
201         uv.epoch = 2;           /* a ubik version of 0 or 1 has special meaning */
202         memcpy(&uh->version, &uv, sizeof(struct ubik_version));
203         lseek(dbase_fd, 0, SEEK_SET);
204         if (write(dbase_fd, buffer, HDRSIZE) < 0) {
205             fprintf(stderr, "pt_util: error writing ubik version to %s: %s\n",
206                     pfile, strerror(errno));
207             exit(1);
208         }
209     }
210     fprintf(stderr, "Ubik Version is: %d.%d\n", uv.epoch, uv.counter);
211     if (read(dbase_fd, &prh, sizeof(struct prheader)) < 0) {
212         fprintf(stderr, "pt_util: error reading %s: %s\n", pfile,
213                 strerror(errno));
214         exit(1);
215     }
216
217     Initdb();
218     initialize_PT_error_table();
219
220     if (wflag) {
221         struct usr_list *u;
222
223         while (fgets(buffer, sizeof(buffer), dfp)) {
224             int id, oid, cid, flags, quota, uid;
225             char name[PR_MAXNAMELEN], mem[PR_MAXNAMELEN];
226
227             if (isspace(*buffer)) {
228                 sscanf(buffer, "%s %d", mem, &uid);
229
230                 for (u = usr_head; u; u = u->next)
231                     if (u->uid && u->uid == uid)
232                         break;
233                 if (u) {
234                     /* Add user - deferred because it is probably foreign */
235                     u->uid = 0;
236                     if (FindByID(0, uid))
237                         code = PRIDEXIST;
238                     else {
239                         if (!code
240                             && (flags & (PRGRP | PRQUOTA)) ==
241                             (PRGRP | PRQUOTA)) {
242                             gentry.ngroups++;
243                             code = pr_WriteEntry(0, 0, gpos, &gentry);
244                             if (code)
245                                 fprintf(stderr,
246                                         "Error setting group count on %s: %s\n",
247                                         name, error_message(code));
248                         }
249                         code = CreateEntry(0, u->name, &uid, 1 /*idflag */ ,
250                                            1 /*gflag */ ,
251                                            SYSADMINID /*oid */ ,
252                                            SYSADMINID /*cid */ );
253                     }
254                     if (code)
255                         fprintf(stderr, "Error while creating %s: %s\n",
256                                 u->name, error_message(code));
257                     continue;
258                 }
259                 /* Add user to group */
260                 if (id == ANYUSERID || id == AUTHUSERID || uid == ANONYMOUSID) {
261                     code = PRPERM;
262                 } else if ((upos = FindByID(0, uid))
263                            && (gpos = FindByID(0, id))) {
264                     code = pr_ReadEntry(0, 0, upos, &uentry);
265                     if (!code)
266                         code = pr_ReadEntry(0, 0, gpos, &gentry);
267                     if (!code)
268                         code = AddToEntry(0, &gentry, gpos, uid);
269                     if (!code)
270                         code = AddToEntry(0, &uentry, upos, id);
271                 } else
272                     code = PRNOENT;
273
274                 if (code)
275                     fprintf(stderr, "Error while adding %s to %s: %s\n", mem,
276                             name, error_message(code));
277             } else {
278                 sscanf(buffer, "%s %d/%d %d %d %d", name, &flags, &quota, &id,
279                        &oid, &cid);
280
281                 if (FindByID(0, id))
282                     code = PRIDEXIST;
283                 else
284                     code = CreateEntry(0, name, &id, 1 /*idflag */ ,
285                                        flags & PRGRP, oid, cid);
286                 if (code == PRBADNAM) {
287                     u = (struct usr_list *)malloc(sizeof(struct usr_list));
288                     u->next = usr_head;
289                     u->uid = id;
290                     strcpy(u->name, name);
291                     usr_head = u;
292                 } else if (code) {
293                     fprintf(stderr, "Error while creating %s: %s\n", name,
294                             error_message(code));
295                 } else if ((flags & PRACCESS)
296                            || (flags & (PRGRP | PRQUOTA)) ==
297                            (PRGRP | PRQUOTA)) {
298                     gpos = FindByID(0, id);
299                     code = pr_ReadEntry(0, 0, gpos, &gentry);
300                     if (!code) {
301                         gentry.flags = flags;
302                         gentry.ngroups = quota;
303                         code = pr_WriteEntry(0, 0, gpos, &gentry);
304                     }
305                     if (code)
306                         fprintf(stderr,
307                                 "Error while setting flags on %s: %s\n", name,
308                                 error_message(code));
309                 }
310             }
311         }
312         for (u = usr_head; u; u = u->next)
313             if (u->uid)
314                 fprintf(stderr, "Error while creating %s: %s\n", u->name,
315                         error_message(PRBADNAM));
316     } else {
317         for (i = 0; i < HASHSIZE; i++) {
318             upos = nflag ? ntohl(prh.nameHash[i]) : ntohl(prh.idHash[i]);
319             while (upos)
320                 upos = display_entry(upos);
321         }
322         if (flags & DO_GRP)
323             display_groups();
324     }
325
326     lseek(dbase_fd, 0, L_SET);  /* rewind to beginning of file */
327     if (read(dbase_fd, buffer, HDRSIZE) < 0) {
328         fprintf(stderr, "pt_util: error reading %s: %s\n", pfile,
329                 strerror(errno));
330         exit(1);
331     }
332     uh = (struct ubik_hdr *)buffer;
333     if ((uh->version.epoch != uv.epoch)
334         || (uh->version.counter != uv.counter)) {
335         fprintf(stderr,
336                 "pt_util: Ubik Version number changed during execution.\n");
337         fprintf(stderr, "Old Version = %d.%d, new version = %d.%d\n",
338                 uv.epoch, uv.counter, uh->version.epoch, uh->version.counter);
339     }
340     close(dbase_fd);
341     exit(0);
342 }
343
344 int
345 display_entry(offset)
346      int offset;
347 {
348     register int i;
349
350     lseek(dbase_fd, offset + HDRSIZE, L_SET);
351     read(dbase_fd, &pre, sizeof(struct prentry));
352
353     fix_pre(&pre);
354
355     if ((pre.flags & PRFREE) == 0) {
356         if (pre.flags & PRGRP) {
357             if (flags & DO_GRP)
358                 add_group(pre.id);
359         } else {
360             if (print_id(pre.id) && (flags & DO_USR))
361                 fprintf(dfp, FMT_BASE, pre.name, pre.flags, pre.ngroups,
362                         pre.id, pre.owner, pre.creator);
363             checkin(&pre);
364         }
365     }
366     return (nflag ? pre.nextName : pre.nextID);
367 }
368
369 void
370 add_group(id)
371      long id;
372 {
373     struct grp_list *g;
374     register long i;
375
376     i = grp_count++ % 1024;
377     if (i == 0) {
378         g = (struct grp_list *)malloc(sizeof(struct grp_list));
379         g->next = grp_head;
380         grp_head = g;
381     }
382     g = grp_head;
383     g->groups[i] = id;
384 }
385
386 void
387 display_groups()
388 {
389     register int i, id;
390     struct grp_list *g;
391
392     g = grp_head;
393     while (grp_count--) {
394         i = grp_count % 1024;
395         id = g->groups[i];
396         display_group(id);
397         if (i == 0) {
398             grp_head = g->next;
399             free(g);
400             g = grp_head;
401         }
402     }
403 }
404
405 void
406 display_group(id)
407      int id;
408 {
409     register int i, offset;
410     int print_grp = 0;
411
412     offset = ntohl(prh.idHash[IDHash(id)]);
413     while (offset) {
414         lseek(dbase_fd, offset + HDRSIZE, L_SET);
415         if (read(dbase_fd, &pre, sizeof(struct prentry)) < 0) {
416             fprintf(stderr, "pt_util: read i/o error: %s\n", strerror(errno));
417             exit(1);
418         }
419         fix_pre(&pre);
420         if (pre.id == id)
421             break;
422         offset = pre.nextID;
423     }
424
425     if (print_id(id)) {
426         fprintf(dfp, FMT_BASE, pre.name, pre.flags, pre.ngroups, pre.id,
427                 pre.owner, pre.creator);
428         print_grp = 1;
429     }
430
431     if ((flags & DO_MEM) == 0)
432         return;
433
434     for (i = 0; i < PRSIZE; i++) {
435         if ((id = pre.entries[i]) == 0)
436             break;
437         if (id == PRBADID)
438             continue;
439         if (print_id(id) || print_grp == 1) {
440             if (print_grp == 0) {
441                 fprintf(dfp, FMT_BASE, pre.name, pre.flags, pre.ngroups,
442                         pre.id, pre.owner, pre.creator);
443                 print_grp = 2;
444             }
445             fprintf(dfp, FMT_MEM, id_to_name(id), id);
446         }
447     }
448     if (i == PRSIZE) {
449         offset = pre.next;
450         while (offset) {
451             lseek(dbase_fd, offset + HDRSIZE, L_SET);
452             read(dbase_fd, &prco, sizeof(struct contentry));
453             prco.next = ntohl(prco.next);
454             for (i = 0; i < COSIZE; i++) {
455                 prco.entries[i] = ntohl(prco.entries[i]);
456                 if ((id = prco.entries[i]) == 0)
457                     break;
458                 if (id == PRBADID)
459                     continue;
460                 if (print_id(id) || print_grp == 1) {
461                     if (print_grp == 0) {
462                         fprintf(dfp, FMT_BASE, pre.name, pre.flags,
463                                 pre.ngroups, pre.id, pre.owner, pre.creator);
464                         print_grp = 2;
465                     }
466                     fprintf(dfp, FMT_MEM, id_to_name(id), id);
467                 }
468             }
469             if ((i == COSIZE) && prco.next)
470                 offset = prco.next;
471             else
472                 offset = 0;
473         }
474     }
475 }
476
477 void
478 fix_pre(pre)
479      struct prentry *pre;
480 {
481     register int i;
482
483     pre->flags = ntohl(pre->flags);
484     pre->id = ntohl(pre->id);
485     pre->cellid = ntohl(pre->cellid);
486     pre->next = ntohl(pre->next);
487     pre->nextID = ntohl(pre->nextID);
488     pre->nextName = ntohl(pre->nextName);
489     pre->owner = ntohl(pre->owner);
490     pre->creator = ntohl(pre->creator);
491     pre->ngroups = ntohl(pre->ngroups);
492     pre->nusers = ntohl(pre->nusers);
493     pre->count = ntohl(pre->count);
494     pre->instance = ntohl(pre->instance);
495     pre->owned = ntohl(pre->owned);
496     pre->nextOwned = ntohl(pre->nextOwned);
497     pre->parent = ntohl(pre->parent);
498     pre->sibling = ntohl(pre->sibling);
499     pre->child = ntohl(pre->child);
500     for (i = 0; i < PRSIZE; i++) {
501         pre->entries[i] = ntohl(pre->entries[i]);
502     }
503 }
504
505 char *
506 id_to_name(id)
507      int id;
508 {
509     register int offset;
510     static struct prentry pre;
511     char *name;
512
513     name = check_core(id);
514     if (name)
515         return (name);
516     offset = ntohl(prh.idHash[IDHash(id)]);
517     while (offset) {
518         lseek(dbase_fd, offset + HDRSIZE, L_SET);
519         if (read(dbase_fd, &pre, sizeof(struct prentry)) < 0) {
520             fprintf(stderr, "pt_util: read i/o error: %s\n", strerror(errno));
521             exit(1);
522         }
523         pre.id = ntohl(pre.id);
524         if (pre.id == id) {
525             name = checkin(&pre);
526             return (name);
527         }
528         offset = ntohl(pre.nextID);
529     }
530     return 0;
531 }
532
533 char *
534 checkin(pre)
535      struct prentry *pre;
536 {
537     struct hash_entry *he, *last;
538     register int id;
539
540     id = pre->id;
541     last = (struct hash_entry *)0;
542     he = hat[IDHash(id)];
543     while (he) {
544         if (id == he->h_id)
545             return (he->h_name);
546         last = he;
547         he = he->next;
548     }
549     he = (struct hash_entry *)malloc(sizeof(struct hash_entry));
550     if (he == 0) {
551         fprintf(stderr, "pt_util: No Memory for internal hash table.\n");
552         exit(1);
553     }
554     he->h_id = id;
555     he->next = (struct hash_entry *)0;
556     strncpy(he->h_name, pre->name, PR_MAXNAMELEN);
557     if (last == (struct hash_entry *)0)
558         hat[IDHash(id)] = he;
559     else
560         last->next = he;
561     return (he->h_name);
562 }
563
564 char *
565 check_core(id)
566      register int id;
567 {
568     struct hash_entry *he;
569     he = hat[IDHash(id)];
570     while (he) {
571         if (id == he->h_id)
572             return (he->h_name);
573         he = he->next;
574     }
575     return 0;
576 }