]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blob - misc/uuidd.c
Merge branch 'maint' into next
[thirdparty/e2fsprogs.git] / misc / uuidd.c
1 /*
2 * uuidd.c --- UUID-generation daemon
3 *
4 * Copyright (C) 2007 Theodore Ts'o
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12 #define _GNU_SOURCE /* for setres[ug]id() */
13
14 #include "config.h"
15 #include <stdio.h>
16 #ifdef HAVE_STDLIB_H
17 #include <stdlib.h>
18 #endif
19 #include <unistd.h>
20 #include <inttypes.h>
21 #include <errno.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <sys/socket.h>
25 #include <sys/un.h>
26 #include <fcntl.h>
27 #include <signal.h>
28 #include <string.h>
29 #ifdef HAVE_GETOPT_H
30 #include <getopt.h>
31 #else
32 extern int getopt(int argc, char * const argv[], const char *optstring);
33 extern char *optarg;
34 extern int optind;
35 #endif
36 #include "uuid/uuid.h"
37 #include "uuid/uuidd.h"
38 #include "nls-enable.h"
39
40 #ifdef __GNUC__
41 #define CODE_ATTR(x) __attribute__(x)
42 #else
43 #define CODE_ATTR(x)
44 #endif
45
46 static void usage(const char *progname)
47 {
48 fprintf(stderr, _("Usage: %s [-d] [-p pidfile] [-s socketpath] "
49 "[-T timeout]\n"), progname);
50 fprintf(stderr, _(" %s [-r|t] [-n num] [-s socketpath]\n"),
51 progname);
52 fprintf(stderr, _(" %s -k\n"), progname);
53 exit(1);
54 }
55
56 static void die(const char *msg)
57 {
58 perror(msg);
59 exit(1);
60 }
61
62 static void create_daemon(void)
63 {
64 pid_t pid;
65 uid_t euid;
66
67 pid = fork();
68 if (pid == -1) {
69 perror("fork");
70 exit(1);
71 } else if (pid != 0) {
72 exit(0);
73 }
74
75 close(0);
76 close(1);
77 close(2);
78 open("/dev/null", O_RDWR);
79 open("/dev/null", O_RDWR);
80 open("/dev/null", O_RDWR);
81
82 if (chdir("/")) {} /* Silence warn_unused_result warning */
83 (void) setsid();
84 euid = geteuid();
85 if (setreuid(euid, euid) < 0)
86 die("setreuid");
87 }
88
89 static ssize_t read_all(int fd, char *buf, size_t count)
90 {
91 ssize_t ret;
92 ssize_t c = 0;
93 int tries = 0;
94
95 memset(buf, 0, count);
96 while (count > 0) {
97 ret = read(fd, buf, count);
98 if (ret <= 0) {
99 if ((errno == EAGAIN || errno == EINTR || ret == 0) &&
100 (tries++ < 5))
101 continue;
102 return c ? c : -1;
103 }
104 if (ret > 0)
105 tries = 0;
106 count -= ret;
107 buf += ret;
108 c += ret;
109 }
110 return c;
111 }
112
113 static int write_all(int fd, char *buf, size_t count)
114 {
115 ssize_t ret;
116 int c = 0;
117
118 while (count > 0) {
119 ret = write(fd, buf, count);
120 if (ret < 0) {
121 if ((errno == EAGAIN) || (errno == EINTR))
122 continue;
123 return -1;
124 }
125 count -= ret;
126 buf += ret;
127 c += ret;
128 }
129 return c;
130 }
131
132 static const char *cleanup_pidfile, *cleanup_socket;
133
134 static void terminate_intr(int signo CODE_ATTR((unused)))
135 {
136 (void) unlink(cleanup_pidfile);
137 if (cleanup_socket)
138 (void) unlink(cleanup_socket);
139 exit(0);
140 }
141
142 static int call_daemon(const char *socket_path, int op, char *buf,
143 int buflen, int *num, const char **err_context)
144 {
145 char op_buf[8];
146 int op_len;
147 int s;
148 ssize_t ret;
149 int32_t reply_len = 0;
150 struct sockaddr_un srv_addr;
151
152 if (((op == 4) || (op == 5)) && !num) {
153 if (err_context)
154 *err_context = _("bad arguments");
155 errno = EINVAL;
156 return -1;
157 }
158
159 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
160 if (err_context)
161 *err_context = _("socket");
162 return -1;
163 }
164
165 srv_addr.sun_family = AF_UNIX;
166 strncpy(srv_addr.sun_path, socket_path, sizeof(srv_addr.sun_path));
167 srv_addr.sun_path[sizeof(srv_addr.sun_path)-1] = '\0';
168
169 if (connect(s, (const struct sockaddr *) &srv_addr,
170 sizeof(struct sockaddr_un)) < 0) {
171 if (err_context)
172 *err_context = _("connect");
173 close(s);
174 return -1;
175 }
176
177 if (op == 5) {
178 if ((*num)*16 > buflen-4)
179 *num = (buflen-4) / 16;
180 }
181 op_buf[0] = op;
182 op_len = 1;
183 if ((op == 4) || (op == 5)) {
184 memcpy(op_buf+1, num, sizeof(int));
185 op_len += sizeof(int);
186 }
187
188 ret = write_all(s, op_buf, op_len);
189 if (ret < op_len) {
190 if (err_context)
191 *err_context = _("write");
192 close(s);
193 return -1;
194 }
195
196 ret = read_all(s, (char *) &reply_len, sizeof(reply_len));
197 if (ret < 0) {
198 if (err_context)
199 *err_context = _("read count");
200 close(s);
201 return -1;
202 }
203 if (reply_len < 0 || reply_len > buflen) {
204 if (err_context)
205 *err_context = _("bad response length");
206 close(s);
207 return -1;
208 }
209 ret = read_all(s, (char *) buf, reply_len);
210
211 if ((ret > 0) && (op == 4)) {
212 if (reply_len >= (int) (16+sizeof(int)))
213 memcpy(buf+16, num, sizeof(int));
214 else
215 *num = -1;
216 }
217 if ((ret > 0) && (op == 5)) {
218 if (*num >= (int) sizeof(int))
219 memcpy(buf, num, sizeof(int));
220 else
221 *num = -1;
222 }
223
224 close(s);
225
226 return ret;
227 }
228
229 static void server_loop(const char *socket_path, const char *pidfile_path,
230 int debug, int timeout, int quiet)
231 {
232 struct sockaddr_un my_addr, from_addr;
233 struct flock fl;
234 socklen_t fromlen;
235 int32_t reply_len = 0;
236 uuid_t uu;
237 mode_t save_umask;
238 char reply_buf[1024], *cp;
239 char op, str[37];
240 int i, s, ns, len, num;
241 int fd_pidfile, ret;
242
243 fd_pidfile = open(pidfile_path, O_CREAT | O_RDWR, 0664);
244 if (fd_pidfile < 0) {
245 if (!quiet)
246 fprintf(stderr, "Failed to open/create %s: %s\n",
247 pidfile_path, strerror(errno));
248 exit(1);
249 }
250 cleanup_pidfile = pidfile_path;
251 cleanup_socket = 0;
252 signal(SIGALRM, terminate_intr);
253 alarm(30);
254 fl.l_type = F_WRLCK;
255 fl.l_whence = SEEK_SET;
256 fl.l_start = 0;
257 fl.l_len = 0;
258 fl.l_pid = 0;
259 while (fcntl(fd_pidfile, F_SETLKW, &fl) < 0) {
260 if ((errno == EAGAIN) || (errno == EINTR))
261 continue;
262 if (!quiet)
263 fprintf(stderr, "Failed to lock %s: %s\n",
264 pidfile_path, strerror(errno));
265 exit(1);
266 }
267 ret = call_daemon(socket_path, 0, reply_buf, sizeof(reply_buf), 0, 0);
268 if (ret > 0) {
269 if (!quiet)
270 printf(_("uuidd daemon already running at pid %s\n"),
271 reply_buf);
272 exit(1);
273 }
274 alarm(0);
275
276 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
277 if (!quiet)
278 fprintf(stderr, _("Couldn't create unix stream "
279 "socket: %s"), strerror(errno));
280 exit(1);
281 }
282
283 /*
284 * Make sure the socket isn't using fd numbers 0-2 to avoid it
285 * getting closed by create_daemon()
286 */
287 while (!debug && s <= 2) {
288 s = dup(s);
289 if (s < 0) {
290 perror("dup");
291 exit(1);
292 }
293 }
294
295 /*
296 * Create the address we will be binding to.
297 */
298 my_addr.sun_family = AF_UNIX;
299 strncpy(my_addr.sun_path, socket_path, sizeof(my_addr.sun_path));
300 my_addr.sun_path[sizeof(my_addr.sun_path)-1] = '\0';
301 (void) unlink(socket_path);
302 save_umask = umask(0);
303 if (bind(s, (const struct sockaddr *) &my_addr,
304 sizeof(struct sockaddr_un)) < 0) {
305 if (!quiet)
306 fprintf(stderr,
307 _("Couldn't bind unix socket %s: %s\n"),
308 socket_path, strerror(errno));
309 exit(1);
310 }
311 (void) umask(save_umask);
312
313 if (listen(s, 5) < 0) {
314 if (!quiet)
315 fprintf(stderr, _("Couldn't listen on unix "
316 "socket %s: %s\n"), socket_path,
317 strerror(errno));
318 exit(1);
319 }
320
321 cleanup_socket = socket_path;
322 if (!debug)
323 create_daemon();
324 signal(SIGHUP, terminate_intr);
325 signal(SIGINT, terminate_intr);
326 signal(SIGTERM, terminate_intr);
327 signal(SIGALRM, terminate_intr);
328 signal(SIGPIPE, SIG_IGN);
329
330 sprintf(reply_buf, "%8d\n", getpid());
331 if (ftruncate(fd_pidfile, 0)) {} /* Silence warn_unused_result */
332 write_all(fd_pidfile, reply_buf, strlen(reply_buf));
333 if (fd_pidfile > 1)
334 close(fd_pidfile); /* Unlock the pid file */
335
336 while (1) {
337 fromlen = sizeof(from_addr);
338 if (timeout > 0)
339 alarm(timeout);
340 ns = accept(s, (struct sockaddr *) &from_addr, &fromlen);
341 alarm(0);
342 if (ns < 0) {
343 if ((errno == EAGAIN) || (errno == EINTR))
344 continue;
345 perror("accept");
346 exit(1);
347 }
348 len = read(ns, &op, 1);
349 if (len != 1) {
350 if (len < 0)
351 perror("read");
352 else
353 printf(_("Error reading from client, "
354 "len = %d\n"), len);
355 goto shutdown_socket;
356 }
357 if ((op == 4) || (op == 5)) {
358 if (read_all(ns, (char *) &num, sizeof(num)) != 4)
359 goto shutdown_socket;
360 if (debug)
361 printf(_("operation %d, incoming num = %d\n"),
362 op, num);
363 } else if (debug)
364 printf("operation %d\n", op);
365
366 switch(op) {
367 case UUIDD_OP_GETPID:
368 sprintf(reply_buf, "%d", getpid());
369 reply_len = strlen(reply_buf)+1;
370 break;
371 case UUIDD_OP_GET_MAXOP:
372 sprintf(reply_buf, "%d", UUIDD_MAX_OP);
373 reply_len = strlen(reply_buf)+1;
374 break;
375 case UUIDD_OP_TIME_UUID:
376 num = 1;
377 uuid__generate_time(uu, &num);
378 if (debug) {
379 uuid_unparse(uu, str);
380 printf(_("Generated time UUID: %s\n"), str);
381 }
382 memcpy(reply_buf, uu, sizeof(uu));
383 reply_len = sizeof(uu);
384 break;
385 case UUIDD_OP_RANDOM_UUID:
386 num = 1;
387 uuid__generate_random(uu, &num);
388 if (debug) {
389 uuid_unparse(uu, str);
390 printf(_("Generated random UUID: %s\n"), str);
391 }
392 memcpy(reply_buf, uu, sizeof(uu));
393 reply_len = sizeof(uu);
394 break;
395 case UUIDD_OP_BULK_TIME_UUID:
396 uuid__generate_time(uu, &num);
397 if (debug) {
398 uuid_unparse(uu, str);
399 printf(P_("Generated time UUID %s and "
400 "subsequent UUID\n",
401 "Generated time UUID %s and %d "
402 "subsequent UUIDs\n", num),
403 str, num);
404 }
405 memcpy(reply_buf, uu, sizeof(uu));
406 reply_len = sizeof(uu);
407 memcpy(reply_buf+reply_len, &num, sizeof(num));
408 reply_len += sizeof(num);
409 break;
410 case UUIDD_OP_BULK_RANDOM_UUID:
411 if (num < 0)
412 num = 1;
413 if (num > 1000)
414 num = 1000;
415 if (num*16 > (int) (sizeof(reply_buf)-sizeof(num)))
416 num = (sizeof(reply_buf)-sizeof(num)) / 16;
417 uuid__generate_random((unsigned char *) reply_buf +
418 sizeof(num), &num);
419 if (debug) {
420 printf(_("Generated %d UUID's:\n"), num);
421 for (i=0, cp=reply_buf+sizeof(num);
422 i < num; i++, cp+=16) {
423 uuid_unparse((unsigned char *)cp, str);
424 printf("\t%s\n", str);
425 }
426 }
427 reply_len = (num*16) + sizeof(num);
428 memcpy(reply_buf, &num, sizeof(num));
429 break;
430 default:
431 if (debug)
432 printf(_("Invalid operation %d\n"), op);
433 goto shutdown_socket;
434 }
435 write_all(ns, (char *) &reply_len, sizeof(reply_len));
436 write_all(ns, reply_buf, reply_len);
437 shutdown_socket:
438 close(ns);
439 }
440 }
441
442 int main(int argc, char **argv)
443 {
444 const char *socket_path = UUIDD_SOCKET_PATH;
445 const char *pidfile_path = UUIDD_PIDFILE_PATH;
446 const char *err_context;
447 char buf[1024], *cp;
448 char str[37], *tmp;
449 uuid_t uu;
450 uid_t uid;
451 gid_t gid;
452 int i, c, ret;
453 int debug = 0, do_type = 0, do_kill = 0, num = 0;
454 int timeout = 0, quiet = 0, drop_privs = 0;
455
456 #ifdef ENABLE_NLS
457 setlocale(LC_MESSAGES, "");
458 setlocale(LC_CTYPE, "");
459 bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
460 textdomain(NLS_CAT_NAME);
461 #endif
462
463 while ((c = getopt (argc, argv, "dkn:qp:s:tT:r")) != EOF) {
464 switch (c) {
465 case 'd':
466 debug++;
467 drop_privs = 1;
468 break;
469 case 'k':
470 do_kill++;
471 drop_privs = 1;
472 break;
473 case 'n':
474 num = strtol(optarg, &tmp, 0);
475 if ((num < 0) || *tmp) {
476 fprintf(stderr, _("Bad number: %s\n"), optarg);
477 exit(1);
478 }
479 break;
480 case 'p':
481 pidfile_path = optarg;
482 drop_privs = 1;
483 break;
484 case 'q':
485 quiet++;
486 break;
487 case 's':
488 socket_path = optarg;
489 drop_privs = 1;
490 break;
491 case 't':
492 do_type = UUIDD_OP_TIME_UUID;
493 drop_privs = 1;
494 break;
495 case 'T':
496 timeout = strtol(optarg, &tmp, 0);
497 if ((timeout < 0) || *tmp) {
498 fprintf(stderr, _("Bad number: %s\n"), optarg);
499 exit(1);
500 }
501 break;
502 case 'r':
503 do_type = UUIDD_OP_RANDOM_UUID;
504 drop_privs = 1;
505 break;
506 default:
507 usage(argv[0]);
508 }
509 }
510 uid = getuid();
511 if (uid && drop_privs) {
512 gid = getgid();
513 #ifdef HAVE_SETRESGID
514 if (setresgid(gid, gid, gid) < 0)
515 die("setresgid");
516 #else
517 if (setregid(gid, gid) < 0)
518 die("setregid");
519 #endif
520
521 #ifdef HAVE_SETRESUID
522 if (setresuid(uid, uid, uid) < 0)
523 die("setresuid");
524 #else
525 if (setreuid(uid, uid) < 0)
526 die("setreuid");
527 #endif
528 }
529 if (num && do_type) {
530 ret = call_daemon(socket_path, do_type+2, buf,
531 sizeof(buf), &num, &err_context);
532 if (ret < 0) {
533 printf(_("Error calling uuidd daemon (%s): %s\n"),
534 err_context, strerror(errno));
535 exit(1);
536 }
537 if (do_type == UUIDD_OP_TIME_UUID) {
538 if (ret != sizeof(uu) + sizeof(num))
539 goto unexpected_size;
540
541 uuid_unparse((unsigned char *) buf, str);
542
543 printf(P_("%s and subsequent UUID\n",
544 "%s and subsequent %d UUIDs\n", num),
545 str, num);
546 } else {
547 printf("%s", _("List of UUID's:\n"));
548 cp = buf + 4;
549 if (ret != (int) (sizeof(num) + num*sizeof(uu)))
550 goto unexpected_size;
551 for (i=0; i < num; i++, cp+=16) {
552 uuid_unparse((unsigned char *) cp, str);
553 printf("\t%s\n", str);
554 }
555 }
556 exit(0);
557 }
558 if (do_type) {
559 ret = call_daemon(socket_path, do_type, (char *) &uu,
560 sizeof(uu), 0, &err_context);
561 if (ret < 0) {
562 printf(_("Error calling uuidd daemon (%s): %s\n"),
563 err_context, strerror(errno));
564 exit(1);
565 }
566 if (ret != sizeof(uu)) {
567 unexpected_size:
568 printf(_("Unexpected reply length from server %d\n"),
569 ret);
570 exit(1);
571 }
572 uuid_unparse(uu, str);
573
574 printf("%s\n", str);
575 exit(0);
576 }
577
578 if (do_kill) {
579 ret = call_daemon(socket_path, 0, buf, sizeof(buf), 0, 0);
580 if ((ret > 0) && ((do_kill = atoi((char *) buf)) > 0)) {
581 ret = kill(do_kill, SIGTERM);
582 if (ret < 0) {
583 if (!quiet)
584 fprintf(stderr,
585 _("Couldn't kill uuidd running "
586 "at pid %d: %s\n"), do_kill,
587 strerror(errno));
588 exit(1);
589 }
590 if (!quiet)
591 printf(_("Killed uuidd running at pid %d\n"),
592 do_kill);
593 }
594 exit(0);
595 }
596
597 server_loop(socket_path, pidfile_path, debug, timeout, quiet);
598 return 0;
599 }