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