]> git.pld-linux.org Git - projects/setup.git/blob - delpasswd.c
- added verifyp(), don't mess with files if there is no reason to
[projects/setup.git] / delpasswd.c
1 /*
2  * $Id$
3  * 
4  * Copyright (c) 2001 Michal Moskal <malekith@pld-linux.org>.
5  * Copyright (c) 2009 Jan RÄ™korajski <baggins@pld-linux.org>.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
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.
22  *
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
33  * SUCH DAMAGE.
34  *
35  *
36  * 
37  * USAGE: delpasswd [-u|-g] name1 name2 ...
38  *
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. 
42  *
43  * Written for PLD Linux (http://www.pld-linux.org/) setup package.
44  *
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
50  *
51  */
52
53 #include <sys/types.h>
54 #include <sys/mman.h>
55 #include <sys/stat.h>
56 #include <unistd.h>
57 #include <fcntl.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include <signal.h>
61
62 #if 0
63 #define FILE1 "passwd"
64 #define FILE2 "shadow"
65 #define FILE3 "group"
66 #define FILE4 "gshadow"
67 #else
68 #define FILE1 "/etc/passwd"
69 #define FILE2 "/etc/shadow"
70 #define FILE3 "/etc/group"
71 #define FILE4 "/etc/gshadow"
72 #endif
73
74 /* #define OLD_LOCK */
75
76 #define LOCK_FILE "/etc/.pwd.lock"
77
78 /* maybe "-" or sth? */
79 #define BACKUP ".old"
80
81 /* #define SILENT */
82
83 void eputs(const char *msg)
84 {
85         write(2, msg, strlen(msg));
86 }
87
88 void fatal(const char *msg)
89 {
90         eputs(msg);
91         eputs("\n");
92         exit(1);
93 }
94
95 char *map_file(const char *name, int *sz)
96 {
97         int fd;
98         void *ptr;
99         struct stat st;
100
101         fd = open(name, O_RDONLY);
102         if (fd == -1)
103                 return NULL;
104         if (fstat(fd, &st) < 0)
105                 return NULL;
106         *sz = st.st_size;
107         ptr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
108         if (ptr == MAP_FAILED)
109                 return NULL;
110
111         return ptr;
112 }
113
114 int exist(char *id, int id_len, int namesc, const char **names)
115 {
116         int i;
117
118         for (i = 0; i < namesc; i++) {
119                 if (strlen(names[i]) == id_len && memcmp(id, names[i], id_len) == 0)
120                         return 1;
121         }
122
123         return 0;
124 }
125
126 void itoa(char *buf, long i)
127 {
128         char tmp[32];
129         char *p;
130
131         if (i < 0) {
132                 strcpy(buf, "-");
133                 buf++;
134                 i = -i;
135         }
136         if (i == 0) {
137                 strcpy(buf, "0"); 
138                 return;
139         }
140         for (p = tmp; i; i /= 10)
141                 *p++ = (i % 10) + '0';
142         while (p > tmp)
143                 *buf++ = *--p;
144         *buf = 0;
145 }
146
147 #ifndef OLD_LOCK
148 int lock_fd = -1;
149 void noop(int x)
150 {
151         (void)x;
152 }
153 #endif
154
155 int try_lock(const char *name)
156 {
157 #ifdef OLD_LOCK
158         char file[strlen(name) + 32], lock[strlen(name) + 32];
159         char buf[32];
160         int fd;
161         long pid;
162
163         strcpy(lock, name);
164         strcpy(file, name);
165         strcat(lock, ".lock");
166         itoa(buf, (long)getpid());
167         strcat(file, ".");
168         strcat(file, buf);
169         
170         fd = open(file, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
171         if (fd < 0)
172                 return -1;
173         write(fd, buf, strlen(buf));
174         close(fd);
175
176         if (link(file, lock) == 0) {
177                 unlink(file);
178                 return 0;
179         }
180
181         fd = open(lock, O_RDONLY);
182         if (fd < 0)
183                 goto oops;
184         memset(buf, 0, sizeof(buf));
185         read(fd, buf, sizeof(buf));
186         pid = atol(buf);
187         if (pid == 0 || kill(pid, 0) != 0) {
188                 /* stale lock */
189                 unlink(file);
190                 unlink(lock);
191                 /* try again */
192                 return try_lock(name);
193         }
194
195 oops:
196         unlink(file);
197         return -1;
198 #else
199         struct flock fl;
200         
201         if (lock_fd != -1)
202                 return -1;
203         lock_fd = open(LOCK_FILE, O_RDWR|O_CREAT, 0600);
204         if (lock_fd == -1)
205                 return -1;
206         signal(SIGALRM, noop);
207         alarm(15);
208         memset(&fl, 0, sizeof(fl));
209         fl.l_type = F_WRLCK;
210         fl.l_whence = SEEK_SET;
211         if (fcntl(lock_fd, F_SETLKW, &fl) != 0) {
212                 alarm(0);
213                 close(lock_fd);
214                 lock_fd = -1;
215                 return -1;
216         }
217         alarm(0);
218         
219         return 0;
220 #endif
221 }
222
223 void unlock(const char *name)
224 {
225 #ifdef OLD_LOCK
226         char lock[strlen(name) + 32];
227
228         strcpy(lock, name);
229         strcat(lock, ".lock");
230         unlink(lock);
231 #else
232         if (lock_fd != -1)
233                 close(lock_fd);
234         lock_fd = -1;
235 #endif
236 }
237
238 void lock(const char *name)
239 {
240         int n;
241
242         n = 5;
243         while (n--) {
244                 if (try_lock(name) == 0)
245                         return;
246                 eputs("waiting for lock...\n");
247                 sleep(1);
248         }
249         fatal("cannot get lock");
250 }
251
252 int verifyp(const char *old_name, int namesc, const char **names)
253 {
254         char *old, *tmp, *id;
255         int i, fd;
256         int old_sz;
257
258         // Fail silently if file does not exist
259         if (access(old_name, F_OK) == -1)
260                 return -1;
261
262         old = map_file(backup_name, &old_sz);
263         if (old == NULL)
264                 fatal("cannot mmap old");
265         
266         for (i = 0; i < old_sz; ) {
267                 id = old + i;
268                 while (i < old_sz && old[i] != ':' && old[i] != '\n')
269                         i++;
270                 if (i < old_sz && old[i] == ':') {
271                         int id_len, line_len;
272
273                         id_len = i - (id - old);
274                         while (i < old_sz && old[i] != '\n')
275                                 i++;
276                         if (i < old_sz)
277                                 i++;
278                         line_len = i - (id - old);
279                         
280                         if (exist(id, id_len, namesc, names))
281                                 return 1;
282                 } else if (i < old_sz)
283                         i++;
284         }
285         return 0;
286 }
287
288 int delp(const char *old_name, const char *backup_name,
289                 int namesc, const char **names)
290 {
291         char *old, *tmp, *id;
292         int i, fd;
293         int old_sz;
294
295         // Fail silently if file does not exist
296         if (access(old_name, F_OK) == -1)
297                 return -1;
298
299         lock(old_name);
300         tmp = map_file(old_name, &old_sz);
301         if (tmp == NULL)
302                 fatal("cannot mmap old for backup");
303         
304         fd = open(backup_name, O_WRONLY|O_CREAT|O_TRUNC, 0600);
305         if (fd < 0)
306                 fatal("cannot make backup");
307         write(fd, tmp, old_sz);
308         close(fd);
309         
310         old = map_file(backup_name, &old_sz);
311         if (old == NULL)
312                 fatal("cannot mmap old");
313         
314 #ifndef SILENT
315         eputs("removing from `");
316         eputs(old_name);
317         eputs("'\n");
318 #endif /* SILENT */
319
320         fd = open(old_name, O_WRONLY|O_TRUNC);
321         if (fd < 0)
322                 fatal("cannot open old file");
323         
324         for (i = 0; i < old_sz; ) {
325                 id = old + i;
326                 while (i < old_sz && old[i] != ':' && old[i] != '\n')
327                         i++;
328                 if (i < old_sz && old[i] == ':') {
329                         int id_len, line_len;
330
331                         id_len = i - (id - old);
332                         while (i < old_sz && old[i] != '\n')
333                                 i++;
334                         if (i < old_sz)
335                                 i++;
336                         line_len = i - (id - old);
337                         
338                         if (!exist(id, id_len, namesc, names)) {
339                                 write(fd, id, line_len);
340                         }
341 #ifndef SILENT
342                         else {
343                                 eputs(old_name);
344                                 eputs(": removing `");
345                                 write(2, id, id_len);
346                                 eputs("'\n");
347                         }
348 #endif /* SILENT */
349                 } else if (i < old_sz)
350                         i++;
351         }
352
353         close(fd);
354         unlock(old_name);
355
356         return 0;
357 }
358
359 int main(int argc, const char **argv)
360 {
361         int what = 0;
362
363         if (argc < 3)
364                 fatal("Usage: delpasswd [-u|-g] name1 name2 ... nameN");
365
366         if (strncmp(argv[1], "-u", 2) == 0)
367                 what = 1;
368         else if (strncmp(argv[1], "-g", 2) == 0)
369                 what = 2;
370
371         if (what == 0)
372                 fatal("Usage: delpasswd [-u|-g] name1 name2 ... nameN");
373 #if 1
374         if (what == 1) {
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);
379         }
380         if (what == 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);
385         }
386 #else
387         delp("test", "test.old", argc-2, argv+2);
388 #endif
389         return 0;
390 }
This page took 0.079236 seconds and 4 git commands to generate.