From patchwork Fri Mar 26 14:25:32 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Layton X-Patchwork-Id: 48642 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.samba.org (fn.samba.org [216.83.154.106]) by ozlabs.org (Postfix) with ESMTP id B680AB7CCD for ; Sat, 27 Mar 2010 01:26:09 +1100 (EST) Received: from fn.samba.org (localhost [127.0.0.1]) by lists.samba.org (Postfix) with ESMTP id B61654664D; Fri, 26 Mar 2010 08:26:09 -0600 (MDT) X-Spam-Checker-Version: SpamAssassin 3.2.5 (2008-06-10) on fn.samba.org X-Spam-Level: X-Spam-Status: No, score=-9.9 required=3.8 tests=BAYES_00, RCVD_IN_DNSWL_HI, SPF_HELO_PASS,SPF_NEUTRAL autolearn=ham version=3.2.5 X-Original-To: linux-cifs-client@lists.samba.org Delivered-To: linux-cifs-client@lists.samba.org Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by lists.samba.org (Postfix) with ESMTP id DE5434664D for ; Fri, 26 Mar 2010 08:25:47 -0600 (MDT) Received: from int-mx05.intmail.prod.int.phx2.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.18]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id o2QEPkEX013272 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Fri, 26 Mar 2010 10:25:46 -0400 Received: from localhost.localdomain (vpn-10-105.rdu.redhat.com [10.11.10.105]) by int-mx05.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id o2QEPdCe026868 for ; Fri, 26 Mar 2010 10:25:45 -0400 From: Jeff Layton To: linux-cifs-client@lists.samba.org Date: Fri, 26 Mar 2010 10:25:32 -0400 Message-Id: <1269613542-6402-10-git-send-email-jlayton@samba.org> In-Reply-To: <1269613542-6402-1-git-send-email-jlayton@samba.org> References: <1269613542-6402-1-git-send-email-jlayton@samba.org> X-Scanned-By: MIMEDefang 2.67 on 10.5.11.18 Subject: [linux-cifs-client] [PATCH 09/19] mount.cifs: clean up setting of password field X-BeenThere: linux-cifs-client@lists.samba.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: The Linux CIFS VFS client List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-cifs-client-bounces@lists.samba.org Errors-To: linux-cifs-client-bounces@lists.samba.org From: Jeff Layton Add a function to set and escape the password properly. Signed-off-by: Jeff Layton --- mount.cifs.c | 193 +++++++++++++++++++++++++--------------------------------- 1 files changed, 84 insertions(+), 109 deletions(-) diff --git a/mount.cifs.c b/mount.cifs.c index 46a8161..d380e54 100644 --- a/mount.cifs.c +++ b/mount.cifs.c @@ -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;ipassword[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)