aboutsummaryrefslogtreecommitdiff
path: root/loginutils/deluser.c
blob: 8e7df737c0f5f504b860e548e61133f334bb49a0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
/* vi: set sw=4 ts=4: */
/*
 * deluser/delgroup implementation for busybox
 *
 * Copyright (C) 1999 by Lineo, inc. and John Beppu
 * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
 * Copyright (C) 2007 by Tito Ragusa <farmatito@tiscali.it>
 *
 * Licensed under GPLv2, see file LICENSE in this source tree.
 */
//config:config DELUSER
//config:	bool "deluser (9.1 kb)"
//config:	default y
//config:	help
//config:	Utility for deleting a user account.
//config:
//config:config DELGROUP
//config:	bool "delgroup (6.4 kb)"
//config:	default y
//config:	help
//config:	Utility for deleting a group account.
//config:
//config:config FEATURE_DEL_USER_FROM_GROUP
//config:	bool "Support removing users from groups"
//config:	default y
//config:	depends on DELGROUP
//config:	help
//config:	If called with two non-option arguments, deluser
//config:	or delgroup will remove an user from a specified group.

//                   APPLET_NOEXEC:name      main     location         suid_type     help
//applet:IF_DELUSER( APPLET_NOEXEC(deluser,  deluser, BB_DIR_USR_SBIN, BB_SUID_DROP, deluser))
//applet:IF_DELGROUP(APPLET_NOEXEC(delgroup, deluser, BB_DIR_USR_SBIN, BB_SUID_DROP, delgroup))

//kbuild:lib-$(CONFIG_DELUSER) += deluser.o
//kbuild:lib-$(CONFIG_DELGROUP) += deluser.o

//usage:#define deluser_trivial_usage
//usage:       IF_LONG_OPTS("[--remove-home] ") "USER"
//usage:#define deluser_full_usage "\n\n"
//usage:       "Delete USER from the system"
//	--remove-home is self-explanatory enough to put it in --help

//usage:#define delgroup_trivial_usage
//usage:	IF_FEATURE_DEL_USER_FROM_GROUP("[USER] ")"GROUP"
//usage:#define delgroup_full_usage "\n\n"
//usage:       "Delete group GROUP from the system"
//usage:	IF_FEATURE_DEL_USER_FROM_GROUP(" or user USER from group GROUP")

#include "libbb.h"

int deluser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int deluser_main(int argc, char **argv)
{
	/* User or group name */
	char *name;
	/* Username (non-NULL only in "delgroup USER GROUP" case) */
	char *member;
	/* Name of passwd or group file */
	const char *pfile;
	/* Name of shadow or gshadow file */
	const char *sfile;
	/* Are we deluser or delgroup? */
	int do_deluser = (ENABLE_DELUSER && (!ENABLE_DELGROUP || applet_name[3] == 'u'));

#if !ENABLE_LONG_OPTS
	const int opt_delhome = 0;
#else
	int opt_delhome = 0;
	if (do_deluser) {
		opt_delhome = getopt32long(argv, "",
				"remove-home\0" No_argument "\xff");
		argv += opt_delhome;
		argc -= opt_delhome;
	}
#endif

	if (geteuid() != 0)
		bb_simple_error_msg_and_die(bb_msg_perm_denied_are_you_root);

	name = argv[1];
	member = NULL;

	switch (argc) {
	case 3:
		if (!ENABLE_FEATURE_DEL_USER_FROM_GROUP || do_deluser)
			break;
		/* It's "delgroup USER GROUP" */
		member = name;
		name = argv[2];
		/* Fallthrough */

	case 2:
		if (do_deluser) {
			/* "deluser USER" */
			struct passwd *pw;

			pw = xgetpwnam(name); /* bail out if USER is wrong */
			pfile = bb_path_passwd_file;
			if (ENABLE_FEATURE_SHADOWPASSWDS)
				sfile = bb_path_shadow_file;
			if (opt_delhome) {
				struct stat st;

				/* Make sure home is an actual directory before
				 * removing it (e.g. users with /dev/null as home) */
				if (stat(pw->pw_dir, &st) == 0 && S_ISDIR(st.st_mode))
					remove_file(pw->pw_dir, FILEUTILS_RECUR);
			}
		} else {
			struct group *gr;
 do_delgroup:
			/* "delgroup GROUP" or "delgroup USER GROUP" */
			if (do_deluser < 0) { /* delgroup after deluser? */
				gr = getgrnam(name);
				if (!gr)
					return EXIT_SUCCESS;
			} else {
				gr = xgetgrnam(name); /* bail out if GROUP is wrong */
			}
			if (!member) {
				/* "delgroup GROUP" */
				struct passwd *pw;
				/* Check if the group is in use */
				while ((pw = getpwent()) != NULL) {
					if (pw->pw_gid == gr->gr_gid)
						bb_error_msg_and_die("'%s' still has '%s' as their primary group!",
							pw->pw_name, name);
				}
				//endpwent();
			}
			pfile = bb_path_group_file;
			if (ENABLE_FEATURE_SHADOWPASSWDS)
				sfile = bb_path_gshadow_file;
		}

		/* Modify pfile, then sfile */
		do {
			if (update_passwd(pfile, name, NULL, member) == -1)
				return EXIT_FAILURE;
			if (ENABLE_FEATURE_SHADOWPASSWDS) {
				pfile = sfile;
				sfile = NULL;
			}
		} while (ENABLE_FEATURE_SHADOWPASSWDS && pfile);

		if (do_deluser > 0) {
			/* Delete user from all groups */
			if (update_passwd(bb_path_group_file, NULL, NULL, name) == -1)
				return EXIT_FAILURE;

			if (ENABLE_DELGROUP) {
				/* "deluser USER" also should try to delete
				 * same-named group. IOW: do "delgroup USER"
				 */
// On debian deluser is a perl script that calls userdel.
// From man userdel:
//  If USERGROUPS_ENAB is defined to yes in /etc/login.defs, userdel will
//  delete the group with the same name as the user.
				do_deluser = -1;
				goto do_delgroup;
			}
		}
		return EXIT_SUCCESS;
	}
	/* Reached only if number of command line args is wrong */
	bb_show_usage();
}