aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/connect.c
diff options
context:
space:
mode:
authorSean Finney <seanius@seanius.net>2011-04-11 09:19:32 -0400
committerSteve French <sfrench@us.ibm.com>2011-05-19 10:10:54 -0400
commitb946845a9dc523c759cae2b6a0f6827486c3221a (patch)
tree15345fcb639fa2da178ade7fc704117ac0fb0ce4 /fs/cifs/connect.c
parentc1508ca23653245266e2e3ab69a8dad464f7a569 (diff)
cifs: cifs_parse_mount_options: do not tokenize mount options in-place
To keep strings passed to cifs_parse_mount_options re-usable (which is needed to clean up the DFS referral handling), tokenize a copy of the mount options instead. If values are needed from this tokenized string, they too must be duplicated (previously, some options were copied and others duplicated). Since we are not on the critical path and any cleanup is relatively easy, the extra memory usage shouldn't be a problem (and it is a bit simpler than trying to implement something smarter). Reviewed-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Sean Finney <seanius@seanius.net> Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru> Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs/connect.c')
-rw-r--r--fs/cifs/connect.c109
1 files changed, 74 insertions, 35 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index c7ebeee38c67..20c60ddaa5a1 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -818,10 +818,11 @@ extract_hostname(const char *unc)
818} 818}
819 819
820static int 820static int
821cifs_parse_mount_options(char *options, const char *devname, 821cifs_parse_mount_options(const char *mountdata, const char *devname,
822 struct smb_vol *vol) 822 struct smb_vol *vol)
823{ 823{
824 char *value, *data, *end; 824 char *value, *data, *end;
825 char *mountdata_copy, *options;
825 unsigned int temp_len, i, j; 826 unsigned int temp_len, i, j;
826 char separator[2]; 827 char separator[2];
827 short int override_uid = -1; 828 short int override_uid = -1;
@@ -861,9 +862,14 @@ cifs_parse_mount_options(char *options, const char *devname,
861 862
862 vol->actimeo = CIFS_DEF_ACTIMEO; 863 vol->actimeo = CIFS_DEF_ACTIMEO;
863 864
864 if (!options) 865 if (!mountdata)
865 return 1; 866 goto cifs_parse_mount_err;
867
868 mountdata_copy = kstrndup(mountdata, PAGE_SIZE, GFP_KERNEL);
869 if (!mountdata_copy)
870 goto cifs_parse_mount_err;
866 871
872 options = mountdata_copy;
867 end = options + strlen(options); 873 end = options + strlen(options);
868 if (strncmp(options, "sep=", 4) == 0) { 874 if (strncmp(options, "sep=", 4) == 0) {
869 if (options[4] != 0) { 875 if (options[4] != 0) {
@@ -889,17 +895,22 @@ cifs_parse_mount_options(char *options, const char *devname,
889 if (!value) { 895 if (!value) {
890 printk(KERN_WARNING 896 printk(KERN_WARNING
891 "CIFS: invalid or missing username\n"); 897 "CIFS: invalid or missing username\n");
892 return 1; /* needs_arg; */ 898 goto cifs_parse_mount_err;
893 } else if (!*value) { 899 } else if (!*value) {
894 /* null user, ie anonymous, authentication */ 900 /* null user, ie anonymous, authentication */
895 vol->nullauth = 1; 901 vol->nullauth = 1;
896 } 902 }
897 if (strnlen(value, MAX_USERNAME_SIZE) < 903 if (strnlen(value, MAX_USERNAME_SIZE) <
898 MAX_USERNAME_SIZE) { 904 MAX_USERNAME_SIZE) {
899 vol->username = value; 905 vol->username = kstrdup(value, GFP_KERNEL);
906 if (!vol->username) {
907 printk(KERN_WARNING "CIFS: no memory "
908 "for username\n");
909 goto cifs_parse_mount_err;
910 }
900 } else { 911 } else {
901 printk(KERN_WARNING "CIFS: username too long\n"); 912 printk(KERN_WARNING "CIFS: username too long\n");
902 return 1; 913 goto cifs_parse_mount_err;
903 } 914 }
904 } else if (strnicmp(data, "pass", 4) == 0) { 915 } else if (strnicmp(data, "pass", 4) == 0) {
905 if (!value) { 916 if (!value) {
@@ -963,7 +974,7 @@ cifs_parse_mount_options(char *options, const char *devname,
963 if (vol->password == NULL) { 974 if (vol->password == NULL) {
964 printk(KERN_WARNING "CIFS: no memory " 975 printk(KERN_WARNING "CIFS: no memory "
965 "for password\n"); 976 "for password\n");
966 return 1; 977 goto cifs_parse_mount_err;
967 } 978 }
968 for (i = 0, j = 0; i < temp_len; i++, j++) { 979 for (i = 0, j = 0; i < temp_len; i++, j++) {
969 vol->password[j] = value[i]; 980 vol->password[j] = value[i];
@@ -979,7 +990,7 @@ cifs_parse_mount_options(char *options, const char *devname,
979 if (vol->password == NULL) { 990 if (vol->password == NULL) {
980 printk(KERN_WARNING "CIFS: no memory " 991 printk(KERN_WARNING "CIFS: no memory "
981 "for password\n"); 992 "for password\n");
982 return 1; 993 goto cifs_parse_mount_err;
983 } 994 }
984 strcpy(vol->password, value); 995 strcpy(vol->password, value);
985 } 996 }
@@ -989,11 +1000,16 @@ cifs_parse_mount_options(char *options, const char *devname,
989 vol->UNCip = NULL; 1000 vol->UNCip = NULL;
990 } else if (strnlen(value, INET6_ADDRSTRLEN) < 1001 } else if (strnlen(value, INET6_ADDRSTRLEN) <
991 INET6_ADDRSTRLEN) { 1002 INET6_ADDRSTRLEN) {
992 vol->UNCip = value; 1003 vol->UNCip = kstrdup(value, GFP_KERNEL);
1004 if (!vol->UNCip) {
1005 printk(KERN_WARNING "CIFS: no memory "
1006 "for UNC IP\n");
1007 goto cifs_parse_mount_err;
1008 }
993 } else { 1009 } else {
994 printk(KERN_WARNING "CIFS: ip address " 1010 printk(KERN_WARNING "CIFS: ip address "
995 "too long\n"); 1011 "too long\n");
996 return 1; 1012 goto cifs_parse_mount_err;
997 } 1013 }
998 } else if (strnicmp(data, "sec", 3) == 0) { 1014 } else if (strnicmp(data, "sec", 3) == 0) {
999 if (!value || !*value) { 1015 if (!value || !*value) {
@@ -1006,7 +1022,7 @@ cifs_parse_mount_options(char *options, const char *devname,
1006 /* vol->secFlg |= CIFSSEC_MUST_SEAL | 1022 /* vol->secFlg |= CIFSSEC_MUST_SEAL |
1007 CIFSSEC_MAY_KRB5; */ 1023 CIFSSEC_MAY_KRB5; */
1008 cERROR(1, "Krb5 cifs privacy not supported"); 1024 cERROR(1, "Krb5 cifs privacy not supported");
1009 return 1; 1025 goto cifs_parse_mount_err;
1010 } else if (strnicmp(value, "krb5", 4) == 0) { 1026 } else if (strnicmp(value, "krb5", 4) == 0) {
1011 vol->secFlg |= CIFSSEC_MAY_KRB5; 1027 vol->secFlg |= CIFSSEC_MAY_KRB5;
1012 } else if (strnicmp(value, "ntlmsspi", 8) == 0) { 1028 } else if (strnicmp(value, "ntlmsspi", 8) == 0) {
@@ -1036,7 +1052,7 @@ cifs_parse_mount_options(char *options, const char *devname,
1036 vol->nullauth = 1; 1052 vol->nullauth = 1;
1037 } else { 1053 } else {
1038 cERROR(1, "bad security option: %s", value); 1054 cERROR(1, "bad security option: %s", value);
1039 return 1; 1055 goto cifs_parse_mount_err;
1040 } 1056 }
1041 } else if (strnicmp(data, "vers", 3) == 0) { 1057 } else if (strnicmp(data, "vers", 3) == 0) {
1042 if (!value || !*value) { 1058 if (!value || !*value) {
@@ -1060,12 +1076,12 @@ cifs_parse_mount_options(char *options, const char *devname,
1060 if (!value || !*value) { 1076 if (!value || !*value) {
1061 printk(KERN_WARNING "CIFS: invalid path to " 1077 printk(KERN_WARNING "CIFS: invalid path to "
1062 "network resource\n"); 1078 "network resource\n");
1063 return 1; /* needs_arg; */ 1079 goto cifs_parse_mount_err;
1064 } 1080 }
1065 if ((temp_len = strnlen(value, 300)) < 300) { 1081 if ((temp_len = strnlen(value, 300)) < 300) {
1066 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL); 1082 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
1067 if (vol->UNC == NULL) 1083 if (vol->UNC == NULL)
1068 return 1; 1084 goto cifs_parse_mount_err;
1069 strcpy(vol->UNC, value); 1085 strcpy(vol->UNC, value);
1070 if (strncmp(vol->UNC, "//", 2) == 0) { 1086 if (strncmp(vol->UNC, "//", 2) == 0) {
1071 vol->UNC[0] = '\\'; 1087 vol->UNC[0] = '\\';
@@ -1074,27 +1090,32 @@ cifs_parse_mount_options(char *options, const char *devname,
1074 printk(KERN_WARNING 1090 printk(KERN_WARNING
1075 "CIFS: UNC Path does not begin " 1091 "CIFS: UNC Path does not begin "
1076 "with // or \\\\ \n"); 1092 "with // or \\\\ \n");
1077 return 1; 1093 goto cifs_parse_mount_err;
1078 } 1094 }
1079 } else { 1095 } else {
1080 printk(KERN_WARNING "CIFS: UNC name too long\n"); 1096 printk(KERN_WARNING "CIFS: UNC name too long\n");
1081 return 1; 1097 goto cifs_parse_mount_err;
1082 } 1098 }
1083 } else if ((strnicmp(data, "domain", 3) == 0) 1099 } else if ((strnicmp(data, "domain", 3) == 0)
1084 || (strnicmp(data, "workgroup", 5) == 0)) { 1100 || (strnicmp(data, "workgroup", 5) == 0)) {
1085 if (!value || !*value) { 1101 if (!value || !*value) {
1086 printk(KERN_WARNING "CIFS: invalid domain name\n"); 1102 printk(KERN_WARNING "CIFS: invalid domain name\n");
1087 return 1; /* needs_arg; */ 1103 goto cifs_parse_mount_err;
1088 } 1104 }
1089 /* BB are there cases in which a comma can be valid in 1105 /* BB are there cases in which a comma can be valid in
1090 a domain name and need special handling? */ 1106 a domain name and need special handling? */
1091 if (strnlen(value, 256) < 256) { 1107 if (strnlen(value, 256) < 256) {
1092 vol->domainname = value; 1108 vol->domainname = kstrdup(value, GFP_KERNEL);
1109 if (!vol->domainname) {
1110 printk(KERN_WARNING "CIFS: no memory "
1111 "for domainname\n");
1112 goto cifs_parse_mount_err;
1113 }
1093 cFYI(1, "Domain name set"); 1114 cFYI(1, "Domain name set");
1094 } else { 1115 } else {
1095 printk(KERN_WARNING "CIFS: domain name too " 1116 printk(KERN_WARNING "CIFS: domain name too "
1096 "long\n"); 1117 "long\n");
1097 return 1; 1118 goto cifs_parse_mount_err;
1098 } 1119 }
1099 } else if (strnicmp(data, "srcaddr", 7) == 0) { 1120 } else if (strnicmp(data, "srcaddr", 7) == 0) {
1100 vol->srcaddr.ss_family = AF_UNSPEC; 1121 vol->srcaddr.ss_family = AF_UNSPEC;
@@ -1102,7 +1123,7 @@ cifs_parse_mount_options(char *options, const char *devname,
1102 if (!value || !*value) { 1123 if (!value || !*value) {
1103 printk(KERN_WARNING "CIFS: srcaddr value" 1124 printk(KERN_WARNING "CIFS: srcaddr value"
1104 " not specified.\n"); 1125 " not specified.\n");
1105 return 1; /* needs_arg; */ 1126 goto cifs_parse_mount_err;
1106 } 1127 }
1107 i = cifs_convert_address((struct sockaddr *)&vol->srcaddr, 1128 i = cifs_convert_address((struct sockaddr *)&vol->srcaddr,
1108 value, strlen(value)); 1129 value, strlen(value));
@@ -1110,20 +1131,20 @@ cifs_parse_mount_options(char *options, const char *devname,
1110 printk(KERN_WARNING "CIFS: Could not parse" 1131 printk(KERN_WARNING "CIFS: Could not parse"
1111 " srcaddr: %s\n", 1132 " srcaddr: %s\n",
1112 value); 1133 value);
1113 return 1; 1134 goto cifs_parse_mount_err;
1114 } 1135 }
1115 } else if (strnicmp(data, "prefixpath", 10) == 0) { 1136 } else if (strnicmp(data, "prefixpath", 10) == 0) {
1116 if (!value || !*value) { 1137 if (!value || !*value) {
1117 printk(KERN_WARNING 1138 printk(KERN_WARNING
1118 "CIFS: invalid path prefix\n"); 1139 "CIFS: invalid path prefix\n");
1119 return 1; /* needs_argument */ 1140 goto cifs_parse_mount_err;
1120 } 1141 }
1121 if ((temp_len = strnlen(value, 1024)) < 1024) { 1142 if ((temp_len = strnlen(value, 1024)) < 1024) {
1122 if (value[0] != '/') 1143 if (value[0] != '/')
1123 temp_len++; /* missing leading slash */ 1144 temp_len++; /* missing leading slash */
1124 vol->prepath = kmalloc(temp_len+1, GFP_KERNEL); 1145 vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
1125 if (vol->prepath == NULL) 1146 if (vol->prepath == NULL)
1126 return 1; 1147 goto cifs_parse_mount_err;
1127 if (value[0] != '/') { 1148 if (value[0] != '/') {
1128 vol->prepath[0] = '/'; 1149 vol->prepath[0] = '/';
1129 strcpy(vol->prepath+1, value); 1150 strcpy(vol->prepath+1, value);
@@ -1132,24 +1153,33 @@ cifs_parse_mount_options(char *options, const char *devname,
1132 cFYI(1, "prefix path %s", vol->prepath); 1153 cFYI(1, "prefix path %s", vol->prepath);
1133 } else { 1154 } else {
1134 printk(KERN_WARNING "CIFS: prefix too long\n"); 1155 printk(KERN_WARNING "CIFS: prefix too long\n");
1135 return 1; 1156 goto cifs_parse_mount_err;
1136 } 1157 }
1137 } else if (strnicmp(data, "iocharset", 9) == 0) { 1158 } else if (strnicmp(data, "iocharset", 9) == 0) {
1138 if (!value || !*value) { 1159 if (!value || !*value) {
1139 printk(KERN_WARNING "CIFS: invalid iocharset " 1160 printk(KERN_WARNING "CIFS: invalid iocharset "
1140 "specified\n"); 1161 "specified\n");
1141 return 1; /* needs_arg; */ 1162 goto cifs_parse_mount_err;
1142 } 1163 }
1143 if (strnlen(value, 65) < 65) { 1164 if (strnlen(value, 65) < 65) {
1144 if (strnicmp(value, "default", 7)) 1165 if (strnicmp(value, "default", 7)) {
1145 vol->iocharset = value; 1166 vol->iocharset = kstrdup(value,
1167 GFP_KERNEL);
1168
1169 if (!vol->iocharset) {
1170 printk(KERN_WARNING "CIFS: no "
1171 "memory for"
1172 "charset\n");
1173 goto cifs_parse_mount_err;
1174 }
1175 }
1146 /* if iocharset not set then load_nls_default 1176 /* if iocharset not set then load_nls_default
1147 is used by caller */ 1177 is used by caller */
1148 cFYI(1, "iocharset set to %s", value); 1178 cFYI(1, "iocharset set to %s", value);
1149 } else { 1179 } else {
1150 printk(KERN_WARNING "CIFS: iocharset name " 1180 printk(KERN_WARNING "CIFS: iocharset name "
1151 "too long.\n"); 1181 "too long.\n");
1152 return 1; 1182 goto cifs_parse_mount_err;
1153 } 1183 }
1154 } else if (!strnicmp(data, "uid", 3) && value && *value) { 1184 } else if (!strnicmp(data, "uid", 3) && value && *value) {
1155 vol->linux_uid = simple_strtoul(value, &value, 0); 1185 vol->linux_uid = simple_strtoul(value, &value, 0);
@@ -1262,7 +1292,7 @@ cifs_parse_mount_options(char *options, const char *devname,
1262 if (vol->actimeo > CIFS_MAX_ACTIMEO) { 1292 if (vol->actimeo > CIFS_MAX_ACTIMEO) {
1263 cERROR(1, "CIFS: attribute cache" 1293 cERROR(1, "CIFS: attribute cache"
1264 "timeout too large"); 1294 "timeout too large");
1265 return 1; 1295 goto cifs_parse_mount_err;
1266 } 1296 }
1267 } 1297 }
1268 } else if (strnicmp(data, "credentials", 4) == 0) { 1298 } else if (strnicmp(data, "credentials", 4) == 0) {
@@ -1406,7 +1436,7 @@ cifs_parse_mount_options(char *options, const char *devname,
1406#ifndef CONFIG_CIFS_FSCACHE 1436#ifndef CONFIG_CIFS_FSCACHE
1407 cERROR(1, "FS-Cache support needs CONFIG_CIFS_FSCACHE" 1437 cERROR(1, "FS-Cache support needs CONFIG_CIFS_FSCACHE"
1408 "kernel config option set"); 1438 "kernel config option set");
1409 return 1; 1439 goto cifs_parse_mount_err;
1410#endif 1440#endif
1411 vol->fsc = true; 1441 vol->fsc = true;
1412 } else if (strnicmp(data, "mfsymlinks", 10) == 0) { 1442 } else if (strnicmp(data, "mfsymlinks", 10) == 0) {
@@ -1421,12 +1451,12 @@ cifs_parse_mount_options(char *options, const char *devname,
1421 if (devname == NULL) { 1451 if (devname == NULL) {
1422 printk(KERN_WARNING "CIFS: Missing UNC name for mount " 1452 printk(KERN_WARNING "CIFS: Missing UNC name for mount "
1423 "target\n"); 1453 "target\n");
1424 return 1; 1454 goto cifs_parse_mount_err;
1425 } 1455 }
1426 if ((temp_len = strnlen(devname, 300)) < 300) { 1456 if ((temp_len = strnlen(devname, 300)) < 300) {
1427 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL); 1457 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
1428 if (vol->UNC == NULL) 1458 if (vol->UNC == NULL)
1429 return 1; 1459 goto cifs_parse_mount_err;
1430 strcpy(vol->UNC, devname); 1460 strcpy(vol->UNC, devname);
1431 if (strncmp(vol->UNC, "//", 2) == 0) { 1461 if (strncmp(vol->UNC, "//", 2) == 0) {
1432 vol->UNC[0] = '\\'; 1462 vol->UNC[0] = '\\';
@@ -1434,21 +1464,21 @@ cifs_parse_mount_options(char *options, const char *devname,
1434 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) { 1464 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
1435 printk(KERN_WARNING "CIFS: UNC Path does not " 1465 printk(KERN_WARNING "CIFS: UNC Path does not "
1436 "begin with // or \\\\ \n"); 1466 "begin with // or \\\\ \n");
1437 return 1; 1467 goto cifs_parse_mount_err;
1438 } 1468 }
1439 value = strpbrk(vol->UNC+2, "/\\"); 1469 value = strpbrk(vol->UNC+2, "/\\");
1440 if (value) 1470 if (value)
1441 *value = '\\'; 1471 *value = '\\';
1442 } else { 1472 } else {
1443 printk(KERN_WARNING "CIFS: UNC name too long\n"); 1473 printk(KERN_WARNING "CIFS: UNC name too long\n");
1444 return 1; 1474 goto cifs_parse_mount_err;
1445 } 1475 }
1446 } 1476 }
1447 1477
1448 if (vol->multiuser && !(vol->secFlg & CIFSSEC_MAY_KRB5)) { 1478 if (vol->multiuser && !(vol->secFlg & CIFSSEC_MAY_KRB5)) {
1449 cERROR(1, "Multiuser mounts currently require krb5 " 1479 cERROR(1, "Multiuser mounts currently require krb5 "
1450 "authentication!"); 1480 "authentication!");
1451 return 1; 1481 goto cifs_parse_mount_err;
1452 } 1482 }
1453 1483
1454 if (vol->UNCip == NULL) 1484 if (vol->UNCip == NULL)
@@ -1466,7 +1496,12 @@ cifs_parse_mount_options(char *options, const char *devname,
1466 printk(KERN_NOTICE "CIFS: ignoring forcegid mount option " 1496 printk(KERN_NOTICE "CIFS: ignoring forcegid mount option "
1467 "specified with no gid= option.\n"); 1497 "specified with no gid= option.\n");
1468 1498
1499 kfree(mountdata_copy);
1469 return 0; 1500 return 0;
1501
1502cifs_parse_mount_err:
1503 kfree(mountdata_copy);
1504 return 1;
1470} 1505}
1471 1506
1472/** Returns true if srcaddr isn't specified and rhs isn't 1507/** Returns true if srcaddr isn't specified and rhs isn't
@@ -2707,8 +2742,12 @@ cleanup_volume_info(struct smb_vol **pvolume_info)
2707 return; 2742 return;
2708 2743
2709 volume_info = *pvolume_info; 2744 volume_info = *pvolume_info;
2745 kfree(volume_info->username);
2710 kzfree(volume_info->password); 2746 kzfree(volume_info->password);
2711 kfree(volume_info->UNC); 2747 kfree(volume_info->UNC);
2748 kfree(volume_info->UNCip);
2749 kfree(volume_info->domainname);
2750 kfree(volume_info->iocharset);
2712 kfree(volume_info->prepath); 2751 kfree(volume_info->prepath);
2713 kfree(volume_info); 2752 kfree(volume_info);
2714 *pvolume_info = NULL; 2753 *pvolume_info = NULL;