]> andersk Git - moira.git/blob - clients/moira/delete.c
7e0c4643f94492fef14d1d83c19c77896e659826
[moira.git] / clients / moira / delete.c
1 /* $Id$
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
26 RCSID("$Header$");
27
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,
32                         int verbose);
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);
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
46 int 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
94 void 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
135 int 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
195 int 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
283 int 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
360 int 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...\n");
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
403 int 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...\n");
420               return SUB_NORMAL;
421             case TRUE:
422               break;
423             default:
424               Put_message("Filesystem Not Deleted, aborting...\n\n");
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
451 static 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
474 static 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
503 void 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
581 int 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 #if 0
596     case MR_NO_WILDCARD:
597       Put_message("Wildcards are not accepted here.");
598       return DM_NORMAL;
599 #endif
600     case MR_NO_MATCH:
601     case MR_LIST:
602       Put_message("There is no list that matches that name.");
603       return DM_NORMAL;
604     default:
605       com_err(program_name, status, " in DeleteList (get_list_info).");
606       return DM_NORMAL;
607     }
608
609   top = list = QueueTop(list);
610   one_list = (QueueCount(list) == 1);
611   while (list)
612     {
613       char **info = list->q_data;
614       if (one_list)
615         {
616           sprintf(buf, "Are you sure that you want to delete the list %s",
617                   info[L_NAME]);
618           if (Confirm(buf))
619             AttemptToDeleteList(info, TRUE);
620         }
621       else
622         {
623           sprintf(buf, "Delete the list %s", info[L_NAME]);
624           switch (YesNoQuestion(buf, FALSE))
625             {
626             case TRUE:
627               AttemptToDeleteList(info, TRUE);
628               break;
629             case FALSE:
630               break;
631             default:
632               Put_message("Aborting...");
633               FreeQueue(top);
634               return DM_QUIT;
635             }
636         }
637       list = list->q_forw;
638     }
639   FreeQueue(top);
640   return DM_NORMAL;
641 }
642
643 /*      Function Name: DeleteUser
644  *      Description: Deletes a user from the database.
645  *      Arguments: argc, argv - name of the user in argv[1].
646  *      Returns: DM_NORMAL.
647  */
648
649 int DeleteUser(int argc, char **argv)
650 {
651   int status;
652   char buf[BUFSIZ];
653   char *name = argv[1]; /* name of the user we are deleting. */
654 #ifndef ATHENA
655   struct mqelem *local, *member_of = NULL;
656 #endif
657
658   if (!ValidName(name))
659     return DM_NORMAL;
660
661   if (!Confirm("Are you sure that you want to delete this user?"))
662     return DM_NORMAL;
663
664   status = do_mr_query("delete_user", 1, &name, NULL, NULL);
665   if (status != MR_IN_USE && status != 0)
666     {
667       com_err(program_name, status, ": user not deleted");
668       return DM_NORMAL;
669     }
670   if (status == 0)
671     {
672       sprintf(buf, "User %s deleted.", name);
673       Put_message(buf);
674 #ifdef ATHENA
675       /* delete this return if the policy decision below is reversed */
676       return DM_NORMAL;
677 #endif
678     }
679 #ifdef ATHENA
680   /* Design decision not to allow registered users to be deleted.
681    */
682   Put_message("Sorry, registered users cannot be deleted from the database.");
683   Put_message("Deactivate the user now, and the system manager will expunge later.");
684 #else
685   else if (status == MR_IN_USE)
686     {
687
688       /*
689        * Check:
690        * 1) Query - Delete home filesytem.
691        * 2) Query - Delete user Group.
692        * 2) Is the user an ACE of any object in the database?
693        * 3) Query - Remove user from all list of which he is a member.
694        *
695        * If all these have been accomplished, then attempt to delete
696        * the user again.
697        */
698       if ((DeleteHomeFilesys(name, TRUE) == SUB_ERROR) ||
699           (DeleteUserGroup(name, TRUE) == SUB_ERROR) ||
700           (CheckIfAce(name, "user", TRUE) == SUB_ERROR) ||
701           (RemoveItemFromLists(name, "user", &member_of, TRUE) == SUB_ERROR) ||
702           (RealDeleteUser(name) == SUB_ERROR))
703         return DM_NORMAL;
704     }
705
706   /*
707    * Query - Delete all empty lists created by removing this user from them.
708    */
709
710   local = member_of;
711   while (local)
712     {
713       char **info = local->q_data;
714       if (CheckListForDeletion(info[0], TRUE) == SUB_ERROR)
715         break;
716       local = local->q_forw;
717     }
718
719   FreeQueue(member_of); /* Free memory and return. */
720 #endif
721   return DM_NORMAL;
722 }
This page took 0.080259 seconds and 3 git commands to generate.