2 * Copyright (c) 1991 - 1994, Julianne Frances Haugh
3 * Copyright (c) 1996 - 2000, Marek Michałkiewicz
4 * Copyright (c) 2000 - 2006, Tomasz Kłoczko
5 * Copyright (c) 2007 - 2011, Nicolas François
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the copyright holders or contributors may not be used to
17 * endorse or promote products derived from this software without
18 * specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46 #ifdef ACCT_TOOLS_SETUID
50 #endif /* ACCT_TOOLS_SETUID */
55 #include "prototypes.h"
61 #endif /* SHADOWGRP */
67 #include "exitcodes.h"
72 #define E_PW_UPDATE 1 /* can't update password file */
73 #define E_NOTFOUND 6 /* specified user doesn't exist */
74 #define E_USER_BUSY 8 /* user currently logged in */
75 #define E_GRP_UPDATE 10 /* can't update group file */
76 #define E_HOMEDIR 12 /* can't remove home directory */
83 static char *user_name;
85 static gid_t user_gid;
86 static char *user_home;
88 static bool fflg = false;
89 static bool rflg = false;
91 static bool is_shadow_pwd;
94 static bool is_shadow_grp;
95 static bool sgr_locked = false;
96 #endif /* SHADOWGRP */
97 static bool pw_locked = false;
98 static bool gr_locked = false;
99 static bool spw_locked = false;
101 /* local function prototypes */
102 static void usage (int status);
103 static void update_groups (void);
104 static void remove_usergroup (void);
105 static void close_files (void);
106 static void fail_exit (int);
107 static void open_files (void);
108 static void update_user (void);
109 static void user_cancel (const char *);
111 #ifdef EXTRA_CHECK_HOME_DIR
112 static bool path_prefix (const char *, const char *);
113 #endif /* EXTRA_CHECK_HOME_DIR */
114 static int is_owner (uid_t, const char *);
115 static int remove_mailbox (void);
117 static int remove_tcbdir (const char *user_name, uid_t user_id);
118 #endif /* WITH_TCB */
121 * usage - display usage message and exit
123 static void usage (int status)
125 fputs (_("Usage: userdel [options] LOGIN\n"
128 " -f, --force force removal of files,\n"
129 " even if not owned by user\n"
130 " -h, --help display this help message and exit\n"
131 " -r, --remove remove home directory and mail spool\n"
132 "\n"), (E_SUCCESS != status) ? stderr : stdout);
137 * update_groups - delete user from secondary group set
139 * update_groups() takes the user name that was given and searches
140 * the group files for membership in any group.
142 * we also check to see if they have any groups they own (the same
143 * name is their user name) and delete them too (only if USERGROUPS_ENAB
146 static void update_groups (void)
148 const struct group *grp;
152 const struct sgrp *sgrp;
154 #endif /* SHADOWGRP */
157 * Scan through the entire group file looking for the groups that
158 * the user is a member of.
160 for (gr_rewind (), grp = gr_next (); NULL != grp; grp = gr_next ()) {
163 * See if the user specified this group as one of their
166 if (!is_on_list (grp->gr_mem, user_name)) {
171 * Delete the username from the list of group members and
172 * update the group entry to reflect the change.
174 ngrp = __gr_dup (grp);
177 _("%s: Out of memory. Cannot update %s.\n"),
181 ngrp->gr_mem = del_list (ngrp->gr_mem, user_name);
182 if (gr_update (ngrp) == 0) {
184 _("%s: failed to prepare the new %s entry '%s'\n"),
185 Prog, gr_dbname (), ngrp->gr_name);
190 * Update the DBM group file with the new entry as well.
193 audit_logger (AUDIT_DEL_USER, Prog,
194 "deleting user from group",
195 user_name, (unsigned int) user_id,
196 SHADOW_AUDIT_SUCCESS);
197 #endif /* WITH_AUDIT */
198 SYSLOG ((LOG_INFO, "delete '%s' from group '%s'\n",
199 user_name, ngrp->gr_name));
202 if (getdef_bool ("USERGROUPS_ENAB")) {
207 if (!is_shadow_grp) {
212 * Scan through the entire shadow group file looking for the groups
213 * that the user is a member of. Both the administrative list and
214 * the ordinary membership list is checked.
216 for (sgr_rewind (), sgrp = sgr_next ();
218 sgrp = sgr_next ()) {
219 bool was_member, was_admin;
222 * See if the user specified this group as one of their
225 was_member = is_on_list (sgrp->sg_mem, user_name);
226 was_admin = is_on_list (sgrp->sg_adm, user_name);
228 if (!was_member && !was_admin) {
232 nsgrp = __sgr_dup (sgrp);
235 _("%s: Out of memory. Cannot update %s.\n"),
236 Prog, sgr_dbname ());
241 nsgrp->sg_mem = del_list (nsgrp->sg_mem, user_name);
245 nsgrp->sg_adm = del_list (nsgrp->sg_adm, user_name);
248 if (sgr_update (nsgrp) == 0) {
250 _("%s: failed to prepare the new %s entry '%s'\n"),
251 Prog, sgr_dbname (), nsgrp->sg_name);
255 audit_logger (AUDIT_DEL_USER, Prog,
256 "deleting user from shadow group",
257 user_name, (unsigned int) user_id,
258 SHADOW_AUDIT_SUCCESS);
259 #endif /* WITH_AUDIT */
260 SYSLOG ((LOG_INFO, "delete '%s' from shadow group '%s'\n",
261 user_name, nsgrp->sg_name));
263 #endif /* SHADOWGRP */
267 * remove_usergroup - delete the user's group if it is a usergroup
269 * An usergroup is removed if
270 * + it has the same name as the user
271 * + it is the primary group of the user
272 * + it has no other members
273 * + it is not the primary group of any other user
275 static void remove_usergroup (void)
277 const struct group *grp;
278 const struct passwd *pwd = NULL;
280 grp = gr_locate (user_name);
282 /* This user has no usergroup. */
286 if (grp->gr_gid != user_gid) {
288 _("%s: group %s not removed because it is not the primary group of user %s.\n"),
289 Prog, grp->gr_name, user_name);
293 if (NULL != grp->gr_mem[0]) {
294 /* The usergroup has other members. */
296 _("%s: group %s not removed because it has other members.\n"),
303 * Scan the passwd file to check if this group is still
304 * used as a primary group.
307 while ((pwd = getpwent ()) != NULL) {
308 if (strcmp (pwd->pw_name, user_name) == 0) {
311 if (pwd->pw_gid == grp->gr_gid) {
313 _("%s: group %s is the primary group of another user and is not removed.\n"),
323 * We can remove this group, it is not the primary
324 * group of any remaining user.
326 if (gr_remove (grp->gr_name) == 0) {
328 _("%s: cannot remove entry '%s' from %s\n"),
329 Prog, grp->gr_name, gr_dbname ());
330 fail_exit (E_GRP_UPDATE);
334 audit_logger (AUDIT_DEL_GROUP, Prog,
336 grp->gr_name, AUDIT_NO_ID,
337 SHADOW_AUDIT_SUCCESS);
338 #endif /* WITH_AUDIT */
340 "removed group '%s' owned by '%s'\n",
341 grp->gr_name, user_name));
344 if (sgr_locate (user_name) != NULL) {
345 if (sgr_remove (user_name) == 0) {
347 _("%s: cannot remove entry '%s' from %s\n"),
348 Prog, user_name, sgr_dbname ());
349 fail_exit (E_GRP_UPDATE);
352 audit_logger (AUDIT_DEL_GROUP, Prog,
353 "deleting shadow group",
354 grp->gr_name, AUDIT_NO_ID,
355 SHADOW_AUDIT_SUCCESS);
356 #endif /* WITH_AUDIT */
358 "removed shadow group '%s' owned by '%s'\n",
359 grp->gr_name, user_name));
362 #endif /* SHADOWGRP */
367 * close_files - close all of the files that were opened
369 * close_files() closes all of the files that were opened for this
370 * new user. This causes any modified entries to be written out.
372 static void close_files (void)
374 if (pw_close () == 0) {
375 fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, pw_dbname ());
376 SYSLOG ((LOG_ERR, "failure while writing changes to %s", pw_dbname ()));
377 fail_exit (E_PW_UPDATE);
379 if (pw_unlock () == 0) {
380 fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, pw_dbname ());
381 SYSLOG ((LOG_ERR, "failed to unlock %s", pw_dbname ()));
387 if (spw_close () == 0) {
389 _("%s: failure while writing changes to %s\n"), Prog, spw_dbname ());
390 SYSLOG ((LOG_ERR, "failure while writing changes to %s", spw_dbname ()));
391 fail_exit (E_PW_UPDATE);
393 if (spw_unlock () == 0) {
394 fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, spw_dbname ());
395 SYSLOG ((LOG_ERR, "failed to unlock %s", spw_dbname ()));
401 if (gr_close () == 0) {
402 fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, gr_dbname ());
403 SYSLOG ((LOG_ERR, "failure while writing changes to %s", gr_dbname ()));
404 fail_exit (E_GRP_UPDATE);
406 if (gr_unlock () == 0) {
407 fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, gr_dbname ());
408 SYSLOG ((LOG_ERR, "failed to unlock %s", gr_dbname ()));
415 if (sgr_close () == 0) {
417 _("%s: failure while writing changes to %s\n"), Prog, sgr_dbname ());
418 SYSLOG ((LOG_ERR, "failure while writing changes to %s", sgr_dbname ()));
419 fail_exit (E_GRP_UPDATE);
422 if (sgr_unlock () == 0) {
423 fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sgr_dbname ());
424 SYSLOG ((LOG_ERR, "failed to unlock %s", sgr_dbname ()));
429 #endif /* SHADOWGRP */
433 * fail_exit - exit with a failure code after unlocking the files
435 static void fail_exit (int code)
438 if (pw_unlock () == 0) {
439 fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, pw_dbname ());
440 SYSLOG ((LOG_ERR, "failed to unlock %s", pw_dbname ()));
445 if (gr_unlock () == 0) {
446 fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, gr_dbname ());
447 SYSLOG ((LOG_ERR, "failed to unlock %s", gr_dbname ()));
452 if (spw_unlock () == 0) {
453 fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, spw_dbname ());
454 SYSLOG ((LOG_ERR, "failed to unlock %s", spw_dbname ()));
460 if (sgr_unlock () == 0) {
461 fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sgr_dbname ());
462 SYSLOG ((LOG_ERR, "failed to unlock %s", sgr_dbname ()));
466 #endif /* SHADOWGRP */
469 audit_logger (AUDIT_DEL_USER, Prog,
471 user_name, (unsigned int) user_id,
472 SHADOW_AUDIT_FAILURE);
473 #endif /* WITH_AUDIT */
479 * open_files - lock and open the password files
481 * open_files() opens the two password files.
484 static void open_files (void)
486 if (pw_lock () == 0) {
488 _("%s: cannot lock %s; try again later.\n"),
491 audit_logger (AUDIT_DEL_USER, Prog,
492 "locking password file",
493 user_name, (unsigned int) user_id,
494 SHADOW_AUDIT_FAILURE);
495 #endif /* WITH_AUDIT */
496 fail_exit (E_PW_UPDATE);
499 if (pw_open (O_RDWR) == 0) {
501 _("%s: cannot open %s\n"), Prog, pw_dbname ());
503 audit_logger (AUDIT_DEL_USER, Prog,
504 "opening password file",
505 user_name, (unsigned int) user_id,
506 SHADOW_AUDIT_FAILURE);
507 #endif /* WITH_AUDIT */
508 fail_exit (E_PW_UPDATE);
511 if (spw_lock () == 0) {
513 _("%s: cannot lock %s; try again later.\n"),
514 Prog, spw_dbname ());
516 audit_logger (AUDIT_DEL_USER, Prog,
517 "locking shadow password file",
518 user_name, (unsigned int) user_id,
519 SHADOW_AUDIT_FAILURE);
520 #endif /* WITH_AUDIT */
521 fail_exit (E_PW_UPDATE);
524 if (spw_open (O_RDWR) == 0) {
526 _("%s: cannot open %s\n"),
527 Prog, spw_dbname ());
529 audit_logger (AUDIT_DEL_USER, Prog,
530 "opening shadow password file",
531 user_name, (unsigned int) user_id,
532 SHADOW_AUDIT_FAILURE);
533 #endif /* WITH_AUDIT */
534 fail_exit (E_PW_UPDATE);
537 if (gr_lock () == 0) {
539 _("%s: cannot lock %s; try again later.\n"),
542 audit_logger (AUDIT_DEL_USER, Prog,
543 "locking group file",
544 user_name, (unsigned int) user_id,
545 SHADOW_AUDIT_FAILURE);
546 #endif /* WITH_AUDIT */
547 fail_exit (E_GRP_UPDATE);
550 if (gr_open (O_RDWR) == 0) {
551 fprintf (stderr, _("%s: cannot open %s\n"), Prog, gr_dbname ());
553 audit_logger (AUDIT_DEL_USER, Prog,
554 "opening group file",
555 user_name, (unsigned int) user_id,
556 SHADOW_AUDIT_FAILURE);
557 #endif /* WITH_AUDIT */
558 fail_exit (E_GRP_UPDATE);
562 if (sgr_lock () == 0) {
564 _("%s: cannot lock %s; try again later.\n"),
565 Prog, sgr_dbname ());
567 audit_logger (AUDIT_DEL_USER, Prog,
568 "locking shadow group file",
569 user_name, (unsigned int) user_id,
570 SHADOW_AUDIT_FAILURE);
571 #endif /* WITH_AUDIT */
572 fail_exit (E_GRP_UPDATE);
575 if (sgr_open (O_RDWR) == 0) {
576 fprintf (stderr, _("%s: cannot open %s\n"),
577 Prog, sgr_dbname ());
579 audit_logger (AUDIT_DEL_USER, Prog,
580 "opening shadow group file",
581 user_name, (unsigned int) user_id,
582 SHADOW_AUDIT_FAILURE);
583 #endif /* WITH_AUDIT */
584 fail_exit (E_GRP_UPDATE);
587 #endif /* SHADOWGRP */
591 * update_user - delete the user entries
593 * update_user() deletes the password file entries for this user
594 * and will update the group entries as required.
596 static void update_user (void)
598 if (pw_remove (user_name) == 0) {
600 _("%s: cannot remove entry '%s' from %s\n"),
601 Prog, user_name, pw_dbname ());
602 fail_exit (E_PW_UPDATE);
605 && (spw_locate (user_name) != NULL)
606 && (spw_remove (user_name) == 0)) {
608 _("%s: cannot remove entry '%s' from %s\n"),
609 Prog, user_name, spw_dbname ());
610 fail_exit (E_PW_UPDATE);
613 audit_logger (AUDIT_DEL_USER, Prog,
614 "deleting user entries",
615 user_name, (unsigned int) user_id,
616 SHADOW_AUDIT_SUCCESS);
617 #endif /* WITH_AUDIT */
618 SYSLOG ((LOG_INFO, "delete user '%s'\n", user_name));
622 * user_cancel - cancel cron and at jobs
624 * user_cancel calls a script for additional cleanups like removal of
625 * cron, at, or print jobs.
628 static void user_cancel (const char *user)
634 cmd = getdef_str ("USERDEL_CMD");
641 (void) run_command (cmd, argv, NULL, &status);
644 #ifdef EXTRA_CHECK_HOME_DIR
645 static bool path_prefix (const char *s1, const char *s2)
647 return ( (strncmp (s2, s1, strlen (s1)) == 0)
648 && ( ('\0' == s2[strlen (s1)])
649 || ('/' == s2[strlen (s1)])));
651 #endif /* EXTRA_CHECK_HOME_DIR */
654 * is_owner - Check if path is owned by uid
657 * 1: path exists and is owned by uid
658 * 0: path is not owned by uid, or a failure occurred
659 * -1: path does not exist
661 static int is_owner (uid_t uid, const char *path)
666 if (stat (path, &st) != 0) {
667 if ((ENOENT == errno) || (ENOTDIR == errno)) {
668 /* The file or directory does not exist */
674 return (st.st_uid == uid) ? 1 : 0;
677 static int remove_mailbox (void)
684 maildir = getdef_str ("MAIL_DIR");
685 #ifdef MAIL_SPOOL_DIR
686 if ((NULL == maildir) && (getdef_str ("MAIL_FILE") == NULL)) {
687 maildir = MAIL_SPOOL_DIR;
689 #endif /* MAIL_SPOOL_DIR */
690 if (NULL == maildir) {
693 snprintf (mailfile, sizeof mailfile, "%s/%s", maildir, user_name);
695 if (access (mailfile, F_OK) != 0) {
696 if (ENOENT == errno) {
698 _("%s: %s mail spool (%s) not found\n"),
699 Prog, user_name, mailfile);
703 _("%s: warning: can't remove %s: %s\n"),
704 Prog, mailfile, strerror (errno));
705 SYSLOG ((LOG_ERR, "Cannot remove %s: %s", mailfile, strerror (errno)));
707 audit_logger (AUDIT_DEL_USER, Prog,
708 "deleting mail file",
709 user_name, (unsigned int) user_id,
710 SHADOW_AUDIT_FAILURE);
711 #endif /* WITH_AUDIT */
717 if (unlink (mailfile) != 0) {
719 _("%s: warning: can't remove %s: %s\n"),
720 Prog, mailfile, strerror (errno));
721 SYSLOG ((LOG_ERR, "Cannot remove %s: %s", mailfile, strerror (errno)));
723 audit_logger (AUDIT_DEL_USER, Prog,
724 "deleting mail file",
725 user_name, (unsigned int) user_id,
726 SHADOW_AUDIT_FAILURE);
727 #endif /* WITH_AUDIT */
734 audit_logger (AUDIT_DEL_USER, Prog,
735 "deleting mail file",
736 user_name, (unsigned int) user_id,
737 SHADOW_AUDIT_SUCCESS);
739 #endif /* WITH_AUDIT */
742 i = is_owner (user_id, mailfile);
745 _("%s: %s not owned by %s, not removing\n"),
746 Prog, mailfile, user_name);
748 "%s not owned by %s, not removed",
749 mailfile, strerror (errno)));
751 audit_logger (AUDIT_DEL_USER, Prog,
752 "deleting mail file",
753 user_name, (unsigned int) user_id,
754 SHADOW_AUDIT_FAILURE);
755 #endif /* WITH_AUDIT */
757 } else if (i == -1) {
758 return 0; /* mailbox doesn't exist */
760 if (unlink (mailfile) != 0) {
762 _("%s: warning: can't remove %s: %s\n"),
763 Prog, mailfile, strerror (errno));
764 SYSLOG ((LOG_ERR, "Cannot remove %s: %s", mailfile, strerror (errno)));
766 audit_logger (AUDIT_DEL_USER, Prog,
767 "deleting mail file",
768 user_name, (unsigned int) user_id,
769 SHADOW_AUDIT_FAILURE);
770 #endif /* WITH_AUDIT */
777 audit_logger (AUDIT_DEL_USER, Prog,
778 "deleting mail file",
779 user_name, (unsigned int) user_id,
780 SHADOW_AUDIT_SUCCESS);
782 #endif /* WITH_AUDIT */
787 static int remove_tcbdir (const char *user_name, uid_t user_id)
791 size_t bufsize = (sizeof TCB_DIR) + strlen (user_name) + 2;
793 if (!getdef_bool ("USE_TCB")) {
797 buf = malloc (buflen);
799 fprintf (stderr, _("%s: Can't allocate memory, "
800 "tcb entry for %s not removed.\n"),
804 snprintf (buf, buflen, TCB_DIR "/%s", user_name);
805 if (shadowtcb_drop_priv () == SHADOWTCB_FAILURE) {
806 fprintf (stderr, _("%s: Cannot drop privileges: %s\n"),
807 Prog, strerror (errno));
808 shadowtcb_gain_priv ();
812 /* Only remove directory contents with dropped privileges.
813 * We will regain them and remove the user's tcb directory afterwards.
815 if (remove_tree (buf, false) != 0) {
816 fprintf (stderr, _("%s: Cannot remove the content of %s: %s\n"),
817 Prog, buf, strerror (errno));
818 shadowtcb_gain_priv ();
822 shadowtcb_gain_priv ();
824 if (shadowtcb_remove (user_name) == SHADOWTCB_FAILURE) {
825 fprintf (stderr, _("%s: Cannot remove tcb files for %s: %s\n"),
826 Prog, user_name, strerror (errno));
831 #endif /* WITH_TCB */
834 * main - userdel command
836 int main (int argc, char **argv)
838 int errors = 0; /* Error in the removal of the home directory */
840 #ifdef ACCT_TOOLS_SETUID
842 pam_handle_t *pamh = NULL;
845 #endif /* ACCT_TOOLS_SETUID */
849 #endif /* WITH_AUDIT */
852 * Get my name so that I can use it to report errors.
854 Prog = Basename (argv[0]);
855 (void) setlocale (LC_ALL, "");
856 (void) bindtextdomain (PACKAGE, LOCALEDIR);
857 (void) textdomain (PACKAGE);
861 * Parse the command line options.
864 static struct option long_options[] = {
865 {"force", no_argument, NULL, 'f'},
866 {"help", no_argument, NULL, 'h'},
867 {"remove", no_argument, NULL, 'r'},
868 {NULL, 0, NULL, '\0'}
870 while ((c = getopt_long (argc, argv, "fhr",
871 long_options, NULL)) != -1) {
873 case 'f': /* force remove even if not owned by user */
879 case 'r': /* remove home dir and mailbox */
888 if ((optind + 1) != argc) {
894 #ifdef ACCT_TOOLS_SETUID
897 struct passwd *pampw;
898 pampw = getpwuid (getuid ()); /* local, no need for xgetpwuid */
901 _("%s: Cannot determine your user name.\n"),
906 retval = pam_start ("userdel", pampw->pw_name, &conv, &pamh);
909 if (PAM_SUCCESS == retval) {
910 retval = pam_authenticate (pamh, 0);
913 if (PAM_SUCCESS == retval) {
914 retval = pam_acct_mgmt (pamh, 0);
918 (void) pam_end (pamh, retval);
920 if (PAM_SUCCESS != retval) {
921 fprintf (stderr, _("%s: PAM authentication failed\n"), Prog);
925 #endif /* ACCT_TOOLS_SETUID */
927 is_shadow_pwd = spw_file_present ();
929 is_shadow_grp = sgr_file_present ();
930 #endif /* SHADOWGRP */
933 * Start with a quick check to see if the user exists.
935 user_name = argv[argc - 1];
938 pwd = getpwnam (user_name); /* local, no need for xgetpwnam */
940 fprintf (stderr, _("%s: user '%s' does not exist\n"),
943 audit_logger (AUDIT_DEL_USER, Prog,
944 "deleting user not found",
945 user_name, AUDIT_NO_ID,
946 SHADOW_AUDIT_FAILURE);
947 #endif /* WITH_AUDIT */
950 user_id = pwd->pw_uid;
951 user_gid = pwd->pw_gid;
952 user_home = xstrdup (pwd->pw_dir);
955 if (shadowtcb_set_user (user_name) == SHADOWTCB_FAILURE) {
958 #endif /* WITH_TCB */
962 * Now make sure it isn't an NIS user.
969 _("%s: user %s is a NIS user\n"), Prog, user_name);
970 if ( !yp_get_default_domain (&nis_domain)
971 && !yp_master (nis_domain, "passwd.byname", &nis_master)) {
973 _("%s: %s is the NIS master\n"),
980 * Check to make certain the user isn't logged in.
981 * Note: This is a best effort basis. The user may log in between,
982 * a cron job may be started on her behalf, etc.
984 if (user_busy (user_name, user_id) != 0) {
987 audit_logger (AUDIT_DEL_USER, Prog,
988 "deleting user logged in",
989 user_name, AUDIT_NO_ID,
990 SHADOW_AUDIT_FAILURE);
991 #endif /* WITH_AUDIT */
997 * Do the hard stuff - open the files, create the user entries,
998 * create the home directory, then close and update the files.
1005 errors += remove_mailbox ();
1008 int home_owned = is_owner (user_id, user_home);
1009 if (-1 == home_owned) {
1011 _("%s: %s home directory (%s) not found\n"),
1012 Prog, user_name, user_home);
1014 } else if ((0 == home_owned) && !fflg) {
1016 _("%s: %s not owned by %s, not removing\n"),
1017 Prog, user_home, user_name);
1024 #ifdef EXTRA_CHECK_HOME_DIR
1025 /* This may be slow, the above should be good enough. */
1026 if (rflg && !fflg) {
1029 * For safety, refuse to remove the home directory if it
1030 * would result in removing some other user's home
1031 * directory. Still not perfect so be careful, but should
1032 * prevent accidents if someone has /home or / as home
1033 * directory... --marekm
1036 while ((pwd = getpwent ())) {
1037 if (strcmp (pwd->pw_name, user_name) == 0) {
1040 if (path_prefix (user_home, pwd->pw_dir)) {
1042 _("%s: not removing directory %s (would remove home of user %s)\n"),
1043 Prog, user_home, pwd->pw_name);
1052 #endif /* EXTRA_CHECK_HOME_DIR */
1055 if (remove_tree (user_home, true) != 0) {
1057 _("%s: error removing directory %s\n"),
1065 audit_logger (AUDIT_DEL_USER, Prog,
1066 "deleting home directory",
1067 user_name, (unsigned int) user_id,
1068 SHADOW_AUDIT_SUCCESS);
1070 #endif /* WITH_AUDIT */
1074 audit_logger (AUDIT_DEL_USER, Prog,
1075 "deleting home directory",
1076 user_name, AUDIT_NO_ID,
1077 SHADOW_AUDIT_FAILURE);
1079 #endif /* WITH_AUDIT */
1082 if (is_selinux_enabled () > 0) {
1083 const char *args[5];
1084 args[0] = "/usr/sbin/semanage";
1087 args[3] = user_name;
1089 safe_system (args[0], args, NULL, true);
1091 #endif /* WITH_SELINUX */
1094 * Cancel any crontabs or at jobs. Have to do this before we remove
1095 * the entry from /etc/passwd.
1097 user_cancel (user_name);
1101 errors += remove_tcbdir (user_name, user_id);
1102 #endif /* WITH_TCB */
1104 nscd_flush_cache ("passwd");
1105 nscd_flush_cache ("group");
1107 return ((0 != errors) ? E_HOMEDIR : E_SUCCESS);