]> andersk Git - moira.git/blob - clients/blanche/blanche.c
don't fail to start if user not found in db
[moira.git] / clients / blanche / blanche.c
1 /* $Header$
2  *
3  * Command line oriented Moira List tool.
4  *
5  * by Mark Rosenstein, September 1988.
6  *
7  * Copyright 1989 by the Massachusetts Institute of Technology.
8  *
9  * (c) Copyright 1988 by the Massachusetts Institute of Technology.
10  * For copying and distribution information, please see the file
11  * <mit-copyright.h>.
12  */
13
14 /* ### Aren't there a lot of sq abstraction barrier violations here?
15    Do we need to improve the support for queue operations? */
16
17 #include <mit-copyright.h>
18 #include <stdio.h>
19 #include <ctype.h>
20 #include <moira.h>
21 #include <moira_site.h>
22
23 #ifndef LINT
24 static char blanche_rcsid[] = "$Header$";
25 #endif
26
27
28 struct member {
29     int type;
30     char *name;
31 };
32
33 /* It is important to membercmp that M_USER < M_LIST < M_STRING */
34 #define M_ANY           0
35 #define M_USER          1
36 #define M_LIST          2
37 #define M_STRING        3
38 #define M_KERBEROS      4
39
40 /* argument parsing macro */
41 #define argis(a,b) ((strcmp(*arg+1, a) == 0) || (strcmp(*arg+1, b) == 0))
42
43 /* flags from command line */
44 int infoflg, verbose, syncflg, memberflg, recursflg, debugflg, noauth;
45 int showusers, showstrings, showkerberos, showlists;
46
47 /* various member lists */
48 struct save_queue *addlist, *dellist, *memberlist, *synclist;
49
50 char *listname, *whoami;
51
52 extern char *index();
53 extern int errno;
54
55 int show_list_info(), show_list_count(), get_list_members(), scream();
56 int show_list_members();
57 struct member *parse_member();
58
59
60
61 main(argc, argv)
62 int argc;
63 char **argv;
64 {
65     int status;
66     char **arg = argv;
67     char *membervec[3], *motd;
68     struct member *memberstruct;
69     char *server = NULL;
70
71     /* clear all flags & lists */
72     infoflg = verbose = syncflg = memberflg = debugflg = recursflg = 0;
73     noauth = showusers = showstrings = showkerberos = showlists = 0;
74     listname = NULL;
75     addlist = sq_create();
76     dellist = sq_create();
77     memberlist = sq_create();
78     synclist = sq_create();
79     whoami = argv[0];
80
81     /* parse args, building addlist, dellist, & synclist */
82     while (++arg - argv < argc) {
83         if  (**arg == '-')
84         {
85             if (argis("m", "members"))
86                 memberflg++;
87             else if (argis("u", "users"))
88                 showusers++;
89             else if (argis("s", "strings"))
90                 showstrings++;
91             else if (argis("l", "lists"))
92                 showlists++;
93             else if (argis("k", "kerberos"))
94                 showkerberos++;
95             else if (argis("D", "debug"))
96                 debugflg++;
97             else if (argis("i","info"))
98               infoflg++;
99             else if (argis("n","noauth"))
100               noauth++;
101             else if (argis("v","verbose"))
102               verbose++;
103             else if (argis("r","recursive"))
104               recursflg++;
105             else if (argis("S","server"))
106                 if (arg - argv < argc - 1) {
107                     ++arg;
108                     server = *arg;
109                 } else
110                     usage(argv);
111             else if (argis("a","add"))
112                 if (arg - argv < argc - 1) {
113                     ++arg;
114                     if (memberstruct = parse_member(*arg))
115                         sq_save_data(addlist, memberstruct);
116                 } else
117                     usage(argv);
118             else if (argis("d","delete"))
119                 if (arg - argv < argc - 1) {
120                     ++arg;
121                     if (memberstruct = parse_member(*arg))
122                         sq_save_data(dellist, memberstruct);
123                 } else
124                     usage(argv);
125             else if (argis("f","file"))
126                 if (arg - argv < argc - 1) {
127                     FILE *in;
128                     char buf[BUFSIZ];
129
130                     syncflg++;
131                     ++arg;
132                     if (!strcmp(*arg, "-"))
133                       in = stdin;
134                     else {
135                         in = fopen(*arg, "r");
136                         if (!in) {
137                             com_err(whoami, errno, 
138                                     "while opening %s for input", *arg);
139                             exit(2);
140                         }
141                     }
142                     while (fgets(buf, BUFSIZ, in))
143                       if (memberstruct = parse_member(buf))
144                         sq_save_data(synclist, memberstruct);
145                     if (!feof(in))
146                       com_err(whoami, errno, "while reading from %s", *arg);
147                 } else
148                   usage(argv);
149             else
150                 usage(argv);
151         }
152         else if (listname == NULL)
153           listname = *arg;
154         else
155           usage(argv);
156     }
157     if (listname == NULL)
158       usage(argv);
159
160     /* if no other options specified, turn on list members flag */
161     if (!(infoflg || syncflg ||
162           addlist->q_next != addlist || dellist->q_next != dellist))
163       memberflg++;
164
165     /* If none of {users,strings,lists,kerberos} specified, turn them all on */
166     if (!(showusers || showstrings || showlists || showkerberos))
167       showusers = showstrings = showlists = showkerberos = 1;
168
169     /* fire up Moira */
170     if (status = mr_connect(server)) {
171         com_err(whoami, status, "unable to connect to the Moira server");
172         exit(2);
173     }
174     if ( status = mr_motd(&motd) ) {
175         com_err(whoami, status, "unable to check server status");
176         exit(2);
177     }
178     if (motd) {
179         fprintf(stderr, "The Moira server is currently unavailable:\n%s\n", motd);
180         mr_disconnect();
181         exit(2);
182     }
183
184     if (!noauth && (status = mr_auth("blanche"))) {
185         if (status == MR_USER_AUTH)
186           com_err(whoami, status, "");
187         else {
188             com_err(whoami, status, "unable to authenticate to Moira");
189             com_err(whoami, 0,
190                     " Try the -noauth flag if you don't need authentication");
191             exit(2);
192         }
193     }
194
195     /* display list info if requested to */
196     if (infoflg) {
197         status = mr_query("get_list_info", 1, &listname, show_list_info,NULL);
198         if (status)
199           com_err(whoami, status, "while getting list information");
200         if (verbose && !memberflg) {
201             status = mr_query("count_members_of_list", 1, &listname,
202                                show_list_count, NULL);
203             if (status)
204               com_err(whoami, status, "while getting list count");
205         }
206     }
207
208     /* if we're synchronizing to a file, we need to:
209      *  get the current members of the list
210      *  for each member of the sync file
211      *     if they are on the list, remove them from the in-memory copy
212      *     if they're not on the list, add them to add-list
213      *  if anyone is left on the in-memory copy, put them on the delete-list
214      * lastly, reset memberlist so we can use it again later
215      */
216     if (syncflg) {
217         status = mr_query("get_members_of_list", 1, &listname,
218                            get_list_members, (char *)memberlist);
219         if (status)
220           com_err(whoami, status, "getting members of list %s", listname);
221         while (sq_get_data(synclist, &memberstruct)) {
222             struct save_queue *q;
223             int removed = 0;
224
225             for (q = memberlist->q_next; q != memberlist; q = q->q_next) {
226                 if (membercmp(q->q_data, memberstruct) == 0) {
227                     q->q_prev->q_next = q->q_next;
228                     q->q_next->q_prev = q->q_prev;
229                     removed++;
230                     break;
231                 }
232             }
233             if (!removed)
234               sq_save_data(addlist, memberstruct);
235         }
236         while (sq_get_data(memberlist, &memberstruct))
237           sq_save_data(dellist, memberstruct);
238         sq_destroy(memberlist);
239         memberlist = sq_create();
240     }
241
242     /* Process the add list */
243     while (sq_get_data(addlist, &memberstruct)) {
244         membervec[0] = listname;
245         membervec[2] = memberstruct->name;
246         if (verbose) {
247             printf("Adding member ");
248             show_list_member(memberstruct);
249         }
250         switch (memberstruct->type) {
251         case M_ANY:
252         case M_USER:
253             membervec[1] = "USER";
254             status = mr_query("add_member_to_list", 3, membervec, scream, NULL);
255             if (status == MR_SUCCESS)
256               break;
257             else if (status != MR_USER || memberstruct->type != M_ANY) {
258                 com_err(whoami, status, "while adding member %s to %s",
259                         memberstruct->name, listname);
260                 break;
261             }
262         case M_LIST:
263             membervec[1] = "LIST";
264             status = mr_query("add_member_to_list", 3, membervec,
265                                scream, NULL);
266             if (status == MR_SUCCESS)
267               break;
268             else if (status != MR_LIST || memberstruct->type != M_ANY) {
269                 com_err(whoami, status, "while adding member %s to %s",
270                         memberstruct->name, listname);
271                 break;
272             }
273         case M_STRING:
274             membervec[1] = "STRING";
275             status = mr_query("add_member_to_list", 3, membervec,
276                                scream, NULL);
277             if (status != MR_SUCCESS)
278               com_err(whoami, status, "while adding member %s to %s",
279                       memberstruct->name, listname);
280             break;
281         case M_KERBEROS:
282             membervec[1] = "KERBEROS";
283             status = mr_query("add_member_to_list", 3, membervec,
284                                scream, NULL);
285             if (status != MR_SUCCESS)
286               com_err(whoami, status, "while adding member %s to %s",
287                       memberstruct->name, listname);
288         }
289     }
290
291     /* Process the delete list */
292     while (sq_get_data(dellist, &memberstruct)) {
293         membervec[0] = listname;
294         membervec[2] = memberstruct->name;
295         if (verbose) {
296             printf("Deleting member ");
297             show_list_member(memberstruct);
298         }
299         switch (memberstruct->type) {
300         case M_ANY:
301         case M_USER:
302             membervec[1] = "USER";
303             status = mr_query("delete_member_from_list", 3, membervec,
304                                scream, NULL);
305             if (status == MR_SUCCESS)
306               break;
307             else if ((status != MR_USER && status != MR_NO_MATCH) ||
308                      memberstruct->type != M_ANY) {
309                 com_err(whoami, status, "while deleting member %s from %s",
310                         memberstruct->name, listname);
311                 break;
312             }
313         case M_LIST:
314             membervec[1] = "LIST";
315             status = mr_query("delete_member_from_list", 3, membervec,
316                                scream, NULL);
317             if (status == MR_SUCCESS)
318               break;
319             else if ((status != MR_LIST && status != MR_NO_MATCH) ||
320                      memberstruct->type != M_ANY) {
321                 com_err(whoami, status, "while deleting member %s from %s",
322                         memberstruct->name, listname);
323                 break;
324             }
325         case M_STRING:
326             membervec[1] = "STRING";
327             status = mr_query("delete_member_from_list", 3, membervec,
328                                scream, NULL);
329             if (status == MR_STRING && memberstruct->type == M_ANY)
330               com_err(whoami, 0, " Unable to find member %s to delete from %s",
331                       memberstruct->name, listname);
332             else if (status != MR_SUCCESS)
333               com_err(whoami, status, "while deleting member %s from %s",
334                       memberstruct->name, listname);
335             break;
336         case M_KERBEROS:
337             membervec[1] = "KERBEROS";
338             status = mr_query("delete_member_from_list", 3, membervec,
339                                scream, NULL);
340             if (status != MR_SUCCESS)
341               com_err(whoami, status, "while deleting member %s from %s",
342                       memberstruct->name, listname);
343         }
344     }
345
346     /* Display the members of the list now, if requested */
347     if (memberflg) {
348         if (recursflg)
349           recursive_display_list_members();
350         else {
351             status = mr_query("get_members_of_list", 1, &listname,
352                                get_list_members, (char *)memberlist);
353             if (status)
354               com_err(whoami, status, "while getting members of list %s",
355                       listname);
356             while (sq_get_data(memberlist, &memberstruct))
357               show_list_member(memberstruct);
358         }
359     }
360
361     /* We're done! */
362     mr_disconnect();
363     exit(0);
364 }
365
366 usage(argv)
367 char **argv;
368 {
369     fprintf(stderr, "Usage: %s [options] listname [options]\n",argv[0]);
370     fprintf(stderr, "Options are\n");
371     fprintf(stderr, "   -v | -verbose\n");
372     fprintf(stderr, "   -m | -members\n");
373     fprintf(stderr, "   -u | -users\n");
374     fprintf(stderr, "   -l | -lists\n");
375     fprintf(stderr, "   -s | -strings\n");
376     fprintf(stderr, "   -k | -kerberos\n");
377     fprintf(stderr, "   -i | -info\n");
378     fprintf(stderr, "   -r | -recursive\n");
379     fprintf(stderr, "   -a | -add member\n");
380     fprintf(stderr, "   -d | -delete member\n");
381     fprintf(stderr, "   -f | -file filename\n");
382     fprintf(stderr, "   -n | -noauth\n");
383     fprintf(stderr, "   -S | -server host:port\n");
384     fprintf(stderr, "   -D | -debug\n");
385     exit(1);
386 }
387
388
389 /* Display the members stored in the queue */
390
391 show_list_member(memberstruct)
392 struct member *memberstruct;
393 {
394     char *s;
395
396     switch (memberstruct->type) {
397     case M_USER:
398         if (!showusers)
399           return;
400         s = "USER";
401         break;
402     case M_LIST:
403         if (!showlists)
404           return;
405         s = "LIST";
406         break;
407     case M_STRING:
408         if (!showstrings)
409           return;
410         s = "STRING";
411         break;
412     case M_KERBEROS:
413         if (!showkerberos)
414           return;
415         s = "KERBEROS";
416         break;
417     case M_ANY:
418         printf("%s\n", memberstruct->name);
419         return;
420     }
421
422     if (verbose)
423       printf("%s:%s\n", s, memberstruct->name);
424     else {
425         if (memberstruct->type == M_LIST)
426           printf("LIST:%s\n", memberstruct->name);
427         else if (memberstruct->type == M_KERBEROS)
428           printf("KERBEROS:%s\n", memberstruct->name);
429         else if (memberstruct->type == M_STRING &&
430                  !index(memberstruct->name, '@'))
431           printf("STRING:%s\n", memberstruct->name);
432         else
433           printf("%s\n", memberstruct->name);
434     }
435 }
436
437
438 /* Show the retrieved information about a list */
439
440 show_list_info(argc, argv, hint)
441 int argc;
442 char **argv;
443 int hint;
444 {
445     printf("List: %s\n", argv[0]);
446     printf("Description: %s\n", argv[9]);
447     printf("Flags: %s, %s, and %s\n",
448            atoi(argv[1]) ? "active" : "inactive",
449            atoi(argv[2]) ? "public" : "private",
450            atoi(argv[3]) ? "hidden" : "visible");
451     printf("%s is %sa maillist and is %sa group", argv[0],
452            atoi(argv[4]) ? "" : "not ",
453            atoi(argv[5]) ? "" : "not ");
454     if (atoi(argv[5]))
455       printf(" with GID %d\n", atoi(argv[6]));
456     else
457       printf("\n");
458     printf("Owner: %s %s\n", argv[7], argv[8]);
459     printf("Last modified by %s with %s on %s\n", argv[11], argv[12], argv[10]);
460     return(MR_CONT);
461 }
462
463
464 /* Show the retrieve list member count */
465
466 show_list_count(argc, argv, hint)
467 int argc;
468 char **argv;
469 int hint;
470 {
471     printf("Members: %s\n", argv[0]);
472 }
473
474
475 /* Recursively find all of the members of listname, and then display them */
476
477 recursive_display_list_members()
478 {
479     int status, count, savecount;
480     struct save_queue *lists, *members;
481     struct member *m, *m1, *data;
482
483     lists = sq_create();
484     members = sq_create();
485     m = (struct member *) malloc(sizeof(struct member));
486     m->type = M_LIST;
487     m->name = listname;
488     sq_save_data(lists, m);
489
490     while (sq_get_data(lists, &m)) {
491         sq_destroy(memberlist);
492         memberlist = sq_create();
493         if (debugflg)
494           fprintf(stderr, "Fetching members of %s\n", m->name);
495         status = mr_query("get_members_of_list", 1, &(m->name),
496                            get_list_members, (char *)memberlist);
497         if (status)
498           com_err(whoami, status, "while getting members of list %s", m->name);
499         while (sq_get_data(memberlist, &m1)) {
500             if (m1->type == M_LIST)
501               unique_add_member(lists, m1);
502             else
503               unique_add_member(members, m1);
504         }
505     }
506     savecount = count = sq_count_elts(members);
507     data = (struct member *) malloc(count * sizeof(struct member));
508     count = 0;
509     while (sq_get_data(members, &m))
510       bcopy(m, &data[count++], sizeof(struct member));
511     qsort(data, count, sizeof(struct member), membercmp);
512     for (count = 0; count < savecount; count++) {
513         show_list_member(&data[count]);
514     }
515 }
516
517
518 /* add a struct member to a queue if that member isn't already there. */
519
520 unique_add_member(q, m)
521 struct save_queue  *q;
522 struct member *m;
523 {
524     struct save_queue *qp;
525
526     for (qp = q->q_next; qp != q; qp = qp->q_next) {
527         if (!membercmp(qp->q_data, m))
528           return;
529     }
530     sq_save_data(q, m);
531 }
532
533
534 /* Collect the retrieved members of the list */
535
536 get_list_members(argc, argv, q)
537 int argc;
538 char **argv;
539 struct save_queue *q;
540 {
541     struct member *m;
542
543     m = (struct member *) malloc(sizeof(struct member));
544     switch (argv[0][0]) {
545     case 'U':
546         m->type = M_USER;
547         break;
548     case 'L':
549         m->type = M_LIST;
550         break;
551     case 'S':
552         m->type = M_STRING;
553         break;
554     case 'K':
555         m->type = M_KERBEROS;
556         break;
557     }
558     m->name = strsave(argv[1]);
559     sq_save_data(q, m);
560     return(MR_CONT);
561 }
562
563
564 /* Called only if a query returns a value that we weren't expecting */
565
566 scream()
567 {
568     fprintf(stderr, "Programmer botch\n");
569     exit(3);
570 }
571
572
573 /* Parse a line of input, fetching a member.  NULL is returned if a member
574  * is not found.  Only the first token on the line is parsed.  ';' is a
575  * comment character.
576  */
577
578 struct member *parse_member(s)
579 register char *s;
580 {
581     register struct member *m;
582     char *p;
583
584     while (*s && isspace(*s))
585       s++;
586     p = s;
587     while (*p && isprint(*p) && !isspace(*p) && *p != ';')
588       p++;
589     *p = 0;
590     if (p == s || strlen(s) == 0)
591       return(NULL);
592
593     if ((m = (struct member *) malloc(sizeof(struct member))) == NULL)
594       return(NULL);
595
596     if (p = index(s, ':')) {
597         *p = 0;
598         m->name = ++p;
599         if (!strcasecmp("user", s))
600           m->type = M_USER;
601         else if (!strcasecmp("list", s))
602           m->type = M_LIST;
603         else if (!strcasecmp("string", s))
604           m->type = M_STRING;
605         else if (!strcasecmp("kerberos", s))
606           m->type = M_KERBEROS;
607         else {
608             m->type = M_STRING;
609             *(--p) = ':';
610             m->name = s;
611         }
612         m->name = strsave(m->name);
613         return(m);
614     }
615     m->name = strsave(s);
616     if (index(s, '@') || index(s, '!') || index(s, '%'))
617       m->type = M_STRING;
618     else
619       m->type = M_ANY;
620     return(m);
621 }
622
623
624   /* 
625    * This routine two compares members by the following rules:
626    * 1.  A USER is less than a LIST
627    * 2.  A LIST is less than a STRING
628    * 3.  If two members are of the same type, the one alphabetically first
629    *     is less than the other
630    * It returs < 0 if the first member is less, 0 if they are identical, and
631    * > 0 if the second member is less (the first member is greater).
632    */
633
634 int membercmp(m1, m2)
635   struct member *m1, *m2;
636 {
637     if (m1->type == M_ANY || m2->type  == M_ANY || (m1->type == m2->type))
638         return(strcmp(m1->name, m2->name));
639     else
640         return(m1->type - m2->type);
641 }
642
643
644 sq_count_elts(q)
645 struct save_queue *q;
646 {
647     char  *foo;
648     int count;
649
650     count = 0;
651     while (sq_get_data(q, &foo))
652       count++;
653     return(count);
654 }
This page took 0.088738 seconds and 5 git commands to generate.