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);
397 argv[L_MEMACE_TYPE] = argv[L_MEMACE_NAME] = "NONE";
401 argv[L_ACE_NAME] = owner->name;
406 argv[L_ACE_TYPE] = "USER";
407 status = mr_query("add_list", 13, argv, NULL, NULL);
408 if (owner->type != M_ANY || status != MR_USER)
412 argv[L_ACE_TYPE] = "LIST";
413 status = mr_query("add_list", 13, argv, NULL, NULL);
417 argv[L_ACE_TYPE] = "KERBEROS";
418 status = mrcl_validate_kerberos_member(argv[L_ACE_NAME],
420 if (mrcl_get_message())
421 mrcl_com_err(whoami);
422 status = mr_query("add_list", 13, argv, NULL, NULL);
425 argv[L_ACE_TYPE] = argv[L_ACE_NAME] = "NONE";
426 status = mr_query("add_list", 13, argv, NULL, NULL);
432 argv[L_ACE_TYPE] = "USER";
433 argv[L_ACE_NAME] = get_username();
435 status = mr_query("add_list", 13, argv, NULL, NULL);
440 com_err(whoami, status, "while creating list.");
448 status = mr_query("get_list_info", 1, &listname,
449 save_list_info, argv);
452 com_err(whoami, status, "while getting list information");
458 argv[L_NAME + 1] = newname;
460 argv[L_ACTIVE + 1] = active ? "1" : "0";
462 argv[L_PUBLIC + 1] = public ? "1" : "0";
464 argv[L_HIDDEN + 1] = hidden ? "1" : "0";
466 argv[L_MAILLIST + 1] = maillist ? "1" : "0";
468 argv[L_GROUP + 1] = grouplist ? "1" : "0";
470 argv[L_NFSGROUP + 1] = nfsgroup ? "1" : "0";
472 argv[L_DESC + 1] = desc;
476 if (memacl->type == M_ANY)
478 status = mr_query("get_user_account_by_login", 1,
479 &memacl->name, NULL, NULL);
480 if (status == MR_NO_MATCH)
481 memacl->type = M_LIST;
483 memacl->type = M_USER;
485 argv[L_MEMACE_TYPE + 1] = typename[memacl->type];
486 argv[L_MEMACE_NAME + 1] = memacl->name;
487 if (memacl->type == M_KERBEROS)
489 status = mrcl_validate_kerberos_member(argv[L_MEMACE_NAME + 1],
490 &argv[L_MEMACE_NAME + 1]);
491 if (mrcl_get_message())
492 mrcl_com_err(whoami);
498 argv[L_ACE_NAME + 1] = owner->name;
503 argv[L_ACE_TYPE + 1] = "USER";
504 status = mr_query("update_list", 14, argv, NULL, NULL);
505 if (owner->type != M_ANY || status != MR_USER)
509 argv[L_ACE_TYPE + 1] = "LIST";
510 status = mr_query("update_list", 14, argv, NULL, NULL);
514 argv[L_ACE_TYPE + 1] = "KERBEROS";
515 status = mrcl_validate_kerberos_member(argv[L_ACE_NAME + 1],
516 &argv[L_ACE_NAME + 1]);
517 if (mrcl_get_message())
518 mrcl_com_err(whoami);
519 status = mr_query("update_list", 14, argv, NULL, NULL);
522 argv[L_ACE_TYPE + 1] = argv[L_ACE_NAME + 1] = "NONE";
523 status = mr_query("update_list", 14, argv, NULL, NULL);
528 status = mr_query("update_list", 14, argv, NULL, NULL);
532 com_err(whoami, status, "while updating list.");
539 /* display list info if requested to */
542 status = mr_query("get_list_info", 1, &listname, show_list_info, NULL);
545 com_err(whoami, status, "while getting list information");
548 if (verbose && !memberflg)
550 status = mr_query("count_members_of_list", 1, &listname,
551 show_list_count, NULL);
554 com_err(whoami, status, "while getting list count");
560 /* if we're synchronizing to a file, we need to:
561 * get the current members of the list
562 * for each member of the sync file
563 * if they are on the list, remove them from the in-memory copy
564 * if they're not on the list, add them to add-list
565 * if anyone is left on the in-memory copy, put them on the delete-list
566 * lastly, reset memberlist so we can use it again later
570 status = mr_query("get_members_of_list", 1, &listname,
571 get_list_members, memberlist);
574 com_err(whoami, status, "getting members of list %s", listname);
577 while (sq_get_data(synclist, &memberstruct))
579 struct save_queue *q;
582 for (q = memberlist->q_next; q != memberlist; q = q->q_next)
584 if (membercmp(q->q_data, memberstruct) == 0)
586 q->q_prev->q_next = q->q_next;
587 q->q_next->q_prev = q->q_prev;
593 sq_save_data(addlist, memberstruct);
595 while (sq_get_data(memberlist, &memberstruct))
596 sq_save_data(dellist, memberstruct);
597 sq_destroy(memberlist);
598 memberlist = sq_create();
601 /* Process the add list */
602 while (sq_get_data(addlist, &memberstruct))
604 /* canonicalize string if necessary */
605 if (memberstruct->type != M_KERBEROS &&
606 (p = strchr(memberstruct->name, '@')))
608 char *host = canonicalize_hostname(strdup(++p));
609 static char **mailhubs = NULL;
618 mailhubs = malloc(sizeof(char *));
620 status = mr_query("get_alias", 3, argv, collect,
622 if (status != MR_SUCCESS && status != MR_NO_MATCH)
624 com_err(whoami, status,
625 " while reading list of MAILHUB servers");
629 for (i = 0; (p = mailhubs[i]); i++)
631 if (!strcasecmp(p, host))
633 host = strdup(memberstruct->name);
634 *(strchr(memberstruct->name, '@')) = 0;
635 if (memberstruct->type == M_STRING)
636 memberstruct->type = M_ANY;
637 fprintf(stderr, "Warning: \"%s\" converted to "
638 "\"%s\" because it is a local name.\n",
639 host, memberstruct->name);
645 /* now continue adding member */
646 membervec[0] = listname;
647 membervec[2] = memberstruct->name;
648 membervec[3] = memberstruct->tag;
651 printf("Adding member ");
652 show_list_member(memberstruct);
654 switch (memberstruct->type)
658 membervec[1] = "USER";
659 status = mr_query("add_tagged_member_to_list", 4, membervec,
661 if (status == MR_SUCCESS)
663 else if (status != MR_USER || memberstruct->type != M_ANY)
665 com_err(whoami, status, "while adding member %s to %s",
666 memberstruct->name, listname);
671 membervec[1] = "LIST";
672 status = mr_query("add_tagged_member_to_list", 4, membervec,
674 if (status == MR_SUCCESS)
676 if (!strcmp(membervec[0], get_username()))
678 fprintf(stderr, "\nWARNING: \"LIST:%s\" was just added "
679 "to list \"%s\".\n", membervec[2], membervec[0]);
680 fprintf(stderr, "If you meant to add yourself to the list "
681 "\"%s\", type:\n", membervec[2]);
682 fprintf(stderr, "\tblanche %s -d %s\t(to undo this)\n",
683 membervec[0], membervec[2]);
684 fprintf(stderr, "\tblanche %s -a %s\t(to add yourself to "
685 "that list)\n", membervec[2], membervec[0]);
689 else if (status != MR_LIST || memberstruct->type != M_ANY)
691 com_err(whoami, status, "while adding member %s to %s",
692 memberstruct->name, listname);
697 status = mrcl_validate_string_member(memberstruct->name);
698 if (memberstruct->type == M_ANY && status == MRCL_WARN)
700 /* if user is trying to add something which isn't a
701 remote string, or a list, or a user, and didn't
702 explicitly specify `STRING:', it's probably a typo */
703 com_err(whoami, MR_NO_MATCH, "while adding member %s to %s",
704 memberstruct->name, listname);
709 mrcl_com_err(whoami);
711 if (status == MRCL_REJECT)
717 membervec[1] = "STRING";
718 status = mr_query("add_tagged_member_to_list", 4, membervec,
720 if (status != MR_SUCCESS)
722 com_err(whoami, status, "while adding member %s to %s",
723 memberstruct->name, listname);
728 membervec[1] = "KERBEROS";
729 status = mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
730 if (mrcl_get_message())
731 mrcl_com_err(whoami);
732 status = mr_query("add_tagged_member_to_list", 4, membervec,
734 if (status != MR_SUCCESS)
736 com_err(whoami, status, "while adding member %s to %s",
737 memberstruct->name, listname);
742 membervec[1] = "MACHINE";
743 membervec[2] = canonicalize_hostname(strdup(memberstruct->name));
744 status = mr_query("add_tagged_member_to_list", 4, membervec,
746 if (status != MR_SUCCESS)
748 com_err(whoami, status, "while adding member %s to %s",
749 memberstruct->name, listname);
756 /* Process the delete list */
757 while (sq_get_data(dellist, &memberstruct))
759 membervec[0] = listname;
760 membervec[2] = memberstruct->name;
763 printf("Deleting member ");
764 show_list_member(memberstruct);
766 switch (memberstruct->type)
770 membervec[1] = "USER";
771 status = mr_query("delete_member_from_list", 3, membervec,
773 if (status == MR_SUCCESS)
775 else if ((status != MR_USER && status != MR_NO_MATCH) ||
776 memberstruct->type != M_ANY)
778 com_err(whoami, status, "while deleting member %s from %s",
779 memberstruct->name, listname);
784 membervec[1] = "LIST";
785 status = mr_query("delete_member_from_list", 3, membervec,
787 if (status == MR_SUCCESS)
789 else if ((status != MR_LIST && status != MR_NO_MATCH) ||
790 memberstruct->type != M_ANY)
792 if (status == MR_PERM && memberstruct->type == M_ANY &&
793 !strcmp(membervec[2], get_username()))
795 /* M_ANY means we've fallen through from the user
796 * case. The user is trying to remove himself from
797 * a list, but we got MR_USER or MR_NO_MATCH above,
798 * meaning he's not really on it, and we got MR_PERM
799 * when trying to remove LIST:$USER because he's not
800 * on the acl. That error is useless, so return
801 * MR_NO_MATCH instead. However, this will generate the
802 * wrong error if the user was trying to remove the list
803 * with his username from a list he doesn't administrate
804 * without explicitly specifying "list:".
806 status = MR_NO_MATCH;
808 com_err(whoami, status, "while deleting member %s from %s",
809 memberstruct->name, listname);
814 membervec[1] = "STRING";
815 status = mr_query("delete_member_from_list", 3, membervec,
817 if (status == MR_STRING && memberstruct->type == M_ANY)
819 com_err(whoami, 0, " Unable to find member %s to delete from %s",
820 memberstruct->name, listname);
822 if (!strcmp(membervec[0], get_username()))
824 fprintf(stderr, "(If you were trying to remove yourself "
825 "from the list \"%s\",\n", membervec[2]);
826 fprintf(stderr, "the correct command is \"blanche %s -d "
827 "%s\".)\n", membervec[2], membervec[0]);
830 else if (status != MR_SUCCESS)
832 com_err(whoami, status, "while deleting member %s from %s",
833 memberstruct->name, listname);
838 membervec[1] = "KERBEROS";
839 status = mr_query("delete_member_from_list", 3, membervec,
841 if (status == MR_STRING || status == MR_NO_MATCH)
843 /* Try canonicalizing the Kerberos principal and trying
844 * again. If we succeed, print the message from mrcl.
845 * Otherwise, just pretend we never did this and print
846 * the original error message.
848 mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
849 if (mrcl_get_message())
851 if (mr_query("delete_member_from_list", 3, membervec,
852 NULL, NULL) == MR_SUCCESS)
853 mrcl_com_err(whoami);
857 if (status != MR_SUCCESS)
859 com_err(whoami, status, "while deleting member %s from %s",
860 memberstruct->name, listname);
864 membervec[1] = "MACHINE";
865 membervec[2] = canonicalize_hostname(memberstruct->name);
866 status = mr_query("delete_member_from_list", 3, membervec,
868 if (status != MR_SUCCESS)
870 com_err(whoami, status, "while deleting member %s from %s",
871 memberstruct->name, listname);
878 /* Process the tag list */
879 while (sq_get_data(taglist, &memberstruct))
881 membervec[0] = listname;
882 membervec[2] = memberstruct->name;
883 membervec[3] = memberstruct->tag;
886 printf("Tagging member ");
887 show_list_member(memberstruct);
889 switch (memberstruct->type)
893 membervec[1] = "USER";
894 status = mr_query("tag_member_of_list", 4, membervec,
896 if (status == MR_SUCCESS)
898 else if ((status != MR_USER && status != MR_NO_MATCH) ||
899 memberstruct->type != M_ANY)
901 com_err(whoami, status, "while changing tag on member %s of %s",
902 memberstruct->name, listname);
907 membervec[1] = "LIST";
908 status = mr_query("tag_member_of_list", 4, membervec,
910 if (status == MR_SUCCESS)
912 else if ((status != MR_LIST && status != MR_NO_MATCH) ||
913 memberstruct->type != M_ANY)
915 com_err(whoami, status, "while changing tag on member %s of %s",
916 memberstruct->name, listname);
921 membervec[1] = "STRING";
922 status = mr_query("tag_member_of_list", 4, membervec,
924 if (status == MR_STRING && memberstruct->type == M_ANY)
926 com_err(whoami, 0, " Unable to find member %s on list %s",
927 memberstruct->name, listname);
930 else if (status != MR_SUCCESS)
932 com_err(whoami, status, "while retagging member %s on %s",
933 memberstruct->name, listname);
938 membervec[1] = "KERBEROS";
939 status = mr_query("tag_member_of_list", 4, membervec,
941 if (status == MR_STRING || status == MR_NO_MATCH)
943 /* Try canonicalizing the Kerberos principal and trying
944 * again. If we succeed, print the message from mrcl.
945 * Otherwise, just pretend we never did this and print
946 * the original error message.
948 mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
949 if (mrcl_get_message())
951 if (mr_query("tag_member_of_list", 4, membervec,
952 NULL, NULL) == MR_SUCCESS)
953 mrcl_com_err(whoami);
957 if (status != MR_SUCCESS)
959 com_err(whoami, status, "while changing tag on member %s of %s",
960 memberstruct->name, listname);
966 /* Display the members of the list now, if requested */
970 recursive_display_list_members();
973 status = mr_query(showtags ? "get_tagged_members_of_list" :
974 "get_members_of_list", 1, &listname,
975 get_list_members, memberlist);
977 com_err(whoami, status, "while getting members of list %s",
979 while (sq_get_data(memberlist, &memberstruct))
980 show_list_member(memberstruct);
986 exit(success ? 0 : 1);
989 void usage(char **argv)
991 #define USAGE_OPTIONS_FORMAT " %-39s%s\n"
992 fprintf(stderr, "Usage: %s listname [options]\n", argv[0]);
993 fprintf(stderr, "Options are\n");
994 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-v | -verbose",
996 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-m | -members",
997 "-R | -rename newname");
998 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-u | -users",
1000 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-l | -lists",
1002 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-s | -strings",
1004 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-k | -kerberos",
1006 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-i | -info",
1008 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-r | -recursive",
1010 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-a | -add member",
1012 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-d | -delete member",
1014 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-al | -addlist filename",
1016 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-dl | -deletelist filename",
1018 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-f | -file filename",
1020 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-at | -addtagged member tag",
1022 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-ct | -changetag member tag",
1023 "-D | -desc description");
1024 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-t | -tags",
1025 "-O | -owner owner");
1026 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-n | -noauth",
1027 "-MA | -memacl membership_acl");
1028 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-db | -database host[:port]",
1034 /* Display the members stored in the queue */
1036 void show_list_member(struct member *memberstruct)
1040 switch (memberstruct->type)
1068 printf("%s\n", memberstruct->name);
1073 printf("%s:%s", s, memberstruct->name);
1076 if (memberstruct->type == M_LIST)
1077 printf("LIST:%s", memberstruct->name);
1078 else if (memberstruct->type == M_KERBEROS)
1079 printf("KERBEROS:%s", memberstruct->name);
1080 else if (memberstruct->type == M_STRING &&
1081 !strchr(memberstruct->name, '@'))
1082 printf("STRING:%s", memberstruct->name);
1083 else if (memberstruct->type == M_MACHINE)
1084 printf("MACHINE:%s", memberstruct->name);
1086 printf("%s", memberstruct->name);
1088 if (showtags && *(memberstruct->tag))
1089 printf(" (%s)\n", memberstruct->tag);
1095 /* Show the retrieved information about a list */
1097 int show_list_info(int argc, char **argv, void *hint)
1099 printf("List: %s\n", argv[L_NAME]);
1100 printf("Description: %s\n", argv[L_DESC]);
1101 printf("Flags: %s, %s, and %s\n",
1102 atoi(argv[L_ACTIVE]) ? "active" : "inactive",
1103 atoi(argv[L_PUBLIC]) ? "public" : "private",
1104 atoi(argv[L_HIDDEN]) ? "hidden" : "visible");
1105 printf("%s is %sa maillist and is %sa group", argv[L_NAME],
1106 atoi(argv[L_MAILLIST]) ? "" : "not ",
1107 atoi(argv[L_GROUP]) ? "" : "not ");
1108 if (atoi(argv[L_GROUP]))
1110 if (atoi(argv[L_NFSGROUP]))
1111 printf(" (and an NFS group)");
1112 printf(" with GID %d\n", atoi(argv[L_GID]));
1116 printf("Owner: %s %s\n", argv[L_ACE_TYPE], argv[L_ACE_NAME]);
1117 if (strcmp(argv[L_MEMACE_TYPE], "NONE"))
1118 printf("Membership ACL: %s %s\n", argv[L_MEMACE_TYPE],
1119 argv[L_MEMACE_NAME]);
1120 printf("Last modified by %s with %s on %s\n",
1121 argv[L_MODBY], argv[L_MODWITH], argv[L_MODTIME]);
1126 /* Copy retrieved information about a list into a new argv */
1128 int save_list_info(int argc, char **argv, void *hint)
1130 char **nargv = hint;
1132 for (argc = 0; argc < 14; argc++)
1133 nargv[argc + 1] = strdup(argv[argc]);
1137 /* Show the retrieve list member count */
1139 int show_list_count(int argc, char **argv, void *hint)
1141 printf("Members: %s\n", argv[0]);
1146 /* Recursively find all of the members of listname, and then display them */
1148 void recursive_display_list_members(void)
1150 int status, count, savecount;
1151 struct save_queue *lists, *members;
1152 struct member *m, *m1, *data;
1154 lists = sq_create();
1155 members = sq_create();
1156 m = malloc(sizeof(struct member));
1159 sq_save_data(lists, m);
1161 while (sq_get_data(lists, &m))
1163 sq_destroy(memberlist);
1164 memberlist = sq_create();
1165 status = mr_query("get_members_of_list", 1, &(m->name),
1166 get_list_members, memberlist);
1168 com_err(whoami, status, "while getting members of list %s", m->name);
1169 while (sq_get_data(memberlist, &m1))
1171 if (m1->type == M_LIST)
1172 unique_add_member(lists, m1);
1174 unique_add_member(members, m1);
1177 savecount = count = sq_count_elts(members);
1178 data = malloc(count * sizeof(struct member));
1180 while (sq_get_data(members, &m))
1181 memcpy(&data[count++], m, sizeof(struct member));
1182 qsort(data, count, sizeof(struct member), membercmp);
1183 for (count = 0; count < savecount; count++)
1184 show_list_member(&data[count]);
1188 /* add a struct member to a queue if that member isn't already there. */
1190 void unique_add_member(struct save_queue *q, struct member *m)
1192 struct save_queue *qp;
1194 for (qp = q->q_next; qp != q; qp = qp->q_next)
1196 if (!membercmp(qp->q_data, m))
1203 /* Collect the retrieved members of the list */
1205 int get_list_members(int argc, char **argv, void *sq)
1207 struct save_queue *q = sq;
1210 m = malloc(sizeof(struct member));
1223 m->type = M_KERBEROS;
1226 m->type = M_MACHINE;
1229 m->name = strdup(argv[1]);
1231 m->tag = strdup(argv[2]);
1233 m->tag = strdup("");
1239 /* Open file, parse members from file, and put them on the specified queue */
1240 void get_members_from_file(char *filename, struct save_queue *queue)
1244 struct member *memberstruct;
1246 if (!strcmp(filename, "-"))
1250 in = fopen(filename, "r");
1253 com_err(whoami, errno, "while opening %s for input", filename);
1258 while (fgets(buf, BUFSIZ, in))
1260 if ((memberstruct = parse_member(buf)))
1261 sq_save_data(queue, memberstruct);
1265 com_err(whoami, errno, "while reading from %s", filename);
1271 /* Collect the possible expansions of the alias MAILHUB */
1273 int collect(int argc, char **argv, void *l)
1278 for (i = 0; (*list)[i]; i++)
1280 *list = realloc(*list, (i + 2) * sizeof(char *));
1281 (*list)[i] = strdup(argv[2]);
1282 (*list)[i + 1] = NULL;
1287 /* Parse a line of input, fetching a member. NULL is returned if a member
1288 * is not found. ';' is a comment character.
1291 struct member *parse_member(char *s)
1296 while (*s && isspace(*s))
1299 while (*p && *p != '\n' && *p != ';')
1301 if (isprint(*p) && !isspace(*p))
1308 if (p == s || strlen(s) == 0)
1311 if (!(m = malloc(sizeof(struct member))))
1313 m->tag = strdup("");
1315 if ((p = strchr(s, ':')))
1319 if (!strcasecmp("user", s))
1321 else if (!strcasecmp("list", s))
1323 else if (!strcasecmp("string", s))
1325 else if (!strcasecmp("kerberos", s))
1326 m->type = M_KERBEROS;
1327 else if (!strcasecmp("machine", s))
1328 m->type = M_MACHINE;
1329 else if (!strcasecmp("none", s))
1337 m->name = strdup(m->name);
1341 m->name = strdup(s);
1342 m->type = strcasecmp(s, "none") ? M_ANY : M_NONE;
1349 * This routine two compares members by the following rules:
1350 * 1. A USER is less than a LIST
1351 * 2. A LIST is less than a STRING
1352 * 3. If two members are of the same type, the one alphabetically first
1353 * is less than the other
1354 * It returs < 0 if the first member is less, 0 if they are identical, and
1355 * > 0 if the second member is less (the first member is greater).
1358 int membercmp(const void *mem1, const void *mem2)
1360 const struct member *m1 = mem1, *m2 = mem2;
1362 if (m1->type == M_ANY || m2->type == M_ANY || (m1->type == m2->type))
1363 return strcmp(m1->name, m2->name);
1365 return m1->type - m2->type;
1369 int sq_count_elts(struct save_queue *q)
1375 while (sq_get_data(q, &foo))
1380 char *get_username(void)
1384 username = getenv("USER");
1387 username = mrcl_krb_user();
1390 com_err(whoami, 0, "Could not determine username");