]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blobdiff - misc/uuidd.c
Move the check_plausibility() function from misc to lib/support
[thirdparty/e2fsprogs.git] / misc / uuidd.c
index 2fb10575189f4b32d7c20d182bf2a24196916ab9..4db3fa94883d5affa0b7c208ba0b50add7a792cd 100644 (file)
@@ -11,6 +11,7 @@
 
 #define _GNU_SOURCE /* for setres[ug]id() */
 
+#include "config.h"
 #include <stdio.h>
 #ifdef HAVE_STDLIB_H
 #include <stdlib.h>
@@ -24,6 +25,7 @@
 #include <sys/un.h>
 #include <fcntl.h>
 #include <signal.h>
+#include <string.h>
 #ifdef HAVE_GETOPT_H
 #include <getopt.h>
 #else
@@ -33,7 +35,8 @@ extern int optind;
 #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)
@@ -51,6 +54,12 @@ static void usage(const char *progname)
        exit(1);
 }
 
+static void die(const char *msg)
+{
+       perror(msg);
+       exit(1);
+}
+
 static void create_daemon(void)
 {
        pid_t pid;
@@ -71,20 +80,44 @@ static void create_daemon(void)
        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;
@@ -107,17 +140,139 @@ static void terminate_intr(int signo CODE_ATTR((unused)))
        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)
@@ -126,11 +281,24 @@ static void server_loop(const char *socket_path, int debug,
                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,
@@ -151,8 +319,6 @@ static void server_loop(const char *socket_path, int debug,
                exit(1);
        }
 
-       if (fd_pidfile > 1)
-               close(fd_pidfile); /* Unlock the pid file */
        cleanup_socket = socket_path;
        if (!debug)
                create_daemon();
@@ -162,6 +328,12 @@ static void server_loop(const char *socket_path, int debug,
        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)
@@ -194,12 +366,12 @@ static void server_loop(const char *socket_path, int debug,
 
                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;
@@ -225,8 +397,11 @@ static void server_loop(const char *socket_path, int debug,
                        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);
@@ -240,12 +415,13 @@ static void server_loop(const char *socket_path, int debug,
                                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);
                                }
                        }
@@ -257,137 +433,13 @@ static void server_loop(const char *socket_path, int debug,
                                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;
@@ -398,7 +450,7 @@ int main(int argc, char **argv)
        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;
 
@@ -413,11 +465,11 @@ int main(int argc, char **argv)
                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);
@@ -425,20 +477,21 @@ int main(int argc, char **argv)
                                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);
@@ -449,7 +502,7 @@ int main(int argc, char **argv)
                        break;
                case 'r':
                        do_type = UUIDD_OP_RANDOM_UUID;
-                       drop_privs++;
+                       drop_privs = 1;
                        break;
                default:
                        usage(argv[0]);
@@ -458,15 +511,20 @@ int main(int argc, char **argv)
        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) {
@@ -483,9 +541,11 @@ int main(int argc, char **argv)
 
                        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;
@@ -535,8 +595,6 @@ int main(int argc, char **argv)
                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;
 }