Bigger patch for (partial) tinylogin integration
[platform/upstream/busybox.git] / loginutils / deluser.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * deluser (remove lusers from the system ;) for TinyLogin
4  *
5  * Copyright (C) 1999 by Lineo, inc. and John Beppu
6  * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21  *
22  */
23
24 #include <sys/stat.h>
25 #include <unistd.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include "busybox.h"
30
31 #define PASSWD_FILE     "/etc/passwd"
32 #define GROUP_FILE      "/etc/group"
33 #define SHADOW_FILE             "/etc/shadow"
34 #define GSHADOW_FILE    "/etc/gshadow"
35
36
37 /* where to start and stop deletion */
38 typedef struct {
39         size_t start;
40         size_t stop;
41 } Bounds;
42
43 /* An interesting side-effect of boundary()'s
44  * implementation is that the first user (typically root)
45  * cannot be removed.  Let's call it a feature. */
46 static inline Bounds boundary(const char *buffer, const char *login)
47 {
48         char needle[256];
49         char *start;
50         char *stop;
51         Bounds b;
52
53         snprintf(needle, 256, "\n%s:", login);
54         needle[255] = 0;
55         start = strstr(buffer, needle);
56         if (!start) {
57                 b.start = 0;
58                 b.stop = 0;
59                 return b;
60         }
61         start++;
62
63         stop = index(start, '\n');      /* index is a BSD-ism */
64         b.start = start - buffer;
65         b.stop = stop - buffer;
66         return b;
67 }
68
69 /* grep -v ^login (except it only deletes the first match) */
70 /* ...in fact, I think I'm going to simplify this later */
71 static int del_line_matching(const char *login, const char *filename)
72 {
73         char *buffer;
74         FILE *passwd;
75         size_t len;
76         Bounds b;
77         struct stat statbuf;
78
79         /* load into buffer */
80         passwd = fopen(filename, "r");
81         if (!passwd) {
82                 return 1;
83         }
84         stat(filename, &statbuf);
85         len = statbuf.st_size;
86         buffer = (char *) malloc(len * sizeof(char));
87
88         if (!buffer) {
89                 fclose(passwd);
90                 return 1;
91         }
92         fread(buffer, len, sizeof(char), passwd);
93
94         fclose(passwd);
95
96         /* find the user to remove */
97         b = boundary(buffer, login);
98         if (b.stop == 0) {
99                 free(buffer);
100                 return 1;
101         }
102
103         /* write the file w/o the user */
104         passwd = fopen(filename, "w");
105         if (!passwd) {
106                 return 1;
107         }
108         fwrite(buffer, (b.start - 1), sizeof(char), passwd);
109         fwrite(&buffer[b.stop], (len - b.stop), sizeof(char), passwd);
110
111         fclose(passwd);
112
113         return 0;
114 }
115
116 /* ________________________________________________________________________ */
117 int delgroup_main(int argc, char **argv)
118 {
119         /* int successful; */
120         int failure;
121
122         if (argc != 2) {
123                 show_usage();
124         } else {
125
126                 failure = del_line_matching(argv[1], GROUP_FILE);
127 #ifdef CONFIG_FEATURE_SHADOWPASSWDS
128                 if (access(GSHADOW_FILE, W_OK) == 0) {
129                         /* EDR the |= works if the error is not 0, so he had it wrong */
130                         failure |= del_line_matching(argv[1], GSHADOW_FILE);
131                 }
132 #endif                                                  /* CONFIG_FEATURE_SHADOWPASSWDS */
133                 /* if (!successful) { */
134                 if (failure) {
135                         error_msg_and_die("%s: Group could not be removed\n", argv[1]);
136                 }
137
138         }
139         return (EXIT_SUCCESS);
140 }
141
142 /* ________________________________________________________________________ */
143 int deluser_main(int argc, char **argv)
144 {
145         /* int successful; */
146         int failure;
147
148         if (argc != 2) {
149                 show_usage();
150         } else {
151
152                 failure = del_line_matching(argv[1], PASSWD_FILE);
153                 /* if (!successful) { */
154                 if (failure) {
155                         error_msg_and_die("%s: User could not be removed from %s\n",
156                                                           argv[1], PASSWD_FILE);
157                 }
158 #ifdef CONFIG_FEATURE_SHADOWPASSWDS
159                 failure = del_line_matching(argv[1], SHADOW_FILE);
160                 /* if (!successful) { */
161                 if (failure) {
162                         error_msg_and_die("%s: User could not be removed from %s\n",
163                                                           argv[1], SHADOW_FILE);
164                 }
165                 failure = del_line_matching(argv[1], GSHADOW_FILE);
166                 /* if (!successful) { */
167                 if (failure) {
168                         error_msg_and_die("%s: User could not be removed from %s\n",
169                                                           argv[1], GSHADOW_FILE);
170                 }
171 #endif                                                  /* CONFIG_FEATURE_SHADOWPASSWDS */
172                 failure = del_line_matching(argv[1], GROUP_FILE);
173                 /* if (!successful) { */
174                 if (failure) {
175                         error_msg_and_die("%s: User could not be removed from %s\n",
176                                                           argv[1], GROUP_FILE);
177                 }
178
179         }
180         return (EXIT_SUCCESS);
181 }
182
183 /* $Id: deluser.c,v 1.1 2002/06/04 20:45:05 sandman Exp $ */