3 * This is the file user.c for the Moira Client, which allows users
4 * to quickly and easily maintain most parts of the Moira database.
5 * It Contains: Functions for manipulating user information.
8 * By: Chris D. Peterson
10 * Copyright (C) 1988-1998 by the Massachusetts Institute of Technology.
11 * For copying and distribution information, please see the file
15 #include <mit-copyright.h>
17 #include <moira_site.h>
32 void CorrectCapitalization(char **name);
33 char **AskUserInfo(char **info, Bool name);
34 struct mqelem *GetUserInfo(int type, char *name1, char *name2);
43 #define DEFAULT_SHELL "/bin/athena/tcsh"
45 #define DEFAULT_SHELL "/bin/csh"
47 #define DEFAULT_CLASS "?"
49 #define DEFAULT_WINCONSOLESHELL "cmd"
51 /* Function Name: UserState
52 * Description: Convert a numeric state into a descriptive string.
53 * Arguments: state value
54 * Returns: pointer to statically allocated string.
57 static char *states[] = {
60 "Half Registered (2)",
62 "Not registerable (4)",
63 "Enrolled/Registerable (5)",
64 "Enrolled/Not Registerable (6)",
68 static char *UserState(int state)
70 static char buf[BUFSIZ];
72 if (state < 0 || state >= US_END)
74 sprintf(buf, "Unknown (%d)", state);
81 /* Function Name: PrintUserName
82 * Description: Print name of a user.
83 * Arguments: info - the information about a user.
87 static void PrintUserName(char **info)
89 char buf[BUFSIZ], print_buf[BUFSIZ];
90 sprintf(buf, "%s, %s %s", info[U_LAST], info[U_FIRST], info[U_MIDDLE]);
91 sprintf(print_buf, "%-40s User Name: %s", buf, info[U_NAME]);
92 Put_message(print_buf);
95 /* Function Name: PrintUserInfo
96 * Description: Prints Information about a user.
97 * Arguments: info - an argument list with the user information
102 static void PrintUserInfo(char **info)
104 char name[BUFSIZ], buf[BUFSIZ];
107 sprintf(name, "%s, %s %s", info[U_LAST], info[U_FIRST], info[U_MIDDLE]);
108 sprintf(buf, "Login name: %-20s Full name: %s", info[U_NAME], name);
110 sprintf(buf, "User id: %-23s Login shell: %-10s",
111 info[U_UID], info[U_SHELL]);
113 sprintf(buf, "Class: %-25s Windows Console Shell: %-10s",
114 info[U_CLASS], info[U_WINCONSOLESHELL]);
116 sprintf(buf, "Account is: %-20s MIT ID number: %s",
117 UserState(atoi(info[U_STATE])), info[U_MITID]);
119 status = atoi(info[U_STATE]);
120 if (status == 0 || status == 2)
122 sprintf(buf, "User %s secure Account Coupon to register",
123 atoi(info[U_SECURE]) ? "needs" : "does not need");
126 sprintf(buf, "Comments: %s", info[U_COMMENT]);
128 sprintf(buf, MOD_FORMAT, info[U_MODBY], info[U_MODTIME], info[U_MODWITH]);
132 /* Function Name: SetUserDefaults
133 * Description: Sets the default values for add user.
134 * Arguments: info - a blank user info array of char *'s.
135 * Returns: args - the filled info structure.
138 static char **SetUserDefaults(char **info)
140 info[U_NAME] = strdup(UNIQUE_LOGIN);
141 info[U_UID] = strdup(UNIQUE_UID);
142 info[U_SHELL] = strdup(DEFAULT_SHELL);
143 info[U_WINCONSOLESHELL] = strdup(DEFAULT_WINCONSOLESHELL);
144 info[U_LAST] = strdup(DEFAULT_NONE);
145 info[U_FIRST] = strdup(DEFAULT_NONE);
146 info[U_MIDDLE] = strdup(DEFAULT_NONE);
147 info[U_STATE] = strdup(DEFAULT_NO);
148 info[U_MITID] = strdup(DEFAULT_NONE);
149 info[U_CLASS] = strdup(DEFAULT_CLASS);
150 info[U_COMMENT] = strdup("");
151 info[U_SIGNATURE] = strdup("");
152 info[U_SECURE] = strdup("0");
153 info[U_MODTIME] = info[U_MODBY] = info[U_MODWITH] = info[U_END] = NULL;
158 /* Check that the supplied name follows the capitalization rules, and
159 * offer to correct it if not.
162 void CorrectCapitalization(char **name)
164 char temp_buf[BUFSIZ], fixname[BUFSIZ];
166 strcpy(fixname, *name);
168 if (strcmp(fixname, *name))
170 Put_message("You entered a name which does not follow the capitalization conventions.");
171 sprintf(temp_buf, "Correct it to \"%s\"", fixname);
172 if (YesNoQuestion(temp_buf, 1) == TRUE)
175 *name = strdup(fixname);
181 /* Function Name: AskUserInfo.
182 * Description: This function askes the user for information about a
183 * machine and saves it into a structure.
184 * Arguments: info - a pointer the the structure to put the info into.
185 * flags - Flags asking us which info we want.
186 * Returns: the args to pass to the query.
187 * NOTES: the return args are not necessarily in the correct order to
188 * use the #defined names (e.g args[UID] is not the uid anymore).
191 char **AskUserInfo(char **info, Bool name)
194 char temp_buf[BUFSIZ], *newname;
198 sprintf(temp_buf, "\nChanging Attributes of user %s.\n", info[U_NAME]);
199 Put_message(temp_buf);
203 struct mqelem *elem = NULL;
206 if (GetValueFromUser("User's last name", &info[U_LAST]) == SUB_ERROR)
208 CorrectCapitalization(&info[U_LAST]);
209 if (GetValueFromUser("User's first name", &info[U_FIRST]) == SUB_ERROR)
211 CorrectCapitalization(&info[U_FIRST]);
212 if (GetValueFromUser("User's middle name", &info[U_MIDDLE]) == SUB_ERROR)
214 CorrectCapitalization(&info[U_MIDDLE]);
215 argv[0] = info[U_FIRST];
216 argv[1] = info[U_LAST];
217 if (do_mr_query("get_user_account_by_name", 2, argv,
218 StoreInfo, &elem) == MR_SUCCESS)
220 Put_message("A user by that name already exists in the database.");
221 Loop(QueueTop(elem), PrintUserInfo);
222 Loop(QueueTop(elem), FreeInfo);
224 if (YesNoQuestion("Add new user anyway", TRUE) != TRUE)
230 newname = strdup(info[U_NAME]);
231 if (GetValueFromUser("The new login name for this user", &newname) ==
235 else if (GetValueFromUser("Login name for this user", &info[U_NAME]) ==
239 strcpy(temp_buf, info[U_UID]);
240 if (GetValueFromUser("User's UID", &info[U_UID]) == SUB_ERROR)
242 if (strcmp(info[U_UID], UNIQUE_UID) && strcmp(info[U_UID], temp_buf))
244 struct mqelem *elem = NULL;
245 if (do_mr_query("get_user_account_by_uid", 1, &info[U_UID],
246 StoreInfo, &elem) == MR_SUCCESS)
248 Put_message("A user with that uid already exists in the database.");
249 Loop(QueueTop(elem), PrintUserInfo);
250 Loop(QueueTop(elem), FreeInfo);
252 if (YesNoQuestion("Add new user anyway", TRUE) != TRUE)
257 if (GetValueFromUser("User's shell", &info[U_SHELL]) == SUB_ERROR)
259 if (GetValueFromUser("Windows console shell", &info[U_WINCONSOLESHELL])
264 if (GetValueFromUser("User's last name", &info[U_LAST]) == SUB_ERROR)
266 CorrectCapitalization(&info[U_LAST]);
267 if (GetValueFromUser("User's first name", &info[U_FIRST]) == SUB_ERROR)
269 CorrectCapitalization(&info[U_FIRST]);
270 if (GetValueFromUser("User's middle name", &info[U_MIDDLE]) == SUB_ERROR)
272 CorrectCapitalization(&info[U_MIDDLE]);
277 if (GetValueFromUser("User's status (? for help)", &info[U_STATE]) ==
280 if (isdigit(info[U_STATE][0]))
282 Put_message("Valid status numbers:");
283 for (i = 0; i < US_END; i++)
285 sprintf(temp_buf, " %d: %s", i, states[i]);
286 Put_message(temp_buf);
289 if (GetValueFromUser("User's MIT ID number", &info[U_MITID]) == SUB_ERROR)
291 RemoveHyphens(info[U_MITID]);
292 if (GetTypeFromUser("User's MIT Year (class)", "class", &info[U_CLASS]) ==
295 if (GetValueFromUser("Comments", &info[U_COMMENT]) == SUB_ERROR)
298 state = atoi(info[U_STATE]);
299 if (!name || state == 0 || state == 2)
301 if (YesNoQuestion("User needs secure Account Coupon to register",
302 atoi(info[U_SECURE]) ? TRUE : FALSE) == FALSE)
304 free(info[U_SECURE]);
305 info[U_SECURE] = strdup("0");
309 free(info[U_SECURE]);
310 info[U_SECURE] = strdup("1");
314 info[U_SIGNATURE] = strdup("");
316 FreeAndClear(&info[U_MODTIME], TRUE);
317 FreeAndClear(&info[U_MODBY], TRUE);
318 FreeAndClear(&info[U_MODWITH], TRUE);
321 * Slide the newname into the #2 slot, this screws up all future references
322 * to this list, since we slip the pointer into a info list it gets freed
323 * when the rest of the list gets freed.
326 SlipInNewName(info, newname);
331 /* Function Name: GetUserInfo
332 * Description: Stores the user information in a queue.
333 * Arguments: type - type of field given to get info, one of:
334 * LOGIN, UID, BY_NAME, CLASS.
335 * name1 - name of thing specified by type (wildcards okay)
336 * name2 - other name, only used in get user by first and last.
338 * Returns: the first element of the queue containing the user info.
342 struct mqelem *GetUserInfo(int type, char *name1, char *name2)
346 struct mqelem *elem = NULL;
352 if ((status = do_mr_query("get_user_account_by_login", 1, args,
355 com_err(program_name, status,
356 " when attempting to get_user_account_by_login.");
362 if ((status = do_mr_query("get_user_account_by_uid", 1, args,
365 com_err(program_name, status,
366 " when attempting to get_user_account_by_uid.");
373 if ((status = do_mr_query("get_user_account_by_name", 2, args,
376 com_err(program_name, status,
377 " when attempting to get_user_account_by_name.");
383 if ((status = do_mr_query("get_user_account_by_class", 1, args,
386 com_err(program_name, status,
387 " when attempting to get_user_account_by_class.");
393 if ((status = do_mr_query("get_user_account_by_id", 1, args,
396 com_err(program_name, status,
397 " when attempting to get_user_account_by_id.");
402 return QueueTop(elem) ;
405 /* Function Name: AddNewUser
406 * Description: Adds a new user to the database.
408 * Returns: DM_NORMAL.
411 int AddNewUser(int argc, char **argv)
414 char **args, *info[MAX_ARGS_SIZE];
416 if (!(args = AskUserInfo(SetUserDefaults(info), FALSE)))
418 Put_message("Aborted.");
421 if ((status = do_mr_query("add_user_account", CountArgs(args),
423 com_err(program_name, status, " in add_user_account");
425 Put_message("New user added to database.");
431 /* Function Name: GetLoginName
432 * Description: Asks the user for a login name and reserves
435 * Returns: a malloced login name for the user.
438 static char *GetLoginName(void)
443 if (GetValueFromUser("Login name for this user? ", &name) == SUB_ERROR)
445 Put_message("KERBEROS code not added, did not reserve name with kerberos.");
450 /* Function Name: ChooseUser
451 * Description: Choose a user from a list and return the uid.
452 * Arguments: top - a queue of user information.
453 * Returns: uid - the malloced uid of the user that was chosen.
456 static char *ChooseUser(struct mqelem *elem)
460 char **info = elem->q_data;
462 switch (YesNoQuitQuestion("Is this the user you want (y/n/q)", FALSE))
465 return strdup(info[U_UID]);
468 default: /* quit or ^C. */
476 /* Function Name: GetUidNumberFromName
477 * Description: Gets the users uid number, from the name.
479 * Returns: uid - a malloced string containing the uid.
482 static char *GetUidNumberFromName(void)
484 char *args[5], *uid, first[BUFSIZ], last[BUFSIZ];
486 struct mqelem *top = NULL;
488 if (!Prompt_input("First Name: ", first, BUFSIZ))
490 if (!Prompt_input("Last Name: ", last, BUFSIZ))
498 switch ((status = do_mr_query("get_user_account_by_name", 2, args,
504 Put_message("There is no user in the database with that name.");
507 com_err(program_name, status, " in get_account_user_by_name.");
512 if (QueueCount(top) == 1) /* This is a unique name. */
514 char **info = top->q_data;
515 Put_message("User ID Number retrieved for the user: ");
518 uid = strdup(info[U_UID]);
523 Put_message("That name is not unique, choose the user that you want.");
524 uid = ChooseUser(top);
529 /* Function Name: SetUserPassword
530 * Description: Set the new kerberos password for this user.
531 * Arguments: name - kerberos principle name for this user, (login name).
535 static void SetUserPassword(char *name)
537 name = name; /* make saber happy. */
538 Put_message("Kerberos password not changed, code non-existant.");
539 /* clever message to call account_admin, if this fails. */
542 /* Function Name: GiveBackLogin
543 * Description: Gives back previously reserved kerberous principle.
544 * Arguments: name - principle to give back.
548 static void GiveBackLogin(char *name)
550 name = name; /* make saber happy. */
551 Put_message("kerberos code not implemented, name not given back.");
552 /* send mail to db maintainer if this fails. */
555 /* Function Name: RegisterUser
556 * Description: This function registers a user.
558 * Returns: DM_NORMAL.
561 int RegisterUser(int argc, char **argv)
563 char *args[MAX_ARGS_SIZE];
564 char *login, *potype = NULL;
565 char temp_buf[BUFSIZ];
568 for (i = 0; i < MAX_ARGS_SIZE; i++)
571 Put_message("This function has NO kerberos support, so strange things");
572 Put_message("may happen if you use it to register a user.");
574 switch (YesNoQuestion("Do you know the users UID Number (y/n)", FALSE))
577 Prompt_input("What is the UID number of the user? ", temp_buf, BUFSIZ);
578 args[0] = strdup(temp_buf);
581 if (!(args[0] = GetUidNumberFromName()))
588 sprintf(temp_buf, "u%s", args[0]);
589 login = strdup(temp_buf);
590 if (GetValueFromUser("Login name for this user? ", &login) == SUB_ERROR)
593 FreeInfo(args); /* This work because the NULL temination is ok. */
596 Put_message("KERBEROS code not added, did not reserve name with kerberos.");
599 sprintf(temp_buf, "IMAP");
600 potype = strdup(temp_buf);
601 if (GetValueFromUser("P.O. Box Type for this user? ", &potype) == SUB_ERROR)
607 if (strcmp(potype, "POP") && strcmp(potype, "IMAP"))
609 sprintf(temp_buf, "Unknown P.O. Box type.");
610 Put_message(temp_buf);
617 switch ((status = do_mr_query("register_user", CountArgs(args),
621 sprintf(temp_buf, "User %s successfully registered.", login);
622 Put_message(temp_buf);
623 SetUserPassword(login);
626 GiveBackLogin(login);
627 sprintf(temp_buf, "The username %s is already in use.", login);
628 Put_message(temp_buf);
631 com_err(program_name, status, " in register_user");
638 /* Function Name: RealUpdateUser
639 * Description: actuall updates the user information.
640 * Arguments: info - all current information for the user fields.
641 * junk - an UNUSED boolean.
645 static void RealUpdateUser(char **info, Bool junk)
648 char error_buf[BUFSIZ];
649 char **args = AskUserInfo(info, TRUE);
653 Put_message("Aborted.");
656 if ((status = do_mr_query("update_user_account", CountArgs(args),
659 com_err(program_name, status, " in ModifyFields");
660 sprintf(error_buf, "User %s not updated due to errors.", info[NAME]);
661 Put_message(error_buf);
665 /* Function Name: UpdateUser
666 * Description: Modify some of the information about a user.
667 * Arguments: argc, argv - login name of the user in argv[1].
668 * Returns: DM_NORMAL.
671 int UpdateUser(int argc, char **argv)
675 elem = GetUserInfo(LOGIN, argv[1], NULL);
676 QueryLoop(elem, NullPrint, RealUpdateUser, "Update the user");
682 /* Function Name: RealDeactivateUser
683 * Description: sets the user's status to 3.
684 * Arguments: info - all current information for the user fields
685 * one_item - indicates the user hasn't been queried yet
689 static void RealDeactivateUser(char **info, Bool one_item)
692 char txt_buf[BUFSIZ];
693 char *qargs[2], **args;
694 struct mqelem *elem = NULL;
698 sprintf(txt_buf, "Deactivate user %s (y/n)", info[NAME]);
699 if (YesNoQuestion(txt_buf, FALSE) != TRUE)
703 qargs[0] = info[NAME];
705 if ((status = do_mr_query("update_user_status", 2, qargs, NULL, NULL)))
707 com_err(program_name, status, " in update_user_status");
708 sprintf(txt_buf, "User %s not deactivated due to errors.", info[NAME]);
709 Put_message(txt_buf);
711 else if (YesNoQuestion("Also deactivate matching list and filesystem (y/n)",
714 status = do_mr_query("get_list_info", 1, &(info[NAME]), StoreInfo,
716 if (status == MR_SUCCESS)
718 args = QueueTop(elem)->q_data;
719 free(args[L_ACTIVE]);
720 args[L_ACTIVE] = strdup("0");
721 FreeAndClear(&args[L_MODTIME], TRUE);
722 FreeAndClear(&args[L_MODBY], TRUE);
723 FreeAndClear(&args[L_MODWITH], TRUE);
724 SlipInNewName(args, strdup(args[L_NAME]));
725 if ((status = do_mr_query("update_list", CountArgs(args), args,
728 com_err(program_name, status, " updating list, "
729 "not deactivating list or filesystem");
738 else if (status != MR_NO_MATCH)
740 com_err(program_name, status, " getting list info, "
741 "not deactivating list or filesystem");
745 if ((status = do_mr_query("get_filesys_by_label", 1, &(info[NAME]),
748 com_err(program_name, status, " getting filsys info, "
749 "not deactivating filesystem");
752 args = QueueTop(elem)->q_data;
754 args[FS_TYPE] = strdup("ERR");
755 free(args[FS_COMMENTS]);
756 args[FS_COMMENTS] = strdup("Locker disabled; call 3-1325 for help");
757 FreeAndClear(&args[FS_MODTIME], TRUE);
758 FreeAndClear(&args[FS_MODBY], TRUE);
759 FreeAndClear(&args[FS_MODWITH], TRUE);
760 SlipInNewName(args, strdup(args[FS_NAME]));
761 if ((status = do_mr_query("update_filesys", CountArgs(args), args,
764 com_err(program_name, status, " updating filesystem, "
765 "not deactivating filesystem");
776 /* Function Name: DeactivateUser
777 * Description: sets the user's status to 3.
778 * Arguments: argc, argv - login name of the user in argv[1].
779 * Returns: DM_NORMAL.
782 int DeactivateUser(int argc, char **argv)
786 elem = GetUserInfo(LOGIN, argv[1], NULL);
787 QueryLoop(elem, NullPrint, RealDeactivateUser, "Deactivate user");
794 /* ------------------------- Top Menu ------------------------- */
796 /* DeleteUser() in delete.c */
798 /* Function Name: DeleteUserByUid
799 * Description: Deletes the user given a uid number.
800 * Arguments: argc, argv - uid if user in argv[1].
801 * Returns: DM_NORMAL.
802 * NOTES: This just gets the username from the mr server
803 * and performs a DeleteUser().
806 int DeleteUserByUid(int argc, char **argv)
809 struct mqelem *elem = NULL;
812 if (!ValidName(argv[1]))
815 if ((status = do_mr_query("get_user_account_by_uid", 1, argv + 1, StoreInfo,
817 com_err(program_name, status, " in get_user_account_by_uid");
820 argv[1] = info[U_NAME];
822 DeleteUser(argc, argv);
826 /* ------------------------- Show User Information ------------------------- */
828 /* Function Name: ShowUserByLogin
829 * Description: Shows user information given a login name.
830 * Arguments: argc, argv - login name in argv[1].
834 int ShowUserByLogin(int argc, char *argv[])
836 struct mqelem *top, *elem;
838 elem = top = GetUserInfo(LOGIN, argv[1], NULL);
839 Loop(elem, PrintUserInfo);
845 /* Function Name: RetrieveUserByName
846 * Description: Show information on a user give fist and/or last name.
847 * Arguments: argc, argv - argv[1] - first name.
848 * argv[2] - last name.
849 * Returns: DM_NORMAL.
852 int ShowUserByName(int argc, char *argv[])
857 top = GetUserInfo(BY_NAME, argv[1], argv[2]);
859 if (!top) /* if there was an error then return. */
862 if (!PromptWithDefault("Print full information, or just the names (f/n)?",
870 Loop(top, PrintUserInfo);
874 Loop(top, PrintUserName);
882 /* Function Name: ShowUserByClass
883 * Description: Shows real and login names of all users in class.
884 * Arguments: argc, argv - argv[1] contains the class.
888 int ShowUserByClass(int argc, char **argv)
892 if (YesNoQuestion("This will take a long time. Are you sure", 0) == FALSE)
894 top = GetUserInfo(CLASS, argv[1], NULL);
895 Loop(top, PrintUserName);
902 /* Function Name: ShowUserById
903 * Description: Shows user information given an ID number.
904 * Arguments: argc, argv - ID number in argv[1].
908 int ShowUserById(int argc, char *argv[])
910 struct mqelem *top, *elem;
912 elem = top = GetUserInfo(ID, argv[1], NULL);
913 Loop(elem, PrintUserInfo);
920 /* Function Name: GetKrbmap
921 * Description: Shows user <-> Kerberos mappings
922 * Arguments: argc, argv - argv[1] contains the user login name,
923 * argv[2] contains the principal
927 int GetKrbmap(int argc, char **argv)
930 struct mqelem *elem = NULL, *top;
933 if ((stat = do_mr_query("get_kerberos_user_map", 2, &argv[1],
936 com_err(program_name, stat, " in GetKrbMap.");
940 top = elem = QueueTop(elem);
944 char **info = elem->q_data;
945 sprintf(buf, "User: %-9s Principal: %s",
946 info[KMAP_USER], info[KMAP_PRINCIPAL]);
951 FreeQueue(QueueTop(top));
956 /* Function Name: AddKrbmap
957 * Description: Add a new user <-> Kerberos mapping
958 * Arguments: argc, argv - argv[1] contains the user login name,
959 * argv[2] contains the principal
963 int AddKrbmap(int argc, char **argv)
967 if (!strchr(argv[KMAP_PRINCIPAL + 1], '@'))
969 Put_message("Please specify a realm for the kerberos principal.");
972 if ((stat = do_mr_query("add_kerberos_user_map", 2, &argv[1],
975 com_err(program_name, stat, " in AddKrbMap.");
976 if (stat == MR_EXISTS)
977 Put_message("No user or principal may have more than one mapping.");
983 /* Function Name: DeleteKrbmap
984 * Description: Remove a user <-> Kerberos mapping
985 * Arguments: argc, argv - argv[1] contains the user login name,
986 * argv[2] contains the principal
990 int DeleteKrbmap(int argc, char **argv)
994 if ((stat = do_mr_query("delete_kerberos_user_map", 2, &argv[1],
996 com_err(program_name, stat, " in DeleteKrbMap.");