4 * Copyright (c) 2001 Michal Moskal <malekith@pld-linux.org>.
5 * Copyright (c) 2009 Jan Rękorajski <baggins@pld-linux.org>.
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. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Michal Moskal.
19 * 4. Neither the name of the author nor the names of any co-contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY MICHAL MOSKAL AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * USAGE: delpasswd [-u|-g] name1 name2 ...
39 * Remove specified groups from /etc/{passwd,shadow,group}.
40 * It is usable as part of setup package, during upgrade where some system
41 * users/groups should be removed. UIDs/GIDs are *not* checked anyhow.
43 * Written for PLD Linux (http://www.pld-linux.org/) setup package.
45 * Compilation against uClibc:
46 * UCROOT=/usr/lib/bootdisk/usr
47 * gcc -I$UCROOT/include -nostdlib -O2 delpasswd.c $UCROOT/lib/crt0.o \
48 * $UCROOT/lib/libc.a -lgcc -o delpasswd
49 * strip -R .comment -R .note delpasswd
53 #include <sys/types.h>
63 #define FILE1 "passwd"
64 #define FILE2 "shadow"
66 #define FILE4 "gshadow"
68 #define FILE1 "/etc/passwd"
69 #define FILE2 "/etc/shadow"
70 #define FILE3 "/etc/group"
71 #define FILE4 "/etc/gshadow"
74 /* #define OLD_LOCK */
76 #define LOCK_FILE "/etc/.pwd.lock"
78 /* maybe "-" or sth? */
83 void eputs(const char *msg)
85 write(2, msg, strlen(msg));
88 void fatal(const char *msg)
95 char *map_file(const char *name, int *sz)
101 fd = open(name, O_RDONLY);
104 if (fstat(fd, &st) < 0)
107 ptr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
108 if (ptr == MAP_FAILED)
114 int exist(char *id, int id_len, int namesc, const char **names)
118 for (i = 0; i < namesc; i++) {
119 if (strlen(names[i]) == id_len && memcmp(id, names[i], id_len) == 0)
126 void itoa(char *buf, long i)
140 for (p = tmp; i; i /= 10)
141 *p++ = (i % 10) + '0';
155 int try_lock(const char *name)
158 char file[strlen(name) + 32], lock[strlen(name) + 32];
165 strcat(lock, ".lock");
166 itoa(buf, (long)getpid());
170 fd = open(file, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
173 write(fd, buf, strlen(buf));
176 if (link(file, lock) == 0) {
181 fd = open(lock, O_RDONLY);
184 memset(buf, 0, sizeof(buf));
185 read(fd, buf, sizeof(buf));
187 if (pid == 0 || kill(pid, 0) != 0) {
192 return try_lock(name);
203 lock_fd = open(LOCK_FILE, O_RDWR|O_CREAT, 0600);
206 signal(SIGALRM, noop);
208 memset(&fl, 0, sizeof(fl));
210 fl.l_whence = SEEK_SET;
211 if (fcntl(lock_fd, F_SETLKW, &fl) != 0) {
223 void unlock(const char *name)
226 char lock[strlen(name) + 32];
229 strcat(lock, ".lock");
238 void lock(const char *name)
244 if (try_lock(name) == 0)
246 eputs("waiting for lock...\n");
249 fatal("cannot get lock");
252 int verifyp(const char *old_name, int namesc, const char **names)
254 char *old, *tmp, *id;
258 // Fail silently if file does not exist
259 if (access(old_name, F_OK) == -1)
262 old = map_file(backup_name, &old_sz);
264 fatal("cannot mmap old");
266 for (i = 0; i < old_sz; ) {
268 while (i < old_sz && old[i] != ':' && old[i] != '\n')
270 if (i < old_sz && old[i] == ':') {
271 int id_len, line_len;
273 id_len = i - (id - old);
274 while (i < old_sz && old[i] != '\n')
278 line_len = i - (id - old);
280 if (exist(id, id_len, namesc, names))
282 } else if (i < old_sz)
288 int delp(const char *old_name, const char *backup_name,
289 int namesc, const char **names)
291 char *old, *tmp, *id;
295 // Fail silently if file does not exist
296 if (access(old_name, F_OK) == -1)
300 tmp = map_file(old_name, &old_sz);
302 fatal("cannot mmap old for backup");
304 fd = open(backup_name, O_WRONLY|O_CREAT|O_TRUNC, 0600);
306 fatal("cannot make backup");
307 write(fd, tmp, old_sz);
310 old = map_file(backup_name, &old_sz);
312 fatal("cannot mmap old");
315 eputs("removing from `");
320 fd = open(old_name, O_WRONLY|O_TRUNC);
322 fatal("cannot open old file");
324 for (i = 0; i < old_sz; ) {
326 while (i < old_sz && old[i] != ':' && old[i] != '\n')
328 if (i < old_sz && old[i] == ':') {
329 int id_len, line_len;
331 id_len = i - (id - old);
332 while (i < old_sz && old[i] != '\n')
336 line_len = i - (id - old);
338 if (!exist(id, id_len, namesc, names)) {
339 write(fd, id, line_len);
344 eputs(": removing `");
345 write(2, id, id_len);
349 } else if (i < old_sz)
359 int main(int argc, const char **argv)
364 fatal("Usage: delpasswd [-u|-g] name1 name2 ... nameN");
366 if (strncmp(argv[1], "-u", 2) == 0)
368 else if (strncmp(argv[1], "-g", 2) == 0)
372 fatal("Usage: delpasswd [-u|-g] name1 name2 ... nameN");
375 if (verifyp(FILE1, argc-2, argv+2))
376 delp(FILE1, FILE1 BACKUP, argc-2, argv+2);
377 if (verifyp(FILE2, argc-2, argv+2))
378 delp(FILE2, FILE2 BACKUP, argc-2, argv+2);
381 if (verifyp(FILE3, argc-2, argv+2))
382 delp(FILE3, FILE3 BACKUP, argc-2, argv+2);
383 if (verifyp(FILE4, argc-2, argv+2))
384 delp(FILE4, FILE4 BACKUP, argc-2, argv+2);
387 delp("test", "test.old", argc-2, argv+2);