]> andersk Git - moira.git/blob - clients/blanche/blanche.c
declare membercmp();
[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;
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         membervec[0] = listname;
240         membervec[2] = memberstruct->name;
241         if (verbose) {
242             printf("Adding member ");
243             show_list_member(memberstruct);
244         }
245         switch (memberstruct->type) {
246         case M_ANY:
247         case M_USER:
248             membervec[1] = "USER";
249             status = mr_query("add_member_to_list", 3, membervec, scream, NULL);
250             if (status == MR_SUCCESS)
251               break;
252             else if (status != MR_USER || memberstruct->type != M_ANY) {
253                 com_err(whoami, status, "while adding member %s to %s",
254                         memberstruct->name, listname);
255                 break;
256             }
257         case M_LIST:
258             membervec[1] = "LIST";
259             status = mr_query("add_member_to_list", 3, membervec,
260                                scream, NULL);
261             if (status == MR_SUCCESS)
262               break;
263             else if (status != MR_LIST || memberstruct->type != M_ANY) {
264                 com_err(whoami, status, "while adding member %s to %s",
265                         memberstruct->name, listname);
266                 break;
267             }
268         case M_STRING:
269             membervec[1] = "STRING";
270             status = mr_query("add_member_to_list", 3, membervec,
271                                scream, NULL);
272             if (status != MR_SUCCESS)
273               com_err(whoami, status, "while adding member %s to %s",
274                       memberstruct->name, listname);
275             break;
276         case M_KERBEROS:
277             membervec[1] = "KERBEROS";
278             status = mr_query("add_member_to_list", 3, membervec,
279                                scream, NULL);
280             if (status != MR_SUCCESS)
281               com_err(whoami, status, "while adding member %s to %s",
282                       memberstruct->name, listname);
283         }
284     }
285
286     /* Process the delete list */
287     while (sq_get_data(dellist, &memberstruct)) {
288         membervec[0] = listname;
289         membervec[2] = memberstruct->name;
290         if (verbose) {
291             printf("Deleting member ");
292             show_list_member(memberstruct);
293         }
294         switch (memberstruct->type) {
295         case M_ANY:
296         case M_USER:
297             membervec[1] = "USER";
298             status = mr_query("delete_member_from_list", 3, membervec,
299                                scream, NULL);
300             if (status == MR_SUCCESS)
301               break;
302             else if ((status != MR_USER && status != MR_NO_MATCH) ||
303                      memberstruct->type != M_ANY) {
304                 com_err(whoami, status, "while deleting member %s from %s",
305                         memberstruct->name, listname);
306                 break;
307             }
308         case M_LIST:
309             membervec[1] = "LIST";
310             status = mr_query("delete_member_from_list", 3, membervec,
311                                scream, NULL);
312             if (status == MR_SUCCESS)
313               break;
314             else if ((status != MR_LIST && status != MR_NO_MATCH) ||
315                      memberstruct->type != M_ANY) {
316                 com_err(whoami, status, "while deleting member %s from %s",
317                         memberstruct->name, listname);
318                 break;
319             }
320         case M_STRING:
321             membervec[1] = "STRING";
322             status = mr_query("delete_member_from_list", 3, membervec,
323                                scream, NULL);
324             if (status == MR_STRING && memberstruct->type == M_ANY)
325               com_err(whoami, 0, " Unable to find member %s to delete from %s",
326                       memberstruct->name, listname);
327             else if (status != MR_SUCCESS)
328               com_err(whoami, status, "while deleting member %s from %s",
329                       memberstruct->name, listname);
330             break;
331         case M_KERBEROS:
332             membervec[1] = "KERBEROS";
333             status = mr_query("delete_member_from_list", 3, membervec,
334                                scream, NULL);
335             if (status != MR_SUCCESS)
336               com_err(whoami, status, "while deleting member %s from %s",
337                       memberstruct->name, listname);
338         }
339     }
340
341     /* Display the members of the list now, if requested */
342     if (memberflg) {
343         if (recursflg)
344           recursive_display_list_members();
345         else {
346             status = mr_query("get_members_of_list", 1, &listname,
347                                get_list_members, (char *)memberlist);
348             if (status)
349               com_err(whoami, status, "while getting members of list %s",
350                       listname);
351             while (sq_get_data(memberlist, &memberstruct))
352               show_list_member(memberstruct);
353         }
354     }
355
356     /* We're done! */
357     mr_disconnect();
358     exit(0);
359 }
360
361 usage(argv)
362 char **argv;
363 {
364     fprintf(stderr, "Usage: %s [options] listname [options]\n",argv[0]);
365     fprintf(stderr, "Options are\n");
366     fprintf(stderr, "   -v | -verbose\n");
367     fprintf(stderr, "   -m | -members\n");
368     fprintf(stderr, "   -u | -users\n");
369     fprintf(stderr, "   -l | -lists\n");
370     fprintf(stderr, "   -s | -strings\n");
371     fprintf(stderr, "   -k | -kerberos\n");
372     fprintf(stderr, "   -i | -info\n");
373     fprintf(stderr, "   -r | -recursive\n");
374     fprintf(stderr, "   -a | -add member\n");
375     fprintf(stderr, "   -d | -delete member\n");
376     fprintf(stderr, "   -al | -addlist filename\n");
377     fprintf(stderr, "   -dl | -deletelist filename\n");
378     fprintf(stderr, "   -f | -file filename\n");
379     fprintf(stderr, "   -n | -noauth\n");
380     fprintf(stderr, "   -S | -server host[:port]\n");
381     fprintf(stderr, "   -D | -debug\n");
382     exit(1);
383 }
384
385
386 /* Display the members stored in the queue */
387
388 show_list_member(memberstruct)
389 struct member *memberstruct;
390 {
391     char *s = "";
392
393     switch (memberstruct->type) {
394     case M_USER:
395         if (!showusers)
396           return;
397         s = "USER";
398         break;
399     case M_LIST:
400         if (!showlists)
401           return;
402         s = "LIST";
403         break;
404     case M_STRING:
405         if (!showstrings)
406           return;
407         s = "STRING";
408         break;
409     case M_KERBEROS:
410         if (!showkerberos)
411           return;
412         s = "KERBEROS";
413         break;
414     case M_ANY:
415         printf("%s\n", memberstruct->name);
416         return;
417     }
418
419     if (verbose)
420       printf("%s:%s\n", s, memberstruct->name);
421     else {
422         if (memberstruct->type == M_LIST)
423           printf("LIST:%s\n", memberstruct->name);
424         else if (memberstruct->type == M_KERBEROS)
425           printf("KERBEROS:%s\n", memberstruct->name);
426         else if (memberstruct->type == M_STRING &&
427                  !index(memberstruct->name, '@'))
428           printf("STRING:%s\n", memberstruct->name);
429         else
430           printf("%s\n", memberstruct->name);
431     }
432 }
433
434
435 /* Show the retrieved information about a list */
436
437 show_list_info(argc, argv, hint)
438 int argc;
439 char **argv;
440 int hint;
441 {
442     printf("List: %s\n", argv[0]);
443     printf("Description: %s\n", argv[9]);
444     printf("Flags: %s, %s, and %s\n",
445            atoi(argv[1]) ? "active" : "inactive",
446            atoi(argv[2]) ? "public" : "private",
447            atoi(argv[3]) ? "hidden" : "visible");
448     printf("%s is %sa maillist and is %sa group", argv[0],
449            atoi(argv[4]) ? "" : "not ",
450            atoi(argv[5]) ? "" : "not ");
451     if (atoi(argv[5]))
452       printf(" with GID %d\n", atoi(argv[6]));
453     else
454       printf("\n");
455     printf("Owner: %s %s\n", argv[7], argv[8]);
456     printf("Last modified by %s with %s on %s\n", argv[11], argv[12], argv[10]);
457     return(MR_CONT);
458 }
459
460
461 /* Show the retrieve list member count */
462
463 show_list_count(argc, argv, hint)
464 int argc;
465 char **argv;
466 int hint;
467 {
468     printf("Members: %s\n", argv[0]);
469 }
470
471
472 /* Recursively find all of the members of listname, and then display them */
473
474 recursive_display_list_members()
475 {
476     int status, count, savecount;
477     struct save_queue *lists, *members;
478     struct member *m, *m1, *data;
479
480     lists = sq_create();
481     members = sq_create();
482     m = (struct member *) malloc(sizeof(struct member));
483     m->type = M_LIST;
484     m->name = listname;
485     sq_save_data(lists, m);
486
487     while (sq_get_data(lists, &m)) {
488         sq_destroy(memberlist);
489         memberlist = sq_create();
490         if (debugflg)
491           fprintf(stderr, "Fetching members of %s\n", m->name);
492         status = mr_query("get_members_of_list", 1, &(m->name),
493                            get_list_members, (char *)memberlist);
494         if (status)
495           com_err(whoami, status, "while getting members of list %s", m->name);
496         while (sq_get_data(memberlist, &m1)) {
497             if (m1->type == M_LIST)
498               unique_add_member(lists, m1);
499             else
500               unique_add_member(members, m1);
501         }
502     }
503     savecount = count = sq_count_elts(members);
504     data = (struct member *) malloc(count * sizeof(struct member));
505     count = 0;
506     while (sq_get_data(members, &m))
507       bcopy(m, &data[count++], sizeof(struct member));
508     qsort(data, count, sizeof(struct member), membercmp);
509     for (count = 0; count < savecount; count++) {
510         show_list_member(&data[count]);
511     }
512 }
513
514
515 /* add a struct member to a queue if that member isn't already there. */
516
517 unique_add_member(q, m)
518 struct save_queue  *q;
519 struct member *m;
520 {
521     struct save_queue *qp;
522
523     for (qp = q->q_next; qp != q; qp = qp->q_next) {
524         if (!membercmp(qp->q_data, m))
525           return;
526     }
527     sq_save_data(q, m);
528 }
529
530
531 /* Collect the retrieved members of the list */
532
533 get_list_members(argc, argv, q)
534 int argc;
535 char **argv;
536 struct save_queue *q;
537 {
538     struct member *m;
539
540     m = (struct member *) malloc(sizeof(struct member));
541     switch (argv[0][0]) {
542     case 'U':
543         m->type = M_USER;
544         break;
545     case 'L':
546         m->type = M_LIST;
547         break;
548     case 'S':
549         m->type = M_STRING;
550         break;
551     case 'K':
552         m->type = M_KERBEROS;
553         break;
554     }
555     m->name = strsave(argv[1]);
556     sq_save_data(q, m);
557     return(MR_CONT);
558 }
559
560
561 /* Called only if a query returns a value that we weren't expecting */
562
563 scream()
564 {
565     fprintf(stderr, "Programmer botch\n");
566     exit(3);
567 }
568
569
570 /* Open file, parse members from file, and put them on the specified queue */
571 get_members_from_file(filename, queue)
572 char *filename;
573 struct save_queue *queue;
574 {
575     FILE *in;
576     char buf[BUFSIZ];
577     struct member *memberstruct;
578
579     if (!strcmp(filename, "-"))
580       in = stdin;
581     else {
582         in = fopen(filename, "r");
583         if (!in) {
584             com_err(whoami, errno, "while opening %s for input", filename);
585             exit(2);
586         }
587     }
588
589     while (fgets(buf, BUFSIZ, in))
590       if (memberstruct = parse_member(buf))
591         sq_save_data(queue, memberstruct);
592     if (!feof(in))
593       com_err(whoami, errno, "while reading from %s", filename);
594 }
595
596
597 /* Parse a line of input, fetching a member.  NULL is returned if a member
598  * is not found.  ';' is a comment character.
599  */
600
601 struct member *parse_member(s)
602 register char *s;
603 {
604     register struct member *m;
605     char *p, *lastchar;
606
607     while (*s && isspace(*s))
608       s++;
609     lastchar = p = s;
610     while (*p && *p != '\n' && *p != ';')
611       if (isprint(*p) && !isspace(*p))
612         lastchar = p++;
613       else
614         p++;
615     lastchar++;
616     *lastchar = 0;
617     if (p == s || strlen(s) == 0)
618       return(NULL);
619
620     if ((m = (struct member *) malloc(sizeof(struct member))) == NULL)
621       return(NULL);
622
623     if (p = index(s, ':')) {
624         *p = 0;
625         m->name = ++p;
626         if (!strcasecmp("user", s))
627           m->type = M_USER;
628         else if (!strcasecmp("list", s))
629           m->type = M_LIST;
630         else if (!strcasecmp("string", s))
631           m->type = M_STRING;
632         else if (!strcasecmp("kerberos", s))
633           m->type = M_KERBEROS;
634         else {
635             m->type = M_STRING;
636             *(--p) = ':';
637             m->name = s;
638         }
639         m->name = strsave(m->name);
640         return(m);
641     }
642     m->name = strsave(s);
643     if (index(s, '@') || index(s, '!') || index(s, '%') || index(s, ' '))
644       m->type = M_STRING;
645     else
646       m->type = M_ANY;
647     return(m);
648 }
649
650
651   /* 
652    * This routine two compares members by the following rules:
653    * 1.  A USER is less than a LIST
654    * 2.  A LIST is less than a STRING
655    * 3.  If two members are of the same type, the one alphabetically first
656    *     is less than the other
657    * It returs < 0 if the first member is less, 0 if they are identical, and
658    * > 0 if the second member is less (the first member is greater).
659    */
660
661 int membercmp(m1, m2)
662   struct member *m1, *m2;
663 {
664     if (m1->type == M_ANY || m2->type  == M_ANY || (m1->type == m2->type))
665         return(strcmp(m1->name, m2->name));
666     else
667         return(m1->type - m2->type);
668 }
669
670
671 sq_count_elts(q)
672 struct save_queue *q;
673 {
674     char  *foo;
675     int count;
676
677     count = 0;
678     while (sq_get_data(q, &foo))
679       count++;
680     return(count);
681 }
This page took 3.848254 seconds and 5 git commands to generate.