The file mode is passed from client to server as a printf string
formatted with %04o (unsigned) so use strtoul() not strtol() to
parse it.  Error out on modes > 07777.

There is no way that the mode can ever be -1 so remove those checks.

This rabbit hole brought to you by:
usr.bin/rdistd/server.c:994: warning: comparison between signed and unsigned

 - todd

Index: rdist/client.c
===================================================================
RCS file: /cvs/src/usr.bin/rdist/client.c,v
retrieving revision 1.35
diff -u -p -r1.35 client.c
--- rdist/client.c      9 Dec 2015 19:39:10 -0000       1.35
+++ rdist/client.c      30 Mar 2016 20:52:16 -0000
@@ -772,8 +772,8 @@ update(char *rname, opt_t opts, struct s
 {
        off_t size;
        time_t mtime;
-       unsigned short lmode;
-       unsigned short rmode;
+       mode_t lmode;
+       mode_t rmode;
        char *owner = NULL, *group = NULL;
        int done, n;
        u_char *cp;
@@ -1042,7 +1042,7 @@ statupdate(int u, char *starget, opt_t o
 {
        int rv = 0;
        char ername[PATH_MAX*4];
-       int lmode = st->st_mode & 07777;
+       mode_t lmode = st->st_mode & 07777;
 
        if (u == US_CHMOG) {
                if (IS_ON(opts, DO_VERIFY)) {
Index: rdistd/server.c
===================================================================
RCS file: /cvs/src/usr.bin/rdistd/server.c,v
retrieving revision 1.42
diff -u -p -r1.42 server.c
--- rdistd/server.c     30 Mar 2016 20:51:59 -0000      1.42
+++ rdistd/server.c     30 Mar 2016 20:52:16 -0000
@@ -60,8 +60,8 @@ int   oumask;                 /* Old umask */
 
 static int cattarget(char *);
 static int setownership(char *, int, uid_t, gid_t, int);
-static int setfilemode(char *, int, int, int);
-static int fchog(int, char *, char *, char *, int);
+static int setfilemode(char *, int, mode_t, int);
+static int fchog(int, char *, char *, char *, mode_t);
 static int removefile(struct stat *, int);
 static void doclean(char *);
 static void clean(char *);
@@ -70,9 +70,9 @@ static void docmdspecial(void);
 static void query(char *);
 static int chkparent(char *, opt_t);
 static char *savetarget(char *, opt_t);
-static void recvfile(char *, opt_t, int, char *, char *, time_t, time_t, 
off_t);
-static void recvdir(opt_t, int, char *, char *);
-static void recvlink(char *, opt_t, int, off_t);
+static void recvfile(char *, opt_t, mode_t, char *, char *, time_t, time_t, 
off_t);
+static void recvdir(opt_t, mode_t, char *, char *);
+static void recvlink(char *, opt_t, mode_t, off_t);
 static void hardlink(char *);
 static void setconfig(char *);
 static void recvit(char *, int);
@@ -148,13 +148,10 @@ setownership(char *file, int fd, uid_t u
  * Set mode of a file
  */
 static int
-setfilemode(char *file, int fd, int mode, int islink)
+setfilemode(char *file, int fd, mode_t mode, int islink)
 {
        int status = -1;
 
-       if (mode == -1)
-               return(0);
-
        if (islink)
                status = fchmodat(AT_FDCWD, file, mode, AT_SYMLINK_NOFOLLOW);
 
@@ -175,7 +172,7 @@ setfilemode(char *file, int fd, int mode
  * Change owner, group and mode of file.
  */
 static int
-fchog(int fd, char *file, char *owner, char *group, int mode)
+fchog(int fd, char *file, char *owner, char *group, mode_t mode)
 {
        static struct group *gr = NULL;
        int i;
@@ -190,7 +187,7 @@ fchog(int fd, char *file, char *owner, c
                        uid = (uid_t) atoi(owner + 1);
                } else if (pw == NULL || strcmp(owner, pw->pw_name) != 0) {
                        if ((pw = getpwnam(owner)) == NULL) {
-                               if (mode != -1 && IS_ON(mode, S_ISUID)) {
+                               if (IS_ON(mode, S_ISUID)) {
                                        message(MT_NOTICE,
                              "%s: unknown login name \"%s\", clearing setuid",
                                                target, owner);
@@ -213,13 +210,10 @@ fchog(int fd, char *file, char *owner, c
        } else {        /* not root, setuid only if user==owner */
                struct passwd *lupw;
 
-               if (mode != -1) {
-                       if (IS_ON(mode, S_ISUID) && 
-                           strcmp(locuser, owner) != 0)
-                               mode &= ~S_ISUID;
-                       if (mode)
-                               mode &= ~S_ISVTX; /* and strip sticky too */
-               }
+               if (IS_ON(mode, S_ISUID) && strcmp(locuser, owner) != 0)
+                       mode &= ~S_ISUID;
+               if (mode)
+                       mode &= ~S_ISVTX; /* and strip sticky too */
 
                if ((lupw = getpwnam(locuser)) != NULL)
                        primegid = lupw->pw_gid;
@@ -230,7 +224,7 @@ fchog(int fd, char *file, char *owner, c
                if ((*group == ':' && 
                     (getgrgid(gid = atoi(group + 1)) == NULL))
                    || ((gr = (struct group *)getgrnam(group)) == NULL)) {
-                       if (mode != -1 && IS_ON(mode, S_ISGID)) {
+                       if (IS_ON(mode, S_ISGID)) {
                                message(MT_NOTICE, 
                                "%s: unknown group \"%s\", clearing setgid",
                                        target, group);
@@ -249,7 +243,7 @@ fchog(int fd, char *file, char *owner, c
                        for (i = 0; gr->gr_mem[i] != NULL; i++)
                                if (strcmp(locuser, gr->gr_mem[i]) == 0)
                                        goto ok;
-               if (mode != -1 && IS_ON(mode, S_ISGID)) {
+               if (IS_ON(mode, S_ISGID)) {
                        message(MT_NOTICE, 
                                "%s: user %s not in group %s, clearing setgid",
                                target, locuser, group);
@@ -268,12 +262,12 @@ ok:
         * or otherwise, set the new file mode.
         */
        if (setownership(file, fd, uid, gid, S_ISLNK(st.st_mode)) < 0) {
-               if (mode != -1 && IS_ON(mode, S_ISUID)) {
+               if (IS_ON(mode, S_ISUID)) {
                        message(MT_NOTICE, 
                                "%s: chown failed, clearing setuid", target);
                        mode &= ~S_ISUID;
                }
-               if (mode != -1 && IS_ON(mode, S_ISGID)) {
+               if (IS_ON(mode, S_ISGID)) {
                        message(MT_NOTICE, 
                                "%s: chown failed, clearing setgid", target);
                        mode &= ~S_ISGID;
@@ -738,7 +732,7 @@ savetarget(char *file, opt_t opts)
  * Receive a file
  */
 static void
-recvfile(char *new, opt_t opts, int mode, char *owner, char *group,
+recvfile(char *new, opt_t opts, mode_t mode, char *owner, char *group,
         time_t mtime, time_t atime, off_t size)
 {
        int f, wrerr, olderrno;
@@ -961,7 +955,7 @@ recvfile(char *new, opt_t opts, int mode
  * Receive a directory
  */
 static void
-recvdir(opt_t opts, int mode, char *owner, char *group)
+recvdir(opt_t opts, mode_t mode, char *owner, char *group)
 {
        static char lowner[100], lgroup[100];
        char *cp;
@@ -1110,7 +1104,7 @@ recvdir(opt_t opts, int mode, char *owne
  * Receive a link
  */
 static void
-recvlink(char *new, opt_t opts, int mode, off_t size)
+recvlink(char *new, opt_t opts, mode_t mode, off_t size)
 {
        char tbuf[PATH_MAX], dbuf[BUFSIZ];
        struct stat stb;
@@ -1256,9 +1250,7 @@ hardlink(char *cmd)
        }
 
        if (lstat(target, &stb) == 0) {
-               int mode = stb.st_mode & S_IFMT;
-
-               if (mode != S_IFREG && mode != S_IFLNK) {
+               if (!S_ISREG(stb.st_mode) && !S_ISLNK(stb.st_mode)) {
                        error("%s: not a regular file", target);
                        return;
                }
@@ -1349,7 +1341,7 @@ setconfig(char *cmd)
 static void
 recvit(char *cmd, int type)
 {
-       int mode;
+       mode_t mode;
        opt_t opts;
        off_t size;
        time_t mtime, atime;
@@ -1357,6 +1349,7 @@ recvit(char *cmd, int type)
        char new[PATH_MAX];
        char fileb[PATH_MAX];
        int64_t freespace = -1, freefiles = -1;
+       unsigned long ulval;
        char *cp = cmd;
 
        /*
@@ -1371,11 +1364,16 @@ recvit(char *cmd, int type)
        /*
         * Get file mode
         */
-       mode = strtol(cp, &cp, 8);
+       ulval = strtoul(cp, &cp, 8);
        if (*cp++ != ' ') {
                error("recvit: mode not delimited");
                return;
        }
+       if (ulval > 07777) {
+               error("recvit: invalid mode");
+               return;
+       }
+       mode = (mode_t)ulval;
 
        /*
         * Get file size
@@ -1536,11 +1534,12 @@ recvit(char *cmd, int type)
 static void
 dochmog(char *cmd)
 {
-       int mode;
+       mode_t mode;
        opt_t opts;
        char *owner, *group, *file;
        char *cp = cmd;
        char fileb[PATH_MAX];
+       unsigned long ulval;
 
        /*
         * Get rdist option flags
@@ -1554,11 +1553,16 @@ dochmog(char *cmd)
        /*
         * Get file mode
         */
-       mode = strtol(cp, &cp, 8);
+       ulval = strtol(cp, &cp, 8);
        if (*cp++ != ' ') {
                error("dochmog: mode not delimited");
                return;
        }
+       if (ulval > 07777) {
+               error("dochmog: invalid mode");
+               return;
+       }
+       mode = (mode_t)ulval;
 
        /*
         * Get file owner name

Reply via email to