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 */
38 char *typename[] = { "ANY", "USER", "LIST", "STRING", "KERBEROS", "NONE" };
40 /* argument parsing macro */
41 #define argis(a, b) (!strcmp(*arg + 1, a) || !strcmp(*arg + 1, b))
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;
48 struct member *owner, *memacl;
51 /* various member lists */
52 struct save_queue *addlist, *dellist, *memberlist, *synclist, *taglist;
54 char *listname, *whoami;
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);
71 int main(int argc, char **argv)
76 struct member *memberstruct;
77 char *server = NULL, *p;
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;
87 addlist = sq_create();
88 dellist = sq_create();
89 memberlist = sq_create();
90 synclist = sq_create();
91 taglist = sq_create();
96 /* parse args, building addlist, dellist, & synclist */
97 while (++arg - argv < argc)
101 if (argis("m", "members"))
103 else if (argis("u", "users"))
105 else if (argis("s", "strings"))
107 else if (argis("l", "lists"))
109 else if (argis("k", "kerberos"))
111 else if (argis("t", "tags"))
113 else if (argis("i", "info"))
115 else if (argis("n", "noauth"))
117 else if (argis("v", "verbose"))
119 else if (argis("r", "recursive"))
121 else if (argis("S", "server") || argis("db", "database"))
123 if (arg - argv < argc - 1)
131 else if (argis("a", "add"))
133 if (arg - argv < argc - 1)
136 if ((memberstruct = parse_member(*arg)))
137 sq_save_data(addlist, memberstruct);
142 else if (argis("at", "addtagged"))
144 if (arg - argv < argc - 2)
147 if ((memberstruct = parse_member(*arg)))
148 sq_save_data(addlist, memberstruct);
149 memberstruct->tag = *++arg;
154 else if (argis("al", "addlist"))
156 if (arg - argv < argc - 1)
159 get_members_from_file(*arg, addlist);
164 else if (argis("d", "delete"))
166 if (arg - argv < argc - 1)
169 if ((memberstruct = parse_member(*arg)))
170 sq_save_data(dellist, memberstruct);
175 else if (argis("dl", "deletelist"))
177 if (arg - argv < argc - 1)
180 get_members_from_file(*arg, dellist);
185 else if (argis("f", "file"))
187 if (arg - argv < argc - 1)
191 get_members_from_file(*arg, synclist);
196 else if (argis("ct", "changetag"))
198 if (arg - argv < argc - 2)
201 if ((memberstruct = parse_member(*arg)))
202 sq_save_data(taglist, memberstruct);
203 memberstruct->tag = *++arg;
208 else if (argis("C", "create"))
210 else if (argis("P", "public"))
215 else if (argis("NP", "private"))
220 else if (argis("A", "active"))
225 else if (argis("I", "inactive"))
230 else if (argis("V", "visible"))
235 else if (argis("H", "hidden"))
240 else if (argis("M", "mail"))
245 else if (argis("NM", "notmail"))
250 else if (argis("G", "group"))
255 else if (argis("NG", "notgroup"))
260 else if (argis("N", "nfs"))
265 else if (argis("NN", "notnfs"))
270 else if (argis("D", "desc"))
272 if (arg - argv < argc - 1)
281 else if (argis("O", "owner"))
283 if (arg - argv < argc - 1)
287 owner = parse_member(*arg);
292 else if (argis("MA", "memacl"))
294 if (arg - argv < argc -1)
298 memacl = parse_member(*arg);
303 else if (argis("R", "rename"))
305 if (arg - argv < argc - 1)
317 else if (listname == NULL)
322 if (listname == NULL)
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))
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;
336 status = mrcl_connect(server, "blanche", 4, !noauth);
337 if (status == MRCL_AUTH_ERROR)
339 com_err(whoami, 0, "Try the -noauth flag if you don't "
340 "need authentication.");
345 /* check for username/listname clash */
346 if (createflag || (setinfo && newname && strcmp(newname, listname)))
348 status = mr_query("get_user_account_by_login", 1,
349 createflag ? &listname : &newname,
351 if (status != MR_NO_MATCH)
352 fprintf(stderr, "WARNING: A user by that name already exists.\n");
355 /* create if needed */
360 argv[L_NAME] = listname;
361 argv[L_ACTIVE] = (active == 0) ? "0" : "1";
362 argv[L_PUBLIC] = (public == 1) ? "1" : "0";
363 argv[L_HIDDEN] = (hidden == 1) ? "1" : "0";
364 argv[L_MAILLIST] = (maillist == 0) ? "0" : "1";
365 argv[L_GROUP] = (grouplist == 1) ? "1" : "0";
366 argv[L_GID] = UNIQUE_GID;
367 argv[L_NFSGROUP] = (nfsgroup == 1) ? "1" : "0";
368 argv[L_DESC] = desc ? desc : "none";
372 if (memacl->type == M_ANY)
374 status = mr_query("get_user_account_by_login", 1,
375 &memacl->name, NULL, NULL);
376 if (status == MR_NO_MATCH)
377 memacl->type = M_LIST;
379 memacl->type = M_USER;
381 argv[L_MEMACE_TYPE] = typename[memacl->type];
382 argv[L_MEMACE_NAME] = memacl->name;
383 if (memacl->type == M_KERBEROS)
385 status = mrcl_validate_kerberos_member(argv[L_MEMACE_NAME],
386 &argv[L_MEMACE_NAME]);
387 if (mrcl_get_message())
388 mrcl_com_err(whoami);
392 argv[L_MEMACE_TYPE] = argv[L_MEMACE_NAME] = "NONE";
396 argv[L_ACE_NAME] = owner->name;
401 argv[L_ACE_TYPE] = "USER";
402 status = mr_query("add_list", 13, argv, NULL, NULL);
403 if (owner->type != M_ANY || status != MR_USER)
407 argv[L_ACE_TYPE] = "LIST";
408 status = mr_query("add_list", 13, argv, NULL, NULL);
412 argv[L_ACE_TYPE] = "KERBEROS";
413 status = mrcl_validate_kerberos_member(argv[L_ACE_NAME],
415 if (mrcl_get_message())
416 mrcl_com_err(whoami);
417 status = mr_query("add_list", 13, argv, NULL, NULL);
420 argv[L_ACE_TYPE] = argv[L_ACE_NAME] = "NONE";
421 status = mr_query("add_list", 13, argv, NULL, NULL);
427 argv[L_ACE_TYPE] = "USER";
428 argv[L_ACE_NAME] = get_username();
430 status = mr_query("add_list", 13, argv, NULL, NULL);
435 com_err(whoami, status, "while creating list.");
443 status = mr_query("get_list_info", 1, &listname,
444 save_list_info, argv);
447 com_err(whoami, status, "while getting list information");
453 argv[L_NAME + 1] = newname;
455 argv[L_ACTIVE + 1] = active ? "1" : "0";
457 argv[L_PUBLIC + 1] = public ? "1" : "0";
459 argv[L_HIDDEN + 1] = hidden ? "1" : "0";
461 argv[L_MAILLIST + 1] = maillist ? "1" : "0";
463 argv[L_GROUP + 1] = grouplist ? "1" : "0";
465 argv[L_NFSGROUP + 1] = nfsgroup ? "1" : "0";
467 argv[L_DESC + 1] = desc;
471 if (memacl->type == M_ANY)
473 status = mr_query("get_user_account_by_login", 1,
474 &memacl->name, NULL, NULL);
475 if (status == MR_NO_MATCH)
476 memacl->type = M_LIST;
478 memacl->type = M_USER;
480 argv[L_MEMACE_TYPE + 1] = typename[memacl->type];
481 argv[L_MEMACE_NAME + 1] = memacl->name;
482 if (memacl->type == M_KERBEROS)
484 status = mrcl_validate_kerberos_member(argv[L_MEMACE_NAME + 1],
485 &argv[L_MEMACE_NAME + 1]);
486 if (mrcl_get_message())
487 mrcl_com_err(whoami);
493 argv[L_ACE_NAME + 1] = owner->name;
498 argv[L_ACE_TYPE + 1] = "USER";
499 status = mr_query("update_list", 14, argv, NULL, NULL);
500 if (owner->type != M_ANY || status != MR_USER)
504 argv[L_ACE_TYPE + 1] = "LIST";
505 status = mr_query("update_list", 14, argv, NULL, NULL);
509 argv[L_ACE_TYPE + 1] = "KERBEROS";
510 status = mrcl_validate_kerberos_member(argv[L_ACE_NAME + 1],
511 &argv[L_ACE_NAME + 1]);
512 if (mrcl_get_message())
513 mrcl_com_err(whoami);
514 status = mr_query("update_list", 14, argv, NULL, NULL);
517 argv[L_ACE_TYPE + 1] = argv[L_ACE_NAME + 1] = "NONE";
518 status = mr_query("update_list", 14, argv, NULL, NULL);
523 status = mr_query("update_list", 14, argv, NULL, NULL);
527 com_err(whoami, status, "while updating list.");
534 /* display list info if requested to */
537 status = mr_query("get_list_info", 1, &listname, show_list_info, NULL);
540 com_err(whoami, status, "while getting list information");
543 if (verbose && !memberflg)
545 status = mr_query("count_members_of_list", 1, &listname,
546 show_list_count, NULL);
549 com_err(whoami, status, "while getting list count");
555 /* if we're synchronizing to a file, we need to:
556 * get the current members of the list
557 * for each member of the sync file
558 * if they are on the list, remove them from the in-memory copy
559 * if they're not on the list, add them to add-list
560 * if anyone is left on the in-memory copy, put them on the delete-list
561 * lastly, reset memberlist so we can use it again later
565 status = mr_query("get_members_of_list", 1, &listname,
566 get_list_members, memberlist);
569 com_err(whoami, status, "getting members of list %s", listname);
572 while (sq_get_data(synclist, &memberstruct))
574 struct save_queue *q;
577 for (q = memberlist->q_next; q != memberlist; q = q->q_next)
579 if (membercmp(q->q_data, memberstruct) == 0)
581 q->q_prev->q_next = q->q_next;
582 q->q_next->q_prev = q->q_prev;
588 sq_save_data(addlist, memberstruct);
590 while (sq_get_data(memberlist, &memberstruct))
591 sq_save_data(dellist, memberstruct);
592 sq_destroy(memberlist);
593 memberlist = sq_create();
596 /* Process the add list */
597 while (sq_get_data(addlist, &memberstruct))
599 /* canonicalize string if necessary */
600 if (memberstruct->type != M_KERBEROS &&
601 (p = strchr(memberstruct->name, '@')))
603 char *host = canonicalize_hostname(strdup(++p));
604 static char **mailhubs = NULL;
613 mailhubs = malloc(sizeof(char *));
615 status = mr_query("get_alias", 3, argv, collect,
617 if (status != MR_SUCCESS && status != MR_NO_MATCH)
619 com_err(whoami, status,
620 " while reading list of MAILHUB servers");
624 for (i = 0; (p = mailhubs[i]); i++)
626 if (!strcasecmp(p, host))
628 host = strdup(memberstruct->name);
629 *(strchr(memberstruct->name, '@')) = 0;
630 if (memberstruct->type == M_STRING)
631 memberstruct->type = M_ANY;
632 fprintf(stderr, "Warning: \"%s\" converted to "
633 "\"%s\" because it is a local name.\n",
634 host, memberstruct->name);
640 /* now continue adding member */
641 membervec[0] = listname;
642 membervec[2] = memberstruct->name;
643 membervec[3] = memberstruct->tag;
646 printf("Adding member ");
647 show_list_member(memberstruct);
649 switch (memberstruct->type)
653 membervec[1] = "USER";
654 status = mr_query("add_tagged_member_to_list", 4, membervec,
656 if (status == MR_SUCCESS)
658 else if (status != MR_USER || memberstruct->type != M_ANY)
660 com_err(whoami, status, "while adding member %s to %s",
661 memberstruct->name, listname);
666 membervec[1] = "LIST";
667 status = mr_query("add_tagged_member_to_list", 4, membervec,
669 if (status == MR_SUCCESS)
671 if (!strcmp(membervec[0], get_username()))
673 fprintf(stderr, "\nWARNING: \"LIST:%s\" was just added "
674 "to list \"%s\".\n", membervec[2], membervec[0]);
675 fprintf(stderr, "If you meant to add yourself to the list "
676 "\"%s\", type:\n", membervec[2]);
677 fprintf(stderr, "\tblanche %s -d %s\t(to undo this)\n",
678 membervec[0], membervec[2]);
679 fprintf(stderr, "\tblanche %s -a %s\t(to add yourself to "
680 "that list)\n", membervec[2], membervec[0]);
684 else if (status != MR_LIST || memberstruct->type != M_ANY)
686 com_err(whoami, status, "while adding member %s to %s",
687 memberstruct->name, listname);
692 status = mrcl_validate_string_member(memberstruct->name);
693 if (memberstruct->type == M_ANY && status == MRCL_WARN)
695 /* if user is trying to add something which isn't a
696 remote string, or a list, or a user, and didn't
697 explicitly specify `STRING:', it's probably a typo */
698 com_err(whoami, MR_NO_MATCH, "while adding member %s to %s",
699 memberstruct->name, listname);
704 mrcl_com_err(whoami);
706 if (status == MRCL_REJECT)
712 membervec[1] = "STRING";
713 status = mr_query("add_tagged_member_to_list", 4, membervec,
715 if (status != MR_SUCCESS)
717 com_err(whoami, status, "while adding member %s to %s",
718 memberstruct->name, listname);
723 membervec[1] = "KERBEROS";
724 status = mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
725 if (mrcl_get_message())
726 mrcl_com_err(whoami);
727 status = mr_query("add_tagged_member_to_list", 4, membervec,
729 if (status != MR_SUCCESS)
731 com_err(whoami, status, "while adding member %s to %s",
732 memberstruct->name, listname);
739 /* Process the delete list */
740 while (sq_get_data(dellist, &memberstruct))
742 membervec[0] = listname;
743 membervec[2] = memberstruct->name;
746 printf("Deleting member ");
747 show_list_member(memberstruct);
749 switch (memberstruct->type)
753 membervec[1] = "USER";
754 status = mr_query("delete_member_from_list", 3, membervec,
756 if (status == MR_SUCCESS)
758 else if ((status != MR_USER && status != MR_NO_MATCH) ||
759 memberstruct->type != M_ANY)
761 com_err(whoami, status, "while deleting member %s from %s",
762 memberstruct->name, listname);
767 membervec[1] = "LIST";
768 status = mr_query("delete_member_from_list", 3, membervec,
770 if (status == MR_SUCCESS)
772 else if ((status != MR_LIST && status != MR_NO_MATCH) ||
773 memberstruct->type != M_ANY)
775 if (status == MR_PERM && memberstruct->type == M_ANY &&
776 !strcmp(membervec[2], get_username()))
778 /* M_ANY means we've fallen through from the user
779 * case. The user is trying to remove himself from
780 * a list, but we got MR_USER or MR_NO_MATCH above,
781 * meaning he's not really on it, and we got MR_PERM
782 * when trying to remove LIST:$USER because he's not
783 * on the acl. That error is useless, so return
784 * MR_NO_MATCH instead. However, this will generate the
785 * wrong error if the user was trying to remove the list
786 * with his username from a list he doesn't administrate
787 * without explicitly specifying "list:".
789 status = MR_NO_MATCH;
791 com_err(whoami, status, "while deleting member %s from %s",
792 memberstruct->name, listname);
797 membervec[1] = "STRING";
798 status = mr_query("delete_member_from_list", 3, membervec,
800 if (status == MR_STRING && memberstruct->type == M_ANY)
802 com_err(whoami, 0, " Unable to find member %s to delete from %s",
803 memberstruct->name, listname);
805 if (!strcmp(membervec[0], get_username()))
807 fprintf(stderr, "(If you were trying to remove yourself "
808 "from the list \"%s\",\n", membervec[2]);
809 fprintf(stderr, "the correct command is \"blanche %s -d "
810 "%s\".)\n", membervec[2], membervec[0]);
813 else if (status != MR_SUCCESS)
815 com_err(whoami, status, "while deleting member %s from %s",
816 memberstruct->name, listname);
821 membervec[1] = "KERBEROS";
822 status = mr_query("delete_member_from_list", 3, membervec,
824 if (status == MR_STRING || status == MR_NO_MATCH)
826 /* Try canonicalizing the Kerberos principal and trying
827 * again. If we succeed, print the message from mrcl.
828 * Otherwise, just pretend we never did this and print
829 * the original error message.
831 mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
832 if (mrcl_get_message())
834 if (mr_query("delete_member_from_list", 3, membervec,
835 NULL, NULL) == MR_SUCCESS)
836 mrcl_com_err(whoami);
840 if (status != MR_SUCCESS)
842 com_err(whoami, status, "while deleting member %s from %s",
843 memberstruct->name, listname);
849 /* Process the tag list */
850 while (sq_get_data(taglist, &memberstruct))
852 membervec[0] = listname;
853 membervec[2] = memberstruct->name;
854 membervec[3] = memberstruct->tag;
857 printf("Tagging member ");
858 show_list_member(memberstruct);
860 switch (memberstruct->type)
864 membervec[1] = "USER";
865 status = mr_query("tag_member_of_list", 4, membervec,
867 if (status == MR_SUCCESS)
869 else if ((status != MR_USER && status != MR_NO_MATCH) ||
870 memberstruct->type != M_ANY)
872 com_err(whoami, status, "while changing tag on member %s of %s",
873 memberstruct->name, listname);
878 membervec[1] = "LIST";
879 status = mr_query("tag_member_of_list", 4, membervec,
881 if (status == MR_SUCCESS)
883 else if ((status != MR_LIST && status != MR_NO_MATCH) ||
884 memberstruct->type != M_ANY)
886 com_err(whoami, status, "while changing tag on member %s of %s",
887 memberstruct->name, listname);
892 membervec[1] = "STRING";
893 status = mr_query("tag_member_of_list", 4, membervec,
895 if (status == MR_STRING && memberstruct->type == M_ANY)
897 com_err(whoami, 0, " Unable to find member %s on list %s",
898 memberstruct->name, listname);
901 else if (status != MR_SUCCESS)
903 com_err(whoami, status, "while retagging member %s on %s",
904 memberstruct->name, listname);
909 membervec[1] = "KERBEROS";
910 status = mr_query("tag_member_of_list", 4, membervec,
912 if (status == MR_STRING || status == MR_NO_MATCH)
914 /* Try canonicalizing the Kerberos principal and trying
915 * again. If we succeed, print the message from mrcl.
916 * Otherwise, just pretend we never did this and print
917 * the original error message.
919 mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
920 if (mrcl_get_message())
922 if (mr_query("tag_member_of_list", 4, membervec,
923 NULL, NULL) == MR_SUCCESS)
924 mrcl_com_err(whoami);
928 if (status != MR_SUCCESS)
930 com_err(whoami, status, "while changing tag on member %s of %s",
931 memberstruct->name, listname);
937 /* Display the members of the list now, if requested */
941 recursive_display_list_members();
944 status = mr_query(showtags ? "get_tagged_members_of_list" :
945 "get_members_of_list", 1, &listname,
946 get_list_members, memberlist);
948 com_err(whoami, status, "while getting members of list %s",
950 while (sq_get_data(memberlist, &memberstruct))
951 show_list_member(memberstruct);
957 exit(success ? 0 : 1);
960 void usage(char **argv)
962 #define USAGE_OPTIONS_FORMAT " %-39s%s\n"
963 fprintf(stderr, "Usage: %s listname [options]\n", argv[0]);
964 fprintf(stderr, "Options are\n");
965 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-v | -verbose",
967 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-m | -members",
968 "-R | -rename newname");
969 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-u | -users",
971 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-l | -lists",
973 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-s | -strings",
975 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-k | -kerberos",
977 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-i | -info",
979 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-r | -recursive",
981 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-a | -add member",
983 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-d | -delete member",
985 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-al | -addlist filename",
987 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-dl | -deletelist filename",
989 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-f | -file filename",
991 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-at | -addtagged member tag",
993 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-ct | -changetag member tag",
994 "-D | -desc description");
995 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-t | -tags",
996 "-O | -owner owner");
997 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-n | -noauth",
998 "-MA | -memacl membership_acl");
999 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-db | -database host[:port]",
1005 /* Display the members stored in the queue */
1007 void show_list_member(struct member *memberstruct)
1011 switch (memberstruct->type)
1034 printf("%s\n", memberstruct->name);
1039 printf("%s:%s", s, memberstruct->name);
1042 if (memberstruct->type == M_LIST)
1043 printf("LIST:%s", memberstruct->name);
1044 else if (memberstruct->type == M_KERBEROS)
1045 printf("KERBEROS:%s", memberstruct->name);
1046 else if (memberstruct->type == M_STRING &&
1047 !strchr(memberstruct->name, '@'))
1048 printf("STRING:%s", memberstruct->name);
1050 printf("%s", memberstruct->name);
1052 if (showtags && *(memberstruct->tag))
1053 printf(" (%s)\n", memberstruct->tag);
1059 /* Show the retrieved information about a list */
1061 int show_list_info(int argc, char **argv, void *hint)
1063 printf("List: %s\n", argv[L_NAME]);
1064 printf("Description: %s\n", argv[L_DESC]);
1065 printf("Flags: %s, %s, and %s\n",
1066 atoi(argv[L_ACTIVE]) ? "active" : "inactive",
1067 atoi(argv[L_PUBLIC]) ? "public" : "private",
1068 atoi(argv[L_HIDDEN]) ? "hidden" : "visible");
1069 printf("%s is %sa maillist and is %sa group", argv[L_NAME],
1070 atoi(argv[L_MAILLIST]) ? "" : "not ",
1071 atoi(argv[L_GROUP]) ? "" : "not ");
1072 if (atoi(argv[L_GROUP]))
1074 if (atoi(argv[L_NFSGROUP]))
1075 printf(" (and an NFS group)");
1076 printf(" with GID %d\n", atoi(argv[L_GID]));
1080 printf("Owner: %s %s\n", argv[L_ACE_TYPE], argv[L_ACE_NAME]);
1081 if (strcmp(argv[L_MEMACE_TYPE], "NONE"))
1082 printf("Membership ACL: %s %s\n", argv[L_MEMACE_TYPE],
1083 argv[L_MEMACE_NAME]);
1084 printf("Last modified by %s with %s on %s\n",
1085 argv[L_MODBY], argv[L_MODWITH], argv[L_MODTIME]);
1090 /* Copy retrieved information about a list into a new argv */
1092 int save_list_info(int argc, char **argv, void *hint)
1094 char **nargv = hint;
1096 for (argc = 0; argc < 14; argc++)
1097 nargv[argc + 1] = strdup(argv[argc]);
1101 /* Show the retrieve list member count */
1103 int show_list_count(int argc, char **argv, void *hint)
1105 printf("Members: %s\n", argv[0]);
1110 /* Recursively find all of the members of listname, and then display them */
1112 void recursive_display_list_members(void)
1114 int status, count, savecount;
1115 struct save_queue *lists, *members;
1116 struct member *m, *m1, *data;
1118 lists = sq_create();
1119 members = sq_create();
1120 m = malloc(sizeof(struct member));
1123 sq_save_data(lists, m);
1125 while (sq_get_data(lists, &m))
1127 sq_destroy(memberlist);
1128 memberlist = sq_create();
1129 status = mr_query("get_members_of_list", 1, &(m->name),
1130 get_list_members, memberlist);
1132 com_err(whoami, status, "while getting members of list %s", m->name);
1133 while (sq_get_data(memberlist, &m1))
1135 if (m1->type == M_LIST)
1136 unique_add_member(lists, m1);
1138 unique_add_member(members, m1);
1141 savecount = count = sq_count_elts(members);
1142 data = malloc(count * sizeof(struct member));
1144 while (sq_get_data(members, &m))
1145 memcpy(&data[count++], m, sizeof(struct member));
1146 qsort(data, count, sizeof(struct member), membercmp);
1147 for (count = 0; count < savecount; count++)
1148 show_list_member(&data[count]);
1152 /* add a struct member to a queue if that member isn't already there. */
1154 void unique_add_member(struct save_queue *q, struct member *m)
1156 struct save_queue *qp;
1158 for (qp = q->q_next; qp != q; qp = qp->q_next)
1160 if (!membercmp(qp->q_data, m))
1167 /* Collect the retrieved members of the list */
1169 int get_list_members(int argc, char **argv, void *sq)
1171 struct save_queue *q = sq;
1174 m = malloc(sizeof(struct member));
1187 m->type = M_KERBEROS;
1190 m->name = strdup(argv[1]);
1192 m->tag = strdup(argv[2]);
1194 m->tag = strdup("");
1200 /* Open file, parse members from file, and put them on the specified queue */
1201 void get_members_from_file(char *filename, struct save_queue *queue)
1205 struct member *memberstruct;
1207 if (!strcmp(filename, "-"))
1211 in = fopen(filename, "r");
1214 com_err(whoami, errno, "while opening %s for input", filename);
1219 while (fgets(buf, BUFSIZ, in))
1221 if ((memberstruct = parse_member(buf)))
1222 sq_save_data(queue, memberstruct);
1226 com_err(whoami, errno, "while reading from %s", filename);
1232 /* Collect the possible expansions of the alias MAILHUB */
1234 int collect(int argc, char **argv, void *l)
1239 for (i = 0; (*list)[i]; i++)
1241 *list = realloc(*list, (i + 2) * sizeof(char *));
1242 (*list)[i] = strdup(argv[2]);
1243 (*list)[i + 1] = NULL;
1248 /* Parse a line of input, fetching a member. NULL is returned if a member
1249 * is not found. ';' is a comment character.
1252 struct member *parse_member(char *s)
1257 while (*s && isspace(*s))
1260 while (*p && *p != '\n' && *p != ';')
1262 if (isprint(*p) && !isspace(*p))
1269 if (p == s || strlen(s) == 0)
1272 if (!(m = malloc(sizeof(struct member))))
1274 m->tag = strdup("");
1276 if ((p = strchr(s, ':')))
1280 if (!strcasecmp("user", s))
1282 else if (!strcasecmp("list", s))
1284 else if (!strcasecmp("string", s))
1286 else if (!strcasecmp("kerberos", s))
1287 m->type = M_KERBEROS;
1288 else if (!strcasecmp("none", s))
1296 m->name = strdup(m->name);
1300 m->name = strdup(s);
1301 m->type = strcasecmp(s, "none") ? M_ANY : M_NONE;
1308 * This routine two compares members by the following rules:
1309 * 1. A USER is less than a LIST
1310 * 2. A LIST is less than a STRING
1311 * 3. If two members are of the same type, the one alphabetically first
1312 * is less than the other
1313 * It returs < 0 if the first member is less, 0 if they are identical, and
1314 * > 0 if the second member is less (the first member is greater).
1317 int membercmp(const void *mem1, const void *mem2)
1319 const struct member *m1 = mem1, *m2 = mem2;
1321 if (m1->type == M_ANY || m2->type == M_ANY || (m1->type == m2->type))
1322 return strcmp(m1->name, m2->name);
1324 return m1->type - m2->type;
1328 int sq_count_elts(struct save_queue *q)
1334 while (sq_get_data(q, &foo))
1339 char *get_username(void)
1343 username = getenv("USER");
1346 username = mrcl_krb_user();
1349 com_err(whoami, 0, "Could not determine username");