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