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, "Authentication error while working on list %s",
341 com_err(whoami, 0, "Try the -noauth flag if you don't "
342 "need authentication.");
347 /* check for username/listname clash */
348 if (createflag || (setinfo && newname && strcmp(newname, listname)))
350 status = mr_query("get_user_account_by_login", 1,
351 createflag ? &listname : &newname,
353 if (status != MR_NO_MATCH)
354 fprintf(stderr, "WARNING: A user by that name already exists.\n");
357 /* create if needed */
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";
374 if (memacl->type == M_ANY)
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;
381 memacl->type = M_USER;
383 argv[L_MEMACE_TYPE] = typename[memacl->type];
384 argv[L_MEMACE_NAME] = memacl->name;
385 if (memacl->type == M_KERBEROS)
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);
394 argv[L_MEMACE_TYPE] = argv[L_MEMACE_NAME] = "NONE";
398 argv[L_ACE_NAME] = owner->name;
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)
409 argv[L_ACE_TYPE] = "LIST";
410 status = mr_query("add_list", 13, argv, NULL, NULL);
414 argv[L_ACE_TYPE] = "KERBEROS";
415 status = mrcl_validate_kerberos_member(argv[L_ACE_NAME],
417 if (mrcl_get_message())
418 mrcl_com_err(whoami);
419 status = mr_query("add_list", 13, argv, NULL, NULL);
422 argv[L_ACE_TYPE] = argv[L_ACE_NAME] = "NONE";
423 status = mr_query("add_list", 13, argv, NULL, NULL);
429 argv[L_ACE_TYPE] = "USER";
430 argv[L_ACE_NAME] = get_username();
432 status = mr_query("add_list", 13, argv, NULL, NULL);
437 com_err(whoami, status, "while creating list.");
445 status = mr_query("get_list_info", 1, &listname,
446 save_list_info, argv);
449 com_err(whoami, status, "while getting list information");
455 argv[L_NAME + 1] = newname;
457 argv[L_ACTIVE + 1] = active ? "1" : "0";
459 argv[L_PUBLIC + 1] = public ? "1" : "0";
461 argv[L_HIDDEN + 1] = hidden ? "1" : "0";
463 argv[L_MAILLIST + 1] = maillist ? "1" : "0";
465 argv[L_GROUP + 1] = grouplist ? "1" : "0";
467 argv[L_NFSGROUP + 1] = nfsgroup ? "1" : "0";
469 argv[L_DESC + 1] = desc;
473 if (memacl->type == M_ANY)
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;
480 memacl->type = M_USER;
482 argv[L_MEMACE_TYPE + 1] = typename[memacl->type];
483 argv[L_MEMACE_NAME + 1] = memacl->name;
484 if (memacl->type == M_KERBEROS)
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);
495 argv[L_ACE_NAME + 1] = owner->name;
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)
506 argv[L_ACE_TYPE + 1] = "LIST";
507 status = mr_query("update_list", 14, argv, NULL, NULL);
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);
519 argv[L_ACE_TYPE + 1] = argv[L_ACE_NAME + 1] = "NONE";
520 status = mr_query("update_list", 14, argv, NULL, NULL);
525 status = mr_query("update_list", 14, argv, NULL, NULL);
529 com_err(whoami, status, "while updating list.");
536 /* display list info if requested to */
539 status = mr_query("get_list_info", 1, &listname, show_list_info, NULL);
542 com_err(whoami, status, "while getting list information");
545 if (verbose && !memberflg)
547 status = mr_query("count_members_of_list", 1, &listname,
548 show_list_count, NULL);
551 com_err(whoami, status, "while getting list count");
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
567 status = mr_query("get_members_of_list", 1, &listname,
568 get_list_members, memberlist);
571 com_err(whoami, status, "getting members of list %s", listname);
574 while (sq_get_data(synclist, &memberstruct))
576 struct save_queue *q;
579 for (q = memberlist->q_next; q != memberlist; q = q->q_next)
581 if (membercmp(q->q_data, memberstruct) == 0)
583 q->q_prev->q_next = q->q_next;
584 q->q_next->q_prev = q->q_prev;
590 sq_save_data(addlist, memberstruct);
592 while (sq_get_data(memberlist, &memberstruct))
593 sq_save_data(dellist, memberstruct);
594 sq_destroy(memberlist);
595 memberlist = sq_create();
598 /* Process the add list */
599 while (sq_get_data(addlist, &memberstruct))
601 /* canonicalize string if necessary */
602 if (memberstruct->type != M_KERBEROS &&
603 (p = strchr(memberstruct->name, '@')))
605 char *host = canonicalize_hostname(strdup(++p));
606 static char **mailhubs = NULL;
615 mailhubs = malloc(sizeof(char *));
617 status = mr_query("get_alias", 3, argv, collect,
619 if (status != MR_SUCCESS && status != MR_NO_MATCH)
621 com_err(whoami, status,
622 " while reading list of MAILHUB servers");
626 for (i = 0; (p = mailhubs[i]); i++)
628 if (!strcasecmp(p, host))
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);
642 /* now continue adding member */
643 membervec[0] = listname;
644 membervec[2] = memberstruct->name;
645 membervec[3] = memberstruct->tag;
648 printf("Adding member ");
649 show_list_member(memberstruct);
651 switch (memberstruct->type)
655 membervec[1] = "USER";
656 status = mr_query("add_tagged_member_to_list", 4, membervec,
658 if (status == MR_SUCCESS)
660 else if (status != MR_USER || memberstruct->type != M_ANY)
662 com_err(whoami, status, "while adding member %s to %s",
663 memberstruct->name, listname);
668 membervec[1] = "LIST";
669 status = mr_query("add_tagged_member_to_list", 4, membervec,
671 if (status == MR_SUCCESS)
673 if (!strcmp(membervec[0], get_username()))
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]);
686 else if (status != MR_LIST || memberstruct->type != M_ANY)
688 com_err(whoami, status, "while adding member %s to %s",
689 memberstruct->name, listname);
694 status = mrcl_validate_string_member(memberstruct->name);
695 if (memberstruct->type == M_ANY && status == MRCL_WARN)
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);
706 mrcl_com_err(whoami);
708 if (status == MRCL_REJECT)
714 membervec[1] = "STRING";
715 status = mr_query("add_tagged_member_to_list", 4, membervec,
717 if (status != MR_SUCCESS)
719 com_err(whoami, status, "while adding member %s to %s",
720 memberstruct->name, listname);
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,
731 if (status != MR_SUCCESS)
733 com_err(whoami, status, "while adding member %s to %s",
734 memberstruct->name, listname);
741 /* Process the delete list */
742 while (sq_get_data(dellist, &memberstruct))
744 membervec[0] = listname;
745 membervec[2] = memberstruct->name;
748 printf("Deleting member ");
749 show_list_member(memberstruct);
751 switch (memberstruct->type)
755 membervec[1] = "USER";
756 status = mr_query("delete_member_from_list", 3, membervec,
758 if (status == MR_SUCCESS)
760 else if ((status != MR_USER && status != MR_NO_MATCH) ||
761 memberstruct->type != M_ANY)
763 com_err(whoami, status, "while deleting member %s from %s",
764 memberstruct->name, listname);
769 membervec[1] = "LIST";
770 status = mr_query("delete_member_from_list", 3, membervec,
772 if (status == MR_SUCCESS)
774 else if ((status != MR_LIST && status != MR_NO_MATCH) ||
775 memberstruct->type != M_ANY)
777 if (status == MR_PERM && memberstruct->type == M_ANY &&
778 !strcmp(membervec[2], get_username()))
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:".
791 status = MR_NO_MATCH;
793 com_err(whoami, status, "while deleting member %s from %s",
794 memberstruct->name, listname);
799 membervec[1] = "STRING";
800 status = mr_query("delete_member_from_list", 3, membervec,
802 if (status == MR_STRING && memberstruct->type == M_ANY)
804 com_err(whoami, 0, " Unable to find member %s to delete from %s",
805 memberstruct->name, listname);
807 if (!strcmp(membervec[0], get_username()))
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]);
815 else if (status != MR_SUCCESS)
817 com_err(whoami, status, "while deleting member %s from %s",
818 memberstruct->name, listname);
823 membervec[1] = "KERBEROS";
824 status = mr_query("delete_member_from_list", 3, membervec,
826 if (status == MR_STRING || status == MR_NO_MATCH)
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.
833 mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
834 if (mrcl_get_message())
836 if (mr_query("delete_member_from_list", 3, membervec,
837 NULL, NULL) == MR_SUCCESS)
838 mrcl_com_err(whoami);
842 if (status != MR_SUCCESS)
844 com_err(whoami, status, "while deleting member %s from %s",
845 memberstruct->name, listname);
851 /* Process the tag list */
852 while (sq_get_data(taglist, &memberstruct))
854 membervec[0] = listname;
855 membervec[2] = memberstruct->name;
856 membervec[3] = memberstruct->tag;
859 printf("Tagging member ");
860 show_list_member(memberstruct);
862 switch (memberstruct->type)
866 membervec[1] = "USER";
867 status = mr_query("tag_member_of_list", 4, membervec,
869 if (status == MR_SUCCESS)
871 else if ((status != MR_USER && status != MR_NO_MATCH) ||
872 memberstruct->type != M_ANY)
874 com_err(whoami, status, "while changing tag on member %s of %s",
875 memberstruct->name, listname);
880 membervec[1] = "LIST";
881 status = mr_query("tag_member_of_list", 4, membervec,
883 if (status == MR_SUCCESS)
885 else if ((status != MR_LIST && status != MR_NO_MATCH) ||
886 memberstruct->type != M_ANY)
888 com_err(whoami, status, "while changing tag on member %s of %s",
889 memberstruct->name, listname);
894 membervec[1] = "STRING";
895 status = mr_query("tag_member_of_list", 4, membervec,
897 if (status == MR_STRING && memberstruct->type == M_ANY)
899 com_err(whoami, 0, " Unable to find member %s on list %s",
900 memberstruct->name, listname);
903 else if (status != MR_SUCCESS)
905 com_err(whoami, status, "while retagging member %s on %s",
906 memberstruct->name, listname);
911 membervec[1] = "KERBEROS";
912 status = mr_query("tag_member_of_list", 4, membervec,
914 if (status == MR_STRING || status == MR_NO_MATCH)
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.
921 mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
922 if (mrcl_get_message())
924 if (mr_query("tag_member_of_list", 4, membervec,
925 NULL, NULL) == MR_SUCCESS)
926 mrcl_com_err(whoami);
930 if (status != MR_SUCCESS)
932 com_err(whoami, status, "while changing tag on member %s of %s",
933 memberstruct->name, listname);
939 /* Display the members of the list now, if requested */
943 recursive_display_list_members();
946 status = mr_query(showtags ? "get_tagged_members_of_list" :
947 "get_members_of_list", 1, &listname,
948 get_list_members, memberlist);
950 com_err(whoami, status, "while getting members of list %s",
952 while (sq_get_data(memberlist, &memberstruct))
953 show_list_member(memberstruct);
959 exit(success ? 0 : 1);
962 void usage(char **argv)
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",
969 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-m | -members",
970 "-R | -rename newname");
971 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-u | -users",
973 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-l | -lists",
975 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-s | -strings",
977 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-k | -kerberos",
979 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-i | -info",
981 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-r | -recursive",
983 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-a | -add member",
985 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-d | -delete member",
987 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-al | -addlist filename",
989 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-dl | -deletelist filename",
991 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-f | -file filename",
993 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-at | -addtagged member tag",
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]",
1007 /* Display the members stored in the queue */
1009 void show_list_member(struct member *memberstruct)
1013 switch (memberstruct->type)
1036 printf("%s\n", memberstruct->name);
1041 printf("%s:%s", s, memberstruct->name);
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);
1052 printf("%s", memberstruct->name);
1054 if (showtags && *(memberstruct->tag))
1055 printf(" (%s)\n", memberstruct->tag);
1061 /* Show the retrieved information about a list */
1063 int show_list_info(int argc, char **argv, void *hint)
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]))
1076 if (atoi(argv[L_NFSGROUP]))
1077 printf(" (and an NFS group)");
1078 printf(" with GID %d\n", atoi(argv[L_GID]));
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]);
1092 /* Copy retrieved information about a list into a new argv */
1094 int save_list_info(int argc, char **argv, void *hint)
1096 char **nargv = hint;
1098 for (argc = 0; argc < 14; argc++)
1099 nargv[argc + 1] = strdup(argv[argc]);
1103 /* Show the retrieve list member count */
1105 int show_list_count(int argc, char **argv, void *hint)
1107 printf("Members: %s\n", argv[0]);
1112 /* Recursively find all of the members of listname, and then display them */
1114 void recursive_display_list_members(void)
1116 int status, count, savecount;
1117 struct save_queue *lists, *members;
1118 struct member *m, *m1, *data;
1120 lists = sq_create();
1121 members = sq_create();
1122 m = malloc(sizeof(struct member));
1125 sq_save_data(lists, m);
1127 while (sq_get_data(lists, &m))
1129 sq_destroy(memberlist);
1130 memberlist = sq_create();
1131 status = mr_query("get_members_of_list", 1, &(m->name),
1132 get_list_members, memberlist);
1134 com_err(whoami, status, "while getting members of list %s", m->name);
1135 while (sq_get_data(memberlist, &m1))
1137 if (m1->type == M_LIST)
1138 unique_add_member(lists, m1);
1140 unique_add_member(members, m1);
1143 savecount = count = sq_count_elts(members);
1144 data = malloc(count * sizeof(struct member));
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]);
1154 /* add a struct member to a queue if that member isn't already there. */
1156 void unique_add_member(struct save_queue *q, struct member *m)
1158 struct save_queue *qp;
1160 for (qp = q->q_next; qp != q; qp = qp->q_next)
1162 if (!membercmp(qp->q_data, m))
1169 /* Collect the retrieved members of the list */
1171 int get_list_members(int argc, char **argv, void *sq)
1173 struct save_queue *q = sq;
1176 m = malloc(sizeof(struct member));
1189 m->type = M_KERBEROS;
1192 m->name = strdup(argv[1]);
1194 m->tag = strdup(argv[2]);
1196 m->tag = strdup("");
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)
1207 struct member *memberstruct;
1209 if (!strcmp(filename, "-"))
1213 in = fopen(filename, "r");
1216 com_err(whoami, errno, "while opening %s for input", filename);
1221 while (fgets(buf, BUFSIZ, in))
1223 if ((memberstruct = parse_member(buf)))
1224 sq_save_data(queue, memberstruct);
1228 com_err(whoami, errno, "while reading from %s", filename);
1234 /* Collect the possible expansions of the alias MAILHUB */
1236 int collect(int argc, char **argv, void *l)
1241 for (i = 0; (*list)[i]; i++)
1243 *list = realloc(*list, (i + 2) * sizeof(char *));
1244 (*list)[i] = strdup(argv[2]);
1245 (*list)[i + 1] = NULL;
1250 /* Parse a line of input, fetching a member. NULL is returned if a member
1251 * is not found. ';' is a comment character.
1254 struct member *parse_member(char *s)
1259 while (*s && isspace(*s))
1262 while (*p && *p != '\n' && *p != ';')
1264 if (isprint(*p) && !isspace(*p))
1271 if (p == s || strlen(s) == 0)
1274 if (!(m = malloc(sizeof(struct member))))
1276 m->tag = strdup("");
1278 if ((p = strchr(s, ':')))
1282 if (!strcasecmp("user", s))
1284 else if (!strcasecmp("list", s))
1286 else if (!strcasecmp("string", s))
1288 else if (!strcasecmp("kerberos", s))
1289 m->type = M_KERBEROS;
1290 else if (!strcasecmp("none", s))
1298 m->name = strdup(m->name);
1302 m->name = strdup(s);
1303 m->type = strcasecmp(s, "none") ? M_ANY : M_NONE;
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).
1319 int membercmp(const void *mem1, const void *mem2)
1321 const struct member *m1 = mem1, *m2 = mem2;
1323 if (m1->type == M_ANY || m2->type == M_ANY || (m1->type == m2->type))
1324 return strcmp(m1->name, m2->name);
1326 return m1->type - m2->type;
1330 int sq_count_elts(struct save_queue *q)
1336 while (sq_get_data(q, &foo))
1341 char *get_username(void)
1345 username = getenv("USER");
1348 username = mrcl_krb_user();
1351 com_err(whoami, 0, "Could not determine username");