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