]> andersk Git - moira.git/blob - clients/blanche/blanche.c
If mrcl_connect() fails, report what list we were trying to update.
[moira.git] / clients / blanche / blanche.c
1 /* $Id$
2  *
3  * Command line oriented Moira List tool.
4  *
5  * by Mark Rosenstein, September 1988.
6  *
7  * Copyright (C) 1988-1998 by the Massachusetts Institute of Technology.
8  * For copying and distribution information, please see the file
9  * <mit-copyright.h>.
10  */
11
12 #include <mit-copyright.h>
13 #include <moira.h>
14 #include <moira_site.h>
15 #include <mrclient.h>
16
17 #include <ctype.h>
18 #include <errno.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 RCSID("$Header$");
24
25 struct member {
26   int type;
27   char *name, *tag;
28 };
29
30 /* It is important to membercmp that M_USER < M_LIST < M_STRING */
31 #define M_ANY           0
32 #define M_USER          1
33 #define M_LIST          2
34 #define M_STRING        3
35 #define M_KERBEROS      4
36 #define M_NONE          5
37
38 char *typename[] = { "ANY", "USER", "LIST", "STRING", "KERBEROS", "NONE" };
39
40 /* argument parsing macro */
41 #define argis(a, b) (!strcmp(*arg + 1, a) || !strcmp(*arg + 1, b))
42
43 /* flags from command line */
44 int infoflg, verbose, syncflg, memberflg, recursflg, noauth;
45 int showusers, showstrings, showkerberos, showlists, showtags;
46 int createflag, setinfo, active, public, hidden, maillist, grouplist;
47 int nfsgroup;
48 struct member *owner, *memacl;
49 char *desc, *newname;
50
51 /* various member lists */
52 struct save_queue *addlist, *dellist, *memberlist, *synclist, *taglist;
53
54 char *listname, *whoami;
55
56 void usage(char **argv);
57 void show_list_member(struct member *memberstruct);
58 int show_list_info(int argc, char **argv, void *hint);
59 int save_list_info(int argc, char **argv, void *hint);
60 int show_list_count(int argc, char **argv, void *hint);
61 void recursive_display_list_members(void);
62 void unique_add_member(struct save_queue *q, struct member *m);
63 int get_list_members(int argc, char **argv, void *sq);
64 void get_members_from_file(char *filename, struct save_queue *queue);
65 int collect(int argc, char **argv, void *l);
66 struct member *parse_member(char *s);
67 int membercmp(const void *mem1, const void *mem2);
68 int sq_count_elts(struct save_queue *q);
69 char *get_username(void);
70
71 int main(int argc, char **argv)
72 {
73   int status, success;
74   char **arg = argv;
75   char *membervec[4];
76   struct member *memberstruct;
77   char *server = NULL, *p;
78
79   /* clear all flags & lists */
80   infoflg = verbose = syncflg = memberflg = recursflg = 0;
81   noauth = showusers = showstrings = showkerberos = showlists = 0;
82   createflag = setinfo = 0;
83   active = public = hidden = maillist = grouplist = nfsgroup = -1;
84   listname = newname = desc = NULL;
85   owner = NULL;
86   memacl = NULL;
87   addlist = sq_create();
88   dellist = sq_create();
89   memberlist = sq_create();
90   synclist = sq_create();
91   taglist = sq_create();
92   whoami = argv[0];
93
94   success = 1;
95
96   /* parse args, building addlist, dellist, & synclist */
97   while (++arg - argv < argc)
98     {
99       if (**arg == '-')
100         {
101           if (argis("m", "members"))
102             memberflg++;
103           else if (argis("u", "users"))
104             showusers++;
105           else if (argis("s", "strings"))
106             showstrings++;
107           else if (argis("l", "lists"))
108             showlists++;
109           else if (argis("k", "kerberos"))
110             showkerberos++;
111           else if (argis("t", "tags"))
112             showtags++;
113           else if (argis("i", "info"))
114             infoflg++;
115           else if (argis("n", "noauth"))
116             noauth++;
117           else if (argis("v", "verbose"))
118             verbose++;
119           else if (argis("r", "recursive"))
120             recursflg++;
121           else if (argis("S", "server") || argis("db", "database"))
122             {
123               if (arg - argv < argc - 1)
124                 {
125                   ++arg;
126                   server = *arg;
127                 }
128               else
129                 usage(argv);
130             }
131           else if (argis("a", "add"))
132             {
133               if (arg - argv < argc - 1)
134                 {
135                   ++arg;
136                   if ((memberstruct = parse_member(*arg)))
137                     sq_save_data(addlist, memberstruct);
138                 }
139               else
140                 usage(argv);
141             }
142           else if (argis("at", "addtagged"))
143             {
144               if (arg - argv < argc - 2)
145                 {
146                   ++arg;
147                   if ((memberstruct = parse_member(*arg)))
148                     sq_save_data(addlist, memberstruct);
149                   memberstruct->tag = *++arg;
150                 }
151               else
152                 usage(argv);
153             }
154           else if (argis("al", "addlist"))
155             {
156               if (arg - argv < argc - 1)
157                 {
158                   ++arg;
159                   get_members_from_file(*arg, addlist);
160                 }
161               else
162                 usage(argv);
163             }
164           else if (argis("d", "delete"))
165             {
166               if (arg - argv < argc - 1)
167                 {
168                   ++arg;
169                   if ((memberstruct = parse_member(*arg)))
170                     sq_save_data(dellist, memberstruct);
171                 }
172               else
173                 usage(argv);
174             }
175           else if (argis("dl", "deletelist"))
176             {
177               if (arg - argv < argc - 1)
178                 {
179                   ++arg;
180                   get_members_from_file(*arg, dellist);
181                 }
182               else
183                 usage(argv);
184             }
185           else if (argis("f", "file"))
186             {
187               if (arg - argv < argc - 1)
188                 {
189                   syncflg++;
190                   ++arg;
191                   get_members_from_file(*arg, synclist);
192                 }
193               else
194                 usage(argv);
195             }
196           else if (argis("ct", "changetag"))
197             {
198               if (arg - argv < argc - 2)
199                 {
200                   ++arg;
201                   if ((memberstruct = parse_member(*arg)))
202                     sq_save_data(taglist, memberstruct);
203                   memberstruct->tag = *++arg;
204                 }
205               else
206                 usage(argv);
207             }
208           else if (argis("C", "create"))
209             createflag++;
210           else if (argis("P", "public"))
211             {
212               setinfo++;
213               public = 1;
214             }
215           else if (argis("NP", "private"))
216             {
217               setinfo++;
218               public = 0;
219             }
220           else if (argis("A", "active"))
221             {
222               setinfo++;
223               active = 1;
224             }
225           else if (argis("I", "inactive"))
226             {
227               setinfo++;
228               active = 0;
229             }
230           else if (argis("V", "visible"))
231             {
232               setinfo++;
233               hidden = 0;
234             }
235           else if (argis("H", "hidden"))
236             {
237               setinfo++;
238               hidden = 1;
239             }
240           else if (argis("M", "mail"))
241             {
242               setinfo++;
243               maillist = 1;
244             }
245           else if (argis("NM", "notmail"))
246             {
247               setinfo++;
248               maillist = 0;
249             }
250           else if (argis("G", "group"))
251             {
252               setinfo++;
253               grouplist = 1;
254             }
255           else if (argis("NG", "notgroup"))
256             {
257               setinfo++;
258               grouplist = 0;
259             }
260           else if (argis("N", "nfs"))
261             {
262               setinfo++;
263               nfsgroup = 1;
264             }
265           else if (argis("NN", "notnfs"))
266             {
267               setinfo++;
268               nfsgroup = 0;
269             }
270           else if (argis("D", "desc"))
271             {
272               if (arg - argv < argc - 1)
273                 {
274                   setinfo++;
275                   ++arg;
276                   desc = *arg;
277                 }
278               else
279                 usage(argv);
280             }
281           else if (argis("O", "owner"))
282             {
283               if (arg - argv < argc - 1)
284                 {
285                   setinfo++;
286                   ++arg;
287                   owner = parse_member(*arg);
288                 }
289               else
290                 usage(argv);
291             }
292           else if (argis("MA", "memacl"))
293             {
294               if (arg - argv < argc -1)
295                 {
296                   setinfo++;
297                   ++arg;
298                   memacl = parse_member(*arg);
299                 }
300               else
301                 usage(argv);
302             }
303           else if (argis("R", "rename"))
304             {
305               if (arg - argv < argc - 1)
306                 {
307                   setinfo++;
308                   ++arg;
309                   newname = *arg;
310                 }
311               else
312                 usage(argv);
313             }
314           else
315             usage(argv);
316         }
317       else if (listname == NULL)
318         listname = *arg;
319       else
320         usage(argv);
321     }
322   if (listname == NULL)
323     usage(argv);
324
325   /* if no other options specified, turn on list members flag */
326   if (!(infoflg || syncflg || createflag || setinfo ||
327         addlist->q_next != addlist || dellist->q_next != dellist ||
328         taglist->q_next != taglist))
329     memberflg++;
330
331   /* If none of {users,strings,lists,kerberos} specified, turn them all on */
332   if (!(showusers || showstrings || showlists || showkerberos))
333     showusers = showstrings = showlists = showkerberos = 1;
334
335   /* fire up Moira */
336   status = mrcl_connect(server, "blanche", 4, !noauth);
337   if (status == MRCL_AUTH_ERROR)
338     {
339       com_err(whoami, 0, "Authentication error while working on list %s",
340               listname);
341       com_err(whoami, 0, "Try the -noauth flag if you don't "
342               "need authentication.");
343     }
344   if (status)
345     exit(2);
346
347   /* check for username/listname clash */
348   if (createflag || (setinfo && newname && strcmp(newname, listname)))
349     {
350       status = mr_query("get_user_account_by_login", 1,
351                         createflag ? &listname : &newname,
352                         NULL, NULL);
353       if (status != MR_NO_MATCH)
354         fprintf(stderr, "WARNING: A user by that name already exists.\n");
355     }
356
357   /* create if needed */
358   if (createflag)
359     {
360       char *argv[13];
361
362       argv[L_NAME] = listname;
363       argv[L_ACTIVE] = (active == 0) ? "0" : "1";
364       argv[L_PUBLIC] = (public == 1) ? "1" : "0";
365       argv[L_HIDDEN] = (hidden == 1) ? "1" : "0";
366       argv[L_MAILLIST] = (maillist == 0) ? "0" : "1";
367       argv[L_GROUP] = (grouplist == 1) ? "1" : "0";
368       argv[L_GID] = UNIQUE_GID;
369       argv[L_NFSGROUP] = (nfsgroup == 1) ? "1" : "0";
370       argv[L_DESC] = desc ? desc : "none";
371
372       if (memacl)
373         {
374           if (memacl->type == M_ANY)
375             {
376               status = mr_query("get_user_account_by_login", 1,
377                                 &memacl->name, NULL, NULL);
378               if (status == MR_NO_MATCH)
379                 memacl->type = M_LIST;
380               else
381                 memacl->type = M_USER;
382             }
383           argv[L_MEMACE_TYPE] = typename[memacl->type];
384           argv[L_MEMACE_NAME] = memacl->name;
385           if (memacl->type == M_KERBEROS)
386             {
387               status = mrcl_validate_kerberos_member(argv[L_MEMACE_NAME],
388                                                      &argv[L_MEMACE_NAME]);
389               if (mrcl_get_message())
390                 mrcl_com_err(whoami);
391             }
392         }
393       else 
394         argv[L_MEMACE_TYPE] = argv[L_MEMACE_NAME] = "NONE";
395
396       if (owner)
397         {
398           argv[L_ACE_NAME] = owner->name;
399           switch (owner->type)
400             {
401             case M_ANY:
402             case M_USER:
403               argv[L_ACE_TYPE] = "USER";
404               status = mr_query("add_list", 13, argv, NULL, NULL);
405               if (owner->type != M_ANY || status != MR_USER)
406                 break;
407
408             case M_LIST:
409               argv[L_ACE_TYPE] = "LIST";
410               status = mr_query("add_list", 13, argv, NULL, NULL);
411               break;
412
413             case M_KERBEROS:
414               argv[L_ACE_TYPE] = "KERBEROS";
415               status = mrcl_validate_kerberos_member(argv[L_ACE_NAME], 
416                                                      &argv[L_ACE_NAME]);
417               if (mrcl_get_message())
418                 mrcl_com_err(whoami);
419               status = mr_query("add_list", 13, argv, NULL, NULL);
420               break;
421             case M_NONE:
422               argv[L_ACE_TYPE] = argv[L_ACE_NAME] = "NONE";
423               status = mr_query("add_list", 13, argv, NULL, NULL);
424               break;
425             }
426         }
427       else
428         {
429           argv[L_ACE_TYPE] = "USER";
430           argv[L_ACE_NAME] = get_username();
431
432           status = mr_query("add_list", 13, argv, NULL, NULL);
433         }
434
435       if (status)
436         {
437           com_err(whoami, status, "while creating list.");
438           exit(1);
439         }
440     }
441   else if (setinfo)
442     {
443       char *argv[14];
444
445       status = mr_query("get_list_info", 1, &listname,
446                         save_list_info, argv);
447       if (status)
448         {
449           com_err(whoami, status, "while getting list information");
450           exit(1);
451         }
452
453       argv[0] = listname;
454       if (newname)
455         argv[L_NAME + 1] = newname;
456       if (active != -1)
457         argv[L_ACTIVE + 1] = active ? "1" : "0";
458       if (public != -1)
459         argv[L_PUBLIC + 1] = public ? "1" : "0";
460       if (hidden != -1)
461         argv[L_HIDDEN + 1] = hidden ? "1" : "0";
462       if (maillist != -1)
463         argv[L_MAILLIST + 1] = maillist ? "1" : "0";
464       if (grouplist != -1)
465         argv[L_GROUP + 1] = grouplist ? "1" : "0";
466       if (nfsgroup != -1)
467         argv[L_NFSGROUP + 1] = nfsgroup ? "1" : "0";
468       if (desc)
469         argv[L_DESC + 1] = desc;
470
471       if (memacl)
472         {
473           if (memacl->type == M_ANY)
474             {
475               status = mr_query("get_user_account_by_login", 1,
476                                 &memacl->name, NULL, NULL);
477               if (status == MR_NO_MATCH)
478                 memacl->type = M_LIST;
479               else
480                 memacl->type = M_USER;
481             }
482           argv[L_MEMACE_TYPE + 1] = typename[memacl->type];
483           argv[L_MEMACE_NAME + 1] = memacl->name;
484           if (memacl->type == M_KERBEROS)
485             {
486               status = mrcl_validate_kerberos_member(argv[L_MEMACE_NAME + 1],
487                                                      &argv[L_MEMACE_NAME + 1]);
488               if (mrcl_get_message())
489                 mrcl_com_err(whoami);
490             }
491         }
492
493       if (owner)
494         {
495           argv[L_ACE_NAME + 1] = owner->name;
496           switch (owner->type)
497             {
498             case M_ANY:
499             case M_USER:
500               argv[L_ACE_TYPE + 1] = "USER";
501               status = mr_query("update_list", 14, argv, NULL, NULL);
502               if (owner->type != M_ANY || status != MR_USER)
503                 break;
504
505             case M_LIST:
506               argv[L_ACE_TYPE + 1] = "LIST";
507               status = mr_query("update_list", 14, argv, NULL, NULL);
508               break;
509
510             case M_KERBEROS:
511               argv[L_ACE_TYPE + 1] = "KERBEROS";
512               status = mrcl_validate_kerberos_member(argv[L_ACE_NAME + 1],
513                                                      &argv[L_ACE_NAME + 1]);
514               if (mrcl_get_message())
515                 mrcl_com_err(whoami);
516               status = mr_query("update_list", 14, argv, NULL, NULL);
517               break;
518             case M_NONE:
519               argv[L_ACE_TYPE + 1] = argv[L_ACE_NAME + 1] = "NONE";
520               status = mr_query("update_list", 14, argv, NULL, NULL);
521               break;
522             }
523         }
524       else
525         status = mr_query("update_list", 14, argv, NULL, NULL);
526
527       if (status)
528         {
529           com_err(whoami, status, "while updating list.");
530           success = 0;
531         }
532       else if (newname)
533         listname = newname;
534     }
535
536   /* display list info if requested to */
537   if (infoflg)
538     {
539       status = mr_query("get_list_info", 1, &listname, show_list_info, NULL);
540       if (status)
541         {
542           com_err(whoami, status, "while getting list information");
543           success = 0;
544         }
545       if (verbose && !memberflg)
546         {
547           status = mr_query("count_members_of_list", 1, &listname,
548                             show_list_count, NULL);
549           if (status)
550             {
551               com_err(whoami, status, "while getting list count");
552               success = 0;
553             }
554         }
555     }
556
557   /* if we're synchronizing to a file, we need to:
558    *  get the current members of the list
559    *    for each member of the sync file
560    *       if they are on the list, remove them from the in-memory copy
561    *       if they're not on the list, add them to add-list
562    *    if anyone is left on the in-memory copy, put them on the delete-list
563    * lastly, reset memberlist so we can use it again later
564    */
565   if (syncflg)
566     {
567       status = mr_query("get_members_of_list", 1, &listname,
568                         get_list_members, memberlist);
569       if (status)
570         {
571           com_err(whoami, status, "getting members of list %s", listname);
572           exit(2);
573         }
574       while (sq_get_data(synclist, &memberstruct))
575         {
576           struct save_queue *q;
577           int removed = 0;
578
579           for (q = memberlist->q_next; q != memberlist; q = q->q_next)
580             {
581               if (membercmp(q->q_data, memberstruct) == 0)
582                 {
583                   q->q_prev->q_next = q->q_next;
584                   q->q_next->q_prev = q->q_prev;
585                   removed++;
586                   break;
587                 }
588             }
589           if (!removed)
590             sq_save_data(addlist, memberstruct);
591         }
592       while (sq_get_data(memberlist, &memberstruct))
593         sq_save_data(dellist, memberstruct);
594       sq_destroy(memberlist);
595       memberlist = sq_create();
596     }
597
598   /* Process the add list */
599   while (sq_get_data(addlist, &memberstruct))
600     {
601       /* canonicalize string if necessary */
602       if (memberstruct->type != M_KERBEROS &&
603           (p = strchr(memberstruct->name, '@')))
604         {
605           char *host = canonicalize_hostname(strdup(++p));
606           static char **mailhubs = NULL;
607           char *argv[4];
608           int i;
609
610           if (!mailhubs)
611             {
612               argv[0] = "mailhub";
613               argv[1] = "TYPE";
614               argv[2] = "*";
615               mailhubs = malloc(sizeof(char *));
616               mailhubs[0] = NULL;
617               status = mr_query("get_alias", 3, argv, collect,
618                                 &mailhubs);
619               if (status != MR_SUCCESS && status != MR_NO_MATCH)
620                 {
621                   com_err(whoami, status,
622                           " while reading list of MAILHUB servers");
623                   mailhubs[0] = NULL;
624                 }
625             }
626           for (i = 0; (p = mailhubs[i]); i++)
627             {
628               if (!strcasecmp(p, host))
629                 {
630                   host = strdup(memberstruct->name);
631                   *(strchr(memberstruct->name, '@')) = 0;
632                   if (memberstruct->type == M_STRING)
633                       memberstruct->type = M_ANY;
634                   fprintf(stderr, "Warning: \"%s\" converted to "
635                           "\"%s\" because it is a local name.\n",
636                           host, memberstruct->name);
637                   break;
638                 }
639             }
640           free(host);
641         }
642       /* now continue adding member */
643       membervec[0] = listname;
644       membervec[2] = memberstruct->name;
645       membervec[3] = memberstruct->tag;
646       if (verbose)
647         {
648           printf("Adding member ");
649           show_list_member(memberstruct);
650         }
651       switch (memberstruct->type)
652         {
653         case M_ANY:
654         case M_USER:
655           membervec[1] = "USER";
656           status = mr_query("add_tagged_member_to_list", 4, membervec,
657                             NULL, NULL);
658           if (status == MR_SUCCESS)
659             break;
660           else if (status != MR_USER || memberstruct->type != M_ANY)
661             {
662               com_err(whoami, status, "while adding member %s to %s",
663                       memberstruct->name, listname);
664               success = 0;
665               break;
666             }
667         case M_LIST:
668           membervec[1] = "LIST";
669           status = mr_query("add_tagged_member_to_list", 4, membervec,
670                             NULL, NULL);
671           if (status == MR_SUCCESS)
672             {
673               if (!strcmp(membervec[0], get_username()))
674                 {
675                   fprintf(stderr, "\nWARNING: \"LIST:%s\" was just added "
676                           "to list \"%s\".\n", membervec[2], membervec[0]);
677                   fprintf(stderr, "If you meant to add yourself to the list "
678                           "\"%s\", type:\n", membervec[2]);
679                   fprintf(stderr, "\tblanche %s -d %s\t(to undo this)\n",
680                           membervec[0], membervec[2]);
681                   fprintf(stderr, "\tblanche %s -a %s\t(to add yourself to "
682                           "that list)\n", membervec[2], membervec[0]);
683                 }
684               break;
685             }
686           else if (status != MR_LIST || memberstruct->type != M_ANY)
687             {
688               com_err(whoami, status, "while adding member %s to %s",
689                       memberstruct->name, listname);
690               success = 0;
691               break;
692             }
693         case M_STRING:
694           status = mrcl_validate_string_member(memberstruct->name);
695           if (memberstruct->type == M_ANY && status == MRCL_WARN)
696             {
697               /* if user is trying to add something which isn't a
698                  remote string, or a list, or a user, and didn't
699                  explicitly specify `STRING:', it's probably a typo */
700               com_err(whoami, MR_NO_MATCH, "while adding member %s to %s",
701                       memberstruct->name, listname);
702               success = 0;
703               break;
704             }
705           else
706             mrcl_com_err(whoami);
707
708           if (status == MRCL_REJECT)
709             {
710               success = 0;
711               break;
712             }
713
714           membervec[1] = "STRING";
715           status = mr_query("add_tagged_member_to_list", 4, membervec,
716                             NULL, NULL);
717           if (status != MR_SUCCESS)
718             {
719               com_err(whoami, status, "while adding member %s to %s",
720                       memberstruct->name, listname);
721               success = 0;
722             }
723           break;
724         case M_KERBEROS:
725           membervec[1] = "KERBEROS";
726           status = mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
727           if (mrcl_get_message())
728             mrcl_com_err(whoami);
729           status = mr_query("add_tagged_member_to_list", 4, membervec,
730                             NULL, NULL);
731           if (status != MR_SUCCESS)
732             {
733               com_err(whoami, status, "while adding member %s to %s",
734                       memberstruct->name, listname);
735               success = 0;
736             }
737           free(membervec[2]);
738         }
739     }
740
741   /* Process the delete list */
742   while (sq_get_data(dellist, &memberstruct))
743     {
744       membervec[0] = listname;
745       membervec[2] = memberstruct->name;
746       if (verbose)
747         {
748           printf("Deleting member ");
749           show_list_member(memberstruct);
750         }
751       switch (memberstruct->type)
752         {
753         case M_ANY:
754         case M_USER:
755           membervec[1] = "USER";
756           status = mr_query("delete_member_from_list", 3, membervec,
757                             NULL, NULL);
758           if (status == MR_SUCCESS)
759             break;
760           else if ((status != MR_USER && status != MR_NO_MATCH) ||
761                    memberstruct->type != M_ANY)
762             {
763               com_err(whoami, status, "while deleting member %s from %s",
764                       memberstruct->name, listname);
765               success = 0;
766               break;
767             }
768         case M_LIST:
769           membervec[1] = "LIST";
770           status = mr_query("delete_member_from_list", 3, membervec,
771                             NULL, NULL);
772           if (status == MR_SUCCESS)
773             break;
774           else if ((status != MR_LIST && status != MR_NO_MATCH) ||
775                    memberstruct->type != M_ANY)
776             {
777               if (status == MR_PERM && memberstruct->type == M_ANY &&
778                   !strcmp(membervec[2], get_username()))
779                 {
780                   /* M_ANY means we've fallen through from the user
781                    * case. The user is trying to remove himself from
782                    * a list, but we got MR_USER or MR_NO_MATCH above,
783                    * meaning he's not really on it, and we got MR_PERM
784                    * when trying to remove LIST:$USER because he's not
785                    * on the acl. That error is useless, so return
786                    * MR_NO_MATCH instead. However, this will generate the
787                    * wrong error if the user was trying to remove the list
788                    * with his username from a list he doesn't administrate
789                    * without explicitly specifying "list:".
790                    */
791                   status = MR_NO_MATCH;
792                 }
793               com_err(whoami, status, "while deleting member %s from %s",
794                       memberstruct->name, listname);
795               success = 0;
796               break;
797             }
798         case M_STRING:
799           membervec[1] = "STRING";
800           status = mr_query("delete_member_from_list", 3, membervec,
801                             NULL, NULL);
802           if (status == MR_STRING && memberstruct->type == M_ANY)
803             {
804               com_err(whoami, 0, " Unable to find member %s to delete from %s",
805                       memberstruct->name, listname);
806               success = 0;
807               if (!strcmp(membervec[0], get_username()))
808                 {
809                   fprintf(stderr, "(If you were trying to remove yourself "
810                           "from the list \"%s\",\n", membervec[2]);
811                   fprintf(stderr, "the correct command is \"blanche %s -d "
812                           "%s\".)\n", membervec[2], membervec[0]);
813                 }
814             }
815           else if (status != MR_SUCCESS)
816             {
817               com_err(whoami, status, "while deleting member %s from %s",
818                       memberstruct->name, listname);
819               success = 0;
820             }
821           break;
822         case M_KERBEROS:
823           membervec[1] = "KERBEROS";
824           status = mr_query("delete_member_from_list", 3, membervec,
825                             NULL, NULL);
826           if (status == MR_STRING || status == MR_NO_MATCH)
827             {
828               /* Try canonicalizing the Kerberos principal and trying
829                * again.  If we succeed, print the message from mrcl.
830                * Otherwise, just pretend we never did this and print 
831                * the original error message.
832                */
833               mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
834               if (mrcl_get_message())
835                 {
836                   if (mr_query("delete_member_from_list", 3, membervec,
837                                NULL, NULL) == MR_SUCCESS)
838                     mrcl_com_err(whoami);
839                   status = MR_SUCCESS;
840                 }
841             }
842           if (status != MR_SUCCESS)
843             {
844               com_err(whoami, status, "while deleting member %s from %s",
845                       memberstruct->name, listname);
846               success = 0;
847             }
848         }
849     }
850
851   /* Process the tag list */
852   while (sq_get_data(taglist, &memberstruct))
853     {
854       membervec[0] = listname;
855       membervec[2] = memberstruct->name;
856       membervec[3] = memberstruct->tag;
857       if (verbose)
858         {
859           printf("Tagging member ");
860           show_list_member(memberstruct);
861         }
862       switch (memberstruct->type)
863         {
864         case M_ANY:
865         case M_USER:
866           membervec[1] = "USER";
867           status = mr_query("tag_member_of_list", 4, membervec,
868                             NULL, NULL);
869           if (status == MR_SUCCESS)
870             break;
871           else if ((status != MR_USER && status != MR_NO_MATCH) ||
872                    memberstruct->type != M_ANY)
873             {
874               com_err(whoami, status, "while changing tag on member %s of %s",
875                       memberstruct->name, listname);
876               success = 0;
877               break;
878             }
879         case M_LIST:
880           membervec[1] = "LIST";
881           status = mr_query("tag_member_of_list", 4, membervec,
882                             NULL, NULL);
883           if (status == MR_SUCCESS)
884             break;
885           else if ((status != MR_LIST && status != MR_NO_MATCH) ||
886                    memberstruct->type != M_ANY)
887             {
888               com_err(whoami, status, "while changing tag on member %s of %s",
889                       memberstruct->name, listname);
890               success = 0;
891               break;
892             }
893         case M_STRING:
894           membervec[1] = "STRING";
895           status = mr_query("tag_member_of_list", 4, membervec,
896                             NULL, NULL);
897           if (status == MR_STRING && memberstruct->type == M_ANY)
898             {
899               com_err(whoami, 0, " Unable to find member %s on list %s",
900                       memberstruct->name, listname);
901               success = 0;
902             }
903           else if (status != MR_SUCCESS)
904             {
905               com_err(whoami, status, "while retagging member %s on %s",
906                       memberstruct->name, listname);
907               success = 0;
908             }
909           break;
910         case M_KERBEROS:
911           membervec[1] = "KERBEROS";
912           status = mr_query("tag_member_of_list", 4, membervec,
913                             NULL, NULL);
914           if (status == MR_STRING || status == MR_NO_MATCH)
915             {
916               /* Try canonicalizing the Kerberos principal and trying
917                * again.  If we succeed, print the message from mrcl.
918                * Otherwise, just pretend we never did this and print 
919                * the original error message.
920                */
921               mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
922               if (mrcl_get_message())
923                 {
924                   if (mr_query("tag_member_of_list", 4, membervec,
925                                NULL, NULL) == MR_SUCCESS)
926                     mrcl_com_err(whoami);
927                   status = MR_SUCCESS;
928                 }
929             }
930           if (status != MR_SUCCESS)
931             {
932               com_err(whoami, status, "while changing tag on member %s of %s",
933                       memberstruct->name, listname);
934               success = 0;
935             }
936         }
937     }
938
939   /* Display the members of the list now, if requested */
940   if (memberflg)
941     {
942       if (recursflg)
943         recursive_display_list_members();
944       else
945         {
946           status = mr_query(showtags ? "get_tagged_members_of_list" :
947                             "get_members_of_list", 1, &listname,
948                             get_list_members, memberlist);
949           if (status)
950             com_err(whoami, status, "while getting members of list %s",
951                     listname);
952           while (sq_get_data(memberlist, &memberstruct))
953             show_list_member(memberstruct);
954         }
955     }
956
957   /* We're done! */
958   mr_disconnect();
959   exit(success ? 0 : 1);
960 }
961
962 void usage(char **argv)
963 {
964 #define USAGE_OPTIONS_FORMAT "  %-39s%s\n"
965   fprintf(stderr, "Usage: %s listname [options]\n", argv[0]);
966   fprintf(stderr, "Options are\n");
967   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-v  | -verbose",
968           "-C  | -create");
969   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-m  | -members",
970           "-R  | -rename newname");
971   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-u  | -users",
972           "-P  | -public");
973   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-l  | -lists",
974           "-NP | -private");
975   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-s  | -strings",
976           "-A  | -active");
977   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-k  | -kerberos",
978           "-I  | -inactive");
979   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-i  | -info",
980           "-V  | -visible");
981   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-r  | -recursive",
982           "-H  | -hidden");
983   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-a  | -add member",
984           "-M  | -mail");
985   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-d  | -delete member",
986           "-NM | -notmail");
987   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-al | -addlist filename",
988           "-G  | -group");
989   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-dl | -deletelist filename",
990           "-NG | -notgroup");
991   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-f  | -file filename",
992           "-N  | -nfs");
993   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-at | -addtagged member tag",
994           "-NN | -notnfs");
995   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-ct | -changetag member tag",
996           "-D  | -desc description");
997   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-t  | -tags",
998           "-O  | -owner owner");
999   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-n  | -noauth",
1000           "-MA | -memacl membership_acl");
1001   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-db | -database host[:port]",
1002           "");
1003   exit(1);
1004 }
1005
1006
1007 /* Display the members stored in the queue */
1008
1009 void show_list_member(struct member *memberstruct)
1010 {
1011   char *s = "";
1012
1013   switch (memberstruct->type)
1014     {
1015     case M_USER:
1016       if (!showusers)
1017         return;
1018       s = "USER";
1019       break;
1020     case M_LIST:
1021       if (!showlists)
1022         return;
1023       s = "LIST";
1024       break;
1025     case M_STRING:
1026       if (!showstrings)
1027         return;
1028       s = "STRING";
1029       break;
1030     case M_KERBEROS:
1031       if (!showkerberos)
1032         return;
1033       s = "KERBEROS";
1034       break;
1035     case M_ANY:
1036       printf("%s\n", memberstruct->name);
1037       return;
1038     }
1039
1040   if (verbose)
1041     printf("%s:%s", s, memberstruct->name);
1042   else
1043     {
1044       if (memberstruct->type == M_LIST)
1045         printf("LIST:%s", memberstruct->name);
1046       else if (memberstruct->type == M_KERBEROS)
1047         printf("KERBEROS:%s", memberstruct->name);
1048       else if (memberstruct->type == M_STRING &&
1049                !strchr(memberstruct->name, '@'))
1050         printf("STRING:%s", memberstruct->name);
1051       else
1052         printf("%s", memberstruct->name);
1053     }
1054   if (showtags && *(memberstruct->tag))
1055     printf(" (%s)\n", memberstruct->tag);
1056   else
1057     printf("\n");
1058 }
1059
1060
1061 /* Show the retrieved information about a list */
1062
1063 int show_list_info(int argc, char **argv, void *hint)
1064 {
1065   printf("List: %s\n", argv[L_NAME]);
1066   printf("Description: %s\n", argv[L_DESC]);
1067   printf("Flags: %s, %s, and %s\n",
1068          atoi(argv[L_ACTIVE]) ? "active" : "inactive",
1069          atoi(argv[L_PUBLIC]) ? "public" : "private",
1070          atoi(argv[L_HIDDEN]) ? "hidden" : "visible");
1071   printf("%s is %sa maillist and is %sa group", argv[L_NAME],
1072          atoi(argv[L_MAILLIST]) ? "" : "not ",
1073          atoi(argv[L_GROUP]) ? "" : "not ");
1074   if (atoi(argv[L_GROUP]))
1075     {
1076       if (atoi(argv[L_NFSGROUP]))
1077         printf(" (and an NFS group)");
1078       printf(" with GID %d\n", atoi(argv[L_GID]));
1079     }
1080   else
1081     printf("\n");
1082   printf("Owner: %s %s\n", argv[L_ACE_TYPE], argv[L_ACE_NAME]);
1083   if (strcmp(argv[L_MEMACE_TYPE], "NONE"))
1084     printf("Membership ACL: %s %s\n", argv[L_MEMACE_TYPE], 
1085            argv[L_MEMACE_NAME]);
1086   printf("Last modified by %s with %s on %s\n", 
1087          argv[L_MODBY], argv[L_MODWITH], argv[L_MODTIME]);
1088   return MR_CONT;
1089 }
1090
1091
1092 /* Copy retrieved information about a list into a new argv */
1093
1094 int save_list_info(int argc, char **argv, void *hint)
1095 {
1096   char **nargv = hint;
1097
1098   for (argc = 0; argc < 14; argc++)
1099     nargv[argc + 1] = strdup(argv[argc]);
1100   return MR_CONT;
1101 }
1102
1103 /* Show the retrieve list member count */
1104
1105 int show_list_count(int argc, char **argv, void *hint)
1106 {
1107   printf("Members: %s\n", argv[0]);
1108   return MR_CONT;
1109 }
1110
1111
1112 /* Recursively find all of the members of listname, and then display them */
1113
1114 void recursive_display_list_members(void)
1115 {
1116   int status, count, savecount;
1117   struct save_queue *lists, *members;
1118   struct member *m, *m1, *data;
1119
1120   lists = sq_create();
1121   members = sq_create();
1122   m = malloc(sizeof(struct member));
1123   m->type = M_LIST;
1124   m->name = listname;
1125   sq_save_data(lists, m);
1126
1127   while (sq_get_data(lists, &m))
1128     {
1129       sq_destroy(memberlist);
1130       memberlist = sq_create();
1131       status = mr_query("get_members_of_list", 1, &(m->name),
1132                         get_list_members, memberlist);
1133       if (status)
1134         com_err(whoami, status, "while getting members of list %s", m->name);
1135       while (sq_get_data(memberlist, &m1))
1136         {
1137           if (m1->type == M_LIST)
1138             unique_add_member(lists, m1);
1139           else
1140             unique_add_member(members, m1);
1141         }
1142     }
1143   savecount = count = sq_count_elts(members);
1144   data = malloc(count * sizeof(struct member));
1145   count = 0;
1146   while (sq_get_data(members, &m))
1147     memcpy(&data[count++], m, sizeof(struct member));
1148   qsort(data, count, sizeof(struct member), membercmp);
1149   for (count = 0; count < savecount; count++)
1150     show_list_member(&data[count]);
1151 }
1152
1153
1154 /* add a struct member to a queue if that member isn't already there. */
1155
1156 void unique_add_member(struct save_queue *q, struct member *m)
1157 {
1158   struct save_queue *qp;
1159
1160   for (qp = q->q_next; qp != q; qp = qp->q_next)
1161     {
1162       if (!membercmp(qp->q_data, m))
1163         return;
1164     }
1165   sq_save_data(q, m);
1166 }
1167
1168
1169 /* Collect the retrieved members of the list */
1170
1171 int get_list_members(int argc, char **argv, void *sq)
1172 {
1173   struct save_queue *q = sq;
1174   struct member *m;
1175
1176   m = malloc(sizeof(struct member));
1177   switch (argv[0][0])
1178     {
1179     case 'U':
1180       m->type = M_USER;
1181       break;
1182     case 'L':
1183       m->type = M_LIST;
1184       break;
1185     case 'S':
1186       m->type = M_STRING;
1187       break;
1188     case 'K':
1189       m->type = M_KERBEROS;
1190       break;
1191     }
1192   m->name = strdup(argv[1]);
1193   if (argc == 3)
1194     m->tag = strdup(argv[2]);
1195   else
1196     m->tag = strdup("");
1197   sq_save_data(q, m);
1198   return MR_CONT;
1199 }
1200
1201
1202 /* Open file, parse members from file, and put them on the specified queue */
1203 void get_members_from_file(char *filename, struct save_queue *queue)
1204 {
1205   FILE *in;
1206   char buf[BUFSIZ];
1207   struct member *memberstruct;
1208
1209   if (!strcmp(filename, "-"))
1210     in = stdin;
1211   else
1212     {
1213       in = fopen(filename, "r");
1214       if (!in)
1215         {
1216           com_err(whoami, errno, "while opening %s for input", filename);
1217           exit(2);
1218         }
1219     }
1220
1221   while (fgets(buf, BUFSIZ, in))
1222     {
1223       if ((memberstruct = parse_member(buf)))
1224         sq_save_data(queue, memberstruct);
1225     }
1226   if (!feof(in))
1227     {
1228       com_err(whoami, errno, "while reading from %s", filename);
1229       exit(2);
1230     }
1231 }
1232
1233
1234 /* Collect the possible expansions of the alias MAILHUB */
1235
1236 int collect(int argc, char **argv, void *l)
1237 {
1238   char ***list = l;
1239   int i;
1240
1241   for (i = 0; (*list)[i]; i++)
1242     ;
1243   *list = realloc(*list, (i + 2) * sizeof(char *));
1244   (*list)[i] = strdup(argv[2]);
1245   (*list)[i + 1] = NULL;
1246   return MR_CONT;
1247 }
1248
1249
1250 /* Parse a line of input, fetching a member.  NULL is returned if a member
1251  * is not found.  ';' is a comment character.
1252  */
1253
1254 struct member *parse_member(char *s)
1255 {
1256   struct member *m;
1257   char *p, *lastchar;
1258
1259   while (*s && isspace(*s))
1260     s++;
1261   lastchar = p = s;
1262   while (*p && *p != '\n' && *p != ';')
1263     {
1264       if (isprint(*p) && !isspace(*p))
1265         lastchar = p++;
1266       else
1267         p++;
1268     }
1269   lastchar++;
1270   *lastchar = '\0';
1271   if (p == s || strlen(s) == 0)
1272     return NULL;
1273
1274   if (!(m = malloc(sizeof(struct member))))
1275     return NULL;
1276   m->tag = strdup("");
1277
1278   if ((p = strchr(s, ':')))
1279     {
1280       *p = '\0';
1281       m->name = ++p;
1282       if (!strcasecmp("user", s))
1283         m->type = M_USER;
1284       else if (!strcasecmp("list", s))
1285         m->type = M_LIST;
1286       else if (!strcasecmp("string", s))
1287         m->type = M_STRING;
1288       else if (!strcasecmp("kerberos", s))
1289         m->type = M_KERBEROS;
1290       else if (!strcasecmp("none", s))
1291         m->type = M_NONE;
1292       else
1293         {
1294           m->type = M_ANY;
1295           *(--p) = ':';
1296           m->name = s;
1297         }
1298       m->name = strdup(m->name);
1299     }
1300   else
1301     {
1302       m->name = strdup(s);
1303       m->type = strcasecmp(s, "none") ? M_ANY : M_NONE;
1304     }
1305   return m;
1306 }
1307
1308
1309 /*
1310  * This routine two compares members by the following rules:
1311  * 1.  A USER is less than a LIST
1312  * 2.  A LIST is less than a STRING
1313  * 3.  If two members are of the same type, the one alphabetically first
1314  *     is less than the other
1315  * It returs < 0 if the first member is less, 0 if they are identical, and
1316  * > 0 if the second member is less (the first member is greater).
1317  */
1318
1319 int membercmp(const void *mem1, const void *mem2)
1320 {
1321   const struct member *m1 = mem1, *m2 = mem2;
1322
1323   if (m1->type == M_ANY || m2->type == M_ANY || (m1->type == m2->type))
1324     return strcmp(m1->name, m2->name);
1325   else
1326     return m1->type - m2->type;
1327 }
1328
1329
1330 int sq_count_elts(struct save_queue *q)
1331 {
1332   char *foo;
1333   int count;
1334
1335   count = 0;
1336   while (sq_get_data(q, &foo))
1337     count++;
1338   return count;
1339 }
1340
1341 char *get_username(void)
1342 {
1343   char *username;
1344
1345   username = getenv("USER");
1346   if (!username)
1347     {
1348       username = mrcl_krb_user();
1349       if (!username)
1350         {
1351           com_err(whoami, 0, "Could not determine username");
1352           exit(1);
1353         }
1354     }
1355   return username;
1356 }
This page took 0.26263 seconds and 5 git commands to generate.