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