]> git.pld-linux.org Git - projects/setup.git/blob - delpasswd.c
add etc/sub[ug]id
[projects/setup.git] / delpasswd.c
1 /*
2  * 
3  * Copyright (c) 2001 Michal Moskal <malekith@pld-linux.org>.
4  * Copyright (c) 2009 Jan RÄ™korajski <baggins@pld-linux.org>.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by Michal Moskal.
18  * 4. Neither the name of the author nor the names of any co-contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY MICHAL MOSKAL AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  *
35  * 
36  * USAGE: delpasswd [-u|-g] name1 name2 ...
37  *
38  * Remove specified groups from /etc/{passwd,shadow,group}.
39  * It is usable as part of setup package, during upgrade where some system
40  * users/groups should be removed. UIDs/GIDs are *not* checked anyhow. 
41  *
42  * Written for PLD Linux (http://www.pld-linux.org/) setup package.
43  *
44  * Compilation against uClibc:
45  * UCROOT=/usr/lib/bootdisk/usr
46  * gcc -I$UCROOT/include -nostdlib -O2 delpasswd.c $UCROOT/lib/crt0.o \
47  *              $UCROOT/lib/libc.a -lgcc -o delpasswd
48  * strip -R .comment -R .note delpasswd
49  *
50  */
51
52 #include <sys/types.h>
53 #include <sys/mman.h>
54 #include <sys/stat.h>
55 #include <unistd.h>
56 #include <fcntl.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include <signal.h>
60
61 #if 0
62 #define FILE1 "passwd"
63 #define FILE2 "shadow"
64 #define FILE3 "group"
65 #define FILE4 "gshadow"
66 #else
67 #define FILE1 "/etc/passwd"
68 #define FILE2 "/etc/shadow"
69 #define FILE3 "/etc/group"
70 #define FILE4 "/etc/gshadow"
71 #endif
72
73 /* #define OLD_LOCK */
74
75 #define LOCK_FILE "/etc/.pwd.lock"
76
77 /* maybe "-" or sth? */
78 #define BACKUP ".old"
79
80 /* #define SILENT */
81
82 void eputs(const char *msg)
83 {
84         write(2, msg, strlen(msg));
85 }
86
87 void fatal(const char *msg)
88 {
89         eputs(msg);
90         eputs("\n");
91         exit(1);
92 }
93
94 char *map_file(const char *name, ssize_t *sz)
95 {
96         int fd;
97         void *ptr;
98         struct stat st;
99
100         fd = open(name, O_RDONLY);
101         if (fd == -1)
102                 return NULL;
103         if (fstat(fd, &st) < 0)
104                 return NULL;
105         *sz = st.st_size;
106         ptr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
107         if (ptr == MAP_FAILED)
108                 return NULL;
109
110         return ptr;
111 }
112
113 int exist(char *id, int id_len, int namesc, const char **names)
114 {
115         int i;
116
117         for (i = 0; i < namesc; i++) {
118                 if (strlen(names[i]) == id_len && memcmp(id, names[i], id_len) == 0)
119                         return 1;
120         }
121
122         return 0;
123 }
124
125 void itoa(char *buf, long i)
126 {
127         char tmp[32];
128         char *p;
129
130         if (i < 0) {
131                 strcpy(buf, "-");
132                 buf++;
133                 i = -i;
134         }
135         if (i == 0) {
136                 strcpy(buf, "0"); 
137                 return;
138         }
139         for (p = tmp; i; i /= 10)
140                 *p++ = (i % 10) + '0';
141         while (p > tmp)
142                 *buf++ = *--p;
143         *buf = 0;
144 }
145
146 #ifndef OLD_LOCK
147 int lock_fd = -1;
148 void noop(int x)
149 {
150         (void)x;
151 }
152 #endif
153
154 int try_lock(const char *name)
155 {
156 #ifdef OLD_LOCK
157         char file[strlen(name) + 32], lock[strlen(name) + 32];
158         char buf[32];
159         int fd;
160         long pid;
161
162         strcpy(lock, name);
163         strcpy(file, name);
164         strcat(lock, ".lock");
165         itoa(buf, (long)getpid());
166         strcat(file, ".");
167         strcat(file, buf);
168         
169         fd = open(file, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
170         if (fd < 0)
171                 return -1;
172         write(fd, buf, strlen(buf));
173         close(fd);
174
175         if (link(file, lock) == 0) {
176                 unlink(file);
177                 return 0;
178         }
179
180         fd = open(lock, O_RDONLY);
181         if (fd < 0)
182                 goto oops;
183         memset(buf, 0, sizeof(buf));
184         read(fd, buf, sizeof(buf));
185         pid = atol(buf);
186         if (pid == 0 || kill(pid, 0) != 0) {
187                 /* stale lock */
188                 unlink(file);
189                 unlink(lock);
190                 /* try again */
191                 return try_lock(name);
192         }
193
194 oops:
195         unlink(file);
196         return -1;
197 #else
198         struct flock fl;
199         
200         if (lock_fd != -1)
201                 return -1;
202         lock_fd = open(LOCK_FILE, O_RDWR|O_CREAT, 0600);
203         if (lock_fd == -1)
204                 return -1;
205         signal(SIGALRM, noop);
206         alarm(15);
207         memset(&fl, 0, sizeof(fl));
208         fl.l_type = F_WRLCK;
209         fl.l_whence = SEEK_SET;
210         if (fcntl(lock_fd, F_SETLKW, &fl) != 0) {
211                 alarm(0);
212                 close(lock_fd);
213                 lock_fd = -1;
214                 return -1;
215         }
216         alarm(0);
217         
218         return 0;
219 #endif
220 }
221
222 void unlock(const char *name)
223 {
224 #ifdef OLD_LOCK
225         char lock[strlen(name) + 32];
226
227         strcpy(lock, name);
228         strcat(lock, ".lock");
229         unlink(lock);
230 #else
231         if (lock_fd != -1)
232                 close(lock_fd);
233         lock_fd = -1;
234 #endif
235 }
236
237 void lock(const char *name)
238 {
239         int n;
240
241         n = 5;
242         while (n--) {
243                 if (try_lock(name) == 0)
244                         return;
245                 eputs("waiting for lock...\n");
246                 sleep(1);
247         }
248         fatal("cannot get lock");
249 }
250
251 int verifyp(const char *old_name, int namesc, const char **names)
252 {
253         char *old, *id;
254         ssize_t i, old_sz;
255
256         // Fail silently if file does not exist
257         if (access(old_name, F_OK) == -1)
258                 return -1;
259
260         old = map_file(old_name, &old_sz);
261         if (old == NULL)
262                 fatal("cannot mmap old");
263         
264         for (i = 0; i < old_sz; ) {
265                 id = old + i;
266                 while (i < old_sz && old[i] != ':' && old[i] != '\n')
267                         i++;
268                 if (i < old_sz && old[i] == ':') {
269                         int id_len;
270
271                         id_len = i - (id - old);
272                         while (i < old_sz && old[i] != '\n')
273                                 i++;
274                         if (i < old_sz)
275                                 i++;
276
277                         if (exist(id, id_len, namesc, names))
278                                 return 1;
279                 } else if (i < old_sz)
280                         i++;
281         }
282         return 0;
283 }
284
285 int delp(const char *old_name, const char *backup_name,
286                 int namesc, const char **names)
287 {
288         char *old, *tmp, *id;
289         int fd;
290         ssize_t i, old_sz;
291
292         // Fail silently if file does not exist
293         if (access(old_name, F_OK) == -1)
294                 return -1;
295
296         lock(old_name);
297         tmp = map_file(old_name, &old_sz);
298         if (tmp == NULL)
299                 fatal("cannot mmap old for backup");
300         
301         fd = open(backup_name, O_WRONLY|O_CREAT|O_TRUNC, 0600);
302         if (fd < 0)
303                 fatal("cannot make backup");
304         if (write(fd, tmp, old_sz) < 0)
305                 fatal("writting to backup failed");
306         close(fd);
307         
308         old = map_file(backup_name, &old_sz);
309         if (old == NULL)
310                 fatal("cannot mmap old");
311         
312 #ifndef SILENT
313         eputs("removing from `");
314         eputs(old_name);
315         eputs("'\n");
316 #endif /* SILENT */
317
318         fd = open(old_name, O_WRONLY|O_TRUNC);
319         if (fd < 0)
320                 fatal("cannot open old file");
321         
322         for (i = 0; i < old_sz; ) {
323                 id = old + i;
324                 while (i < old_sz && old[i] != ':' && old[i] != '\n')
325                         i++;
326                 if (i < old_sz && old[i] == ':') {
327                         int id_len, line_len;
328
329                         id_len = i - (id - old);
330                         while (i < old_sz && old[i] != '\n')
331                                 i++;
332                         if (i < old_sz)
333                                 i++;
334                         line_len = i - (id - old);
335                         
336                         if (!exist(id, id_len, namesc, names)) {
337                                 write(fd, id, line_len);
338                         }
339 #ifndef SILENT
340                         else {
341                                 eputs(old_name);
342                                 eputs(": removing `");
343                                 write(2, id, id_len);
344                                 eputs("'\n");
345                         }
346 #endif /* SILENT */
347                 } else if (i < old_sz)
348                         i++;
349         }
350
351         close(fd);
352         unlock(old_name);
353
354         return 0;
355 }
356
357 int main(int argc, const char **argv)
358 {
359         int what = 0;
360
361         if (argc < 3)
362                 fatal("Usage: delpasswd [-u|-g] name1 name2 ... nameN");
363
364         if (strncmp(argv[1], "-u", 2) == 0)
365                 what = 1;
366         else if (strncmp(argv[1], "-g", 2) == 0)
367                 what = 2;
368
369         if (what == 0)
370                 fatal("Usage: delpasswd [-u|-g] name1 name2 ... nameN");
371 #if 1
372         if (what == 1) {
373                 if (verifyp(FILE1, argc-2, argv+2))
374                         delp(FILE1, FILE1 BACKUP, argc-2, argv+2);
375                 if (verifyp(FILE2, argc-2, argv+2))
376                         delp(FILE2, FILE2 BACKUP, argc-2, argv+2);
377         }
378         if (what == 2) {
379                 if (verifyp(FILE3, argc-2, argv+2))
380                         delp(FILE3, FILE3 BACKUP, argc-2, argv+2);
381                 if (verifyp(FILE4, argc-2, argv+2))
382                         delp(FILE4, FILE4 BACKUP, argc-2, argv+2);
383         }
384 #else
385         delp("test", "test.old", argc-2, argv+2);
386 #endif
387         return 0;
388 }
This page took 0.058566 seconds and 3 git commands to generate.