]> andersk Git - moira.git/blob - clients/blanche/blanche.c
Remove useless delcaration of index().
[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 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                 if (status == MR_PERM && memberstruct->type == M_ANY)  {
355                   /* M_ANY means we've fallen through from the user case
356                    * The fact that we didn't get MR_PERM there indicates
357                    * that we had permission to remove the specified member 
358                    * from the list if it is a user, but not a list.  This is 
359                    * if we are the member in question.  Since we exist as a user
360                    * we must have gotten the MR_NO_MATCH error, so we will
361                    * return that, since it will be less confusing.  However,
362                    * This will generate the wrongerror if the user was trying
363                    * to remove the list with his/her username from a list they
364                    * don't administrate, without explicitly specifying "list:".
365                    */
366                   status = MR_NO_MATCH;
367                 }
368                 com_err(whoami, status, "while deleting member %s from %s",
369                         memberstruct->name, listname);
370                 break;
371             }
372         case M_STRING:
373             membervec[1] = "STRING";
374             status = mr_query("delete_member_from_list", 3, membervec,
375                                scream, NULL);
376             if (status == MR_STRING && memberstruct->type == M_ANY)
377               com_err(whoami, 0, " Unable to find member %s to delete from %s",
378                       memberstruct->name, listname);
379             else if (status != MR_SUCCESS)
380               com_err(whoami, status, "while deleting member %s from %s",
381                       memberstruct->name, listname);
382             break;
383         case M_KERBEROS:
384             membervec[1] = "KERBEROS";
385             status = mr_query("delete_member_from_list", 3, membervec,
386                                scream, NULL);
387             if (status != MR_SUCCESS)
388               com_err(whoami, status, "while deleting member %s from %s",
389                       memberstruct->name, listname);
390         }
391     }
392
393     /* Display the members of the list now, if requested */
394     if (memberflg) {
395         if (recursflg)
396           recursive_display_list_members();
397         else {
398             status = mr_query("get_members_of_list", 1, &listname,
399                                get_list_members, (char *)memberlist);
400             if (status)
401               com_err(whoami, status, "while getting members of list %s",
402                       listname);
403             while (sq_get_data(memberlist, &memberstruct))
404               show_list_member(memberstruct);
405         }
406     }
407
408     /* We're done! */
409     mr_disconnect();
410     exit(0);
411 }
412
413 usage(argv)
414 char **argv;
415 {
416     fprintf(stderr, "Usage: %s listname [options]\n",argv[0]);
417     fprintf(stderr, "Options are\n");
418     fprintf(stderr, "   -v | -verbose\n");
419     fprintf(stderr, "   -m | -members\n");
420     fprintf(stderr, "   -u | -users\n");
421     fprintf(stderr, "   -l | -lists\n");
422     fprintf(stderr, "   -s | -strings\n");
423     fprintf(stderr, "   -k | -kerberos\n");
424     fprintf(stderr, "   -i | -info\n");
425     fprintf(stderr, "   -r | -recursive\n");
426     fprintf(stderr, "   -a | -add member\n");
427     fprintf(stderr, "   -d | -delete member\n");
428     fprintf(stderr, "   -al | -addlist filename\n");
429     fprintf(stderr, "   -dl | -deletelist filename\n");
430     fprintf(stderr, "   -f | -file filename\n");
431     fprintf(stderr, "   -n | -noauth\n");
432     fprintf(stderr, "   -S | -server host[:port]\n");
433     fprintf(stderr, "   -D | -debug\n");
434     exit(1);
435 }
436
437
438 /* Display the members stored in the queue */
439
440 show_list_member(memberstruct)
441 struct member *memberstruct;
442 {
443     char *s = "";
444
445     switch (memberstruct->type) {
446     case M_USER:
447         if (!showusers)
448           return;
449         s = "USER";
450         break;
451     case M_LIST:
452         if (!showlists)
453           return;
454         s = "LIST";
455         break;
456     case M_STRING:
457         if (!showstrings)
458           return;
459         s = "STRING";
460         break;
461     case M_KERBEROS:
462         if (!showkerberos)
463           return;
464         s = "KERBEROS";
465         break;
466     case M_ANY:
467         printf("%s\n", memberstruct->name);
468         return;
469     }
470
471     if (verbose)
472       printf("%s:%s\n", s, memberstruct->name);
473     else {
474         if (memberstruct->type == M_LIST)
475           printf("LIST:%s\n", memberstruct->name);
476         else if (memberstruct->type == M_KERBEROS)
477           printf("KERBEROS:%s\n", memberstruct->name);
478         else if (memberstruct->type == M_STRING &&
479                  !strchr(memberstruct->name, '@'))
480           printf("STRING:%s\n", memberstruct->name);
481         else
482           printf("%s\n", memberstruct->name);
483     }
484 }
485
486
487 /* Show the retrieved information about a list */
488
489 show_list_info(argc, argv, hint)
490 int argc;
491 char **argv;
492 int hint;
493 {
494     printf("List: %s\n", argv[0]);
495     printf("Description: %s\n", argv[9]);
496     printf("Flags: %s, %s, and %s\n",
497            atoi(argv[1]) ? "active" : "inactive",
498            atoi(argv[2]) ? "public" : "private",
499            atoi(argv[3]) ? "hidden" : "visible");
500     printf("%s is %sa maillist and is %sa group", argv[0],
501            atoi(argv[4]) ? "" : "not ",
502            atoi(argv[5]) ? "" : "not ");
503     if (atoi(argv[5]))
504       printf(" with GID %d\n", atoi(argv[6]));
505     else
506       printf("\n");
507     printf("Owner: %s %s\n", argv[7], argv[8]);
508     printf("Last modified by %s with %s on %s\n", argv[11], argv[12], argv[10]);
509     return(MR_CONT);
510 }
511
512
513 /* Show the retrieve list member count */
514
515 show_list_count(argc, argv, hint)
516 int argc;
517 char **argv;
518 int hint;
519 {
520     printf("Members: %s\n", argv[0]);
521 }
522
523
524 /* Recursively find all of the members of listname, and then display them */
525
526 recursive_display_list_members()
527 {
528     int status, count, savecount;
529     struct save_queue *lists, *members;
530     struct member *m, *m1, *data;
531
532     lists = sq_create();
533     members = sq_create();
534     m = (struct member *) malloc(sizeof(struct member));
535     m->type = M_LIST;
536     m->name = listname;
537     sq_save_data(lists, m);
538
539     while (sq_get_data(lists, &m)) {
540         sq_destroy(memberlist);
541         memberlist = sq_create();
542         if (debugflg)
543           fprintf(stderr, "Fetching members of %s\n", m->name);
544         status = mr_query("get_members_of_list", 1, &(m->name),
545                            get_list_members, (char *)memberlist);
546         if (status)
547           com_err(whoami, status, "while getting members of list %s", m->name);
548         while (sq_get_data(memberlist, &m1)) {
549             if (m1->type == M_LIST)
550               unique_add_member(lists, m1);
551             else
552               unique_add_member(members, m1);
553         }
554     }
555     savecount = count = sq_count_elts(members);
556     data = (struct member *) malloc(count * sizeof(struct member));
557     count = 0;
558     while (sq_get_data(members, &m))
559       memcpy(&data[count++], m, sizeof(struct member));
560     qsort(data, count, sizeof(struct member), membercmp);
561     for (count = 0; count < savecount; count++) {
562         show_list_member(&data[count]);
563     }
564 }
565
566
567 /* add a struct member to a queue if that member isn't already there. */
568
569 unique_add_member(q, m)
570 struct save_queue  *q;
571 struct member *m;
572 {
573     struct save_queue *qp;
574
575     for (qp = q->q_next; qp != q; qp = qp->q_next) {
576         if (!membercmp(qp->q_data, m))
577           return;
578     }
579     sq_save_data(q, m);
580 }
581
582
583 /* Collect the retrieved members of the list */
584
585 get_list_members(argc, argv, q)
586 int argc;
587 char **argv;
588 struct save_queue *q;
589 {
590     struct member *m;
591
592     m = (struct member *) malloc(sizeof(struct member));
593     switch (argv[0][0]) {
594     case 'U':
595         m->type = M_USER;
596         break;
597     case 'L':
598         m->type = M_LIST;
599         break;
600     case 'S':
601         m->type = M_STRING;
602         break;
603     case 'K':
604         m->type = M_KERBEROS;
605         break;
606     }
607     m->name = strsave(argv[1]);
608     sq_save_data(q, m);
609     return(MR_CONT);
610 }
611
612
613 /* Called only if a query returns a value that we weren't expecting */
614
615 scream()
616 {
617     fprintf(stderr, "Programmer botch\n");
618     exit(3);
619 }
620
621
622 /* Open file, parse members from file, and put them on the specified queue */
623 get_members_from_file(filename, queue)
624 char *filename;
625 struct save_queue *queue;
626 {
627     FILE *in;
628     char buf[BUFSIZ];
629     struct member *memberstruct;
630
631     if (!strcmp(filename, "-"))
632       in = stdin;
633     else {
634         in = fopen(filename, "r");
635         if (!in) {
636             com_err(whoami, errno, "while opening %s for input", filename);
637             exit(2);
638         }
639     }
640
641     while (fgets(buf, BUFSIZ, in))
642       if (memberstruct = parse_member(buf))
643         sq_save_data(queue, memberstruct);
644     if (!feof(in))
645       com_err(whoami, errno, "while reading from %s", filename);
646 }
647
648
649 /* Collect the possible expansions of the alias MAILHUB */
650
651 int collect(argc, argv, list)
652 int argc;
653 char **argv;
654 char ***list;
655 {
656     int i;
657
658     for (i = 0; (*list)[i]; i++);
659     *list = (char **)realloc(*list, (i + 2) * sizeof(char *));
660     (*list)[i] = strsave(argv[2]);
661     (*list)[i+1] = NULL;
662     return(MR_CONT);
663 }
664
665
666 /* Parse a line of input, fetching a member.  NULL is returned if a member
667  * is not found.  ';' is a comment character.
668  */
669
670 struct member *parse_member(s)
671 register char *s;
672 {
673     register struct member *m;
674     char *p, *lastchar;
675
676     while (*s && isspace(*s))
677       s++;
678     lastchar = p = s;
679     while (*p && *p != '\n' && *p != ';')
680       if (isprint(*p) && !isspace(*p))
681         lastchar = p++;
682       else
683         p++;
684     lastchar++;
685     *lastchar = 0;
686     if (p == s || strlen(s) == 0)
687       return(NULL);
688
689     if ((m = (struct member *) malloc(sizeof(struct member))) == NULL)
690       return(NULL);
691
692     if (p = strchr(s, ':')) {
693         *p = 0;
694         m->name = ++p;
695         if (!strcasecmp("user", s))
696           m->type = M_USER;
697         else if (!strcasecmp("list", s))
698           m->type = M_LIST;
699         else if (!strcasecmp("string", s))
700           m->type = M_STRING;
701         else if (!strcasecmp("kerberos", s))
702           m->type = M_KERBEROS;
703         else {
704             m->type = M_STRING;
705             *(--p) = ':';
706             m->name = s;
707         }
708         m->name = strsave(m->name);
709     } else {
710         m->name = strsave(s);
711         if (strchr(s, '@') || strchr(s, '!') || strchr(s, '%') || strchr(s, ' '))
712           m->type = M_STRING;
713         else
714           m->type = M_ANY;
715     }
716     return(m);
717 }
718
719
720   /* 
721    * This routine two compares members by the following rules:
722    * 1.  A USER is less than a LIST
723    * 2.  A LIST is less than a STRING
724    * 3.  If two members are of the same type, the one alphabetically first
725    *     is less than the other
726    * It returs < 0 if the first member is less, 0 if they are identical, and
727    * > 0 if the second member is less (the first member is greater).
728    */
729
730 int membercmp(m1, m2)
731   struct member *m1, *m2;
732 {
733     if (m1->type == M_ANY || m2->type  == M_ANY || (m1->type == m2->type))
734         return(strcmp(m1->name, m2->name));
735     else
736         return(m1->type - m2->type);
737 }
738
739
740 sq_count_elts(q)
741 struct save_queue *q;
742 {
743     char  *foo;
744     int count;
745
746     count = 0;
747     while (sq_get_data(q, &foo))
748       count++;
749     return(count);
750 }
This page took 0.094958 seconds and 5 git commands to generate.