diff options
-rw-r--r-- | fs/cifs/sess.c | 490 |
1 files changed, 263 insertions, 227 deletions
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index b413fae993aa..c2e7c07c9d5c 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c | |||
@@ -1113,241 +1113,225 @@ sess_auth_kerberos(struct sess_data *sess_data) | |||
1113 | } | 1113 | } |
1114 | #endif /* ! CONFIG_CIFS_UPCALL */ | 1114 | #endif /* ! CONFIG_CIFS_UPCALL */ |
1115 | 1115 | ||
1116 | int | 1116 | /* |
1117 | CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses, | 1117 | * The required kvec buffers have to be allocated before calling this |
1118 | const struct nls_table *nls_cp) | 1118 | * function. |
1119 | */ | ||
1120 | static int | ||
1121 | _sess_auth_rawntlmssp_assemble_req(struct sess_data *sess_data) | ||
1119 | { | 1122 | { |
1120 | int rc = 0; | ||
1121 | int wct; | ||
1122 | struct smb_hdr *smb_buf; | 1123 | struct smb_hdr *smb_buf; |
1123 | char *bcc_ptr; | ||
1124 | char *str_area; | ||
1125 | SESSION_SETUP_ANDX *pSMB; | 1124 | SESSION_SETUP_ANDX *pSMB; |
1125 | struct cifs_ses *ses = sess_data->ses; | ||
1126 | __u32 capabilities; | 1126 | __u32 capabilities; |
1127 | __u16 count; | 1127 | char *bcc_ptr; |
1128 | int resp_buf_type; | ||
1129 | struct kvec iov[3]; | ||
1130 | enum securityEnum type; | ||
1131 | __u16 action, bytes_remaining; | ||
1132 | __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ | ||
1133 | u16 blob_len; | ||
1134 | char *ntlmsspblob = NULL; | ||
1135 | struct sess_data *sess_data; | ||
1136 | 1128 | ||
1137 | if (ses == NULL) { | 1129 | pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; |
1138 | WARN(1, "%s: ses == NULL!", __func__); | 1130 | smb_buf = (struct smb_hdr *)pSMB; |
1139 | return -EINVAL; | 1131 | |
1132 | capabilities = cifs_ssetup_hdr(ses, pSMB); | ||
1133 | if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) { | ||
1134 | cifs_dbg(VFS, "NTLMSSP requires Unicode support\n"); | ||
1135 | return -ENOSYS; | ||
1140 | } | 1136 | } |
1141 | 1137 | ||
1142 | sess_data = kzalloc(sizeof(struct sess_data), GFP_KERNEL); | 1138 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; |
1143 | if (!sess_data) | 1139 | capabilities |= CAP_EXTENDED_SECURITY; |
1144 | return -ENOMEM; | 1140 | pSMB->req.Capabilities |= cpu_to_le32(capabilities); |
1145 | sess_data->xid = xid; | ||
1146 | sess_data->ses = ses; | ||
1147 | sess_data->buf0_type = CIFS_NO_BUFFER; | ||
1148 | sess_data->nls_cp = (struct nls_table *) nls_cp; | ||
1149 | 1141 | ||
1150 | type = select_sectype(ses->server, ses->sectype); | 1142 | bcc_ptr = sess_data->iov[2].iov_base; |
1151 | cifs_dbg(FYI, "sess setup type %d\n", type); | 1143 | /* unicode strings must be word aligned */ |
1152 | if (type == Unspecified) { | 1144 | if ((sess_data->iov[0].iov_len + sess_data->iov[1].iov_len) % 2) { |
1153 | cifs_dbg(VFS, | 1145 | *bcc_ptr = 0; |
1154 | "Unable to select appropriate authentication method!"); | 1146 | bcc_ptr++; |
1155 | return -EINVAL; | ||
1156 | } | 1147 | } |
1148 | unicode_oslm_strings(&bcc_ptr, sess_data->nls_cp); | ||
1157 | 1149 | ||
1158 | switch (type) { | 1150 | sess_data->iov[2].iov_len = (long) bcc_ptr - |
1159 | case LANMAN: | 1151 | (long) sess_data->iov[2].iov_base; |
1160 | sess_auth_lanman(sess_data); | ||
1161 | goto out; | ||
1162 | case NTLM: | ||
1163 | sess_auth_ntlm(sess_data); | ||
1164 | goto out; | ||
1165 | case NTLMv2: | ||
1166 | sess_auth_ntlmv2(sess_data); | ||
1167 | goto out; | ||
1168 | case Kerberos: | ||
1169 | sess_auth_kerberos(sess_data); | ||
1170 | goto out; | ||
1171 | default: | ||
1172 | cifs_dbg(FYI, "Continuing with CIFS_SessSetup\n"); | ||
1173 | } | ||
1174 | 1152 | ||
1175 | if (type == RawNTLMSSP) { | 1153 | return 0; |
1176 | /* if memory allocation is successful, caller of this function | 1154 | } |
1177 | * frees it. | 1155 | |
1178 | */ | 1156 | static void |
1179 | ses->ntlmssp = kmalloc(sizeof(struct ntlmssp_auth), GFP_KERNEL); | 1157 | sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data); |
1180 | if (!ses->ntlmssp) | 1158 | |
1181 | return -ENOMEM; | 1159 | static void |
1182 | ses->ntlmssp->sesskey_per_smbsess = false; | 1160 | sess_auth_rawntlmssp_negotiate(struct sess_data *sess_data) |
1161 | { | ||
1162 | int rc; | ||
1163 | struct smb_hdr *smb_buf; | ||
1164 | SESSION_SETUP_ANDX *pSMB; | ||
1165 | struct cifs_ses *ses = sess_data->ses; | ||
1166 | __u16 bytes_remaining; | ||
1167 | char *bcc_ptr; | ||
1168 | u16 blob_len; | ||
1169 | |||
1170 | cifs_dbg(FYI, "rawntlmssp session setup negotiate phase\n"); | ||
1183 | 1171 | ||
1172 | /* | ||
1173 | * if memory allocation is successful, caller of this function | ||
1174 | * frees it. | ||
1175 | */ | ||
1176 | ses->ntlmssp = kmalloc(sizeof(struct ntlmssp_auth), GFP_KERNEL); | ||
1177 | if (!ses->ntlmssp) { | ||
1178 | rc = -ENOMEM; | ||
1179 | goto out; | ||
1184 | } | 1180 | } |
1181 | ses->ntlmssp->sesskey_per_smbsess = false; | ||
1185 | 1182 | ||
1186 | ssetup_ntlmssp_authenticate: | 1183 | /* wct = 12 */ |
1187 | if (phase == NtLmChallenge) | 1184 | rc = sess_alloc_buffer(sess_data, 12); |
1188 | phase = NtLmAuthenticate; /* if ntlmssp, now final phase */ | 1185 | if (rc) |
1186 | goto out; | ||
1189 | 1187 | ||
1190 | /* same size: negotiate or auth, NTLMSSP or extended security */ | 1188 | pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; |
1191 | wct = 12; | ||
1192 | 1189 | ||
1193 | rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses, | 1190 | /* Build security blob before we assemble the request */ |
1194 | (void **)&smb_buf); | 1191 | build_ntlmssp_negotiate_blob(pSMB->req.SecurityBlob, ses); |
1192 | sess_data->iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE); | ||
1193 | sess_data->iov[1].iov_base = pSMB->req.SecurityBlob; | ||
1194 | pSMB->req.SecurityBlobLength = cpu_to_le16(sizeof(NEGOTIATE_MESSAGE)); | ||
1195 | |||
1196 | rc = _sess_auth_rawntlmssp_assemble_req(sess_data); | ||
1195 | if (rc) | 1197 | if (rc) |
1196 | return rc; | 1198 | goto out; |
1197 | 1199 | ||
1198 | pSMB = (SESSION_SETUP_ANDX *)smb_buf; | 1200 | rc = sess_sendreceive(sess_data); |
1199 | 1201 | ||
1200 | capabilities = cifs_ssetup_hdr(ses, pSMB); | 1202 | pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; |
1203 | smb_buf = (struct smb_hdr *)sess_data->iov[0].iov_base; | ||
1201 | 1204 | ||
1202 | /* we will send the SMB in three pieces: | 1205 | /* If true, rc here is expected and not an error */ |
1203 | a fixed length beginning part, an optional | 1206 | if (sess_data->buf0_type != CIFS_NO_BUFFER && |
1204 | SPNEGO blob (which can be zero length), and a | 1207 | smb_buf->Status.CifsError == |
1205 | last part which will include the strings | 1208 | cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED)) |
1206 | and rest of bcc area. This allows us to avoid | 1209 | rc = 0; |
1207 | a large buffer 17K allocation */ | ||
1208 | iov[0].iov_base = (char *)pSMB; | ||
1209 | iov[0].iov_len = be32_to_cpu(smb_buf->smb_buf_length) + 4; | ||
1210 | |||
1211 | /* setting this here allows the code at the end of the function | ||
1212 | to free the request buffer if there's an error */ | ||
1213 | resp_buf_type = CIFS_SMALL_BUFFER; | ||
1214 | 1210 | ||
1215 | /* 2000 big enough to fit max user, domain, NOS name etc. */ | 1211 | if (rc) |
1216 | str_area = kmalloc(2000, GFP_KERNEL); | 1212 | goto out; |
1217 | if (str_area == NULL) { | 1213 | |
1218 | rc = -ENOMEM; | 1214 | cifs_dbg(FYI, "rawntlmssp session setup challenge phase\n"); |
1219 | goto ssetup_exit; | 1215 | |
1216 | if (smb_buf->WordCount != 4) { | ||
1217 | rc = -EIO; | ||
1218 | cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount); | ||
1219 | goto out; | ||
1220 | } | 1220 | } |
1221 | bcc_ptr = str_area; | ||
1222 | 1221 | ||
1223 | iov[1].iov_base = NULL; | 1222 | ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */ |
1224 | iov[1].iov_len = 0; | 1223 | cifs_dbg(FYI, "UID = %llu\n", ses->Suid); |
1225 | 1224 | ||
1226 | if (type == RawNTLMSSP) { | 1225 | bytes_remaining = get_bcc(smb_buf); |
1227 | if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) { | 1226 | bcc_ptr = pByteArea(smb_buf); |
1228 | cifs_dbg(VFS, "NTLMSSP requires Unicode support\n"); | ||
1229 | rc = -ENOSYS; | ||
1230 | goto ssetup_exit; | ||
1231 | } | ||
1232 | 1227 | ||
1233 | cifs_dbg(FYI, "ntlmssp session setup phase %d\n", phase); | 1228 | blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength); |
1234 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | 1229 | if (blob_len > bytes_remaining) { |
1235 | capabilities |= CAP_EXTENDED_SECURITY; | 1230 | cifs_dbg(VFS, "bad security blob length %d\n", |
1236 | pSMB->req.Capabilities |= cpu_to_le32(capabilities); | 1231 | blob_len); |
1237 | switch(phase) { | 1232 | rc = -EINVAL; |
1238 | case NtLmNegotiate: | 1233 | goto out; |
1239 | build_ntlmssp_negotiate_blob( | 1234 | } |
1240 | pSMB->req.SecurityBlob, ses); | ||
1241 | iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE); | ||
1242 | iov[1].iov_base = pSMB->req.SecurityBlob; | ||
1243 | pSMB->req.SecurityBlobLength = | ||
1244 | cpu_to_le16(sizeof(NEGOTIATE_MESSAGE)); | ||
1245 | break; | ||
1246 | case NtLmAuthenticate: | ||
1247 | /* | ||
1248 | * 5 is an empirical value, large enough to hold | ||
1249 | * authenticate message plus max 10 of av paris, | ||
1250 | * domain, user, workstation names, flags, etc. | ||
1251 | */ | ||
1252 | ntlmsspblob = kzalloc( | ||
1253 | 5*sizeof(struct _AUTHENTICATE_MESSAGE), | ||
1254 | GFP_KERNEL); | ||
1255 | if (!ntlmsspblob) { | ||
1256 | rc = -ENOMEM; | ||
1257 | goto ssetup_exit; | ||
1258 | } | ||
1259 | 1235 | ||
1260 | rc = build_ntlmssp_auth_blob(ntlmsspblob, | 1236 | rc = decode_ntlmssp_challenge(bcc_ptr, blob_len, ses); |
1261 | &blob_len, ses, nls_cp); | 1237 | out: |
1262 | if (rc) | 1238 | sess_free_buffer(sess_data); |
1263 | goto ssetup_exit; | 1239 | |
1264 | iov[1].iov_len = blob_len; | 1240 | if (!rc) { |
1265 | iov[1].iov_base = ntlmsspblob; | 1241 | sess_data->func = sess_auth_rawntlmssp_authenticate; |
1266 | pSMB->req.SecurityBlobLength = cpu_to_le16(blob_len); | 1242 | return; |
1267 | /* | ||
1268 | * Make sure that we tell the server that we are using | ||
1269 | * the uid that it just gave us back on the response | ||
1270 | * (challenge) | ||
1271 | */ | ||
1272 | smb_buf->Uid = ses->Suid; | ||
1273 | break; | ||
1274 | default: | ||
1275 | cifs_dbg(VFS, "invalid phase %d\n", phase); | ||
1276 | rc = -ENOSYS; | ||
1277 | goto ssetup_exit; | ||
1278 | } | ||
1279 | /* unicode strings must be word aligned */ | ||
1280 | if ((iov[0].iov_len + iov[1].iov_len) % 2) { | ||
1281 | *bcc_ptr = 0; | ||
1282 | bcc_ptr++; | ||
1283 | } | ||
1284 | unicode_oslm_strings(&bcc_ptr, nls_cp); | ||
1285 | } else { | ||
1286 | cifs_dbg(VFS, "secType %d not supported!\n", type); | ||
1287 | rc = -ENOSYS; | ||
1288 | goto ssetup_exit; | ||
1289 | } | 1243 | } |
1290 | 1244 | ||
1291 | iov[2].iov_base = str_area; | 1245 | /* Else error. Cleanup */ |
1292 | iov[2].iov_len = (long) bcc_ptr - (long) str_area; | 1246 | kfree(ses->auth_key.response); |
1247 | ses->auth_key.response = NULL; | ||
1248 | kfree(ses->ntlmssp); | ||
1249 | ses->ntlmssp = NULL; | ||
1293 | 1250 | ||
1294 | count = iov[1].iov_len + iov[2].iov_len; | 1251 | sess_data->func = NULL; |
1295 | smb_buf->smb_buf_length = | 1252 | sess_data->result = rc; |
1296 | cpu_to_be32(be32_to_cpu(smb_buf->smb_buf_length) + count); | 1253 | } |
1297 | 1254 | ||
1298 | put_bcc(count, smb_buf); | 1255 | static void |
1256 | sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data) | ||
1257 | { | ||
1258 | int rc; | ||
1259 | struct smb_hdr *smb_buf; | ||
1260 | SESSION_SETUP_ANDX *pSMB; | ||
1261 | struct cifs_ses *ses = sess_data->ses; | ||
1262 | __u16 bytes_remaining; | ||
1263 | char *bcc_ptr; | ||
1264 | char *ntlmsspblob = NULL; | ||
1265 | u16 blob_len; | ||
1299 | 1266 | ||
1300 | rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type, | 1267 | cifs_dbg(FYI, "rawntlmssp session setup authenticate phase\n"); |
1301 | CIFS_LOG_ERROR); | ||
1302 | /* SMB request buf freed in SendReceive2 */ | ||
1303 | 1268 | ||
1304 | pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base; | 1269 | /* wct = 12 */ |
1305 | smb_buf = (struct smb_hdr *)iov[0].iov_base; | 1270 | rc = sess_alloc_buffer(sess_data, 12); |
1271 | if (rc) | ||
1272 | goto out; | ||
1306 | 1273 | ||
1307 | if ((type == RawNTLMSSP) && (resp_buf_type != CIFS_NO_BUFFER) && | 1274 | /* Build security blob before we assemble the request */ |
1308 | (smb_buf->Status.CifsError == | 1275 | pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; |
1309 | cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))) { | 1276 | smb_buf = (struct smb_hdr *)pSMB; |
1310 | if (phase != NtLmNegotiate) { | 1277 | /* |
1311 | cifs_dbg(VFS, "Unexpected more processing error\n"); | 1278 | * 5 is an empirical value, large enough to hold |
1312 | goto ssetup_exit; | 1279 | * authenticate message plus max 10 of av paris, |
1313 | } | 1280 | * domain, user, workstation names, flags, etc. |
1314 | /* NTLMSSP Negotiate sent now processing challenge (response) */ | 1281 | */ |
1315 | phase = NtLmChallenge; /* process ntlmssp challenge */ | 1282 | ntlmsspblob = kzalloc(5*sizeof(struct _AUTHENTICATE_MESSAGE), |
1316 | rc = 0; /* MORE_PROC rc is not an error here, but expected */ | 1283 | GFP_KERNEL); |
1284 | if (!ntlmsspblob) { | ||
1285 | rc = -ENOMEM; | ||
1286 | goto out; | ||
1317 | } | 1287 | } |
1288 | |||
1289 | rc = build_ntlmssp_auth_blob(ntlmsspblob, | ||
1290 | &blob_len, ses, sess_data->nls_cp); | ||
1291 | if (rc) | ||
1292 | goto out_free_ntlmsspblob; | ||
1293 | sess_data->iov[1].iov_len = blob_len; | ||
1294 | sess_data->iov[1].iov_base = ntlmsspblob; | ||
1295 | pSMB->req.SecurityBlobLength = cpu_to_le16(blob_len); | ||
1296 | /* | ||
1297 | * Make sure that we tell the server that we are using | ||
1298 | * the uid that it just gave us back on the response | ||
1299 | * (challenge) | ||
1300 | */ | ||
1301 | smb_buf->Uid = ses->Suid; | ||
1302 | |||
1303 | rc = _sess_auth_rawntlmssp_assemble_req(sess_data); | ||
1318 | if (rc) | 1304 | if (rc) |
1319 | goto ssetup_exit; | 1305 | goto out_free_ntlmsspblob; |
1320 | 1306 | ||
1307 | rc = sess_sendreceive(sess_data); | ||
1308 | if (rc) | ||
1309 | goto out_free_ntlmsspblob; | ||
1310 | |||
1311 | pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; | ||
1312 | smb_buf = (struct smb_hdr *)sess_data->iov[0].iov_base; | ||
1321 | if (smb_buf->WordCount != 4) { | 1313 | if (smb_buf->WordCount != 4) { |
1322 | rc = -EIO; | 1314 | rc = -EIO; |
1323 | cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount); | 1315 | cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount); |
1324 | goto ssetup_exit; | 1316 | goto out_free_ntlmsspblob; |
1325 | } | 1317 | } |
1326 | action = le16_to_cpu(pSMB->resp.Action); | 1318 | |
1327 | if (action & GUEST_LOGIN) | 1319 | if (le16_to_cpu(pSMB->resp.Action) & GUEST_LOGIN) |
1328 | cifs_dbg(FYI, "Guest login\n"); /* BB mark SesInfo struct? */ | 1320 | cifs_dbg(FYI, "Guest login\n"); /* BB mark SesInfo struct? */ |
1329 | ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */ | 1321 | |
1330 | cifs_dbg(FYI, "UID = %llu\n", ses->Suid); | ||
1331 | /* response can have either 3 or 4 word count - Samba sends 3 */ | ||
1332 | /* and lanman response is 3 */ | ||
1333 | bytes_remaining = get_bcc(smb_buf); | 1322 | bytes_remaining = get_bcc(smb_buf); |
1334 | bcc_ptr = pByteArea(smb_buf); | 1323 | bcc_ptr = pByteArea(smb_buf); |
1335 | |||
1336 | blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength); | 1324 | blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength); |
1337 | if (blob_len > bytes_remaining) { | 1325 | if (blob_len > bytes_remaining) { |
1338 | cifs_dbg(VFS, "bad security blob length %d\n", | 1326 | cifs_dbg(VFS, "bad security blob length %d\n", |
1339 | blob_len); | 1327 | blob_len); |
1340 | rc = -EINVAL; | 1328 | rc = -EINVAL; |
1341 | goto ssetup_exit; | 1329 | goto out_free_ntlmsspblob; |
1342 | } | ||
1343 | if (phase == NtLmChallenge) { | ||
1344 | rc = decode_ntlmssp_challenge(bcc_ptr, blob_len, ses); | ||
1345 | if (rc) | ||
1346 | goto ssetup_exit; | ||
1347 | } | 1330 | } |
1348 | bcc_ptr += blob_len; | 1331 | bcc_ptr += blob_len; |
1349 | bytes_remaining -= blob_len; | 1332 | bytes_remaining -= blob_len; |
1350 | 1333 | ||
1334 | |||
1351 | /* BB check if Unicode and decode strings */ | 1335 | /* BB check if Unicode and decode strings */ |
1352 | if (bytes_remaining == 0) { | 1336 | if (bytes_remaining == 0) { |
1353 | /* no string area to decode, do nothing */ | 1337 | /* no string area to decode, do nothing */ |
@@ -1357,61 +1341,113 @@ ssetup_ntlmssp_authenticate: | |||
1357 | ++bcc_ptr; | 1341 | ++bcc_ptr; |
1358 | --bytes_remaining; | 1342 | --bytes_remaining; |
1359 | } | 1343 | } |
1360 | decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses, nls_cp); | 1344 | decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses, |
1345 | sess_data->nls_cp); | ||
1361 | } else { | 1346 | } else { |
1362 | decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses, nls_cp); | 1347 | decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses, |
1348 | sess_data->nls_cp); | ||
1363 | } | 1349 | } |
1364 | 1350 | ||
1365 | ssetup_exit: | 1351 | out_free_ntlmsspblob: |
1366 | kfree(str_area); | ||
1367 | kfree(ntlmsspblob); | 1352 | kfree(ntlmsspblob); |
1368 | ntlmsspblob = NULL; | 1353 | out: |
1369 | if (resp_buf_type == CIFS_SMALL_BUFFER) { | 1354 | sess_free_buffer(sess_data); |
1370 | cifs_dbg(FYI, "ssetup freeing small buf %p\n", iov[0].iov_base); | ||
1371 | cifs_small_buf_release(iov[0].iov_base); | ||
1372 | } else if (resp_buf_type == CIFS_LARGE_BUFFER) | ||
1373 | cifs_buf_release(iov[0].iov_base); | ||
1374 | |||
1375 | /* if ntlmssp, and negotiate succeeded, proceed to authenticate phase */ | ||
1376 | if ((phase == NtLmChallenge) && (rc == 0)) | ||
1377 | goto ssetup_ntlmssp_authenticate; | ||
1378 | |||
1379 | if (!rc) { | ||
1380 | mutex_lock(&ses->server->srv_mutex); | ||
1381 | if (!ses->server->session_estab) { | ||
1382 | if (ses->server->sign) { | ||
1383 | ses->server->session_key.response = | ||
1384 | kmemdup(ses->auth_key.response, | ||
1385 | ses->auth_key.len, GFP_KERNEL); | ||
1386 | if (!ses->server->session_key.response) { | ||
1387 | rc = -ENOMEM; | ||
1388 | mutex_unlock(&ses->server->srv_mutex); | ||
1389 | goto keycp_exit; | ||
1390 | } | ||
1391 | ses->server->session_key.len = | ||
1392 | ses->auth_key.len; | ||
1393 | } | ||
1394 | ses->server->sequence_number = 0x2; | ||
1395 | ses->server->session_estab = true; | ||
1396 | } | ||
1397 | mutex_unlock(&ses->server->srv_mutex); | ||
1398 | 1355 | ||
1399 | cifs_dbg(FYI, "CIFS session established successfully\n"); | 1356 | if (!rc) |
1400 | spin_lock(&GlobalMid_Lock); | 1357 | rc = sess_establish_session(sess_data); |
1401 | ses->status = CifsGood; | ||
1402 | ses->need_reconnect = false; | ||
1403 | spin_unlock(&GlobalMid_Lock); | ||
1404 | } | ||
1405 | 1358 | ||
1406 | keycp_exit: | 1359 | /* Cleanup */ |
1407 | kfree(ses->auth_key.response); | 1360 | kfree(ses->auth_key.response); |
1408 | ses->auth_key.response = NULL; | 1361 | ses->auth_key.response = NULL; |
1409 | kfree(ses->ntlmssp); | 1362 | kfree(ses->ntlmssp); |
1363 | ses->ntlmssp = NULL; | ||
1410 | 1364 | ||
1411 | return rc; | 1365 | sess_data->func = NULL; |
1366 | sess_data->result = rc; | ||
1367 | } | ||
1412 | 1368 | ||
1413 | out: | 1369 | int select_sec(struct cifs_ses *ses, struct sess_data *sess_data) |
1370 | { | ||
1371 | int type; | ||
1372 | |||
1373 | type = select_sectype(ses->server, ses->sectype); | ||
1374 | cifs_dbg(FYI, "sess setup type %d\n", type); | ||
1375 | if (type == Unspecified) { | ||
1376 | cifs_dbg(VFS, | ||
1377 | "Unable to select appropriate authentication method!"); | ||
1378 | return -EINVAL; | ||
1379 | } | ||
1380 | |||
1381 | switch (type) { | ||
1382 | case LANMAN: | ||
1383 | /* LANMAN and plaintext are less secure and off by default. | ||
1384 | * So we make this explicitly be turned on in kconfig (in the | ||
1385 | * build) and turned on at runtime (changed from the default) | ||
1386 | * in proc/fs/cifs or via mount parm. Unfortunately this is | ||
1387 | * needed for old Win (e.g. Win95), some obscure NAS and OS/2 */ | ||
1388 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
1389 | sess_data->func = sess_auth_lanman; | ||
1390 | break; | ||
1391 | #else | ||
1392 | return -EOPNOTSUPP; | ||
1393 | #endif | ||
1394 | case NTLM: | ||
1395 | sess_data->func = sess_auth_ntlm; | ||
1396 | break; | ||
1397 | case NTLMv2: | ||
1398 | sess_data->func = sess_auth_ntlmv2; | ||
1399 | break; | ||
1400 | case Kerberos: | ||
1401 | #ifdef CONFIG_CIFS_UPCALL | ||
1402 | sess_data->func = sess_auth_kerberos; | ||
1403 | break; | ||
1404 | #else | ||
1405 | cifs_dbg(VFS, "Kerberos negotiated but upcall support disabled!\n"); | ||
1406 | return -ENOSYS; | ||
1407 | break; | ||
1408 | #endif /* CONFIG_CIFS_UPCALL */ | ||
1409 | case RawNTLMSSP: | ||
1410 | sess_data->func = sess_auth_rawntlmssp_negotiate; | ||
1411 | break; | ||
1412 | default: | ||
1413 | cifs_dbg(VFS, "secType %d not supported!\n", type); | ||
1414 | return -ENOSYS; | ||
1415 | } | ||
1416 | |||
1417 | return 0; | ||
1418 | } | ||
1419 | |||
1420 | int CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses, | ||
1421 | const struct nls_table *nls_cp) | ||
1422 | { | ||
1423 | int rc = 0; | ||
1424 | struct sess_data *sess_data; | ||
1425 | |||
1426 | if (ses == NULL) { | ||
1427 | WARN(1, "%s: ses == NULL!", __func__); | ||
1428 | return -EINVAL; | ||
1429 | } | ||
1430 | |||
1431 | sess_data = kzalloc(sizeof(struct sess_data), GFP_KERNEL); | ||
1432 | if (!sess_data) | ||
1433 | return -ENOMEM; | ||
1434 | |||
1435 | rc = select_sec(ses, sess_data); | ||
1436 | if (rc) | ||
1437 | goto out; | ||
1438 | |||
1439 | sess_data->xid = xid; | ||
1440 | sess_data->ses = ses; | ||
1441 | sess_data->buf0_type = CIFS_NO_BUFFER; | ||
1442 | sess_data->nls_cp = (struct nls_table *) nls_cp; | ||
1443 | |||
1444 | while (sess_data->func) | ||
1445 | sess_data->func(sess_data); | ||
1446 | |||
1447 | /* Store result before we free sess_data */ | ||
1414 | rc = sess_data->result; | 1448 | rc = sess_data->result; |
1449 | |||
1450 | out: | ||
1415 | kfree(sess_data); | 1451 | kfree(sess_data); |
1416 | return rc; | 1452 | return rc; |
1417 | } | 1453 | } |