Home | History | Annotate | Download | only in misc
      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 
     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 
     57 static void die(const char *msg)
     58 {
     59 	perror(msg);
     60 	exit(1);
     61 }
     62 
     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 
     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 
    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 
    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 
    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 
    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 
    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