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