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