PageRenderTime 54ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/tools/delpasswd.c

https://github.com/freddix/core
C | 390 lines | 281 code | 51 blank | 58 comment | 95 complexity | c70173a1ed05b5243f9912aafbdff52d MD5 | raw file
  1. /*
  2. * $Id: delpasswd.c,v 1.3 2009/03/02 00:19:02 baggins Exp $
  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. #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. #if 0
  61. #define FILE1 "passwd"
  62. #define FILE2 "shadow"
  63. #define FILE3 "group"
  64. #define FILE4 "gshadow"
  65. #else
  66. #define FILE1 "/etc/passwd"
  67. #define FILE2 "/etc/shadow"
  68. #define FILE3 "/etc/group"
  69. #define FILE4 "/etc/gshadow"
  70. #endif
  71. /* #define OLD_LOCK */
  72. #define LOCK_FILE "/etc/.pwd.lock"
  73. /* maybe "-" or sth? */
  74. #define BACKUP ".old"
  75. /* #define SILENT */
  76. void eputs(const char *msg)
  77. {
  78. write(2, msg, strlen(msg));
  79. }
  80. void fatal(const char *msg)
  81. {
  82. eputs(msg);
  83. eputs("\n");
  84. exit(1);
  85. }
  86. char *map_file(const char *name, int *sz)
  87. {
  88. int fd;
  89. void *ptr;
  90. struct stat st;
  91. fd = open(name, O_RDONLY);
  92. if (fd == -1)
  93. return NULL;
  94. if (fstat(fd, &st) < 0)
  95. return NULL;
  96. *sz = st.st_size;
  97. ptr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
  98. if (ptr == MAP_FAILED)
  99. return NULL;
  100. return ptr;
  101. }
  102. int exist(char *id, int id_len, int namesc, const char **names)
  103. {
  104. int i;
  105. for (i = 0; i < namesc; i++) {
  106. if (strlen(names[i]) == id_len && memcmp(id, names[i], id_len) == 0)
  107. return 1;
  108. }
  109. return 0;
  110. }
  111. void itoa(char *buf, long i)
  112. {
  113. char tmp[32];
  114. char *p;
  115. if (i < 0) {
  116. strcpy(buf, "-");
  117. buf++;
  118. i = -i;
  119. }
  120. if (i == 0) {
  121. strcpy(buf, "0");
  122. return;
  123. }
  124. for (p = tmp; i; i /= 10)
  125. *p++ = (i % 10) + '0';
  126. while (p > tmp)
  127. *buf++ = *--p;
  128. *buf = 0;
  129. }
  130. #ifndef OLD_LOCK
  131. int lock_fd = -1;
  132. void noop(int x)
  133. {
  134. (void)x;
  135. }
  136. #endif
  137. int try_lock(const char *name)
  138. {
  139. #ifdef OLD_LOCK
  140. char file[strlen(name) + 32], lock[strlen(name) + 32];
  141. char buf[32];
  142. int fd;
  143. long pid;
  144. strcpy(lock, name);
  145. strcpy(file, name);
  146. strcat(lock, ".lock");
  147. itoa(buf, (long)getpid());
  148. strcat(file, ".");
  149. strcat(file, buf);
  150. fd = open(file, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
  151. if (fd < 0)
  152. return -1;
  153. write(fd, buf, strlen(buf));
  154. close(fd);
  155. if (link(file, lock) == 0) {
  156. unlink(file);
  157. return 0;
  158. }
  159. fd = open(lock, O_RDONLY);
  160. if (fd < 0)
  161. goto oops;
  162. memset(buf, 0, sizeof(buf));
  163. read(fd, buf, sizeof(buf));
  164. pid = atol(buf);
  165. if (pid == 0 || kill(pid, 0) != 0) {
  166. /* stale lock */
  167. unlink(file);
  168. unlink(lock);
  169. /* try again */
  170. return try_lock(name);
  171. }
  172. oops:
  173. unlink(file);
  174. return -1;
  175. #else
  176. struct flock fl;
  177. if (lock_fd != -1)
  178. return -1;
  179. lock_fd = open(LOCK_FILE, O_RDWR|O_CREAT, 0600);
  180. if (lock_fd == -1)
  181. return -1;
  182. signal(SIGALRM, noop);
  183. alarm(15);
  184. memset(&fl, 0, sizeof(fl));
  185. fl.l_type = F_WRLCK;
  186. fl.l_whence = SEEK_SET;
  187. if (fcntl(lock_fd, F_SETLKW, &fl) != 0) {
  188. alarm(0);
  189. close(lock_fd);
  190. lock_fd = -1;
  191. return -1;
  192. }
  193. alarm(0);
  194. return 0;
  195. #endif
  196. }
  197. void unlock(const char *name)
  198. {
  199. #ifdef OLD_LOCK
  200. char lock[strlen(name) + 32];
  201. strcpy(lock, name);
  202. strcat(lock, ".lock");
  203. unlink(lock);
  204. #else
  205. if (lock_fd != -1)
  206. close(lock_fd);
  207. lock_fd = -1;
  208. #endif
  209. }
  210. void lock(const char *name)
  211. {
  212. int n;
  213. n = 5;
  214. while (n--) {
  215. if (try_lock(name) == 0)
  216. return;
  217. eputs("waiting for lock...\n");
  218. sleep(1);
  219. }
  220. fatal("cannot get lock");
  221. }
  222. int verifyp(const char *old_name, int namesc, const char **names)
  223. {
  224. char *old, *id;
  225. int i;
  226. int old_sz;
  227. // Fail silently if file does not exist
  228. if (access(old_name, F_OK) == -1)
  229. return -1;
  230. old = map_file(old_name, &old_sz);
  231. if (old == NULL)
  232. fatal("cannot mmap old");
  233. for (i = 0; i < old_sz; ) {
  234. id = old + i;
  235. while (i < old_sz && old[i] != ':' && old[i] != '\n')
  236. i++;
  237. if (i < old_sz && old[i] == ':') {
  238. int id_len, line_len;
  239. id_len = i - (id - old);
  240. while (i < old_sz && old[i] != '\n')
  241. i++;
  242. if (i < old_sz)
  243. i++;
  244. line_len = i - (id - old);
  245. if (exist(id, id_len, namesc, names))
  246. return 1;
  247. } else if (i < old_sz)
  248. i++;
  249. }
  250. return 0;
  251. }
  252. int delp(const char *old_name, const char *backup_name,
  253. int namesc, const char **names)
  254. {
  255. char *old, *tmp, *id;
  256. int i, fd;
  257. int old_sz;
  258. // Fail silently if file does not exist
  259. if (access(old_name, F_OK) == -1)
  260. return -1;
  261. lock(old_name);
  262. tmp = map_file(old_name, &old_sz);
  263. if (tmp == NULL)
  264. fatal("cannot mmap old for backup");
  265. fd = open(backup_name, O_WRONLY|O_CREAT|O_TRUNC, 0600);
  266. if (fd < 0)
  267. fatal("cannot make backup");
  268. write(fd, tmp, old_sz);
  269. close(fd);
  270. old = map_file(backup_name, &old_sz);
  271. if (old == NULL)
  272. fatal("cannot mmap old");
  273. #ifndef SILENT
  274. eputs("removing from `");
  275. eputs(old_name);
  276. eputs("'\n");
  277. #endif /* SILENT */
  278. fd = open(old_name, O_WRONLY|O_TRUNC);
  279. if (fd < 0)
  280. fatal("cannot open old file");
  281. for (i = 0; i < old_sz; ) {
  282. id = old + i;
  283. while (i < old_sz && old[i] != ':' && old[i] != '\n')
  284. i++;
  285. if (i < old_sz && old[i] == ':') {
  286. int id_len, line_len;
  287. id_len = i - (id - old);
  288. while (i < old_sz && old[i] != '\n')
  289. i++;
  290. if (i < old_sz)
  291. i++;
  292. line_len = i - (id - old);
  293. if (!exist(id, id_len, namesc, names)) {
  294. write(fd, id, line_len);
  295. }
  296. #ifndef SILENT
  297. else {
  298. eputs(old_name);
  299. eputs(": removing `");
  300. write(2, id, id_len);
  301. eputs("'\n");
  302. }
  303. #endif /* SILENT */
  304. } else if (i < old_sz)
  305. i++;
  306. }
  307. close(fd);
  308. unlock(old_name);
  309. return 0;
  310. }
  311. int main(int argc, const char **argv)
  312. {
  313. int what = 0;
  314. if (argc < 3)
  315. fatal("Usage: delpasswd [-u|-g] name1 name2 ... nameN");
  316. if (strncmp(argv[1], "-u", 2) == 0)
  317. what = 1;
  318. else if (strncmp(argv[1], "-g", 2) == 0)
  319. what = 2;
  320. if (what == 0)
  321. fatal("Usage: delpasswd [-u|-g] name1 name2 ... nameN");
  322. #if 1
  323. if (what == 1) {
  324. if (verifyp(FILE1, argc-2, argv+2))
  325. delp(FILE1, FILE1 BACKUP, argc-2, argv+2);
  326. if (verifyp(FILE2, argc-2, argv+2))
  327. delp(FILE2, FILE2 BACKUP, argc-2, argv+2);
  328. }
  329. if (what == 2) {
  330. if (verifyp(FILE3, argc-2, argv+2))
  331. delp(FILE3, FILE3 BACKUP, argc-2, argv+2);
  332. if (verifyp(FILE4, argc-2, argv+2))
  333. delp(FILE4, FILE4 BACKUP, argc-2, argv+2);
  334. }
  335. #else
  336. delp("test", "test.old", argc-2, argv+2);
  337. #endif
  338. return 0;
  339. }