diff mbox

[09/19] mount.cifs: clean up setting of password field

Message ID 1269613542-6402-10-git-send-email-jlayton@samba.org
State New
Headers show

Commit Message

Jeff Layton March 26, 2010, 2:25 p.m. UTC
From: Jeff Layton <jlayton@redhat.com>

Add a function to set and escape the password properly.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 mount.cifs.c |  193 +++++++++++++++++++++++++---------------------------------
 1 files changed, 84 insertions(+), 109 deletions(-)
diff mbox

Patch

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;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)