pwrap: Fix overflow checking
authorRalph Boehme <slow@samba.org>
Mon, 26 Mar 2018 14:42:00 +0000 (16:42 +0200)
committerAndreas Schneider <asn@samba.org>
Mon, 26 Mar 2018 17:11:14 +0000 (19:11 +0200)
Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
src/pam_wrapper.c

index 1bb3161a5f69029e476c00a3ecdae95dc3dbf72d..4b72d69fafb1e4b6322b978558485749a1461f74 100644 (file)
@@ -756,6 +756,100 @@ static void pwrap_clean_stale_dirs(const char *dir)
        return;
 }
 
+static int pso_copy(const char *src, const char *dst, const char *pdir, mode_t mode)
+{
+       int srcfd = -1;
+       int dstfd = -1;
+       int rc = -1;
+       ssize_t bread, bwritten;
+       struct stat sb;
+       char buf[10];
+       int cmp;
+       size_t to_read;
+       bool found_slash;
+
+       cmp = strcmp(src, dst);
+       if (cmp == 0) {
+               return -1;
+       }
+
+       srcfd = open(src, O_RDONLY, 0);
+       if (srcfd < 0) {
+               return -1;
+       }
+
+       if (mode == 0) {
+               rc = fstat(srcfd, &sb);
+               if (rc != 0) {
+                       rc = -1;
+                       goto out;
+               }
+               mode = sb.st_mode;
+       }
+
+       dstfd = open(dst, O_CREAT|O_WRONLY|O_TRUNC, mode);
+       if (dstfd < 0) {
+               rc = -1;
+               goto out;
+       }
+
+       found_slash = false;
+       to_read = 1;
+
+       for (;;) {
+               bread = read(srcfd, buf, to_read);
+               if (bread == 0) {
+                       /* done */
+                       break;
+               } else if (bread < 0) {
+                       errno = EIO;
+                       rc = -1;
+                       goto out;
+               }
+
+               to_read = 1;
+               if (!found_slash && buf[0] == '/') {
+                       found_slash = true;
+                       to_read = 9;
+               }
+
+               if (found_slash && bread == 9) {
+                       cmp = memcmp(buf, "etc/pam.d", 9);
+                       if (cmp == 0) {
+                               memcpy(buf, pdir + 1, 9);
+                       }
+                       found_slash = false;
+               }
+
+               bwritten = write(dstfd, buf, bread);
+               if (bwritten < 0) {
+                       errno = EIO;
+                       rc = -1;
+                       goto out;
+               }
+
+               if (bread != bwritten) {
+                       errno = EFAULT;
+                       rc = -1;
+                       goto out;
+               }
+       }
+
+       rc = 0;
+out:
+       if (srcfd != -1) {
+               close(srcfd);
+       }
+       if (dstfd != -1) {
+               close(dstfd);
+       }
+       if (rc < 0) {
+               unlink(dst);
+       }
+
+       return rc;
+}
+
 static void pwrap_init(void)
 {
        char tmp_config_dir[] = "/tmp/pam.X";
@@ -933,7 +1027,7 @@ static void pwrap_init(void)
        PWRAP_LOG(PWRAP_LOG_TRACE, "Reconstructed PAM path: %s", libpam_path);
 
        PWRAP_LOG(PWRAP_LOG_DEBUG, "Copy %s to %s", libpam_path, pwrap.libpam_so);
-       rc = p_copy(libpam_path, pwrap.libpam_so, pwrap.config_dir, 0644);
+       rc = pso_copy(libpam_path, pwrap.libpam_so, pwrap.config_dir, 0644);
        if (rc != 0) {
                PWRAP_LOG(PWRAP_LOG_ERROR,
                          "Failed to copy %s - error: %s",