#define _GNU_SOURCE /* for setres[ug]id() */
+#include "config.h"
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#include <sys/un.h>
#include <fcntl.h>
#include <signal.h>
+#include <string.h>
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#else
#endif
#include "uuid/uuid.h"
#include "uuid/uuidd.h"
-#include "nls-enable.h"
+#include "support/nls-enable.h"
+#include "ext2fs/ext2fs.h"
#ifdef __GNUC__
#define CODE_ATTR(x) __attribute__(x)
exit(1);
}
+static void die(const char *msg)
+{
+ perror(msg);
+ exit(1);
+}
+
static void create_daemon(void)
{
pid_t pid;
open("/dev/null", O_RDWR);
open("/dev/null", O_RDWR);
- chdir("/");
+ if (chdir("/")) {} /* Silence warn_unused_result warning */
(void) setsid();
euid = geteuid();
- (void) setreuid(euid, euid);
+ if (setreuid(euid, euid) < 0)
+ die("setreuid");
}
-static int read_all(int fd, char *buf, size_t count)
+static ssize_t read_all(int fd, char *buf, size_t count)
{
ssize_t ret;
- int c = 0;
+ ssize_t c = 0;
+ int tries = 0;
memset(buf, 0, count);
while (count > 0) {
ret = read(fd, buf, count);
+ if (ret <= 0) {
+ if ((errno == EAGAIN || errno == EINTR || ret == 0) &&
+ (tries++ < 5))
+ continue;
+ return c ? c : -1;
+ }
+ if (ret > 0)
+ tries = 0;
+ count -= ret;
+ buf += ret;
+ c += ret;
+ }
+ return c;
+}
+
+static int write_all(int fd, char *buf, size_t count)
+{
+ ssize_t ret;
+ int c = 0;
+
+ while (count > 0) {
+ ret = write(fd, buf, count);
if (ret < 0) {
if ((errno == EAGAIN) || (errno == EINTR))
continue;
exit(0);
}
-static void server_loop(const char *socket_path, int debug,
- int fd_pidfile, int timeout, int quiet)
+static int call_daemon(const char *socket_path, int op, char *buf,
+ int buflen, int *num, const char **err_context)
+{
+ char op_buf[8];
+ int op_len;
+ int s;
+ ssize_t ret;
+ int32_t reply_len = 0;
+ struct sockaddr_un srv_addr;
+
+ if (((op == 4) || (op == 5)) && !num) {
+ if (err_context)
+ *err_context = _("bad arguments");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+ if (err_context)
+ *err_context = _("socket");
+ return -1;
+ }
+
+ srv_addr.sun_family = AF_UNIX;
+ strncpy(srv_addr.sun_path, socket_path, sizeof(srv_addr.sun_path));
+ srv_addr.sun_path[sizeof(srv_addr.sun_path)-1] = '\0';
+
+ if (connect(s, (const struct sockaddr *) &srv_addr,
+ sizeof(struct sockaddr_un)) < 0) {
+ if (err_context)
+ *err_context = _("connect");
+ close(s);
+ return -1;
+ }
+
+ if (op == 5) {
+ if ((*num)*16 > buflen-4)
+ *num = (buflen-4) / 16;
+ }
+ op_buf[0] = op;
+ op_len = 1;
+ if ((op == 4) || (op == 5)) {
+ memcpy(op_buf+1, num, sizeof(int));
+ op_len += sizeof(int);
+ }
+
+ ret = write_all(s, op_buf, op_len);
+ if (ret < op_len) {
+ if (err_context)
+ *err_context = _("write");
+ close(s);
+ return -1;
+ }
+
+ ret = read_all(s, (char *) &reply_len, sizeof(reply_len));
+ if (ret < 0) {
+ if (err_context)
+ *err_context = _("read count");
+ close(s);
+ return -1;
+ }
+ if (reply_len < 0 || reply_len > buflen) {
+ if (err_context)
+ *err_context = _("bad response length");
+ close(s);
+ return -1;
+ }
+ ret = read_all(s, (char *) buf, reply_len);
+
+ if ((ret > 0) && (op == 4)) {
+ if (reply_len >= (int) (16+sizeof(int)))
+ memcpy(buf+16, num, sizeof(int));
+ else
+ *num = -1;
+ }
+ if ((ret > 0) && (op == 5)) {
+ if (*num >= (int) sizeof(int))
+ memcpy(buf, num, sizeof(int));
+ else
+ *num = -1;
+ }
+
+ close(s);
+
+ return ret;
+}
+
+static void server_loop(const char *socket_path, const char *pidfile_path,
+ int debug, int timeout, int quiet)
{
struct sockaddr_un my_addr, from_addr;
- unsigned char reply_buf[1024], *cp;
+ struct flock fl;
socklen_t fromlen;
int32_t reply_len = 0;
uuid_t uu;
mode_t save_umask;
- char op, str[37];
+ char reply_buf[1024], *cp;
+ char op, str[UUID_STR_SIZE];
int i, s, ns, len, num;
+ int fd_pidfile, ret;
+
+ fd_pidfile = open(pidfile_path, O_CREAT | O_RDWR, 0664);
+ if (fd_pidfile < 0) {
+ if (!quiet)
+ fprintf(stderr, "Failed to open/create %s: %s\n",
+ pidfile_path, strerror(errno));
+ exit(1);
+ }
+ cleanup_pidfile = pidfile_path;
+ cleanup_socket = 0;
+ signal(SIGALRM, terminate_intr);
+ alarm(30);
+ fl.l_type = F_WRLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0;
+ fl.l_len = 0;
+ fl.l_pid = 0;
+ while (fcntl(fd_pidfile, F_SETLKW, &fl) < 0) {
+ if ((errno == EAGAIN) || (errno == EINTR))
+ continue;
+ if (!quiet)
+ fprintf(stderr, "Failed to lock %s: %s\n",
+ pidfile_path, strerror(errno));
+ exit(1);
+ }
+ ret = call_daemon(socket_path, 0, reply_buf, sizeof(reply_buf), 0, 0);
+ if (ret > 0) {
+ if (!quiet)
+ printf(_("uuidd daemon already running at pid %s\n"),
+ reply_buf);
+ exit(1);
+ }
+ alarm(0);
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
if (!quiet)
exit(1);
}
+ /*
+ * Make sure the socket isn't using fd numbers 0-2 to avoid it
+ * getting closed by create_daemon()
+ */
+ while (!debug && s <= 2) {
+ s = dup(s);
+ if (s < 0) {
+ perror("dup");
+ exit(1);
+ }
+ }
+
/*
* Create the address we will be binding to.
*/
my_addr.sun_family = AF_UNIX;
- strcpy(my_addr.sun_path, socket_path);
+ strncpy(my_addr.sun_path, socket_path, sizeof(my_addr.sun_path));
+ my_addr.sun_path[sizeof(my_addr.sun_path)-1] = '\0';
(void) unlink(socket_path);
save_umask = umask(0);
if (bind(s, (const struct sockaddr *) &my_addr,
exit(1);
}
- if (fd_pidfile > 1)
- close(fd_pidfile); /* Unlock the pid file */
cleanup_socket = socket_path;
if (!debug)
create_daemon();
signal(SIGALRM, terminate_intr);
signal(SIGPIPE, SIG_IGN);
+ sprintf(reply_buf, "%8d\n", getpid());
+ if (ftruncate(fd_pidfile, 0)) {} /* Silence warn_unused_result */
+ write_all(fd_pidfile, reply_buf, strlen(reply_buf));
+ if (fd_pidfile > 1)
+ close(fd_pidfile); /* Unlock the pid file */
+
while (1) {
fromlen = sizeof(from_addr);
if (timeout > 0)
switch(op) {
case UUIDD_OP_GETPID:
- sprintf((char *) reply_buf, "%d", getpid());
- reply_len = strlen((char *) reply_buf)+1;
+ sprintf(reply_buf, "%d", getpid());
+ reply_len = strlen(reply_buf)+1;
break;
case UUIDD_OP_GET_MAXOP:
- sprintf((char *) reply_buf, "%d", UUIDD_MAX_OP);
- reply_len = strlen((char *) reply_buf)+1;
+ sprintf(reply_buf, "%d", UUIDD_MAX_OP);
+ reply_len = strlen(reply_buf)+1;
break;
case UUIDD_OP_TIME_UUID:
num = 1;
uuid__generate_time(uu, &num);
if (debug) {
uuid_unparse(uu, str);
- printf(_("Generated time UUID %s and %d "
- "following\n"), str, num);
+ printf(P_("Generated time UUID %s and "
+ "subsequent UUID\n",
+ "Generated time UUID %s and %d "
+ "subsequent UUIDs\n", num),
+ str, num);
}
memcpy(reply_buf, uu, sizeof(uu));
reply_len = sizeof(uu);
num = 1000;
if (num*16 > (int) (sizeof(reply_buf)-sizeof(num)))
num = (sizeof(reply_buf)-sizeof(num)) / 16;
- uuid__generate_random(reply_buf+sizeof(num), &num);
+ uuid__generate_random((unsigned char *) reply_buf +
+ sizeof(num), &num);
if (debug) {
printf(_("Generated %d UUID's:\n"), num);
for (i=0, cp=reply_buf+sizeof(num);
i < num; i++, cp+=16) {
- uuid_unparse(cp, str);
+ uuid_unparse((unsigned char *)cp, str);
printf("\t%s\n", str);
}
}
printf(_("Invalid operation %d\n"), op);
goto shutdown_socket;
}
- write(ns, &reply_len, sizeof(reply_len));
- write(ns, reply_buf, reply_len);
+ write_all(ns, (char *) &reply_len, sizeof(reply_len));
+ write_all(ns, reply_buf, reply_len);
shutdown_socket:
close(ns);
}
}
-static int call_daemon(const char *socket_path, int op, char *buf,
- int buflen, int *num, const char **err_context)
-{
- char op_buf[8];
- int op_len;
- int s;
- ssize_t ret;
- int32_t reply_len = 0;
- struct sockaddr_un srv_addr;
-
- if (((op == 4) || (op == 5)) && !num) {
- if (err_context)
- *err_context = _("bad arguments");
- errno = EINVAL;
- return -1;
- }
-
- if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
- if (err_context)
- *err_context = _("socket");
- return -1;
- }
-
- srv_addr.sun_family = AF_UNIX;
- strcpy(srv_addr.sun_path, socket_path);
-
- if (connect(s, (const struct sockaddr *) &srv_addr,
- sizeof(struct sockaddr_un)) < 0) {
- if (err_context)
- *err_context = _("connect");
- close(s);
- return -1;
- }
-
- if (op == 5) {
- if ((*num)*16 > buflen-4)
- *num = (buflen-4) / 16;
- }
- op_buf[0] = op;
- op_len = 1;
- if ((op == 4) || (op == 5)) {
- memcpy(op_buf+1, num, sizeof(int));
- op_len += sizeof(int);
- }
-
- ret = write(s, op_buf, op_len);
- if (ret < op_len) {
- if (err_context)
- *err_context = _("write");
- close(s);
- return -1;
- }
-
- ret = read_all(s, (char *) &reply_len, sizeof(reply_len));
- if (ret < 0) {
- if (err_context)
- *err_context = _("read count");
- close(s);
- return -1;
- }
- if (reply_len < 0 || reply_len > buflen) {
- if (err_context)
- *err_context = _("bad response length");
- close(s);
- return -1;
- }
- ret = read_all(s, (char *) buf, reply_len);
-
- if ((ret > 0) && (op == 4)) {
- if (reply_len >= (int) (16+sizeof(int)))
- memcpy(buf+16, num, sizeof(int));
- else
- *num = -1;
- }
- if ((ret > 0) && (op == 5)) {
- if (*num >= (int) sizeof(int))
- memcpy(buf, num, sizeof(int));
- else
- *num = -1;
- }
-
- close(s);
-
- return ret;
-}
-
-static int create_pidfile(const char *socket_path, const char *pidfile_path,
- int quiet)
-{
- int fd, ret;
- char buf[20];
-
- fd = open(pidfile_path, O_CREAT | O_RDWR, 0664);
- if (fd < 0) {
- if (!quiet)
- fprintf(stderr, "Failed to open/create %s: %s\n",
- pidfile_path, strerror(errno));
- exit(1);
- }
- cleanup_pidfile = pidfile_path;
- cleanup_socket = 0;
- signal(SIGALRM, terminate_intr);
- alarm(30);
- if (lockf(fd, F_LOCK, 0) < 0) {
- if (!quiet)
- fprintf(stderr, "Failed to lock %s: %s\n",
- pidfile_path, strerror(errno));
- exit(1);
- }
- ret = call_daemon(socket_path, 0, buf, sizeof(buf), 0, 0);
- if (ret > 0) {
- if (!quiet)
- printf(_("uuidd daemon already running at pid %s\n"),
- buf);
- exit(1);
- }
- alarm(0);
-
- sprintf(buf, "%d\n", getpid());
- ftruncate(fd, 0);
- write(fd, buf, strlen(buf));
- return(fd);
-}
-
int main(int argc, char **argv)
{
const char *socket_path = UUIDD_SOCKET_PATH;
uuid_t uu;
uid_t uid;
gid_t gid;
- int i, c, ret, fd_pidfile = -1;
+ int i, c, ret;
int debug = 0, do_type = 0, do_kill = 0, num = 0;
int timeout = 0, quiet = 0, drop_privs = 0;
switch (c) {
case 'd':
debug++;
- drop_privs++;
+ drop_privs = 1;
break;
case 'k':
do_kill++;
- drop_privs++;
+ drop_privs = 1;
break;
case 'n':
num = strtol(optarg, &tmp, 0);
fprintf(stderr, _("Bad number: %s\n"), optarg);
exit(1);
}
+ break;
case 'p':
pidfile_path = optarg;
- drop_privs++;
+ drop_privs = 1;
break;
case 'q':
quiet++;
break;
case 's':
socket_path = optarg;
- drop_privs++;
+ drop_privs = 1;
break;
case 't':
do_type = UUIDD_OP_TIME_UUID;
- drop_privs++;
+ drop_privs = 1;
break;
case 'T':
timeout = strtol(optarg, &tmp, 0);
break;
case 'r':
do_type = UUIDD_OP_RANDOM_UUID;
- drop_privs++;
+ drop_privs = 1;
break;
default:
usage(argv[0]);
uid = getuid();
if (uid && drop_privs) {
gid = getgid();
-#ifdef HAVE_SETRESUID
- setresuid(uid, uid, uid);
+#ifdef HAVE_SETRESGID
+ if (setresgid(gid, gid, gid) < 0)
+ die("setresgid");
#else
- setreuid(uid, uid);
+ if (setregid(gid, gid) < 0)
+ die("setregid");
#endif
-#ifdef HAVE_SETRESGID
- setresgid(gid, gid, gid);
+
+#ifdef HAVE_SETRESUID
+ if (setresuid(uid, uid, uid) < 0)
+ die("setresuid");
#else
- setregid(gid, gid);
+ if (setreuid(uid, uid) < 0)
+ die("setreuid");
#endif
}
if (num && do_type) {
uuid_unparse((unsigned char *) buf, str);
- printf(_("%s and subsequent %d UUID's\n"), str, num);
+ printf(P_("%s and subsequent UUID\n",
+ "%s and subsequent %d UUIDs\n", num),
+ str, num);
} else {
- printf(_("List of UUID's:\n"));
+ printf("%s", _("List of UUID's:\n"));
cp = buf + 4;
if (ret != (int) (sizeof(num) + num*sizeof(uu)))
goto unexpected_size;
exit(0);
}
- fd_pidfile = create_pidfile(socket_path, pidfile_path, quiet);
-
- server_loop(socket_path, debug, fd_pidfile, timeout, quiet);
+ server_loop(socket_path, pidfile_path, debug, timeout, quiet);
return 0;
}