mount.cifs: clean up setting of password field
authorJeff Layton <jlayton@redhat.com>
Thu, 1 Apr 2010 19:19:16 +0000 (15:19 -0400)
committerJeff Layton <jlayton@redhat.com>
Thu, 1 Apr 2010 19:19:16 +0000 (15:19 -0400)
Add a function to set and escape the password properly.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
mount.cifs.c

index 46a81612a1ecca261b5ee413768faa46139b9d3a..d380e547c80f5cbcd019b4cffa25b6f12aa6e91f 100644 (file)
@@ -227,6 +227,31 @@ mount_cifs_usage(FILE *stream)
        return 0;
 }
 
+/*
+ * CIFS has to "escape" commas in the password field so that they don't
+ * end up getting confused for option delimiters. Copy password into pw
+ * field, turning any commas into double commas.
+ */
+static int
+set_password(struct parsed_mount_info *parsed_info, const char *src)
+{
+       char *dst = parsed_info->password;
+       unsigned int i = 0, j = 0;
+
+       while (src[i]) {
+               if (src[i] == ',')
+                       dst[j++] = ',';
+               dst[j++] = src[i++];
+               if (j > sizeof(parsed_info->password)) {
+                       fprintf(stderr, "Converted password too long!\n");
+                       return EX_USAGE;
+               }
+       }
+       dst[j] = '\0';
+       parsed_info->got_password = 1;
+       return 0;
+}
+
 /* caller frees username if necessary */
 static char * getusername(void) {
        char *username = NULL;
@@ -245,18 +270,18 @@ static char * getusername(void) {
  * ...obviously the only required component is "username". The source string
  * is modified in the process, but it should remain unchanged at the end.
  */
-static void
+static int
 parse_username(char *rawuser, struct parsed_mount_info *parsed_info)
 {
        char *user, *password, slash;
+       int rc = 0;
 
        /* everything after first % sign is a password */
        password = strchr(rawuser, '%');
        if (password) {
-               *(password) = '\0';
-               strlcpy(parsed_info->password, password + 1,
-                               sizeof(parsed_info->password));
-               parsed_info->got_password = 1;
+               rc = set_password(parsed_info, password);
+               if (rc)
+                       return rc;
        }
 
        /* everything after first '/' or '\' is a username */
@@ -279,12 +304,14 @@ parse_username(char *rawuser, struct parsed_mount_info *parsed_info)
        parsed_info->got_user = 1;
        if (password)
                *password = '%';
+
+       return 0;
 }
 
 static int open_cred_file(char *file_name, struct parsed_mount_info *parsed_info)
 {
        char * line_buf;
-       char * temp_val;
+       char * temp_val, *newline;
        FILE * fs;
        int i, length;
 
@@ -310,6 +337,12 @@ static int open_cred_file(char *file_name, struct parsed_mount_info *parsed_info
                                break;
                        /* if whitespace - skip past it */
                }
+
+               /* NULL terminate at newline */
+               newline = strchr(line_buf + i, '\n');
+               if (newline)
+                       *newline = '\0';
+
                if (strncasecmp("username",line_buf+i,8) == 0) {
                        temp_val = strchr(line_buf + i,'=');
                        if(temp_val) {
@@ -333,24 +366,12 @@ static int open_cred_file(char *file_name, struct parsed_mount_info *parsed_info
                        }
                } else if (strncasecmp("password",line_buf+i,8) == 0) {
                        temp_val = strchr(line_buf+i, '=');
-                       if(temp_val) {
-                               /* go past equals sign */
-                               temp_val++;
-                               for(length = 0; length < sizeof(parsed_info->password); length++) {
-                                       if ((temp_val[length] == '\n')
-                                           || (temp_val[length] == '\0')) {
-                                               temp_val[length] = '\0';
-                                               break;
-                                       }
-                               }
-                               if(length > MOUNT_PASSWD_SIZE) {
-                                       fprintf(stderr, "mount.cifs failed: password in credentials file too long\n");
-                                       memset(line_buf, 0, 4096);
-                                       return EX_USAGE;
-                               }
-                               strlcpy(parsed_info->password, temp_val, MOUNT_PASSWD_SIZE + 1);
-                               parsed_info->got_password = 1;
-                       }
+                       if (!temp_val)
+                               continue;
+                       ++temp_val;
+                       i = set_password(parsed_info, temp_val);
+                       if (i)
+                               return i;
                 } else if (strncasecmp("domain",line_buf+i,6) == 0) {
                         temp_val = strchr(line_buf+i,'=');
                         if(temp_val) {
@@ -386,8 +407,7 @@ static int
 get_password_from_file(int file_descript, char *filename, struct parsed_mount_info *parsed_info)
 {
        int rc = 0;
-       int i;
-       char c;
+       char buf[sizeof(parsed_info->password) + 1];
 
        if(filename != NULL) {
                rc = access(filename, R_OK);
@@ -403,38 +423,21 @@ get_password_from_file(int file_descript, char *filename, struct parsed_mount_in
                        return EX_SYSERR;
                }
        }
-       /* else file already open and fd provided */
-
-       for(i=0;i<MOUNT_PASSWD_SIZE;i++) {
-               rc = read(file_descript,&c,1);
-               if(rc < 0) {
-                       fprintf(stderr, "mount.cifs failed. Error %s reading password file\n",strerror(errno));
-                       if(filename != NULL)
-                               close(file_descript);
-                       return EX_SYSERR;
-               } else if(rc == 0) {
-                       if(parsed_info->password[0] == 0) {
-                               if(verboseflag)
-                                       fprintf(stderr, "\nWarning: null password used since cifs password file empty");
-                       }
-                       break;
-               } else /* read valid character */ {
-                       if((c == 0) || (c == '\n')) {
-                               parsed_info->password[i] = '\0';
-                               break;
-                       } else 
-                               parsed_info->password[i] = c;
-               }
-       }
-       if((i == MOUNT_PASSWD_SIZE) && (verboseflag)) {
-               fprintf(stderr, "\nWarning: password longer than %d characters specified in cifs password file",
-                       MOUNT_PASSWD_SIZE);
+
+       memset(buf, 0, sizeof(buf));
+       rc = read(file_descript, buf, sizeof(buf) - 1);
+       if (rc < 0) {
+               fprintf(stderr, "mount.cifs failed. Error %s reading password file\n",strerror(errno));
+               rc = EX_SYSERR;
+               goto get_pw_exit;
        }
-       parsed_info->got_password = 1;
+
+       rc = set_password(parsed_info, buf);
+
+get_pw_exit:
        if(filename != NULL) {
                close(file_descript);
        }
-
        return rc;
 }
 
@@ -507,26 +510,25 @@ parse_options(const char *data, struct parsed_mount_info *parsed_info)
                                        fprintf(stderr, "username too long\n");
                                        return EX_USAGE;
                                }
-                               parse_username(value, parsed_info);
+                               rc = parse_username(value, parsed_info);
+                               if (rc) {
+                                       fprintf(stderr, "problem parsing username\n");
+                                       return rc;
+                               }
                                goto nocopy;
                        }
                } else if (strncmp(data, "pass", 4) == 0) {
+                       if (parsed_info->got_password) {
+                               fprintf(stderr, "password specified twice, ignoring second\n");
+                               goto nocopy;
+                       }
                        if (!value || !*value) {
-                               if(parsed_info->got_password) {
-                                       fprintf(stderr, "\npassword specified twice, ignoring second\n");
-                               } else
-                                       parsed_info->got_password = 1;
-                       } else if (strnlen(value, MOUNT_PASSWD_SIZE) < MOUNT_PASSWD_SIZE) {
-                               if (parsed_info->got_password) {
-                                       fprintf(stderr, "\nmount.cifs warning - password specified twice\n");
-                               } else {
-                                       strlcpy(parsed_info->password, value, MOUNT_PASSWD_SIZE + 1);
-                                       parsed_info->got_password = 1;
-                               }
-                       } else {
-                               fprintf(stderr, "password too long\n");
-                               return EX_USAGE;
+                               parsed_info->got_password = 1;
+                               goto nocopy;
                        }
+                       rc = set_password(parsed_info, value);
+                       if (rc)
+                               return rc;
                        goto nocopy;
                } else if (strncmp(data, "sec", 3) == 0) {
                        if (value) {
@@ -736,31 +738,6 @@ nocopy:
        return 0;
 }
 
-/* replace all (one or more) commas with double commas */
-static int
-replace_commas(char *pass)
-{
-       /* a little extra buffer to simplify conversion */
-       char tmpbuf[MOUNT_PASSWD_SIZE + 3];
-       int i = 0, j = 0;
-
-       /* don't do anything if there are no commas */
-       if (!strchr(pass, ','))
-               return 0;
-
-       while (pass[i]) {
-               if (pass[i] == ',')
-                       tmpbuf[j++] = ',';
-               tmpbuf[j++] = pass[i++];
-               if (j > MOUNT_PASSWD_SIZE + 1) {
-                       fprintf(stderr, "Converted password too long!\n");
-                       return EX_USAGE;
-               }
-       }
-       tmpbuf[j] = '\0';
-       strlcpy(pass, tmpbuf, MOUNT_PASSWD_SIZE + 1);
-       return 0;
-}
 
 /*
  * resolve "host" portion of parsed info to comma-separated list of
@@ -928,10 +905,9 @@ get_pw_from_env(struct parsed_mount_info *parsed_info)
 {
        int rc = 0;
 
-       if (getenv("PASSWD")) {
-               strlcpy(parsed_info->password, getenv("PASSWD"), MOUNT_PASSWD_SIZE + 1);
-               parsed_info->got_password = 1;
-       } else if (getenv("PASSWD_FD"))
+       if (getenv("PASSWD"))
+               rc = set_password(parsed_info, getenv("PASSWD"));
+       else if (getenv("PASSWD_FD"))
                rc = get_password_from_file(atoi(getenv("PASSWD_FD")), NULL, parsed_info);
        else if (getenv("PASSWD_FILE"))
                rc = get_password_from_file(0, getenv("PASSWD_FILE"), parsed_info);
@@ -1034,7 +1010,6 @@ int main(int argc, char ** argv)
        int fakemnt = 0;
        int already_uppercased = 0;
        size_t options_size = MAX_OPTIONS_LEN;
-       int retry = 0; /* set when we have to retry mount with uppercase */
        struct mntent mountent;
        struct parsed_mount_info *parsed_info = NULL;
        FILE * pmntfile;
@@ -1173,8 +1148,9 @@ int main(int argc, char ** argv)
                        strlcpy(parsed_info->domain, optarg, sizeof(parsed_info->domain));
                        break;
                case 'p':
-                       strlcpy(parsed_info->password, optarg, sizeof(parsed_info->password));
-                       parsed_info->got_password = 1;
+                       rc = set_password(parsed_info, optarg);
+                       if (rc)
+                               goto mount_exit;
                        break;
                case 'S':
                        rc = get_password_from_file(0, NULL, parsed_info);
@@ -1281,15 +1257,16 @@ int main(int argc, char ** argv)
        }
 
        if(!parsed_info->got_password) {
-               char *tmp_pass = getpass("Password: "); /* BB obsolete sys call but
-                                                          no good replacement yet. */
+               /* getpass is obsolete, but there's apparently nothing that replaces it */
+               char *tmp_pass = getpass("Password: "); 
                if (!tmp_pass) {
-                       fprintf(stderr, "Password not entered, exiting\n");
-                       rc = EX_USAGE;
+                       fprintf(stderr, "Error reading password, exiting\n");
+                       rc = EX_SYSERR;
                        goto mount_exit;
                }
-               strlcpy(parsed_info->password, tmp_pass, sizeof(parsed_info->password));
-               parsed_info->got_password = 1;
+               rc = set_password(parsed_info, tmp_pass);
+               if (rc)
+                       goto mount_exit;
        }
 
        /* copy in ver= string. It's not really needed, but what the hell */
@@ -1355,8 +1332,6 @@ mount_retry:
                 * Commas have to be doubled, or else they will
                 * look like the parameter separator
                 */
-               if(retry == 0)
-                       replace_commas(parsed_info->password);
                strlcat(options, ",pass=", options_size);
                strlcat(options, parsed_info->password, options_size);
                if (verboseflag)