3 * This is the file delete.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 deleting users and lists.
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>
28 int CheckListForDeletion(char *name, Bool verbose);
29 void CheckAce(char *type, char *name, Bool verbose);
30 int CheckIfAce(char *name, char *type, Bool verbose);
31 int RemoveItemFromLists(char *name, char *type, struct mqelem **elem,
33 int RemoveMembersOfList(char *name, Bool verbose);
34 int DeleteUserGroup(char *name, Bool verbose);
35 int DeleteHomeFilesys(char *name, Bool verbose);
36 void AttemptToDeleteList(char **list_info, Bool ask_first);
38 /* Function Name: CheckListForDeletion
39 * Description: Check one of the lists in which we just removed a member.
40 * if the list is empty then it will delete it.
41 * Arguments: name - name of the list to check.
42 * verbose - verbose mode?
46 int CheckListForDeletion(char *name, Bool verbose)
48 struct mqelem *elem = NULL;
50 char *args[2], buf[BUFSIZ], **info;
52 if ((status = do_mr_query("count_members_of_list", 1, &name, StoreInfo,
55 com_err(program_name, status, " in DeleteList (count_members_of_list).");
59 if (!strcmp(info[NAME], "0"))
63 sprintf(buf, "Delete the empty list %s? ", name);
64 switch (YesNoQuestion(buf, FALSE))
69 Put_message("Not deleting this list.");
73 Put_message("Aborting Deletion!");
78 args[0] = "foo"; /* not used. */
86 /* Function Name: CheckAce
87 * Description: Checks an ace to see of we should delete it.
88 * Arguments: type - the type of this ace.
89 * name - the name of the ace.
90 * verbose - query user?
94 void CheckAce(char *type, char *name, Bool verbose)
96 char *args[2], buf[BUFSIZ];
99 if (strcmp(type, "LIST"))
100 return; /* If the ace is not a list the ignore it. */
104 status = do_mr_query("get_ace_use", 2, args, NULL, NULL);
105 if (status != MR_NO_MATCH)
106 return; /* If this query fails the ace will
107 not be deleted even if it is empty. */
110 sprintf(buf, "Delete the unused Access Control Entity (ACE) %s? ", name);
111 if (YesNoQuestion(buf, FALSE) != TRUE)
113 Put_message("Aborting Deletion!");
120 * NOTE: Delete list expects only the name of the list to delete in argv[1].
121 * since, 'args' already satisfies this, there is no need to create
122 * a special argument list.
128 /* Function Name: CheckIfAce
129 * Description: Checks to see if this is an ace of another data object.
130 * Arguments: name - name of the object.
131 * Returns: SUB_ERROR if this list is an ace, or if the query did not
135 int CheckIfAce(char *name, char *type, Bool verbose)
137 char *args[2], buf[BUFSIZ], **info;
138 struct mqelem *local, *elem;
144 switch ((status = do_mr_query("get_ace_use", 2, args, StoreInfo, &elem)))
149 local = elem = QueueTop(elem);
150 info = local->q_data;
151 if (QueueCount(elem) == 1 &&
152 !strcmp(info[0], "LIST") &&
153 !strcmp(info[1], name))
160 sprintf(buf, "%s %s %s", type, name,
161 "is the ACE for the following data objects:");
164 for (; local != NULL; local = local->q_forw)
166 info = local->q_data;
167 if (!strcmp(info[0], "LIST") &&
168 !strcmp(info[1], name))
170 Print(CountArgs(info), info, NULL);
173 Put_message("The ACE for each of these items must be changed before");
174 sprintf(buf, "the %s %s can be deleted.\n", type, name);
179 com_err(program_name, status, " in CheckIfAce (get_ace_use).");
186 /* Function Name: RemoveItemFromLists
187 * Description: this function removes a list from all other lists of
188 * which it is a member.
189 * Arguments: name - name of the item
190 * elem - a pointer to a queue element. RETURNED
191 * verbose - verbose mode.
192 * Returns: SUB_ERROR if there is an error.
195 int RemoveItemFromLists(char *name, char *type, struct mqelem **elem,
198 struct mqelem *local;
199 char *args[10], temp_buf[BUFSIZ];
208 * Get all list of which this item is a member, and store them in a queue.
211 status = do_mr_query("get_lists_of_member", 2, args, StoreInfo, elem);
213 if (status == MR_NO_MATCH)
216 if (status != MR_SUCCESS)
218 com_err(program_name, status, " in DeleteList (get_lists_of_member).");
223 * If verbose mode, ask user of we should remove our list from
227 local = *elem = QueueTop(*elem);
228 lists = QueueCount(*elem);
233 sprintf(temp_buf, "%s %s is a member of %d other list%s.\n", type,
234 name, lists, ((lists == 1) ? "" : "s"));
235 Put_message(temp_buf);
238 char **info = local->q_data;
239 Print(1, &info[GLOM_NAME], (char *) NULL);
240 local = local->q_forw;
242 Put_message(" "); /* Blank Line. */
243 sprintf(temp_buf, "Remove %s %s from these lists? ", type, name);
244 if (YesNoQuestion(temp_buf, FALSE) != TRUE)
246 Put_message("Aborting...");
254 * Remove this list from all lists that it is a member of.
258 args[DM_MEMBER] = name;
259 args[DM_TYPE] = type;
262 char **info = local->q_data;
263 args[DM_LIST] = info[GLOM_NAME];
264 if ((status = do_mr_query("delete_member_from_list",
265 3, args, NULL, NULL)))
267 com_err(program_name, status, " in delete_member\nAborting\n");
271 local = local->q_forw;
276 /* Function Name: RemoveMembersOfList
277 * Description: Deletes the members of the list.
278 * Arguments: name - name of the list.
279 * verbose - query user, about deletion?
280 * Returns: SUB_ERROR - if we could not delete, or the user abouted.
283 int RemoveMembersOfList(char *name, Bool verbose)
285 char buf[BUFSIZ], *args[10];
286 struct mqelem *local, *elem = NULL;
289 * Get the members of this list.
291 status = do_mr_query("get_members_of_list", 1, &name, StoreInfo, &elem);
292 if (status == MR_NO_MATCH)
297 com_err(program_name, status, " in DeleteList (get_members_of_list).");
301 * If verbose mode, then ask the user if we should delete.
303 local = elem = QueueTop(elem);
304 if (!(members = QueueCount(elem)))
308 sprintf(buf, "List %s has %d member%s:", name, QueueCount(elem),
309 ((members == 1) ? "" : "s"));
311 Put_message(" "); /* Blank Line. */
314 char **info = local->q_data;
315 Print(CountArgs(info), info, NULL);
316 local = local->q_forw;
318 Put_message(" "); /* Blank Line. */
319 sprintf(buf, "Remove th%s member%s from list %s? ",
320 ((members == 1) ? "is" : "ese"),
321 ((members == 1) ? "" : "s"), name);
322 if (YesNoQuestion(buf, FALSE) != TRUE)
324 Put_message("Aborting...");
330 * Perform The Removal.
336 char **info = local->q_data;
339 if ((status = do_mr_query("delete_member_from_list",
340 3, args, NULL, NULL)))
342 com_err(program_name, status, " in delete_member\nAborting\n");
346 local = local->q_forw;
351 /* Function Name: DeleteUserGroup
352 * Description: Deletes the list given by name if it exists.
353 * intended to be used to delete user groups
354 * Arguments: name - the name of the list to delete.
355 * verbose - flag that if TRUE queries the user to
356 * ask if list should be deleted.
357 * Returns: MR_ERROR if there is an error.
360 int DeleteUserGroup(char *name, Bool verbose)
363 char buf[BUFSIZ], *args[10];
365 status = do_mr_query("get_list_info", 1, &name, NULL, NULL);
370 sprintf(buf, "There is also a list named %s, delete it?", name);
371 ans = YesNoQuestion(buf, FALSE);
374 Put_message("Leaving group alone.");
379 Put_message("Aborting...");
383 /* ans == TRUE || ~verbose */
384 args[0] = "foo"; /* not used. */
388 else if (status != MR_NO_MATCH)
390 com_err(program_name, status, " Aborting Delete User.");
396 /* Function Name: DeleteHomeFilesys
397 * Description: Delete the home filesystem for the named user.
398 * Arguments: name - name of the user (and filsystem) to delete.
399 * verbose - if TRUE query user.
400 * Returns: SUB_NORMAL if home filesystem deleted, or nonexistant.
403 int DeleteHomeFilesys(char *name, Bool verbose)
408 switch ((status = do_mr_query("get_filesys_by_label", 1, &name, NULL, NULL)))
415 sprintf(buf, "Delete the filesystem named %s (y/n)?", name);
416 switch (YesNoQuestion(buf, FALSE))
419 Put_message("Filesystem Not Deleted, continuing...");
424 Put_message("Filesystem Not Deleted, aborting...");
428 if ((status = do_mr_query("delete_filesys", 1, &name, NULL,
429 NULL)) != MR_SUCCESS)
431 com_err(program_name, status, " in delete_filesys.");
435 Put_message("Filesystem Successfully Deleted.");
438 com_err(program_name, status, " in get_filesystem_by_label).");
445 /* Function Name: RealDeleteUser
446 * Description: Just Deletes the user.
447 * Arguments: name - name of User to delete
448 * Returns: SUB_ERROR if the deletion failed.
451 static int RealDeleteUser(char *name)
456 if ((status = do_mr_query("delete_user", 1, &name, NULL,
457 NULL)) != MR_SUCCESS)
459 com_err(program_name, status, ": user not deleted");
462 sprintf(buf, "User %s deleted.", name);
468 /* Function Name: RealDeleteList
469 * Description: Just Deletes the list.
470 * Arguments: name - name of list to delete
471 * Returns: SUB_ERROR if the deletion failed.
474 static int RealDeleteList(char *name)
479 if ((status = do_mr_query("delete_list", 1, &name, NULL,
480 NULL)) != MR_SUCCESS)
482 com_err(program_name, status, ": list not deleted");
485 sprintf(buf, "List %s deleted.", name);
491 /* Function Name: AttemptToDeleteList
492 * Description: Atempts to delete list, in the following manner:
493 * 1) try to delet it, if this fails in a known error then
494 * a) try to clean up each of those known methods, or
495 * at least explain why we failed.
496 * Arguments: list_info - info about this list.
497 * ask_first - (T/F) query user before preparing for deletion,
499 * Returns: none - all is taken care of and error messages printed
500 * one way or the other.
503 void AttemptToDeleteList(char **list_info, Bool ask_first)
506 struct mqelem *local, *member_of;
507 char *name = list_info[L_NAME];
511 * Attempt delete. - will only work if:
512 * 1) This list has no members.
513 * 2) This list in a member of no other lists.
514 * 3) This list is not an ace of another object.
517 switch ((status = do_mr_query("delete_list", 1, &name, NULL, NULL)))
520 Put_message("List Sucessfully Deleted.");
521 CheckAce(list_info[L_ACE_TYPE], list_info[L_ACE_NAME], ask_first);
525 * This list is in use. Try to find out why,
526 * and for the cases where we have a good idea of
527 * what to do we will query and then do it.
530 if ((CheckIfAce(name, "list", ask_first) != SUB_NORMAL) ||
531 (RemoveItemFromLists(name, "list",
532 &member_of, ask_first) != SUB_NORMAL))
535 * If the list is it's own ACL, then make the person performing
536 * the delete the owner before removing this person from the list
538 if (!strcmp(list_info[L_ACE_TYPE], "LIST") &&
539 !strcmp(list_info[L_ACE_NAME], list_info[L_NAME]))
541 free(list_info[L_ACE_TYPE]);
542 free(list_info[L_ACE_NAME]);
543 list_info[L_ACE_TYPE] = strdup("USER");
544 list_info[L_ACE_NAME] = strdup(user);
545 SlipInNewName(list_info, strdup(list_info[L_NAME]));
546 if ((status = do_mr_query("update_list", CountArgs(list_info) - 3,
547 list_info, NULL, NULL)) != MR_SUCCESS)
549 com_err(program_name, status, " while updating list owner");
550 Put_message("List may be only partly deleted.");
553 if ((RemoveMembersOfList(name, ask_first) == SUB_NORMAL) &&
554 (RealDeleteList(name) == SUB_NORMAL))
556 CheckAce(list_info[L_ACE_TYPE], list_info[L_ACE_NAME], ask_first);
558 local = QueueTop(member_of);
561 char **info = local->q_data;
562 if (CheckListForDeletion(info[LM_LIST], ask_first) == SUB_ERROR)
564 local = local->q_forw;
566 FreeQueue(member_of);
570 com_err(program_name, status, " in DeleteList (delete_list).");
575 /* Function Name: DeleteList
576 * Description: deletes a list
577 * Arguments: argc, argv - standard Moira argc and argv.
578 * Returns: DM Status Code.
581 int DeleteList(int argc, char *argv[])
584 struct mqelem *top, *list;
590 switch ((status = do_mr_query("get_list_info", 1, argv + 1,
597 Put_message("There is no list that matches that name.");
600 com_err(program_name, status, " in DeleteList (get_list_info).");
604 top = list = QueueTop(list);
605 one_list = (QueueCount(list) == 1);
608 char **info = list->q_data;
611 sprintf(buf, "Are you sure that you want to delete the list %s",
614 AttemptToDeleteList(info, TRUE);
618 sprintf(buf, "Delete the list %s", info[L_NAME]);
619 switch (YesNoQuestion(buf, FALSE))
622 AttemptToDeleteList(info, TRUE);
627 Put_message("Aborting...");
638 /* Function Name: DeleteUser
639 * Description: Deletes a user from the database.
640 * Arguments: argc, argv - name of the user in argv[1].
641 * Returns: DM_NORMAL.
644 int DeleteUser(int argc, char **argv)
648 char *name = argv[1]; /* name of the user we are deleting. */
650 struct mqelem *local, *member_of = NULL;
653 if (!ValidName(name))
656 if (!Confirm("Are you sure that you want to delete this user?"))
659 status = do_mr_query("delete_user", 1, &name, NULL, NULL);
660 if (status != MR_IN_USE && status != 0)
662 com_err(program_name, status, ": user not deleted");
667 sprintf(buf, "User %s deleted.", name);
670 /* delete this return if the policy decision below is reversed */
675 /* Design decision not to allow registered users to be deleted.
677 Put_message("Sorry, registered users cannot be deleted from the database.");
678 Put_message("Deactivate the user now, and the system manager will expunge later.");
680 else if (status == MR_IN_USE)
685 * 1) Query - Delete home filesytem.
686 * 2) Query - Delete user Group.
687 * 2) Is the user an ACE of any object in the database?
688 * 3) Query - Remove user from all list of which he is a member.
690 * If all these have been accomplished, then attempt to delete
693 if ((DeleteHomeFilesys(name, TRUE) == SUB_ERROR) ||
694 (DeleteUserGroup(name, TRUE) == SUB_ERROR) ||
695 (CheckIfAce(name, "user", TRUE) == SUB_ERROR) ||
696 (RemoveItemFromLists(name, "user", &member_of, TRUE) == SUB_ERROR) ||
697 (RealDeleteUser(name) == SUB_ERROR))
702 * Query - Delete all empty lists created by removing this user from them.
708 char **info = local->q_data;
709 if (CheckListForDeletion(info[0], TRUE) == SUB_ERROR)
711 local = local->q_forw;
714 FreeQueue(member_of); /* Free memory and return. */