]> andersk Git - moira.git/blob - clients/blanche/blanche.c
check for string references to local mailhub
[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(), membercmp();
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, *p;
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("al","addlist"))
119                 if (arg - argv < argc - 1) {
120                     ++arg;
121                     get_members_from_file(*arg, addlist);
122                 } else
123                   usage(argv);
124             else if (argis("d","delete"))
125                 if (arg - argv < argc - 1) {
126                     ++arg;
127                     if (memberstruct = parse_member(*arg))
128                         sq_save_data(dellist, memberstruct);
129                 } else
130                     usage(argv);
131             else if (argis("dl","deletelist"))
132                 if (arg - argv < argc - 1) {
133                     ++arg;
134                     get_members_from_file(*arg, dellist);
135                 } else
136                   usage(argv);
137             else if (argis("f","file"))
138                 if (arg - argv < argc - 1) {
139                     syncflg++;
140                     ++arg;
141                     get_members_from_file(*arg, synclist);
142                 } else
143                   usage(argv);
144             else
145                 usage(argv);
146         }
147         else if (listname == NULL)
148           listname = *arg;
149         else
150           usage(argv);
151     }
152     if (listname == NULL)
153       usage(argv);
154
155     /* if no other options specified, turn on list members flag */
156     if (!(infoflg || syncflg ||
157           addlist->q_next != addlist || dellist->q_next != dellist))
158       memberflg++;
159
160     /* If none of {users,strings,lists,kerberos} specified, turn them all on */
161     if (!(showusers || showstrings || showlists || showkerberos))
162       showusers = showstrings = showlists = showkerberos = 1;
163
164     /* fire up Moira */
165     if (status = mr_connect(server)) {
166         com_err(whoami, status, "unable to connect to the Moira server");
167         exit(2);
168     }
169     if ( status = mr_motd(&motd) ) {
170         com_err(whoami, status, "unable to check server status");
171         exit(2);
172     }
173     if (motd) {
174         fprintf(stderr, "The Moira server is currently unavailable:\n%s\n", motd);
175         mr_disconnect();
176         exit(2);
177     }
178
179     if (!noauth && (status = mr_auth("blanche"))) {
180         if (status == MR_USER_AUTH)
181           com_err(whoami, status, "");
182         else {
183             com_err(whoami, status, "unable to authenticate to Moira");
184             com_err(whoami, 0,
185                     " Try the -noauth flag if you don't need authentication");
186             exit(2);
187         }
188     }
189
190     /* display list info if requested to */
191     if (infoflg) {
192         status = mr_query("get_list_info", 1, &listname, show_list_info,NULL);
193         if (status)
194           com_err(whoami, status, "while getting list information");
195         if (verbose && !memberflg) {
196             status = mr_query("count_members_of_list", 1, &listname,
197                                show_list_count, NULL);
198             if (status)
199               com_err(whoami, status, "while getting list count");
200         }
201     }
202
203     /* if we're synchronizing to a file, we need to:
204      *  get the current members of the list
205      *  for each member of the sync file
206      *     if they are on the list, remove them from the in-memory copy
207      *     if they're not on the list, add them to add-list
208      *  if anyone is left on the in-memory copy, put them on the delete-list
209      * lastly, reset memberlist so we can use it again later
210      */
211     if (syncflg) {
212         status = mr_query("get_members_of_list", 1, &listname,
213                            get_list_members, (char *)memberlist);
214         if (status)
215           com_err(whoami, status, "getting members of list %s", listname);
216         while (sq_get_data(synclist, &memberstruct)) {
217             struct save_queue *q;
218             int removed = 0;
219
220             for (q = memberlist->q_next; q != memberlist; q = q->q_next) {
221                 if (membercmp(q->q_data, memberstruct) == 0) {
222                     q->q_prev->q_next = q->q_next;
223                     q->q_next->q_prev = q->q_prev;
224                     removed++;
225                     break;
226                 }
227             }
228             if (!removed)
229               sq_save_data(addlist, memberstruct);
230         }
231         while (sq_get_data(memberlist, &memberstruct))
232           sq_save_data(dellist, memberstruct);
233         sq_destroy(memberlist);
234         memberlist = sq_create();
235     }
236
237     /* Process the add list */
238     while (sq_get_data(addlist, &memberstruct)) {
239         /* canonicalize string if necessary */
240         if (memberstruct->type == M_STRING &&
241             (p = index(memberstruct->name, '@'))) {
242             char *host = canonicalize_hostname(strsave(++p));
243             static char **mailhubs = NULL;
244             char *argv[4];
245             int i, collect();
246
247             if (!mailhubs) {
248                 argv[0] = "mailhub";
249                 argv[1] = "TYPE";
250                 argv[2] = "*";
251                 mailhubs = (char **)malloc(sizeof(char *));
252                 mailhubs[0] = NULL;
253                 status = mr_query("get_alias", 3, argv, collect, &mailhubs);
254                 if (status != MR_SUCCESS && status != MR_NO_MATCH) {
255                     com_err(whoami, status,
256                             " while reading list of MAILHUB servers");
257                     mailhubs[0] = NULL;
258                 }
259             }
260             for (i = 0; p = mailhubs[i]; i++) {
261                 if (!strcasecmp(p, host)) {
262                     host = strsave(memberstruct->name);
263                     *(index(memberstruct->name, '@')) = 0;
264                     memberstruct->type = M_ANY;
265                     fprintf(stderr, "Warning: \"STRING:%s\" converted to \"%s\" because it is a local name.\n",
266                             host, memberstruct->name);
267                     break;
268                 }
269             }
270             free(host);
271         }
272         /* now continue adding member */
273         membervec[0] = listname;
274         membervec[2] = memberstruct->name;
275         if (verbose) {
276             printf("Adding member ");
277             show_list_member(memberstruct);
278         }
279         switch (memberstruct->type) {
280         case M_ANY:
281         case M_USER:
282             membervec[1] = "USER";
283             status = mr_query("add_member_to_list", 3, membervec, scream, NULL);
284             if (status == MR_SUCCESS)
285               break;
286             else if (status != MR_USER || memberstruct->type != M_ANY) {
287                 com_err(whoami, status, "while adding member %s to %s",
288                         memberstruct->name, listname);
289                 break;
290             }
291         case M_LIST:
292             membervec[1] = "LIST";
293             status = mr_query("add_member_to_list", 3, membervec,
294                                scream, NULL);
295             if (status == MR_SUCCESS)
296               break;
297             else if (status != MR_LIST || memberstruct->type != M_ANY) {
298                 com_err(whoami, status, "while adding member %s to %s",
299                         memberstruct->name, listname);
300                 break;
301             }
302         case M_STRING:
303             membervec[1] = "STRING";
304             status = mr_query("add_member_to_list", 3, membervec,
305                                scream, NULL);
306             if (status != MR_SUCCESS)
307               com_err(whoami, status, "while adding member %s to %s",
308                       memberstruct->name, listname);
309             break;
310         case M_KERBEROS:
311             membervec[1] = "KERBEROS";
312             status = mr_query("add_member_to_list", 3, membervec,
313                                scream, NULL);
314             if (status != MR_SUCCESS)
315               com_err(whoami, status, "while adding member %s to %s",
316                       memberstruct->name, listname);
317         }
318     }
319
320     /* Process the delete list */
321     while (sq_get_data(dellist, &memberstruct)) {
322         membervec[0] = listname;
323         membervec[2] = memberstruct->name;
324         if (verbose) {
325             printf("Deleting member ");
326             show_list_member(memberstruct);
327         }
328         switch (memberstruct->type) {
329         case M_ANY:
330         case M_USER:
331             membervec[1] = "USER";
332             status = mr_query("delete_member_from_list", 3, membervec,
333                                scream, NULL);
334             if (status == MR_SUCCESS)
335               break;
336             else if ((status != MR_USER && status != MR_NO_MATCH) ||
337                      memberstruct->type != M_ANY) {
338                 com_err(whoami, status, "while deleting member %s from %s",
339                         memberstruct->name, listname);
340                 break;
341             }
342         case M_LIST:
343             membervec[1] = "LIST";
344             status = mr_query("delete_member_from_list", 3, membervec,
345                                scream, NULL);
346             if (status == MR_SUCCESS)
347               break;
348             else if ((status != MR_LIST && status != MR_NO_MATCH) ||
349                      memberstruct->type != M_ANY) {
350                 com_err(whoami, status, "while deleting member %s from %s",
351                         memberstruct->name, listname);
352                 break;
353             }
354         case M_STRING:
355             membervec[1] = "STRING";
356             status = mr_query("delete_member_from_list", 3, membervec,
357                                scream, NULL);
358             if (status == MR_STRING && memberstruct->type == M_ANY)
359               com_err(whoami, 0, " Unable to find member %s to delete from %s",
360                       memberstruct->name, listname);
361             else if (status != MR_SUCCESS)
362               com_err(whoami, status, "while deleting member %s from %s",
363                       memberstruct->name, listname);
364             break;
365         case M_KERBEROS:
366             membervec[1] = "KERBEROS";
367             status = mr_query("delete_member_from_list", 3, membervec,
368                                scream, NULL);
369             if (status != MR_SUCCESS)
370               com_err(whoami, status, "while deleting member %s from %s",
371                       memberstruct->name, listname);
372         }
373     }
374
375     /* Display the members of the list now, if requested */
376     if (memberflg) {
377         if (recursflg)
378           recursive_display_list_members();
379         else {
380             status = mr_query("get_members_of_list", 1, &listname,
381                                get_list_members, (char *)memberlist);
382             if (status)
383               com_err(whoami, status, "while getting members of list %s",
384                       listname);
385             while (sq_get_data(memberlist, &memberstruct))
386               show_list_member(memberstruct);
387         }
388     }
389
390     /* We're done! */
391     mr_disconnect();
392     exit(0);
393 }
394
395 usage(argv)
396 char **argv;
397 {
398     fprintf(stderr, "Usage: %s [options] listname [options]\n",argv[0]);
399     fprintf(stderr, "Options are\n");
400     fprintf(stderr, "   -v | -verbose\n");
401     fprintf(stderr, "   -m | -members\n");
402     fprintf(stderr, "   -u | -users\n");
403     fprintf(stderr, "   -l | -lists\n");
404     fprintf(stderr, "   -s | -strings\n");
405     fprintf(stderr, "   -k | -kerberos\n");
406     fprintf(stderr, "   -i | -info\n");
407     fprintf(stderr, "   -r | -recursive\n");
408     fprintf(stderr, "   -a | -add member\n");
409     fprintf(stderr, "   -d | -delete member\n");
410     fprintf(stderr, "   -al | -addlist filename\n");
411     fprintf(stderr, "   -dl | -deletelist filename\n");
412     fprintf(stderr, "   -f | -file filename\n");
413     fprintf(stderr, "   -n | -noauth\n");
414     fprintf(stderr, "   -S | -server host[:port]\n");
415     fprintf(stderr, "   -D | -debug\n");
416     exit(1);
417 }
418
419
420 /* Display the members stored in the queue */
421
422 show_list_member(memberstruct)
423 struct member *memberstruct;
424 {
425     char *s = "";
426
427     switch (memberstruct->type) {
428     case M_USER:
429         if (!showusers)
430           return;
431         s = "USER";
432         break;
433     case M_LIST:
434         if (!showlists)
435           return;
436         s = "LIST";
437         break;
438     case M_STRING:
439         if (!showstrings)
440           return;
441         s = "STRING";
442         break;
443     case M_KERBEROS:
444         if (!showkerberos)
445           return;
446         s = "KERBEROS";
447         break;
448     case M_ANY:
449         printf("%s\n", memberstruct->name);
450         return;
451     }
452
453     if (verbose)
454       printf("%s:%s\n", s, memberstruct->name);
455     else {
456         if (memberstruct->type == M_LIST)
457           printf("LIST:%s\n", memberstruct->name);
458         else if (memberstruct->type == M_KERBEROS)
459           printf("KERBEROS:%s\n", memberstruct->name);
460         else if (memberstruct->type == M_STRING &&
461                  !index(memberstruct->name, '@'))
462           printf("STRING:%s\n", memberstruct->name);
463         else
464           printf("%s\n", memberstruct->name);
465     }
466 }
467
468
469 /* Show the retrieved information about a list */
470
471 show_list_info(argc, argv, hint)
472 int argc;
473 char **argv;
474 int hint;
475 {
476     printf("List: %s\n", argv[0]);
477     printf("Description: %s\n", argv[9]);
478     printf("Flags: %s, %s, and %s\n",
479            atoi(argv[1]) ? "active" : "inactive",
480            atoi(argv[2]) ? "public" : "private",
481            atoi(argv[3]) ? "hidden" : "visible");
482     printf("%s is %sa maillist and is %sa group", argv[0],
483            atoi(argv[4]) ? "" : "not ",
484            atoi(argv[5]) ? "" : "not ");
485     if (atoi(argv[5]))
486       printf(" with GID %d\n", atoi(argv[6]));
487     else
488       printf("\n");
489     printf("Owner: %s %s\n", argv[7], argv[8]);
490     printf("Last modified by %s with %s on %s\n", argv[11], argv[12], argv[10]);
491     return(MR_CONT);
492 }
493
494
495 /* Show the retrieve list member count */
496
497 show_list_count(argc, argv, hint)
498 int argc;
499 char **argv;
500 int hint;
501 {
502     printf("Members: %s\n", argv[0]);
503 }
504
505
506 /* Recursively find all of the members of listname, and then display them */
507
508 recursive_display_list_members()
509 {
510     int status, count, savecount;
511     struct save_queue *lists, *members;
512     struct member *m, *m1, *data;
513
514     lists = sq_create();
515     members = sq_create();
516     m = (struct member *) malloc(sizeof(struct member));
517     m->type = M_LIST;
518     m->name = listname;
519     sq_save_data(lists, m);
520
521     while (sq_get_data(lists, &m)) {
522         sq_destroy(memberlist);
523         memberlist = sq_create();
524         if (debugflg)
525           fprintf(stderr, "Fetching members of %s\n", m->name);
526         status = mr_query("get_members_of_list", 1, &(m->name),
527                            get_list_members, (char *)memberlist);
528         if (status)
529           com_err(whoami, status, "while getting members of list %s", m->name);
530         while (sq_get_data(memberlist, &m1)) {
531             if (m1->type == M_LIST)
532               unique_add_member(lists, m1);
533             else
534               unique_add_member(members, m1);
535         }
536     }
537     savecount = count = sq_count_elts(members);
538     data = (struct member *) malloc(count * sizeof(struct member));
539     count = 0;
540     while (sq_get_data(members, &m))
541       bcopy(m, &data[count++], sizeof(struct member));
542     qsort(data, count, sizeof(struct member), membercmp);
543     for (count = 0; count < savecount; count++) {
544         show_list_member(&data[count]);
545     }
546 }
547
548
549 /* add a struct member to a queue if that member isn't already there. */
550
551 unique_add_member(q, m)
552 struct save_queue  *q;
553 struct member *m;
554 {
555     struct save_queue *qp;
556
557     for (qp = q->q_next; qp != q; qp = qp->q_next) {
558         if (!membercmp(qp->q_data, m))
559           return;
560     }
561     sq_save_data(q, m);
562 }
563
564
565 /* Collect the retrieved members of the list */
566
567 get_list_members(argc, argv, q)
568 int argc;
569 char **argv;
570 struct save_queue *q;
571 {
572     struct member *m;
573
574     m = (struct member *) malloc(sizeof(struct member));
575     switch (argv[0][0]) {
576     case 'U':
577         m->type = M_USER;
578         break;
579     case 'L':
580         m->type = M_LIST;
581         break;
582     case 'S':
583         m->type = M_STRING;
584         break;
585     case 'K':
586         m->type = M_KERBEROS;
587         break;
588     }
589     m->name = strsave(argv[1]);
590     sq_save_data(q, m);
591     return(MR_CONT);
592 }
593
594
595 /* Called only if a query returns a value that we weren't expecting */
596
597 scream()
598 {
599     fprintf(stderr, "Programmer botch\n");
600     exit(3);
601 }
602
603
604 /* Open file, parse members from file, and put them on the specified queue */
605 get_members_from_file(filename, queue)
606 char *filename;
607 struct save_queue *queue;
608 {
609     FILE *in;
610     char buf[BUFSIZ];
611     struct member *memberstruct;
612
613     if (!strcmp(filename, "-"))
614       in = stdin;
615     else {
616         in = fopen(filename, "r");
617         if (!in) {
618             com_err(whoami, errno, "while opening %s for input", filename);
619             exit(2);
620         }
621     }
622
623     while (fgets(buf, BUFSIZ, in))
624       if (memberstruct = parse_member(buf))
625         sq_save_data(queue, memberstruct);
626     if (!feof(in))
627       com_err(whoami, errno, "while reading from %s", filename);
628 }
629
630
631 /* Collect the possible expansions of the alias MAILHUB */
632
633 int collect(argc, argv, list)
634 int argc;
635 char **argv;
636 char ***list;
637 {
638     int i;
639
640     for (i = 0; (*list)[i]; i++);
641     *list = (char **)realloc(*list, (i + 2) * sizeof(char *));
642     (*list)[i] = strsave(argv[2]);
643     (*list)[i+1] = NULL;
644     return(MR_CONT);
645 }
646
647
648 /* Parse a line of input, fetching a member.  NULL is returned if a member
649  * is not found.  ';' is a comment character.
650  */
651
652 struct member *parse_member(s)
653 register char *s;
654 {
655     register struct member *m;
656     char *p, *lastchar;
657
658     while (*s && isspace(*s))
659       s++;
660     lastchar = p = s;
661     while (*p && *p != '\n' && *p != ';')
662       if (isprint(*p) && !isspace(*p))
663         lastchar = p++;
664       else
665         p++;
666     lastchar++;
667     *lastchar = 0;
668     if (p == s || strlen(s) == 0)
669       return(NULL);
670
671     if ((m = (struct member *) malloc(sizeof(struct member))) == NULL)
672       return(NULL);
673
674     if (p = index(s, ':')) {
675         *p = 0;
676         m->name = ++p;
677         if (!strcasecmp("user", s))
678           m->type = M_USER;
679         else if (!strcasecmp("list", s))
680           m->type = M_LIST;
681         else if (!strcasecmp("string", s))
682           m->type = M_STRING;
683         else if (!strcasecmp("kerberos", s))
684           m->type = M_KERBEROS;
685         else {
686             m->type = M_STRING;
687             *(--p) = ':';
688             m->name = s;
689         }
690         m->name = strsave(m->name);
691     } else {
692         m->name = strsave(s);
693         if (index(s, '@') || index(s, '!') || index(s, '%') || index(s, ' '))
694           m->type = M_STRING;
695         else
696           m->type = M_ANY;
697     }
698     return(m);
699 }
700
701
702   /* 
703    * This routine two compares members by the following rules:
704    * 1.  A USER is less than a LIST
705    * 2.  A LIST is less than a STRING
706    * 3.  If two members are of the same type, the one alphabetically first
707    *     is less than the other
708    * It returs < 0 if the first member is less, 0 if they are identical, and
709    * > 0 if the second member is less (the first member is greater).
710    */
711
712 int membercmp(m1, m2)
713   struct member *m1, *m2;
714 {
715     if (m1->type == M_ANY || m2->type  == M_ANY || (m1->type == m2->type))
716         return(strcmp(m1->name, m2->name));
717     else
718         return(m1->type - m2->type);
719 }
720
721
722 sq_count_elts(q)
723 struct save_queue *q;
724 {
725     char  *foo;
726     int count;
727
728     count = 0;
729     while (sq_get_data(q, &foo))
730       count++;
731     return(count);
732 }
This page took 0.879982 seconds and 5 git commands to generate.