3 * Command line oriented Moira List tool.
5 * by Mark Rosenstein, September 1988.
7 * Copyright (C) 1988-1998 by the Massachusetts Institute of Technology.
8 * For copying and distribution information, please see the file
12 #include <mit-copyright.h>
14 #include <moira_site.h>
30 /* It is important to membercmp that M_USER < M_LIST < M_STRING */
39 char *typename[] = { "ANY", "USER", "LIST", "STRING", "KERBEROS", "MACHINE",
42 /* argument parsing macro */
43 #define argis(a, b) (!strcmp(*arg + 1, a) || !strcmp(*arg + 1, b))
45 /* flags from command line */
46 int infoflg, verbose, syncflg, memberflg, recursflg, noauth;
47 int showusers, showstrings, showkerberos, showlists, showtags, showmachines;
48 int createflag, setinfo, active, public, hidden, maillist, grouplist;
50 struct member *owner, *memacl;
53 /* various member lists */
54 struct save_queue *addlist, *dellist, *memberlist, *synclist, *taglist;
56 char *listname, *whoami;
58 void usage(char **argv);
59 void show_list_member(struct member *memberstruct);
60 int show_list_info(int argc, char **argv, void *hint);
61 int save_list_info(int argc, char **argv, void *hint);
62 int show_list_count(int argc, char **argv, void *hint);
63 void recursive_display_list_members(void);
64 void unique_add_member(struct save_queue *q, struct member *m);
65 int get_list_members(int argc, char **argv, void *sq);
66 void get_members_from_file(char *filename, struct save_queue *queue);
67 int collect(int argc, char **argv, void *l);
68 struct member *parse_member(char *s);
69 int membercmp(const void *mem1, const void *mem2);
70 int sq_count_elts(struct save_queue *q);
71 char *get_username(void);
73 int main(int argc, char **argv)
78 struct member *memberstruct;
79 char *server = NULL, *p;
81 /* clear all flags & lists */
82 infoflg = verbose = syncflg = memberflg = recursflg = 0;
83 noauth = showusers = showstrings = showkerberos = showlists = 0;
84 showtags = showmachines = createflag = setinfo = 0;
85 active = public = hidden = maillist = grouplist = nfsgroup = -1;
86 listname = newname = desc = NULL;
89 addlist = sq_create();
90 dellist = sq_create();
91 memberlist = sq_create();
92 synclist = sq_create();
93 taglist = sq_create();
98 /* parse args, building addlist, dellist, & synclist */
99 while (++arg - argv < argc)
103 if (argis("m", "members"))
105 else if (argis("u", "users"))
107 else if (argis("s", "strings"))
109 else if (argis("l", "lists"))
111 else if (argis("k", "kerberos"))
113 else if (argis("t", "tags"))
115 else if (argis("i", "info"))
117 else if (argis("n", "noauth"))
119 else if (argis("v", "verbose"))
121 else if (argis("r", "recursive"))
123 else if (argis("S", "server") || argis("db", "database"))
125 if (arg - argv < argc - 1)
133 else if (argis("a", "add"))
135 if (arg - argv < argc - 1)
138 if ((memberstruct = parse_member(*arg)))
139 sq_save_data(addlist, memberstruct);
144 else if (argis("at", "addtagged"))
146 if (arg - argv < argc - 2)
149 if ((memberstruct = parse_member(*arg)))
150 sq_save_data(addlist, memberstruct);
151 memberstruct->tag = *++arg;
156 else if (argis("al", "addlist"))
158 if (arg - argv < argc - 1)
161 get_members_from_file(*arg, addlist);
166 else if (argis("d", "delete"))
168 if (arg - argv < argc - 1)
171 if ((memberstruct = parse_member(*arg)))
172 sq_save_data(dellist, memberstruct);
177 else if (argis("dl", "deletelist"))
179 if (arg - argv < argc - 1)
182 get_members_from_file(*arg, dellist);
187 else if (argis("f", "file"))
189 if (arg - argv < argc - 1)
193 get_members_from_file(*arg, synclist);
198 else if (argis("ct", "changetag"))
200 if (arg - argv < argc - 2)
203 if ((memberstruct = parse_member(*arg)))
204 sq_save_data(taglist, memberstruct);
205 memberstruct->tag = *++arg;
210 else if (argis("C", "create"))
212 else if (argis("P", "public"))
217 else if (argis("NP", "private"))
222 else if (argis("A", "active"))
227 else if (argis("I", "inactive"))
232 else if (argis("V", "visible"))
237 else if (argis("H", "hidden"))
242 else if (argis("M", "mail"))
247 else if (argis("NM", "notmail"))
252 else if (argis("G", "group"))
257 else if (argis("NG", "notgroup"))
262 else if (argis("N", "nfs"))
267 else if (argis("NN", "notnfs"))
272 else if (argis("D", "desc"))
274 if (arg - argv < argc - 1)
283 else if (argis("O", "owner"))
285 if (arg - argv < argc - 1)
289 owner = parse_member(*arg);
294 else if (argis("MA", "memacl"))
296 if (arg - argv < argc -1)
300 memacl = parse_member(*arg);
305 else if (argis("R", "rename"))
307 if (arg - argv < argc - 1)
319 else if (listname == NULL)
324 if (listname == NULL)
327 /* if no other options specified, turn on list members flag */
328 if (!(infoflg || syncflg || createflag || setinfo ||
329 addlist->q_next != addlist || dellist->q_next != dellist ||
330 taglist->q_next != taglist))
333 /* If none of {users,strings,lists,kerberos,machines} specified,
335 if (!(showusers || showstrings || showlists || showkerberos))
336 showusers = showstrings = showlists = showkerberos = showmachines = 1;
339 status = mrcl_connect(server, "blanche", 4, !noauth);
340 if (status == MRCL_AUTH_ERROR)
342 com_err(whoami, 0, "Authentication error while working on list %s",
344 com_err(whoami, 0, "Try the -noauth flag if you don't "
345 "need authentication.");
350 /* check for username/listname clash */
351 if (createflag || (setinfo && newname && strcmp(newname, listname)))
353 status = mr_query("get_user_account_by_login", 1,
354 createflag ? &listname : &newname,
356 if (status != MR_NO_MATCH)
357 fprintf(stderr, "WARNING: A user by that name already exists.\n");
360 /* create if needed */
365 argv[L_NAME] = listname;
366 argv[L_ACTIVE] = (active == 0) ? "0" : "1";
367 argv[L_PUBLIC] = (public == 1) ? "1" : "0";
368 argv[L_HIDDEN] = (hidden == 1) ? "1" : "0";
369 argv[L_MAILLIST] = (maillist == 0) ? "0" : "1";
370 argv[L_GROUP] = (grouplist == 1) ? "1" : "0";
371 argv[L_GID] = UNIQUE_GID;
372 argv[L_NFSGROUP] = (nfsgroup == 1) ? "1" : "0";
373 argv[L_DESC] = desc ? desc : "none";
377 if (memacl->type == M_ANY)
379 status = mr_query("get_user_account_by_login", 1,
380 &memacl->name, NULL, NULL);
381 if (status == MR_NO_MATCH)
382 memacl->type = M_LIST;
384 memacl->type = M_USER;
386 argv[L_MEMACE_TYPE] = typename[memacl->type];
387 argv[L_MEMACE_NAME] = memacl->name;
388 if (memacl->type == M_KERBEROS)
390 status = mrcl_validate_kerberos_member(argv[L_MEMACE_NAME],
391 &argv[L_MEMACE_NAME]);
392 if (mrcl_get_message())
393 mrcl_com_err(whoami);
394 if (status == MRCL_REJECT)
399 argv[L_MEMACE_TYPE] = argv[L_MEMACE_NAME] = "NONE";
403 argv[L_ACE_NAME] = owner->name;
408 argv[L_ACE_TYPE] = "USER";
409 status = mr_query("add_list", 13, argv, NULL, NULL);
410 if (owner->type != M_ANY || status != MR_USER)
414 argv[L_ACE_TYPE] = "LIST";
415 status = mr_query("add_list", 13, argv, NULL, NULL);
419 argv[L_ACE_TYPE] = "KERBEROS";
420 status = mrcl_validate_kerberos_member(argv[L_ACE_NAME],
422 if (mrcl_get_message())
423 mrcl_com_err(whoami);
424 if (status == MRCL_REJECT)
426 status = mr_query("add_list", 13, argv, NULL, NULL);
429 argv[L_ACE_TYPE] = argv[L_ACE_NAME] = "NONE";
430 status = mr_query("add_list", 13, argv, NULL, NULL);
436 argv[L_ACE_TYPE] = "USER";
437 argv[L_ACE_NAME] = get_username();
439 status = mr_query("add_list", 13, argv, NULL, NULL);
444 com_err(whoami, status, "while creating list.");
452 status = mr_query("get_list_info", 1, &listname,
453 save_list_info, argv);
456 com_err(whoami, status, "while getting list information");
462 argv[L_NAME + 1] = newname;
464 argv[L_ACTIVE + 1] = active ? "1" : "0";
466 argv[L_PUBLIC + 1] = public ? "1" : "0";
468 argv[L_HIDDEN + 1] = hidden ? "1" : "0";
470 argv[L_MAILLIST + 1] = maillist ? "1" : "0";
472 argv[L_GROUP + 1] = grouplist ? "1" : "0";
474 argv[L_NFSGROUP + 1] = nfsgroup ? "1" : "0";
476 argv[L_DESC + 1] = desc;
480 if (memacl->type == M_ANY)
482 status = mr_query("get_user_account_by_login", 1,
483 &memacl->name, NULL, NULL);
484 if (status == MR_NO_MATCH)
485 memacl->type = M_LIST;
487 memacl->type = M_USER;
489 argv[L_MEMACE_TYPE + 1] = typename[memacl->type];
490 argv[L_MEMACE_NAME + 1] = memacl->name;
491 if (memacl->type == M_KERBEROS)
493 status = mrcl_validate_kerberos_member(argv[L_MEMACE_NAME + 1],
494 &argv[L_MEMACE_NAME + 1]);
495 if (mrcl_get_message())
496 mrcl_com_err(whoami);
497 if (status == MRCL_REJECT)
504 argv[L_ACE_NAME + 1] = owner->name;
509 argv[L_ACE_TYPE + 1] = "USER";
510 status = mr_query("update_list", 14, argv, NULL, NULL);
511 if (owner->type != M_ANY || status != MR_USER)
515 argv[L_ACE_TYPE + 1] = "LIST";
516 status = mr_query("update_list", 14, argv, NULL, NULL);
520 argv[L_ACE_TYPE + 1] = "KERBEROS";
521 status = mrcl_validate_kerberos_member(argv[L_ACE_NAME + 1],
522 &argv[L_ACE_NAME + 1]);
523 if (mrcl_get_message())
524 mrcl_com_err(whoami);
525 if (status == MRCL_REJECT)
527 status = mr_query("update_list", 14, argv, NULL, NULL);
530 argv[L_ACE_TYPE + 1] = argv[L_ACE_NAME + 1] = "NONE";
531 status = mr_query("update_list", 14, argv, NULL, NULL);
536 status = mr_query("update_list", 14, argv, NULL, NULL);
540 com_err(whoami, status, "while updating list.");
547 /* display list info if requested to */
550 status = mr_query("get_list_info", 1, &listname, show_list_info, NULL);
553 com_err(whoami, status, "while getting list information");
556 if (verbose && !memberflg)
558 status = mr_query("count_members_of_list", 1, &listname,
559 show_list_count, NULL);
562 com_err(whoami, status, "while getting list count");
568 /* if we're synchronizing to a file, we need to:
569 * get the current members of the list
570 * for each member of the sync file
571 * if they are on the list, remove them from the in-memory copy
572 * if they're not on the list, add them to add-list
573 * if anyone is left on the in-memory copy, put them on the delete-list
574 * lastly, reset memberlist so we can use it again later
578 status = mr_query("get_members_of_list", 1, &listname,
579 get_list_members, memberlist);
582 com_err(whoami, status, "getting members of list %s", listname);
585 while (sq_get_data(synclist, &memberstruct))
587 struct save_queue *q;
590 for (q = memberlist->q_next; q != memberlist; q = q->q_next)
592 if (membercmp(q->q_data, memberstruct) == 0)
594 q->q_prev->q_next = q->q_next;
595 q->q_next->q_prev = q->q_prev;
601 sq_save_data(addlist, memberstruct);
603 while (sq_get_data(memberlist, &memberstruct))
604 sq_save_data(dellist, memberstruct);
605 sq_destroy(memberlist);
606 memberlist = sq_create();
609 /* Process the add list */
610 while (sq_get_data(addlist, &memberstruct))
612 /* canonicalize string if necessary */
613 if (memberstruct->type != M_KERBEROS &&
614 (p = strchr(memberstruct->name, '@')))
616 char *host = canonicalize_hostname(strdup(++p));
617 static char **mailhubs = NULL;
626 mailhubs = malloc(sizeof(char *));
628 status = mr_query("get_alias", 3, argv, collect,
630 if (status != MR_SUCCESS && status != MR_NO_MATCH)
632 com_err(whoami, status,
633 " while reading list of MAILHUB servers");
637 for (i = 0; (p = mailhubs[i]); i++)
639 if (!strcasecmp(p, host))
641 host = strdup(memberstruct->name);
642 *(strchr(memberstruct->name, '@')) = 0;
643 if (memberstruct->type == M_STRING)
644 memberstruct->type = M_ANY;
645 fprintf(stderr, "Warning: \"%s\" converted to "
646 "\"%s\" because it is a local name.\n",
647 host, memberstruct->name);
653 /* now continue adding member */
654 membervec[0] = listname;
655 membervec[2] = memberstruct->name;
656 membervec[3] = memberstruct->tag;
659 printf("Adding member ");
660 show_list_member(memberstruct);
662 switch (memberstruct->type)
666 membervec[1] = "USER";
667 status = mr_query("add_tagged_member_to_list", 4, membervec,
669 if (status == MR_SUCCESS)
671 else if (status != MR_USER || memberstruct->type != M_ANY)
673 com_err(whoami, status, "while adding member %s to %s",
674 memberstruct->name, listname);
679 membervec[1] = "LIST";
680 status = mr_query("add_tagged_member_to_list", 4, membervec,
682 if (status == MR_SUCCESS)
684 if (!strcmp(membervec[0], get_username()))
686 fprintf(stderr, "\nWARNING: \"LIST:%s\" was just added "
687 "to list \"%s\".\n", membervec[2], membervec[0]);
688 fprintf(stderr, "If you meant to add yourself to the list "
689 "\"%s\", type:\n", membervec[2]);
690 fprintf(stderr, "\tblanche %s -d %s\t(to undo this)\n",
691 membervec[0], membervec[2]);
692 fprintf(stderr, "\tblanche %s -a %s\t(to add yourself to "
693 "that list)\n", membervec[2], membervec[0]);
697 else if (status != MR_LIST || memberstruct->type != M_ANY)
699 com_err(whoami, status, "while adding member %s to %s",
700 memberstruct->name, listname);
705 status = mrcl_validate_string_member(memberstruct->name);
706 if (memberstruct->type == M_ANY && status == MRCL_WARN)
708 /* if user is trying to add something which isn't a
709 remote string, or a list, or a user, and didn't
710 explicitly specify `STRING:', it's probably a typo */
711 com_err(whoami, MR_NO_MATCH, "while adding member %s to %s",
712 memberstruct->name, listname);
717 mrcl_com_err(whoami);
719 if (status == MRCL_REJECT)
725 membervec[1] = "STRING";
726 status = mr_query("add_tagged_member_to_list", 4, membervec,
728 if (status != MR_SUCCESS)
730 com_err(whoami, status, "while adding member %s to %s",
731 memberstruct->name, listname);
736 membervec[1] = "KERBEROS";
737 status = mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
738 if (mrcl_get_message())
739 mrcl_com_err(whoami);
740 if (status == MRCL_REJECT)
745 status = mr_query("add_tagged_member_to_list", 4, membervec,
747 if (status != MR_SUCCESS)
749 com_err(whoami, status, "while adding member %s to %s",
750 memberstruct->name, listname);
756 membervec[1] = "MACHINE";
757 membervec[2] = canonicalize_hostname(strdup(memberstruct->name));
758 status = mr_query("add_tagged_member_to_list", 4, membervec,
760 if (status != MR_SUCCESS)
762 com_err(whoami, status, "while adding member %s to %s",
763 memberstruct->name, listname);
770 /* Process the delete list */
771 while (sq_get_data(dellist, &memberstruct))
773 membervec[0] = listname;
774 membervec[2] = memberstruct->name;
777 printf("Deleting member ");
778 show_list_member(memberstruct);
780 switch (memberstruct->type)
784 membervec[1] = "USER";
785 status = mr_query("delete_member_from_list", 3, membervec,
787 if (status == MR_SUCCESS)
789 else if ((status != MR_USER && status != MR_NO_MATCH) ||
790 memberstruct->type != M_ANY)
792 com_err(whoami, status, "while deleting member %s from %s",
793 memberstruct->name, listname);
798 membervec[1] = "LIST";
799 status = mr_query("delete_member_from_list", 3, membervec,
801 if (status == MR_SUCCESS)
803 else if ((status != MR_LIST && status != MR_NO_MATCH) ||
804 memberstruct->type != M_ANY)
806 if (status == MR_PERM && memberstruct->type == M_ANY &&
807 !strcmp(membervec[2], get_username()))
809 /* M_ANY means we've fallen through from the user
810 * case. The user is trying to remove himself from
811 * a list, but we got MR_USER or MR_NO_MATCH above,
812 * meaning he's not really on it, and we got MR_PERM
813 * when trying to remove LIST:$USER because he's not
814 * on the acl. That error is useless, so return
815 * MR_NO_MATCH instead. However, this will generate the
816 * wrong error if the user was trying to remove the list
817 * with his username from a list he doesn't administrate
818 * without explicitly specifying "list:".
820 status = MR_NO_MATCH;
822 com_err(whoami, status, "while deleting member %s from %s",
823 memberstruct->name, listname);
828 membervec[1] = "STRING";
829 status = mr_query("delete_member_from_list", 3, membervec,
831 if (status == MR_STRING && memberstruct->type == M_ANY)
833 com_err(whoami, 0, " Unable to find member %s to delete from %s",
834 memberstruct->name, listname);
836 if (!strcmp(membervec[0], get_username()))
838 fprintf(stderr, "(If you were trying to remove yourself "
839 "from the list \"%s\",\n", membervec[2]);
840 fprintf(stderr, "the correct command is \"blanche %s -d "
841 "%s\".)\n", membervec[2], membervec[0]);
844 else if (status != MR_SUCCESS)
846 com_err(whoami, status, "while deleting member %s from %s",
847 memberstruct->name, listname);
852 membervec[1] = "KERBEROS";
853 status = mr_query("delete_member_from_list", 3, membervec,
855 if (status == MR_STRING || status == MR_NO_MATCH)
857 /* Try canonicalizing the Kerberos principal and trying
858 * again. If we succeed, print the message from mrcl.
859 * Otherwise, just pretend we never did this and print
860 * the original error message.
862 mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
863 if (mrcl_get_message())
865 if (mr_query("delete_member_from_list", 3, membervec,
866 NULL, NULL) == MR_SUCCESS)
867 mrcl_com_err(whoami);
871 if (status != MR_SUCCESS)
873 com_err(whoami, status, "while deleting member %s from %s",
874 memberstruct->name, listname);
879 membervec[1] = "MACHINE";
880 membervec[2] = canonicalize_hostname(memberstruct->name);
881 status = mr_query("delete_member_from_list", 3, membervec,
883 if (status != MR_SUCCESS)
885 com_err(whoami, status, "while deleting member %s from %s",
886 memberstruct->name, listname);
893 /* Process the tag list */
894 while (sq_get_data(taglist, &memberstruct))
896 membervec[0] = listname;
897 membervec[2] = memberstruct->name;
898 membervec[3] = memberstruct->tag;
901 printf("Tagging member ");
902 show_list_member(memberstruct);
904 switch (memberstruct->type)
908 membervec[1] = "USER";
909 status = mr_query("tag_member_of_list", 4, membervec,
911 if (status == MR_SUCCESS)
913 else if ((status != MR_USER && status != MR_NO_MATCH) ||
914 memberstruct->type != M_ANY)
916 com_err(whoami, status, "while changing tag on member %s of %s",
917 memberstruct->name, listname);
922 membervec[1] = "LIST";
923 status = mr_query("tag_member_of_list", 4, membervec,
925 if (status == MR_SUCCESS)
927 else if ((status != MR_LIST && status != MR_NO_MATCH) ||
928 memberstruct->type != M_ANY)
930 com_err(whoami, status, "while changing tag on member %s of %s",
931 memberstruct->name, listname);
936 membervec[1] = "STRING";
937 status = mr_query("tag_member_of_list", 4, membervec,
939 if (status == MR_STRING && memberstruct->type == M_ANY)
941 com_err(whoami, 0, " Unable to find member %s on list %s",
942 memberstruct->name, listname);
945 else if (status != MR_SUCCESS)
947 com_err(whoami, status, "while retagging member %s on %s",
948 memberstruct->name, listname);
953 membervec[1] = "KERBEROS";
954 status = mr_query("tag_member_of_list", 4, membervec,
956 if (status == MR_STRING || status == MR_NO_MATCH)
958 /* Try canonicalizing the Kerberos principal and trying
959 * again. If we succeed, print the message from mrcl.
960 * Otherwise, just pretend we never did this and print
961 * the original error message.
963 mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
964 if (mrcl_get_message())
966 if (mr_query("tag_member_of_list", 4, membervec,
967 NULL, NULL) == MR_SUCCESS)
968 mrcl_com_err(whoami);
972 if (status != MR_SUCCESS)
974 com_err(whoami, status, "while changing tag on member %s of %s",
975 memberstruct->name, listname);
981 /* Display the members of the list now, if requested */
985 recursive_display_list_members();
988 status = mr_query(showtags ? "get_tagged_members_of_list" :
989 "get_members_of_list", 1, &listname,
990 get_list_members, memberlist);
992 com_err(whoami, status, "while getting members of list %s",
994 while (sq_get_data(memberlist, &memberstruct))
995 show_list_member(memberstruct);
1001 exit(success ? 0 : 1);
1004 void usage(char **argv)
1006 #define USAGE_OPTIONS_FORMAT " %-39s%s\n"
1007 fprintf(stderr, "Usage: %s listname [options]\n", argv[0]);
1008 fprintf(stderr, "Options are\n");
1009 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-v | -verbose",
1011 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-m | -members",
1012 "-R | -rename newname");
1013 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-u | -users",
1015 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-l | -lists",
1017 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-s | -strings",
1019 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-k | -kerberos",
1021 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-i | -info",
1023 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-r | -recursive",
1025 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-a | -add member",
1027 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-d | -delete member",
1029 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-al | -addlist filename",
1031 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-dl | -deletelist filename",
1033 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-f | -file filename",
1035 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-at | -addtagged member tag",
1037 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-ct | -changetag member tag",
1038 "-D | -desc description");
1039 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-t | -tags",
1040 "-O | -owner owner");
1041 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-n | -noauth",
1042 "-MA | -memacl membership_acl");
1043 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-db | -database host[:port]",
1049 /* Display the members stored in the queue */
1051 void show_list_member(struct member *memberstruct)
1055 switch (memberstruct->type)
1083 printf("%s\n", memberstruct->name);
1088 printf("%s:%s", s, memberstruct->name);
1091 if (memberstruct->type == M_LIST)
1092 printf("LIST:%s", memberstruct->name);
1093 else if (memberstruct->type == M_KERBEROS)
1094 printf("KERBEROS:%s", memberstruct->name);
1095 else if (memberstruct->type == M_STRING &&
1096 !strchr(memberstruct->name, '@'))
1097 printf("STRING:%s", memberstruct->name);
1098 else if (memberstruct->type == M_MACHINE)
1099 printf("MACHINE:%s", memberstruct->name);
1101 printf("%s", memberstruct->name);
1103 if (showtags && *(memberstruct->tag))
1104 printf(" (%s)\n", memberstruct->tag);
1110 /* Show the retrieved information about a list */
1112 int show_list_info(int argc, char **argv, void *hint)
1114 printf("List: %s\n", argv[L_NAME]);
1115 printf("Description: %s\n", argv[L_DESC]);
1116 printf("Flags: %s, %s, and %s\n",
1117 atoi(argv[L_ACTIVE]) ? "active" : "inactive",
1118 atoi(argv[L_PUBLIC]) ? "public" : "private",
1119 atoi(argv[L_HIDDEN]) ? "hidden" : "visible");
1120 printf("%s is %sa maillist and is %sa group", argv[L_NAME],
1121 atoi(argv[L_MAILLIST]) ? "" : "not ",
1122 atoi(argv[L_GROUP]) ? "" : "not ");
1123 if (atoi(argv[L_GROUP]))
1125 if (atoi(argv[L_NFSGROUP]))
1126 printf(" (and an NFS group)");
1127 printf(" with GID %d\n", atoi(argv[L_GID]));
1131 printf("Owner: %s %s\n", argv[L_ACE_TYPE], argv[L_ACE_NAME]);
1132 if (strcmp(argv[L_MEMACE_TYPE], "NONE"))
1133 printf("Membership ACL: %s %s\n", argv[L_MEMACE_TYPE],
1134 argv[L_MEMACE_NAME]);
1135 printf("Last modified by %s with %s on %s\n",
1136 argv[L_MODBY], argv[L_MODWITH], argv[L_MODTIME]);
1141 /* Copy retrieved information about a list into a new argv */
1143 int save_list_info(int argc, char **argv, void *hint)
1145 char **nargv = hint;
1147 for (argc = 0; argc < 14; argc++)
1148 nargv[argc + 1] = strdup(argv[argc]);
1152 /* Show the retrieve list member count */
1154 int show_list_count(int argc, char **argv, void *hint)
1156 printf("Members: %s\n", argv[0]);
1161 /* Recursively find all of the members of listname, and then display them */
1163 void recursive_display_list_members(void)
1165 int status, count, savecount;
1166 struct save_queue *lists, *members;
1167 struct member *m, *m1, *data;
1169 lists = sq_create();
1170 members = sq_create();
1171 m = malloc(sizeof(struct member));
1174 sq_save_data(lists, m);
1176 while (sq_get_data(lists, &m))
1178 sq_destroy(memberlist);
1179 memberlist = sq_create();
1180 status = mr_query("get_members_of_list", 1, &(m->name),
1181 get_list_members, memberlist);
1183 com_err(whoami, status, "while getting members of list %s", m->name);
1184 while (sq_get_data(memberlist, &m1))
1186 if (m1->type == M_LIST)
1187 unique_add_member(lists, m1);
1189 unique_add_member(members, m1);
1192 savecount = count = sq_count_elts(members);
1193 data = malloc(count * sizeof(struct member));
1195 while (sq_get_data(members, &m))
1196 memcpy(&data[count++], m, sizeof(struct member));
1197 qsort(data, count, sizeof(struct member), membercmp);
1198 for (count = 0; count < savecount; count++)
1199 show_list_member(&data[count]);
1203 /* add a struct member to a queue if that member isn't already there. */
1205 void unique_add_member(struct save_queue *q, struct member *m)
1207 struct save_queue *qp;
1209 for (qp = q->q_next; qp != q; qp = qp->q_next)
1211 if (!membercmp(qp->q_data, m))
1218 /* Collect the retrieved members of the list */
1220 int get_list_members(int argc, char **argv, void *sq)
1222 struct save_queue *q = sq;
1225 m = malloc(sizeof(struct member));
1238 m->type = M_KERBEROS;
1241 m->type = M_MACHINE;
1244 m->name = strdup(argv[1]);
1246 m->tag = strdup(argv[2]);
1248 m->tag = strdup("");
1254 /* Open file, parse members from file, and put them on the specified queue */
1255 void get_members_from_file(char *filename, struct save_queue *queue)
1259 struct member *memberstruct;
1261 if (!strcmp(filename, "-"))
1265 in = fopen(filename, "r");
1268 com_err(whoami, errno, "while opening %s for input", filename);
1273 while (fgets(buf, BUFSIZ, in))
1275 if ((memberstruct = parse_member(buf)))
1276 sq_save_data(queue, memberstruct);
1280 com_err(whoami, errno, "while reading from %s", filename);
1286 /* Collect the possible expansions of the alias MAILHUB */
1288 int collect(int argc, char **argv, void *l)
1293 for (i = 0; (*list)[i]; i++)
1295 *list = realloc(*list, (i + 2) * sizeof(char *));
1296 (*list)[i] = strdup(argv[2]);
1297 (*list)[i + 1] = NULL;
1302 /* Parse a line of input, fetching a member. NULL is returned if a member
1303 * is not found. ';' is a comment character.
1306 struct member *parse_member(char *s)
1311 while (*s && isspace(*s))
1314 while (*p && *p != '\n' && *p != ';')
1316 if (isprint(*p) && !isspace(*p))
1323 if (p == s || strlen(s) == 0)
1326 if (!(m = malloc(sizeof(struct member))))
1328 m->tag = strdup("");
1330 if ((p = strchr(s, ':')))
1334 if (!strcasecmp("user", s))
1336 else if (!strcasecmp("list", s))
1338 else if (!strcasecmp("string", s))
1340 else if (!strcasecmp("kerberos", s))
1341 m->type = M_KERBEROS;
1342 else if (!strcasecmp("machine", s))
1343 m->type = M_MACHINE;
1344 else if (!strcasecmp("none", s))
1352 m->name = strdup(m->name);
1356 m->name = strdup(s);
1357 m->type = strcasecmp(s, "none") ? M_ANY : M_NONE;
1364 * This routine two compares members by the following rules:
1365 * 1. A USER is less than a LIST
1366 * 2. A LIST is less than a STRING
1367 * 3. If two members are of the same type, the one alphabetically first
1368 * is less than the other
1369 * It returs < 0 if the first member is less, 0 if they are identical, and
1370 * > 0 if the second member is less (the first member is greater).
1373 int membercmp(const void *mem1, const void *mem2)
1375 const struct member *m1 = mem1, *m2 = mem2;
1377 if (m1->type == M_ANY || m2->type == M_ANY || (m1->type == m2->type))
1378 return strcmp(m1->name, m2->name);
1380 return m1->type - m2->type;
1384 int sq_count_elts(struct save_queue *q)
1390 while (sq_get_data(q, &foo))
1395 char *get_username(void)
1399 username = getenv("USER");
1402 username = mrcl_krb_user();
1405 com_err(whoami, 0, "Could not determine username");