source: trunk/third/moira/clients/moira/delete.c @ 23740

Revision 23740, 18.7 KB checked in by broder, 16 years ago (diff)
In moira: * New CVS snapshot (Trac: #195) * Drop patches that have been incorporated upstream. * Update to build without krb4 on systems that no longer have it. This doesn't build yet on squeeze, which lacks a krb4 library, but I'm committing now before I start hacking away at a patch to fix that.
Line 
1/* $Id: delete.c,v 1.29 1998-07-09 19:03:43 danw Exp $
2 *
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.
6 *
7 *      Created:        5/18/88
8 *      By:             Chris D. Peterson
9 *
10 * Copyright (C) 1988-1998 by the Massachusetts Institute of Technology.
11 * For copying and distribution information, please see the file
12 * <mit-copyright.h>.
13 */
14
15#include <mit-copyright.h>
16#include <moira.h>
17#include <moira_site.h>
18#include "defs.h"
19#include "f_defs.h"
20#include "globals.h"
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25
26RCSID("$Header: /afs/athena.mit.edu/astaff/project/moiradev/repository/moira/clients/moira/delete.c,v 1.29 1998-07-09 19:03:43 danw Exp $");
27
28int CheckListForDeletion(char *name, Bool verbose);
29void CheckAce(char *type, char *name, Bool verbose);
30int CheckIfAce(char *name, char *type, Bool verbose);
31int RemoveItemFromLists(char *name, char *type, struct mqelem **elem,
32                        int verbose);
33int RemoveMembersOfList(char *name, Bool verbose);
34int DeleteUserGroup(char *name, Bool verbose);
35int DeleteHomeFilesys(char *name, Bool verbose);
36void AttemptToDeleteList(char **list_info, Bool ask_first);
37
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?
43 *      Returns: none.
44 */
45
46int CheckListForDeletion(char *name, Bool verbose)
47{
48  struct mqelem *elem = NULL;
49  int status;
50  char *args[2], buf[BUFSIZ], **info;
51
52  if ((status = do_mr_query("count_members_of_list", 1, &name, StoreInfo,
53                            &elem)))
54    {
55      com_err(program_name, status, " in DeleteList (count_members_of_list).");
56      return SUB_NORMAL;
57    }
58  info = elem->q_data;
59  if (!strcmp(info[NAME], "0"))
60    {
61      if (verbose)
62        {
63          sprintf(buf, "Delete the empty list %s? ", name);
64          switch (YesNoQuestion(buf, FALSE))
65            {
66            case TRUE:
67              break;
68            case FALSE:
69              Put_message("Not deleting this list.");
70              FreeQueue(elem);
71              return SUB_NORMAL;
72            default:
73              Put_message("Aborting Deletion!");
74              FreeQueue(elem);
75              return SUB_ERROR;
76            }
77        }
78      args[0] = "foo";          /* not used. */
79      args[1] = name;
80      DeleteList(2, args);
81    }
82  FreeQueue(elem);
83  return SUB_NORMAL;
84}
85
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?
91 *      Returns: none.
92 */
93
94void CheckAce(char *type, char *name, Bool verbose)
95{
96  char *args[2], buf[BUFSIZ];
97  int status;
98
99  if (strcmp(type, "LIST"))
100    return;             /* If the ace is not a list the ignore it. */
101
102  args[0] = type;
103  args[1] = name;
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. */
108  if (verbose)
109    {
110      sprintf(buf, "Delete the unused Access Control Entity (ACE) %s? ", name);
111      if (YesNoQuestion(buf, FALSE) != TRUE)
112        {
113          Put_message("Aborting Deletion!");
114          return;
115        }
116    }
117  /*
118   * Delete the ACE.
119   *
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.
123   */
124  DeleteList(2, args);
125}
126
127
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
132 *               succeed.
133 */
134
135int CheckIfAce(char *name, char *type, Bool verbose)
136{
137  char *args[2], buf[BUFSIZ], **info;
138  struct mqelem *local, *elem;
139  int status;
140  elem = NULL;
141
142  args[0] = type;
143  args[1] = name;
144  switch ((status = do_mr_query("get_ace_use", 2, args, StoreInfo, &elem)))
145    {
146    case MR_NO_MATCH:
147      return DM_NORMAL;
148    case MR_SUCCESS:
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))
154        {
155          FreeQueue(elem);
156          return DM_NORMAL;
157        }
158      if (verbose)
159        {
160          sprintf(buf, "%s %s %s", type, name,
161                  "is the ACE for the following data objects:");
162          Put_message(buf);
163          Put_message("");
164          for (; local != NULL; local = local->q_forw)
165            {
166              info = local->q_data;
167              if (!strcmp(info[0], "LIST") &&
168                  !strcmp(info[1], name))
169                continue;
170              Print(CountArgs(info), info, NULL);
171            }
172          Put_message("");
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);
175          Put_message(buf);
176        }
177      break;
178    default:
179      com_err(program_name, status, " in CheckIfAce (get_ace_use).");
180      return SUB_ERROR;
181    }
182  FreeQueue(elem);
183  return SUB_ERROR;
184}
185
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.
193 */
194
195int RemoveItemFromLists(char *name, char *type, struct mqelem **elem,
196                        int verbose)
197{
198  struct mqelem *local;
199  char *args[10], temp_buf[BUFSIZ];
200  int lists;
201  int status;
202
203  args[0] = type;
204  args[1] = name;
205  *elem = NULL;
206
207  /*
208   * Get all list of which this item is a member, and store them in a queue.
209   */
210
211  status = do_mr_query("get_lists_of_member", 2, args, StoreInfo, elem);
212
213  if (status == MR_NO_MATCH)
214    return SUB_NORMAL;
215
216  if (status != MR_SUCCESS)
217    {
218      com_err(program_name, status, " in DeleteList (get_lists_of_member).");
219      return SUB_ERROR;
220    }
221
222  /*
223   * If verbose mode, ask user of we should remove our list from
224   * all these lists.
225   */
226
227  local = *elem = QueueTop(*elem);
228  lists = QueueCount(*elem);
229  if (lists == 0)
230    return SUB_NORMAL;
231  if (verbose)
232    {
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);
236      while (local)
237        {
238          char **info = local->q_data;
239          Print(1, &info[GLOM_NAME], (char *) NULL);
240            local = local->q_forw;
241        }
242        Put_message(" ");       /* Blank Line. */
243        sprintf(temp_buf, "Remove %s %s from these lists? ", type, name);
244        if (YesNoQuestion(temp_buf, FALSE) != TRUE)
245          {
246            Put_message("Aborting...");
247            FreeQueue(*elem);
248            *elem = NULL;
249            return SUB_ERROR;
250          }
251    }
252
253  /*
254   * Remove this list from all lists that it is a member of.
255   */
256
257  local = *elem;
258  args[DM_MEMBER] = name;
259  args[DM_TYPE] = type;
260  while (local)
261    {
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)))
266        {
267          com_err(program_name, status, " in delete_member\nAborting\n");
268          FreeQueue(*elem);
269          return SUB_ERROR;
270        }
271      local = local->q_forw;
272    }
273  return SUB_NORMAL;
274}
275
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.
281 */
282
283int RemoveMembersOfList(char *name, Bool verbose)
284{
285  char buf[BUFSIZ], *args[10];
286  struct mqelem *local, *elem = NULL;
287  int status, members;
288  /*
289   * Get the members of this list.
290   */
291  status = do_mr_query("get_members_of_list", 1, &name, StoreInfo, &elem);
292  if (status == MR_NO_MATCH)
293    return SUB_NORMAL;
294
295  if (status)
296    {
297      com_err(program_name, status, " in DeleteList (get_members_of_list).");
298      return SUB_ERROR;
299    }
300  /*
301   * If verbose mode, then ask the user if we should delete.
302   */
303  local = elem = QueueTop(elem);
304  if (!(members = QueueCount(elem)))
305    return SUB_NORMAL;
306  if (verbose)
307    {
308      sprintf(buf, "List %s has %d member%s:", name, QueueCount(elem),
309              ((members == 1) ? "" : "s"));
310      Put_message(buf);
311      Put_message(" "); /* Blank Line. */
312      while (local)
313        {
314          char **info = local->q_data;
315          Print(CountArgs(info), info, NULL);
316          local = local->q_forw;
317        }
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)
323        {
324          Put_message("Aborting...");
325          FreeQueue(elem);
326          return SUB_ERROR;
327        }
328    }
329  /*
330   * Perform The Removal.
331   */
332  local = elem;
333  args[0] = name;
334  while (local)
335    {
336      char **info = local->q_data;
337      args[1] = info[0];
338      args[2] = info[1];
339      if ((status = do_mr_query("delete_member_from_list",
340                                3, args, NULL, NULL)))
341        {
342          com_err(program_name, status, " in delete_member\nAborting\n");
343          FreeQueue(elem);
344          return SUB_ERROR;
345        }
346      local = local->q_forw;
347    }
348  return SUB_NORMAL;
349}
350
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.
358 */
359
360int DeleteUserGroup(char *name, Bool verbose)
361{
362  int status, ans;
363  char buf[BUFSIZ], *args[10];
364
365  status = do_mr_query("get_list_info", 1, &name, NULL, NULL);
366  if (!status)
367    {
368      if (verbose)
369        {
370          sprintf(buf, "There is also a list named %s, delete it?", name);
371          ans = YesNoQuestion(buf, FALSE);
372          if (ans == FALSE)
373            {
374              Put_message("Leaving group alone.");
375              return SUB_NORMAL;
376            }
377          if (ans < 0)
378            {
379              Put_message("Aborting...");
380              return SUB_ERROR;
381            }
382        }
383      /* ans == TRUE  || ~verbose */
384      args[0] = "foo";  /* not used. */
385      args[1] = name;
386      DeleteList(2, args);
387    }
388  else if (status != MR_NO_MATCH)
389    {
390      com_err(program_name, status, " Aborting Delete User.");
391      return SUB_ERROR;
392    }
393  return SUB_NORMAL;
394}
395
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.
401 */
402
403int DeleteHomeFilesys(char *name, Bool verbose)
404{
405  int status;
406  char buf[BUFSIZ];
407
408  switch ((status = do_mr_query("get_filesys_by_label", 1, &name, NULL, NULL)))
409    {
410    case MR_NO_MATCH:
411      break;
412    case MR_SUCCESS:
413      if (verbose)
414        {
415          sprintf(buf, "Delete the filesystem named %s (y/n)?", name);
416          switch (YesNoQuestion(buf, FALSE))
417            {
418            case FALSE:
419              Put_message("Filesystem Not Deleted, continuing...");
420              return SUB_NORMAL;
421            case TRUE:
422              break;
423            default:
424              Put_message("Filesystem Not Deleted, aborting...");
425              return SUB_ERROR;
426            }
427        }
428      if ((status = do_mr_query("delete_filesys", 1, &name, NULL,
429                                NULL)) != MR_SUCCESS)
430        {
431          com_err(program_name, status, " in delete_filesys.");
432          return SUB_ERROR;
433        }
434      else
435        Put_message("Filesystem Successfully Deleted.");
436      break;
437    default:
438      com_err(program_name, status, " in get_filesystem_by_label).");
439      return SUB_ERROR;
440    }
441  return SUB_NORMAL;
442}
443
444#ifndef ATHENA
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.
449 */
450
451static int RealDeleteUser(char *name)
452{
453  char buf[BUFSIZ];
454  int status;
455
456  if ((status = do_mr_query("delete_user", 1, &name, NULL,
457                            NULL)) != MR_SUCCESS)
458    {
459      com_err(program_name, status, ": user not deleted");
460      return SUB_ERROR;
461    }
462  sprintf(buf, "User %s deleted.", name);
463  Put_message(buf);
464  return SUB_NORMAL;
465}
466#endif
467
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.
472 */
473
474static int RealDeleteList(char *name)
475{
476  char buf[BUFSIZ];
477  int status;
478
479  if ((status = do_mr_query("delete_list", 1, &name, NULL,
480                            NULL)) != MR_SUCCESS)
481    {
482      com_err(program_name, status, ": list not deleted");
483      return SUB_ERROR;
484    }
485  sprintf(buf, "List %s deleted.", name);
486  Put_message(buf);
487  Put_message("");
488  return SUB_NORMAL;
489}
490
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,
498 *                             and cleaning up?
499 *      Returns: none - all is taken care of and error messages printed
500 *                      one way or the other.
501 */
502
503void AttemptToDeleteList(char **list_info, Bool ask_first)
504{
505  int status;
506  struct mqelem *local, *member_of;
507  char *name = list_info[L_NAME];
508  member_of = NULL;
509
510  /*
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.
515   */
516
517  switch ((status = do_mr_query("delete_list", 1, &name, NULL, NULL)))
518    {
519    case MR_SUCCESS:
520      Put_message("List Sucessfully Deleted.");
521      CheckAce(list_info[L_ACE_TYPE], list_info[L_ACE_NAME], ask_first);
522      break;
523    case MR_IN_USE:
524      /*
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.
528       */
529
530      if ((CheckIfAce(name, "list", ask_first) != SUB_NORMAL) ||
531          (RemoveItemFromLists(name, "list",
532                               &member_of, ask_first) != SUB_NORMAL))
533        break;
534      /*
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
537       */
538      if (!strcmp(list_info[L_ACE_TYPE], "LIST") &&
539          !strcmp(list_info[L_ACE_NAME], list_info[L_NAME]))
540        {
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)
548            {
549              com_err(program_name, status, " while updating list owner");
550              Put_message("List may be only partly deleted.");
551            }
552        }
553      if ((RemoveMembersOfList(name, ask_first) == SUB_NORMAL) &&
554          (RealDeleteList(name) == SUB_NORMAL))
555        {               /* if... */
556          CheckAce(list_info[L_ACE_TYPE], list_info[L_ACE_NAME], ask_first);
557
558          local = QueueTop(member_of);
559          while (local)
560            {
561              char **info = local->q_data;
562              if (CheckListForDeletion(info[LM_LIST], ask_first) == SUB_ERROR)
563                break;
564              local = local->q_forw;
565            }
566          FreeQueue(member_of);
567        }
568      break;
569    default:
570      com_err(program_name, status, " in DeleteList (delete_list).");
571      break;
572    }
573}
574
575/*      Function Name: DeleteList
576 *      Description: deletes a list
577 *      Arguments: argc, argv - standard Moira argc and argv.
578 *      Returns: DM Status Code.
579 */
580
581int DeleteList(int argc, char *argv[])
582{
583  char buf[BUFSIZ];
584  struct mqelem *top, *list;
585  int status;
586  Bool one_list;
587
588  list = NULL;
589
590  switch ((status = do_mr_query("get_list_info", 1, argv + 1,
591                                StoreInfo, &list)))
592    {
593    case MR_SUCCESS:
594      break;
595    case MR_NO_MATCH:
596    case MR_LIST:
597      Put_message("There is no list that matches that name.");
598      return DM_NORMAL;
599    default:
600      com_err(program_name, status, " in DeleteList (get_list_info).");
601      return DM_NORMAL;
602    }
603
604  top = list = QueueTop(list);
605  one_list = (QueueCount(list) == 1);
606  while (list)
607    {
608      char **info = list->q_data;
609      if (one_list)
610        {
611          sprintf(buf, "Are you sure that you want to delete the list %s",
612                  info[L_NAME]);
613          if (Confirm(buf))
614            AttemptToDeleteList(info, TRUE);
615        }
616      else
617        {
618          sprintf(buf, "Delete the list %s", info[L_NAME]);
619          switch (YesNoQuestion(buf, FALSE))
620            {
621            case TRUE:
622              AttemptToDeleteList(info, TRUE);
623              break;
624            case FALSE:
625              break;
626            default:
627              Put_message("Aborting...");
628              FreeQueue(top);
629              return DM_QUIT;
630            }
631        }
632      list = list->q_forw;
633    }
634  FreeQueue(top);
635  return DM_NORMAL;
636}
637
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.
642 */
643
644int DeleteUser(int argc, char **argv)
645{
646  int status;
647  char buf[BUFSIZ];
648  char *name = argv[1]; /* name of the user we are deleting. */
649#ifndef ATHENA
650  struct mqelem *local, *member_of = NULL;
651#endif
652
653  if (!ValidName(name))
654    return DM_NORMAL;
655
656  if (!Confirm("Are you sure that you want to delete this user?"))
657    return DM_NORMAL;
658
659  status = do_mr_query("delete_user", 1, &name, NULL, NULL);
660  if (status != MR_IN_USE && status != 0)
661    {
662      com_err(program_name, status, ": user not deleted");
663      return DM_NORMAL;
664    }
665  if (status == 0)
666    {
667      sprintf(buf, "User %s deleted.", name);
668      Put_message(buf);
669#ifdef ATHENA
670      /* delete this return if the policy decision below is reversed */
671      return DM_NORMAL;
672#endif
673    }
674#ifdef ATHENA
675  /* Design decision not to allow registered users to be deleted.
676   */
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.");
679#else
680  else if (status == MR_IN_USE)
681    {
682
683      /*
684       * Check:
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.
689       *
690       * If all these have been accomplished, then attempt to delete
691       * the user again.
692       */
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))
698        return DM_NORMAL;
699    }
700
701  /*
702   * Query - Delete all empty lists created by removing this user from them.
703   */
704
705  local = member_of;
706  while (local)
707    {
708      char **info = local->q_data;
709      if (CheckListForDeletion(info[0], TRUE) == SUB_ERROR)
710        break;
711      local = local->q_forw;
712    }
713
714  FreeQueue(member_of); /* Free memory and return. */
715#endif
716  return DM_NORMAL;
717}
Note: See TracBrowser for help on using the repository browser.