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);
423 argv[L_ACE_TYPE] = "USER";
424 argv[L_ACE_NAME] = get_username();
426 status = mr_query("add_list", 13, argv, NULL, NULL);
431 com_err(whoami, status, "while creating list.");
439 status = mr_query("get_list_info", 1, &listname,
440 save_list_info, argv);
443 com_err(whoami, status, "while getting list information");
449 argv[L_NAME + 1] = newname;
451 argv[L_ACTIVE + 1] = active ? "1" : "0";
453 argv[L_PUBLIC + 1] = public ? "1" : "0";
455 argv[L_HIDDEN + 1] = hidden ? "1" : "0";
457 argv[L_MAILLIST + 1] = maillist ? "1" : "0";
459 argv[L_GROUP + 1] = grouplist ? "1" : "0";
461 argv[L_NFSGROUP + 1] = nfsgroup ? "1" : "0";
463 argv[L_DESC + 1] = desc;
467 if (memacl->type == M_ANY)
469 status = mr_query("get_user_account_by_login", 1,
470 &memacl->name, NULL, NULL);
471 if (status == MR_NO_MATCH)
472 memacl->type = M_LIST;
474 memacl->type = M_USER;
476 argv[L_MEMACE_TYPE + 1] = typename[memacl->type];
477 argv[L_MEMACE_NAME + 1] = memacl->name;
478 if (memacl->type == M_KERBEROS)
480 status = mrcl_validate_kerberos_member(argv[L_MEMACE_NAME + 1],
481 &argv[L_MEMACE_NAME + 1]);
482 if (mrcl_get_message())
483 mrcl_com_err(whoami);
489 argv[L_ACE_NAME + 1] = owner->name;
494 argv[L_ACE_TYPE + 1] = "USER";
495 status = mr_query("update_list", 14, argv, NULL, NULL);
496 if (owner->type != M_ANY || status != MR_USER)
500 argv[L_ACE_TYPE + 1] = "LIST";
501 status = mr_query("update_list", 14, argv, NULL, NULL);
505 argv[L_ACE_TYPE + 1] = "KERBEROS";
506 status = mrcl_validate_kerberos_member(argv[L_ACE_NAME + 1],
507 &argv[L_ACE_NAME + 1]);
508 if (mrcl_get_message())
509 mrcl_com_err(whoami);
510 status = mr_query("update_list", 14, argv, NULL, NULL);
515 status = mr_query("update_list", 14, argv, NULL, NULL);
519 com_err(whoami, status, "while updating list.");
526 /* display list info if requested to */
529 status = mr_query("get_list_info", 1, &listname, show_list_info, NULL);
532 com_err(whoami, status, "while getting list information");
535 if (verbose && !memberflg)
537 status = mr_query("count_members_of_list", 1, &listname,
538 show_list_count, NULL);
541 com_err(whoami, status, "while getting list count");
547 /* if we're synchronizing to a file, we need to:
548 * get the current members of the list
549 * for each member of the sync file
550 * if they are on the list, remove them from the in-memory copy
551 * if they're not on the list, add them to add-list
552 * if anyone is left on the in-memory copy, put them on the delete-list
553 * lastly, reset memberlist so we can use it again later
557 status = mr_query("get_members_of_list", 1, &listname,
558 get_list_members, memberlist);
561 com_err(whoami, status, "getting members of list %s", listname);
564 while (sq_get_data(synclist, &memberstruct))
566 struct save_queue *q;
569 for (q = memberlist->q_next; q != memberlist; q = q->q_next)
571 if (membercmp(q->q_data, memberstruct) == 0)
573 q->q_prev->q_next = q->q_next;
574 q->q_next->q_prev = q->q_prev;
580 sq_save_data(addlist, memberstruct);
582 while (sq_get_data(memberlist, &memberstruct))
583 sq_save_data(dellist, memberstruct);
584 sq_destroy(memberlist);
585 memberlist = sq_create();
588 /* Process the add list */
589 while (sq_get_data(addlist, &memberstruct))
591 /* canonicalize string if necessary */
592 if (memberstruct->type != M_KERBEROS &&
593 (p = strchr(memberstruct->name, '@')))
595 char *host = canonicalize_hostname(strdup(++p));
596 static char **mailhubs = NULL;
605 mailhubs = malloc(sizeof(char *));
607 status = mr_query("get_alias", 3, argv, collect,
609 if (status != MR_SUCCESS && status != MR_NO_MATCH)
611 com_err(whoami, status,
612 " while reading list of MAILHUB servers");
616 for (i = 0; (p = mailhubs[i]); i++)
618 if (!strcasecmp(p, host))
620 host = strdup(memberstruct->name);
621 *(strchr(memberstruct->name, '@')) = 0;
622 if (memberstruct->type == M_STRING)
623 memberstruct->type = M_ANY;
624 fprintf(stderr, "Warning: \"%s\" converted to "
625 "\"%s\" because it is a local name.\n",
626 host, memberstruct->name);
632 /* now continue adding member */
633 membervec[0] = listname;
634 membervec[2] = memberstruct->name;
635 membervec[3] = memberstruct->tag;
638 printf("Adding member ");
639 show_list_member(memberstruct);
641 switch (memberstruct->type)
645 membervec[1] = "USER";
646 status = mr_query("add_tagged_member_to_list", 4, membervec,
648 if (status == MR_SUCCESS)
650 else if (status != MR_USER || memberstruct->type != M_ANY)
652 com_err(whoami, status, "while adding member %s to %s",
653 memberstruct->name, listname);
658 membervec[1] = "LIST";
659 status = mr_query("add_tagged_member_to_list", 4, membervec,
661 if (status == MR_SUCCESS)
663 if (!strcmp(membervec[0], get_username()))
665 fprintf(stderr, "\nWARNING: \"LIST:%s\" was just added "
666 "to list \"%s\".\n", membervec[2], membervec[0]);
667 fprintf(stderr, "If you meant to add yourself to the list "
668 "\"%s\", type:\n", membervec[2]);
669 fprintf(stderr, "\tblanche %s -d %s\t(to undo this)\n",
670 membervec[0], membervec[2]);
671 fprintf(stderr, "\tblanche %s -a %s\t(to add yourself to "
672 "that list)\n", membervec[2], membervec[0]);
676 else if (status != MR_LIST || memberstruct->type != M_ANY)
678 com_err(whoami, status, "while adding member %s to %s",
679 memberstruct->name, listname);
684 status = mrcl_validate_string_member(memberstruct->name);
685 if (memberstruct->type == M_ANY && status == MRCL_WARN)
687 /* if user is trying to add something which isn't a
688 remote string, or a list, or a user, and didn't
689 explicitly specify `STRING:', it's probably a typo */
690 com_err(whoami, MR_NO_MATCH, "while adding member %s to %s",
691 memberstruct->name, listname);
696 mrcl_com_err(whoami);
698 if (status == MRCL_REJECT)
704 membervec[1] = "STRING";
705 status = mr_query("add_tagged_member_to_list", 4, membervec,
707 if (status != MR_SUCCESS)
709 com_err(whoami, status, "while adding member %s to %s",
710 memberstruct->name, listname);
715 membervec[1] = "KERBEROS";
716 status = mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
717 if (mrcl_get_message())
718 mrcl_com_err(whoami);
719 status = mr_query("add_tagged_member_to_list", 4, membervec,
721 if (status != MR_SUCCESS)
723 com_err(whoami, status, "while adding member %s to %s",
724 memberstruct->name, listname);
731 /* Process the delete list */
732 while (sq_get_data(dellist, &memberstruct))
734 membervec[0] = listname;
735 membervec[2] = memberstruct->name;
738 printf("Deleting member ");
739 show_list_member(memberstruct);
741 switch (memberstruct->type)
745 membervec[1] = "USER";
746 status = mr_query("delete_member_from_list", 3, membervec,
748 if (status == MR_SUCCESS)
750 else if ((status != MR_USER && status != MR_NO_MATCH) ||
751 memberstruct->type != M_ANY)
753 com_err(whoami, status, "while deleting member %s from %s",
754 memberstruct->name, listname);
759 membervec[1] = "LIST";
760 status = mr_query("delete_member_from_list", 3, membervec,
762 if (status == MR_SUCCESS)
764 else if ((status != MR_LIST && status != MR_NO_MATCH) ||
765 memberstruct->type != M_ANY)
767 if (status == MR_PERM && memberstruct->type == M_ANY &&
768 !strcmp(membervec[2], get_username()))
770 /* M_ANY means we've fallen through from the user
771 * case. The user is trying to remove himself from
772 * a list, but we got MR_USER or MR_NO_MATCH above,
773 * meaning he's not really on it, and we got MR_PERM
774 * when trying to remove LIST:$USER because he's not
775 * on the acl. That error is useless, so return
776 * MR_NO_MATCH instead. However, this will generate the
777 * wrong error if the user was trying to remove the list
778 * with his username from a list he doesn't administrate
779 * without explicitly specifying "list:".
781 status = MR_NO_MATCH;
783 com_err(whoami, status, "while deleting member %s from %s",
784 memberstruct->name, listname);
789 membervec[1] = "STRING";
790 status = mr_query("delete_member_from_list", 3, membervec,
792 if (status == MR_STRING && memberstruct->type == M_ANY)
794 com_err(whoami, 0, " Unable to find member %s to delete from %s",
795 memberstruct->name, listname);
797 if (!strcmp(membervec[0], get_username()))
799 fprintf(stderr, "(If you were trying to remove yourself "
800 "from the list \"%s\",\n", membervec[2]);
801 fprintf(stderr, "the correct command is \"blanche %s -d "
802 "%s\".)\n", membervec[2], membervec[0]);
805 else if (status != MR_SUCCESS)
807 com_err(whoami, status, "while deleting member %s from %s",
808 memberstruct->name, listname);
813 membervec[1] = "KERBEROS";
814 status = mr_query("delete_member_from_list", 3, membervec,
816 if (status == MR_STRING || status == MR_NO_MATCH)
818 /* Try canonicalizing the Kerberos principal and trying
819 * again. If we succeed, print the message from mrcl.
820 * Otherwise, just pretend we never did this and print
821 * the original error message.
823 mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
824 if (mrcl_get_message())
826 if (mr_query("delete_member_from_list", 3, membervec,
827 NULL, NULL) == MR_SUCCESS)
828 mrcl_com_err(whoami);
832 if (status != MR_SUCCESS)
834 com_err(whoami, status, "while deleting member %s from %s",
835 memberstruct->name, listname);
841 /* Process the tag list */
842 while (sq_get_data(taglist, &memberstruct))
844 membervec[0] = listname;
845 membervec[2] = memberstruct->name;
846 membervec[3] = memberstruct->tag;
849 printf("Tagging member ");
850 show_list_member(memberstruct);
852 switch (memberstruct->type)
856 membervec[1] = "USER";
857 status = mr_query("tag_member_of_list", 4, membervec,
859 if (status == MR_SUCCESS)
861 else if ((status != MR_USER && status != MR_NO_MATCH) ||
862 memberstruct->type != M_ANY)
864 com_err(whoami, status, "while changing tag on member %s of %s",
865 memberstruct->name, listname);
870 membervec[1] = "LIST";
871 status = mr_query("tag_member_of_list", 4, membervec,
873 if (status == MR_SUCCESS)
875 else if ((status != MR_LIST && status != MR_NO_MATCH) ||
876 memberstruct->type != M_ANY)
878 com_err(whoami, status, "while changing tag on member %s of %s",
879 memberstruct->name, listname);
884 membervec[1] = "STRING";
885 status = mr_query("tag_member_of_list", 4, membervec,
887 if (status == MR_STRING && memberstruct->type == M_ANY)
889 com_err(whoami, 0, " Unable to find member %s on list %s",
890 memberstruct->name, listname);
893 else if (status != MR_SUCCESS)
895 com_err(whoami, status, "while retagging member %s on %s",
896 memberstruct->name, listname);
901 membervec[1] = "KERBEROS";
902 status = mr_query("tag_member_of_list", 4, membervec,
904 if (status == MR_STRING || status == MR_NO_MATCH)
906 /* Try canonicalizing the Kerberos principal and trying
907 * again. If we succeed, print the message from mrcl.
908 * Otherwise, just pretend we never did this and print
909 * the original error message.
911 mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
912 if (mrcl_get_message())
914 if (mr_query("tag_member_of_list", 4, membervec,
915 NULL, NULL) == MR_SUCCESS)
916 mrcl_com_err(whoami);
920 if (status != MR_SUCCESS)
922 com_err(whoami, status, "while changing tag on member %s of %s",
923 memberstruct->name, listname);
929 /* Display the members of the list now, if requested */
933 recursive_display_list_members();
936 status = mr_query(showtags ? "get_tagged_members_of_list" :
937 "get_members_of_list", 1, &listname,
938 get_list_members, memberlist);
940 com_err(whoami, status, "while getting members of list %s",
942 while (sq_get_data(memberlist, &memberstruct))
943 show_list_member(memberstruct);
949 exit(success ? 0 : 1);
952 void usage(char **argv)
954 #define USAGE_OPTIONS_FORMAT " %-39s%s\n"
955 fprintf(stderr, "Usage: %s listname [options]\n", argv[0]);
956 fprintf(stderr, "Options are\n");
957 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-v | -verbose",
959 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-m | -members",
960 "-R | -rename newname");
961 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-u | -users",
963 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-l | -lists",
965 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-s | -strings",
967 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-k | -kerberos",
969 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-i | -info",
971 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-r | -recursive",
973 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-a | -add member",
975 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-d | -delete member",
977 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-al | -addlist filename",
979 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-dl | -deletelist filename",
981 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-f | -file filename",
983 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-at | -addtagged member tag",
985 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-ct | -changetag member tag",
986 "-D | -desc description");
987 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-t | -tags",
988 "-O | -owner owner");
989 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-n | -noauth",
990 "-MA | -memacl membership_acl");
991 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-db | -database host[:port]",
997 /* Display the members stored in the queue */
999 void show_list_member(struct member *memberstruct)
1003 switch (memberstruct->type)
1026 printf("%s\n", memberstruct->name);
1031 printf("%s:%s", s, memberstruct->name);
1034 if (memberstruct->type == M_LIST)
1035 printf("LIST:%s", memberstruct->name);
1036 else if (memberstruct->type == M_KERBEROS)
1037 printf("KERBEROS:%s", memberstruct->name);
1038 else if (memberstruct->type == M_STRING &&
1039 !strchr(memberstruct->name, '@'))
1040 printf("STRING:%s", memberstruct->name);
1042 printf("%s", memberstruct->name);
1044 if (showtags && *(memberstruct->tag))
1045 printf(" (%s)\n", memberstruct->tag);
1051 /* Show the retrieved information about a list */
1053 int show_list_info(int argc, char **argv, void *hint)
1055 printf("List: %s\n", argv[L_NAME]);
1056 printf("Description: %s\n", argv[L_DESC]);
1057 printf("Flags: %s, %s, and %s\n",
1058 atoi(argv[L_ACTIVE]) ? "active" : "inactive",
1059 atoi(argv[L_PUBLIC]) ? "public" : "private",
1060 atoi(argv[L_HIDDEN]) ? "hidden" : "visible");
1061 printf("%s is %sa maillist and is %sa group", argv[L_NAME],
1062 atoi(argv[L_MAILLIST]) ? "" : "not ",
1063 atoi(argv[L_GROUP]) ? "" : "not ");
1064 if (atoi(argv[L_GROUP]))
1066 if (atoi(argv[L_NFSGROUP]))
1067 printf(" (and an NFS group)");
1068 printf(" with GID %d\n", atoi(argv[L_GID]));
1072 printf("Owner: %s %s\n", argv[L_ACE_TYPE], argv[L_ACE_NAME]);
1073 if (strcmp(argv[L_MEMACE_TYPE], "NONE"))
1074 printf("Membership ACL: %s %s\n", argv[L_MEMACE_TYPE],
1075 argv[L_MEMACE_NAME]);
1076 printf("Last modified by %s with %s on %s\n",
1077 argv[L_MODBY], argv[L_MODWITH], argv[L_MODTIME]);
1082 /* Copy retrieved information about a list into a new argv */
1084 int save_list_info(int argc, char **argv, void *hint)
1086 char **nargv = hint;
1088 for (argc = 0; argc < 14; argc++)
1089 nargv[argc + 1] = strdup(argv[argc]);
1093 /* Show the retrieve list member count */
1095 int show_list_count(int argc, char **argv, void *hint)
1097 printf("Members: %s\n", argv[0]);
1102 /* Recursively find all of the members of listname, and then display them */
1104 void recursive_display_list_members(void)
1106 int status, count, savecount;
1107 struct save_queue *lists, *members;
1108 struct member *m, *m1, *data;
1110 lists = sq_create();
1111 members = sq_create();
1112 m = malloc(sizeof(struct member));
1115 sq_save_data(lists, m);
1117 while (sq_get_data(lists, &m))
1119 sq_destroy(memberlist);
1120 memberlist = sq_create();
1121 status = mr_query("get_members_of_list", 1, &(m->name),
1122 get_list_members, memberlist);
1124 com_err(whoami, status, "while getting members of list %s", m->name);
1125 while (sq_get_data(memberlist, &m1))
1127 if (m1->type == M_LIST)
1128 unique_add_member(lists, m1);
1130 unique_add_member(members, m1);
1133 savecount = count = sq_count_elts(members);
1134 data = malloc(count * sizeof(struct member));
1136 while (sq_get_data(members, &m))
1137 memcpy(&data[count++], m, sizeof(struct member));
1138 qsort(data, count, sizeof(struct member), membercmp);
1139 for (count = 0; count < savecount; count++)
1140 show_list_member(&data[count]);
1144 /* add a struct member to a queue if that member isn't already there. */
1146 void unique_add_member(struct save_queue *q, struct member *m)
1148 struct save_queue *qp;
1150 for (qp = q->q_next; qp != q; qp = qp->q_next)
1152 if (!membercmp(qp->q_data, m))
1159 /* Collect the retrieved members of the list */
1161 int get_list_members(int argc, char **argv, void *sq)
1163 struct save_queue *q = sq;
1166 m = malloc(sizeof(struct member));
1179 m->type = M_KERBEROS;
1182 m->name = strdup(argv[1]);
1184 m->tag = strdup(argv[2]);
1186 m->tag = strdup("");
1192 /* Open file, parse members from file, and put them on the specified queue */
1193 void get_members_from_file(char *filename, struct save_queue *queue)
1197 struct member *memberstruct;
1199 if (!strcmp(filename, "-"))
1203 in = fopen(filename, "r");
1206 com_err(whoami, errno, "while opening %s for input", filename);
1211 while (fgets(buf, BUFSIZ, in))
1213 if ((memberstruct = parse_member(buf)))
1214 sq_save_data(queue, memberstruct);
1218 com_err(whoami, errno, "while reading from %s", filename);
1224 /* Collect the possible expansions of the alias MAILHUB */
1226 int collect(int argc, char **argv, void *l)
1231 for (i = 0; (*list)[i]; i++)
1233 *list = realloc(*list, (i + 2) * sizeof(char *));
1234 (*list)[i] = strdup(argv[2]);
1235 (*list)[i + 1] = NULL;
1240 /* Parse a line of input, fetching a member. NULL is returned if a member
1241 * is not found. ';' is a comment character.
1244 struct member *parse_member(char *s)
1249 while (*s && isspace(*s))
1252 while (*p && *p != '\n' && *p != ';')
1254 if (isprint(*p) && !isspace(*p))
1261 if (p == s || strlen(s) == 0)
1264 if (!(m = malloc(sizeof(struct member))))
1266 m->tag = strdup("");
1268 if ((p = strchr(s, ':')))
1272 if (!strcasecmp("user", s))
1274 else if (!strcasecmp("list", s))
1276 else if (!strcasecmp("string", s))
1278 else if (!strcasecmp("kerberos", s))
1279 m->type = M_KERBEROS;
1280 else if (!strcasecmp("none", s))
1288 m->name = strdup(m->name);
1292 m->name = strdup(s);
1293 m->type = strcasecmp(s, "none") ? M_ANY : M_NONE;
1300 * This routine two compares members by the following rules:
1301 * 1. A USER is less than a LIST
1302 * 2. A LIST is less than a STRING
1303 * 3. If two members are of the same type, the one alphabetically first
1304 * is less than the other
1305 * It returs < 0 if the first member is less, 0 if they are identical, and
1306 * > 0 if the second member is less (the first member is greater).
1309 int membercmp(const void *mem1, const void *mem2)
1311 const struct member *m1 = mem1, *m2 = mem2;
1313 if (m1->type == M_ANY || m2->type == M_ANY || (m1->type == m2->type))
1314 return strcmp(m1->name, m2->name);
1316 return m1->type - m2->type;
1320 int sq_count_elts(struct save_queue *q)
1326 while (sq_get_data(q, &foo))
1331 char *get_username(void)
1335 username = getenv("USER");
1338 username = mrcl_krb_user();
1341 com_err(whoami, 0, "Could not determine username");