diff options
Diffstat (limited to 'fs/cifs/connect.c')
| -rw-r--r-- | fs/cifs/connect.c | 743 |
1 files changed, 513 insertions, 230 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 40470b9d5477..e568cc47a7f9 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * fs/cifs/connect.c | 2 | * fs/cifs/connect.c |
| 3 | * | 3 | * |
| 4 | * Copyright (C) International Business Machines Corp., 2002,2004 | 4 | * Copyright (C) International Business Machines Corp., 2002,2005 |
| 5 | * Author(s): Steve French (sfrench@us.ibm.com) | 5 | * Author(s): Steve French (sfrench@us.ibm.com) |
| 6 | * | 6 | * |
| 7 | * This library is free software; you can redistribute it and/or modify | 7 | * This library is free software; you can redistribute it and/or modify |
| @@ -28,6 +28,7 @@ | |||
| 28 | #include <linux/ctype.h> | 28 | #include <linux/ctype.h> |
| 29 | #include <linux/utsname.h> | 29 | #include <linux/utsname.h> |
| 30 | #include <linux/mempool.h> | 30 | #include <linux/mempool.h> |
| 31 | #include <linux/delay.h> | ||
| 31 | #include <asm/uaccess.h> | 32 | #include <asm/uaccess.h> |
| 32 | #include <asm/processor.h> | 33 | #include <asm/processor.h> |
| 33 | #include "cifspdu.h" | 34 | #include "cifspdu.h" |
| @@ -72,6 +73,7 @@ struct smb_vol { | |||
| 72 | unsigned no_xattr:1; /* set if xattr (EA) support should be disabled*/ | 73 | unsigned no_xattr:1; /* set if xattr (EA) support should be disabled*/ |
| 73 | unsigned server_ino:1; /* use inode numbers from server ie UniqueId */ | 74 | unsigned server_ino:1; /* use inode numbers from server ie UniqueId */ |
| 74 | unsigned direct_io:1; | 75 | unsigned direct_io:1; |
| 76 | unsigned remap:1; /* set to remap seven reserved chars in filenames */ | ||
| 75 | unsigned int rsize; | 77 | unsigned int rsize; |
| 76 | unsigned int wsize; | 78 | unsigned int wsize; |
| 77 | unsigned int sockopt; | 79 | unsigned int sockopt; |
| @@ -114,7 +116,7 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
| 114 | spin_unlock(&GlobalMid_Lock); | 116 | spin_unlock(&GlobalMid_Lock); |
| 115 | server->maxBuf = 0; | 117 | server->maxBuf = 0; |
| 116 | 118 | ||
| 117 | cFYI(1, ("Reconnecting tcp session ")); | 119 | cFYI(1, ("Reconnecting tcp session")); |
| 118 | 120 | ||
| 119 | /* before reconnecting the tcp session, mark the smb session (uid) | 121 | /* before reconnecting the tcp session, mark the smb session (uid) |
| 120 | and the tid bad so they are not used until reconnected */ | 122 | and the tid bad so they are not used until reconnected */ |
| @@ -155,9 +157,10 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
| 155 | qhead); | 157 | qhead); |
| 156 | if(mid_entry) { | 158 | if(mid_entry) { |
| 157 | if(mid_entry->midState == MID_REQUEST_SUBMITTED) { | 159 | if(mid_entry->midState == MID_REQUEST_SUBMITTED) { |
| 158 | /* Mark other intransit requests as needing retry so | 160 | /* Mark other intransit requests as needing |
| 159 | we do not immediately mark the session bad again | 161 | retry so we do not immediately mark the |
| 160 | (ie after we reconnect below) as they timeout too */ | 162 | session bad again (ie after we reconnect |
| 163 | below) as they timeout too */ | ||
| 161 | mid_entry->midState = MID_RETRY_NEEDED; | 164 | mid_entry->midState = MID_RETRY_NEEDED; |
| 162 | } | 165 | } |
| 163 | } | 166 | } |
| @@ -175,14 +178,14 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
| 175 | server->workstation_RFC1001_name); | 178 | server->workstation_RFC1001_name); |
| 176 | } | 179 | } |
| 177 | if(rc) { | 180 | if(rc) { |
| 178 | set_current_state(TASK_INTERRUPTIBLE); | 181 | msleep(3000); |
| 179 | schedule_timeout(3 * HZ); | ||
| 180 | } else { | 182 | } else { |
| 181 | atomic_inc(&tcpSesReconnectCount); | 183 | atomic_inc(&tcpSesReconnectCount); |
| 182 | spin_lock(&GlobalMid_Lock); | 184 | spin_lock(&GlobalMid_Lock); |
| 183 | if(server->tcpStatus != CifsExiting) | 185 | if(server->tcpStatus != CifsExiting) |
| 184 | server->tcpStatus = CifsGood; | 186 | server->tcpStatus = CifsGood; |
| 185 | spin_unlock(&GlobalMid_Lock); | 187 | server->sequence_number = 0; |
| 188 | spin_unlock(&GlobalMid_Lock); | ||
| 186 | /* atomic_set(&server->inFlight,0);*/ | 189 | /* atomic_set(&server->inFlight,0);*/ |
| 187 | wake_up(&server->response_q); | 190 | wake_up(&server->response_q); |
| 188 | } | 191 | } |
| @@ -190,12 +193,129 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
| 190 | return rc; | 193 | return rc; |
| 191 | } | 194 | } |
| 192 | 195 | ||
| 196 | /* | ||
| 197 | return codes: | ||
| 198 | 0 not a transact2, or all data present | ||
| 199 | >0 transact2 with that much data missing | ||
| 200 | -EINVAL = invalid transact2 | ||
| 201 | |||
| 202 | */ | ||
| 203 | static int check2ndT2(struct smb_hdr * pSMB, unsigned int maxBufSize) | ||
| 204 | { | ||
| 205 | struct smb_t2_rsp * pSMBt; | ||
| 206 | int total_data_size; | ||
| 207 | int data_in_this_rsp; | ||
| 208 | int remaining; | ||
| 209 | |||
| 210 | if(pSMB->Command != SMB_COM_TRANSACTION2) | ||
| 211 | return 0; | ||
| 212 | |||
| 213 | /* check for plausible wct, bcc and t2 data and parm sizes */ | ||
| 214 | /* check for parm and data offset going beyond end of smb */ | ||
| 215 | if(pSMB->WordCount != 10) { /* coalesce_t2 depends on this */ | ||
| 216 | cFYI(1,("invalid transact2 word count")); | ||
| 217 | return -EINVAL; | ||
| 218 | } | ||
| 219 | |||
| 220 | pSMBt = (struct smb_t2_rsp *)pSMB; | ||
| 221 | |||
| 222 | total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount); | ||
| 223 | data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount); | ||
| 224 | |||
| 225 | remaining = total_data_size - data_in_this_rsp; | ||
| 226 | |||
| 227 | if(remaining == 0) | ||
| 228 | return 0; | ||
| 229 | else if(remaining < 0) { | ||
| 230 | cFYI(1,("total data %d smaller than data in frame %d", | ||
| 231 | total_data_size, data_in_this_rsp)); | ||
| 232 | return -EINVAL; | ||
| 233 | } else { | ||
| 234 | cFYI(1,("missing %d bytes from transact2, check next response", | ||
| 235 | remaining)); | ||
| 236 | if(total_data_size > maxBufSize) { | ||
| 237 | cERROR(1,("TotalDataSize %d is over maximum buffer %d", | ||
| 238 | total_data_size,maxBufSize)); | ||
| 239 | return -EINVAL; | ||
| 240 | } | ||
| 241 | return remaining; | ||
| 242 | } | ||
| 243 | } | ||
| 244 | |||
| 245 | static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB) | ||
| 246 | { | ||
| 247 | struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond; | ||
| 248 | struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB; | ||
| 249 | int total_data_size; | ||
| 250 | int total_in_buf; | ||
| 251 | int remaining; | ||
| 252 | int total_in_buf2; | ||
| 253 | char * data_area_of_target; | ||
| 254 | char * data_area_of_buf2; | ||
| 255 | __u16 byte_count; | ||
| 256 | |||
| 257 | total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount); | ||
| 258 | |||
| 259 | if(total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) { | ||
| 260 | cFYI(1,("total data sizes of primary and secondary t2 differ")); | ||
| 261 | } | ||
| 262 | |||
| 263 | total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount); | ||
| 264 | |||
| 265 | remaining = total_data_size - total_in_buf; | ||
| 266 | |||
| 267 | if(remaining < 0) | ||
| 268 | return -EINVAL; | ||
| 269 | |||
| 270 | if(remaining == 0) /* nothing to do, ignore */ | ||
| 271 | return 0; | ||
| 272 | |||
| 273 | total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount); | ||
| 274 | if(remaining < total_in_buf2) { | ||
| 275 | cFYI(1,("transact2 2nd response contains too much data")); | ||
| 276 | } | ||
| 277 | |||
| 278 | /* find end of first SMB data area */ | ||
| 279 | data_area_of_target = (char *)&pSMBt->hdr.Protocol + | ||
| 280 | le16_to_cpu(pSMBt->t2_rsp.DataOffset); | ||
| 281 | /* validate target area */ | ||
| 282 | |||
| 283 | data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol + | ||
| 284 | le16_to_cpu(pSMB2->t2_rsp.DataOffset); | ||
| 285 | |||
| 286 | data_area_of_target += total_in_buf; | ||
| 287 | |||
| 288 | /* copy second buffer into end of first buffer */ | ||
| 289 | memcpy(data_area_of_target,data_area_of_buf2,total_in_buf2); | ||
| 290 | total_in_buf += total_in_buf2; | ||
| 291 | pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf); | ||
| 292 | byte_count = le16_to_cpu(BCC_LE(pTargetSMB)); | ||
| 293 | byte_count += total_in_buf2; | ||
| 294 | BCC_LE(pTargetSMB) = cpu_to_le16(byte_count); | ||
| 295 | |||
| 296 | byte_count = be32_to_cpu(pTargetSMB->smb_buf_length); | ||
| 297 | byte_count += total_in_buf2; | ||
| 298 | |||
| 299 | /* BB also add check that we are not beyond maximum buffer size */ | ||
| 300 | |||
| 301 | pTargetSMB->smb_buf_length = cpu_to_be32(byte_count); | ||
| 302 | |||
| 303 | if(remaining == total_in_buf2) { | ||
| 304 | cFYI(1,("found the last secondary response")); | ||
| 305 | return 0; /* we are done */ | ||
| 306 | } else /* more responses to go */ | ||
| 307 | return 1; | ||
| 308 | |||
| 309 | } | ||
| 310 | |||
| 193 | static int | 311 | static int |
| 194 | cifs_demultiplex_thread(struct TCP_Server_Info *server) | 312 | cifs_demultiplex_thread(struct TCP_Server_Info *server) |
| 195 | { | 313 | { |
| 196 | int length; | 314 | int length; |
| 197 | unsigned int pdu_length, total_read; | 315 | unsigned int pdu_length, total_read; |
| 198 | struct smb_hdr *smb_buffer = NULL; | 316 | struct smb_hdr *smb_buffer = NULL; |
| 317 | struct smb_hdr *bigbuf = NULL; | ||
| 318 | struct smb_hdr *smallbuf = NULL; | ||
| 199 | struct msghdr smb_msg; | 319 | struct msghdr smb_msg; |
| 200 | struct kvec iov; | 320 | struct kvec iov; |
| 201 | struct socket *csocket = server->ssocket; | 321 | struct socket *csocket = server->ssocket; |
| @@ -204,6 +324,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
| 204 | struct task_struct *task_to_wake = NULL; | 324 | struct task_struct *task_to_wake = NULL; |
| 205 | struct mid_q_entry *mid_entry; | 325 | struct mid_q_entry *mid_entry; |
| 206 | char *temp; | 326 | char *temp; |
| 327 | int isLargeBuf = FALSE; | ||
| 328 | int isMultiRsp; | ||
| 329 | int reconnect; | ||
| 207 | 330 | ||
| 208 | daemonize("cifsd"); | 331 | daemonize("cifsd"); |
| 209 | allow_signal(SIGKILL); | 332 | allow_signal(SIGKILL); |
| @@ -221,17 +344,34 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
| 221 | } | 344 | } |
| 222 | 345 | ||
| 223 | while (server->tcpStatus != CifsExiting) { | 346 | while (server->tcpStatus != CifsExiting) { |
| 224 | if (smb_buffer == NULL) | 347 | if (bigbuf == NULL) { |
| 225 | smb_buffer = cifs_buf_get(); | 348 | bigbuf = cifs_buf_get(); |
| 226 | else | 349 | if(bigbuf == NULL) { |
| 227 | memset(smb_buffer, 0, sizeof (struct smb_hdr)); | 350 | cERROR(1,("No memory for large SMB response")); |
| 228 | 351 | msleep(3000); | |
| 229 | if (smb_buffer == NULL) { | 352 | /* retry will check if exiting */ |
| 230 | cERROR(1,("Can not get memory for SMB response")); | 353 | continue; |
| 231 | set_current_state(TASK_INTERRUPTIBLE); | 354 | } |
| 232 | schedule_timeout(HZ * 3); /* give system time to free memory */ | 355 | } else if(isLargeBuf) { |
| 233 | continue; | 356 | /* we are reusing a dirtry large buf, clear its start */ |
| 357 | memset(bigbuf, 0, sizeof (struct smb_hdr)); | ||
| 234 | } | 358 | } |
| 359 | |||
| 360 | if (smallbuf == NULL) { | ||
| 361 | smallbuf = cifs_small_buf_get(); | ||
| 362 | if(smallbuf == NULL) { | ||
| 363 | cERROR(1,("No memory for SMB response")); | ||
| 364 | msleep(1000); | ||
| 365 | /* retry will check if exiting */ | ||
| 366 | continue; | ||
| 367 | } | ||
| 368 | /* beginning of smb buffer is cleared in our buf_get */ | ||
| 369 | } else /* if existing small buf clear beginning */ | ||
| 370 | memset(smallbuf, 0, sizeof (struct smb_hdr)); | ||
| 371 | |||
| 372 | isLargeBuf = FALSE; | ||
| 373 | isMultiRsp = FALSE; | ||
| 374 | smb_buffer = smallbuf; | ||
| 235 | iov.iov_base = smb_buffer; | 375 | iov.iov_base = smb_buffer; |
| 236 | iov.iov_len = 4; | 376 | iov.iov_len = 4; |
| 237 | smb_msg.msg_control = NULL; | 377 | smb_msg.msg_control = NULL; |
| @@ -243,176 +383,257 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
| 243 | if(server->tcpStatus == CifsExiting) { | 383 | if(server->tcpStatus == CifsExiting) { |
| 244 | break; | 384 | break; |
| 245 | } else if (server->tcpStatus == CifsNeedReconnect) { | 385 | } else if (server->tcpStatus == CifsNeedReconnect) { |
| 246 | cFYI(1,("Reconnecting after server stopped responding")); | 386 | cFYI(1,("Reconnect after server stopped responding")); |
| 247 | cifs_reconnect(server); | 387 | cifs_reconnect(server); |
| 248 | cFYI(1,("call to reconnect done")); | 388 | cFYI(1,("call to reconnect done")); |
| 249 | csocket = server->ssocket; | 389 | csocket = server->ssocket; |
| 250 | continue; | 390 | continue; |
| 251 | } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) { | 391 | } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) { |
| 252 | set_current_state(TASK_INTERRUPTIBLE); | 392 | msleep(1); /* minimum sleep to prevent looping |
| 253 | schedule_timeout(1); /* minimum sleep to prevent looping | ||
| 254 | allowing socket to clear and app threads to set | 393 | allowing socket to clear and app threads to set |
| 255 | tcpStatus CifsNeedReconnect if server hung */ | 394 | tcpStatus CifsNeedReconnect if server hung */ |
| 256 | continue; | 395 | continue; |
| 257 | } else if (length <= 0) { | 396 | } else if (length <= 0) { |
| 258 | if(server->tcpStatus == CifsNew) { | 397 | if(server->tcpStatus == CifsNew) { |
| 259 | cFYI(1,("tcp session abended prematurely (after SMBnegprot)")); | 398 | cFYI(1,("tcp session abend after SMBnegprot")); |
| 260 | /* some servers kill tcp session rather than returning | 399 | /* some servers kill the TCP session rather than |
| 261 | smb negprot error in which case reconnecting here is | 400 | returning an SMB negprot error, in which |
| 262 | not going to help - return error to mount */ | 401 | case reconnecting here is not going to help, |
| 402 | and so simply return error to mount */ | ||
| 263 | break; | 403 | break; |
| 264 | } | 404 | } |
| 265 | if(length == -EINTR) { | 405 | if(length == -EINTR) { |
| 266 | cFYI(1,("cifsd thread killed")); | 406 | cFYI(1,("cifsd thread killed")); |
| 267 | break; | 407 | break; |
| 268 | } | 408 | } |
| 269 | cFYI(1,("Reconnecting after unexpected peek error %d",length)); | 409 | cFYI(1,("Reconnect after unexpected peek error %d", |
| 410 | length)); | ||
| 270 | cifs_reconnect(server); | 411 | cifs_reconnect(server); |
| 271 | csocket = server->ssocket; | 412 | csocket = server->ssocket; |
| 272 | wake_up(&server->response_q); | 413 | wake_up(&server->response_q); |
| 273 | continue; | 414 | continue; |
| 274 | } else if (length > 3) { | 415 | } else if (length < 4) { |
| 275 | pdu_length = ntohl(smb_buffer->smb_buf_length); | 416 | cFYI(1, |
| 276 | /* Only read pdu_length after below checks for too short (due | 417 | ("Frame under four bytes received (%d bytes long)", |
| 277 | to e.g. int overflow) and too long ie beyond end of buf */ | 418 | length)); |
| 278 | cFYI(1,("rfc1002 length(big endian)0x%x)", pdu_length+4)); | 419 | cifs_reconnect(server); |
| 279 | 420 | csocket = server->ssocket; | |
| 280 | temp = (char *) smb_buffer; | 421 | wake_up(&server->response_q); |
| 281 | if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) { | 422 | continue; |
| 282 | cFYI(0,("Received 4 byte keep alive packet")); | 423 | } |
| 283 | } else if (temp[0] == (char) RFC1002_POSITIVE_SESSION_RESPONSE) { | ||
| 284 | cFYI(1,("Good RFC 1002 session rsp")); | ||
| 285 | } else if (temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) { | ||
| 286 | /* we get this from Windows 98 instead of error on SMB negprot response */ | ||
| 287 | cFYI(1,("Negative RFC 1002 Session Response Error 0x%x)",temp[4])); | ||
| 288 | if(server->tcpStatus == CifsNew) { | ||
| 289 | /* if nack on negprot (rather than | ||
| 290 | ret of smb negprot error) reconnecting | ||
| 291 | not going to help, ret error to mount */ | ||
| 292 | break; | ||
| 293 | } else { | ||
| 294 | /* give server a second to | ||
| 295 | clean up before reconnect attempt */ | ||
| 296 | set_current_state(TASK_INTERRUPTIBLE); | ||
| 297 | schedule_timeout(HZ); | ||
| 298 | /* always try 445 first on reconnect | ||
| 299 | since we get NACK on some if we ever | ||
| 300 | connected to port 139 (the NACK is | ||
| 301 | since we do not begin with RFC1001 | ||
| 302 | session initialize frame) */ | ||
| 303 | server->addr.sockAddr.sin_port = htons(CIFS_PORT); | ||
| 304 | cifs_reconnect(server); | ||
| 305 | csocket = server->ssocket; | ||
| 306 | wake_up(&server->response_q); | ||
| 307 | continue; | ||
| 308 | } | ||
| 309 | } else if (temp[0] != (char) 0) { | ||
| 310 | cERROR(1,("Unknown RFC 1002 frame")); | ||
| 311 | cifs_dump_mem(" Received Data: ", temp, length); | ||
| 312 | cifs_reconnect(server); | ||
| 313 | csocket = server->ssocket; | ||
| 314 | continue; | ||
| 315 | } else { | ||
| 316 | if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) | ||
| 317 | || (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) { | ||
| 318 | cERROR(1, | ||
| 319 | ("Invalid size SMB length %d and pdu_length %d", | ||
| 320 | length, pdu_length+4)); | ||
| 321 | cifs_reconnect(server); | ||
| 322 | csocket = server->ssocket; | ||
| 323 | wake_up(&server->response_q); | ||
| 324 | continue; | ||
| 325 | } else { /* length ok */ | ||
| 326 | length = 0; | ||
| 327 | iov.iov_base = 4 + (char *)smb_buffer; | ||
| 328 | iov.iov_len = pdu_length; | ||
| 329 | for (total_read = 0; | ||
| 330 | total_read < pdu_length; | ||
| 331 | total_read += length) { | ||
| 332 | length = kernel_recvmsg(csocket, &smb_msg, | ||
| 333 | &iov, 1, | ||
| 334 | pdu_length - total_read, 0); | ||
| 335 | if (length == 0) { | ||
| 336 | cERROR(1, | ||
| 337 | ("Zero length receive when expecting %d ", | ||
| 338 | pdu_length - total_read)); | ||
| 339 | cifs_reconnect(server); | ||
| 340 | csocket = server->ssocket; | ||
| 341 | wake_up(&server->response_q); | ||
| 342 | continue; | ||
| 343 | } | ||
| 344 | } | ||
| 345 | length += 4; /* account for rfc1002 hdr */ | ||
| 346 | } | ||
| 347 | 424 | ||
| 348 | dump_smb(smb_buffer, length); | 425 | /* the right amount was read from socket - 4 bytes */ |
| 349 | if (checkSMB | ||
| 350 | (smb_buffer, smb_buffer->Mid, total_read+4)) { | ||
| 351 | cERROR(1, ("Bad SMB Received ")); | ||
| 352 | continue; | ||
| 353 | } | ||
| 354 | 426 | ||
| 355 | task_to_wake = NULL; | 427 | pdu_length = ntohl(smb_buffer->smb_buf_length); |
| 356 | spin_lock(&GlobalMid_Lock); | 428 | cFYI(1,("rfc1002 length(big endian)0x%x)", pdu_length+4)); |
| 357 | list_for_each(tmp, &server->pending_mid_q) { | ||
| 358 | mid_entry = list_entry(tmp, struct | ||
| 359 | mid_q_entry, | ||
| 360 | qhead); | ||
| 361 | 429 | ||
| 362 | if ((mid_entry->mid == smb_buffer->Mid) && (mid_entry->midState == MID_REQUEST_SUBMITTED)) { | 430 | temp = (char *) smb_buffer; |
| 363 | cFYI(1, | 431 | if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) { |
| 364 | (" Mid 0x%x matched - waking up ",mid_entry->mid)); | 432 | continue; |
| 365 | task_to_wake = mid_entry->tsk; | 433 | } else if (temp[0] == (char)RFC1002_POSITIVE_SESSION_RESPONSE) { |
| 366 | mid_entry->resp_buf = | 434 | cFYI(1,("Good RFC 1002 session rsp")); |
| 367 | smb_buffer; | 435 | continue; |
| 368 | mid_entry->midState = | 436 | } else if (temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) { |
| 369 | MID_RESPONSE_RECEIVED; | 437 | /* we get this from Windows 98 instead of |
| 370 | } | 438 | an error on SMB negprot response */ |
| 371 | } | 439 | cFYI(1,("Negative RFC1002 Session Response Error 0x%x)", |
| 372 | spin_unlock(&GlobalMid_Lock); | 440 | temp[4])); |
| 373 | if (task_to_wake) { | 441 | if(server->tcpStatus == CifsNew) { |
| 374 | smb_buffer = NULL; /* will be freed by users thread after he is done */ | 442 | /* if nack on negprot (rather than |
| 375 | wake_up_process(task_to_wake); | 443 | ret of smb negprot error) reconnecting |
| 376 | } else if (is_valid_oplock_break(smb_buffer) == FALSE) { | 444 | not going to help, ret error to mount */ |
| 377 | cERROR(1, ("No task to wake, unknown frame rcvd!")); | 445 | break; |
| 378 | cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)); | 446 | } else { |
| 379 | } | 447 | /* give server a second to |
| 448 | clean up before reconnect attempt */ | ||
| 449 | msleep(1000); | ||
| 450 | /* always try 445 first on reconnect | ||
| 451 | since we get NACK on some if we ever | ||
| 452 | connected to port 139 (the NACK is | ||
| 453 | since we do not begin with RFC1001 | ||
| 454 | session initialize frame) */ | ||
| 455 | server->addr.sockAddr.sin_port = | ||
| 456 | htons(CIFS_PORT); | ||
| 457 | cifs_reconnect(server); | ||
| 458 | csocket = server->ssocket; | ||
| 459 | wake_up(&server->response_q); | ||
| 460 | continue; | ||
| 380 | } | 461 | } |
| 381 | } else { | 462 | } else if (temp[0] != (char) 0) { |
| 382 | cFYI(1, | 463 | cERROR(1,("Unknown RFC 1002 frame")); |
| 383 | ("Frame less than four bytes received %d bytes long.", | 464 | cifs_dump_mem(" Received Data: ", temp, length); |
| 384 | length)); | 465 | cifs_reconnect(server); |
| 466 | csocket = server->ssocket; | ||
| 467 | continue; | ||
| 468 | } | ||
| 469 | |||
| 470 | /* else we have an SMB response */ | ||
| 471 | if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) || | ||
| 472 | (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) { | ||
| 473 | cERROR(1, ("Invalid size SMB length %d pdu_length %d", | ||
| 474 | length, pdu_length+4)); | ||
| 385 | cifs_reconnect(server); | 475 | cifs_reconnect(server); |
| 386 | csocket = server->ssocket; | 476 | csocket = server->ssocket; |
| 387 | wake_up(&server->response_q); | 477 | wake_up(&server->response_q); |
| 388 | continue; | 478 | continue; |
| 479 | } | ||
| 480 | |||
| 481 | /* else length ok */ | ||
| 482 | reconnect = 0; | ||
| 483 | |||
| 484 | if(pdu_length > MAX_CIFS_HDR_SIZE - 4) { | ||
| 485 | isLargeBuf = TRUE; | ||
| 486 | memcpy(bigbuf, smallbuf, 4); | ||
| 487 | smb_buffer = bigbuf; | ||
| 389 | } | 488 | } |
| 390 | } | 489 | length = 0; |
| 490 | iov.iov_base = 4 + (char *)smb_buffer; | ||
| 491 | iov.iov_len = pdu_length; | ||
| 492 | for (total_read = 0; total_read < pdu_length; | ||
| 493 | total_read += length) { | ||
| 494 | length = kernel_recvmsg(csocket, &smb_msg, &iov, 1, | ||
| 495 | pdu_length - total_read, 0); | ||
| 496 | if((server->tcpStatus == CifsExiting) || | ||
| 497 | (length == -EINTR)) { | ||
| 498 | /* then will exit */ | ||
| 499 | reconnect = 2; | ||
| 500 | break; | ||
| 501 | } else if (server->tcpStatus == CifsNeedReconnect) { | ||
| 502 | cifs_reconnect(server); | ||
| 503 | csocket = server->ssocket; | ||
| 504 | /* Reconnect wakes up rspns q */ | ||
| 505 | /* Now we will reread sock */ | ||
| 506 | reconnect = 1; | ||
| 507 | break; | ||
| 508 | } else if ((length == -ERESTARTSYS) || | ||
| 509 | (length == -EAGAIN)) { | ||
| 510 | msleep(1); /* minimum sleep to prevent looping, | ||
| 511 | allowing socket to clear and app | ||
| 512 | threads to set tcpStatus | ||
| 513 | CifsNeedReconnect if server hung*/ | ||
| 514 | continue; | ||
| 515 | } else if (length <= 0) { | ||
| 516 | cERROR(1,("Received no data, expecting %d", | ||
| 517 | pdu_length - total_read)); | ||
| 518 | cifs_reconnect(server); | ||
| 519 | csocket = server->ssocket; | ||
| 520 | reconnect = 1; | ||
| 521 | break; | ||
| 522 | } | ||
| 523 | } | ||
| 524 | if(reconnect == 2) | ||
| 525 | break; | ||
| 526 | else if(reconnect == 1) | ||
| 527 | continue; | ||
| 528 | |||
| 529 | length += 4; /* account for rfc1002 hdr */ | ||
| 530 | |||
| 531 | |||
| 532 | dump_smb(smb_buffer, length); | ||
| 533 | if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) { | ||
| 534 | cERROR(1, ("Bad SMB Received ")); | ||
| 535 | continue; | ||
| 536 | } | ||
| 537 | |||
| 538 | |||
| 539 | task_to_wake = NULL; | ||
| 540 | spin_lock(&GlobalMid_Lock); | ||
| 541 | list_for_each(tmp, &server->pending_mid_q) { | ||
| 542 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); | ||
| 543 | |||
| 544 | if ((mid_entry->mid == smb_buffer->Mid) && | ||
| 545 | (mid_entry->midState == MID_REQUEST_SUBMITTED) && | ||
| 546 | (mid_entry->command == smb_buffer->Command)) { | ||
| 547 | if(check2ndT2(smb_buffer,server->maxBuf) > 0) { | ||
| 548 | /* We have a multipart transact2 resp */ | ||
| 549 | isMultiRsp = TRUE; | ||
| 550 | if(mid_entry->resp_buf) { | ||
| 551 | /* merge response - fix up 1st*/ | ||
| 552 | if(coalesce_t2(smb_buffer, | ||
| 553 | mid_entry->resp_buf)) { | ||
| 554 | break; | ||
| 555 | } else { | ||
| 556 | /* all parts received */ | ||
| 557 | goto multi_t2_fnd; | ||
| 558 | } | ||
| 559 | } else { | ||
| 560 | if(!isLargeBuf) { | ||
| 561 | cERROR(1,("1st trans2 resp needs bigbuf")); | ||
| 562 | /* BB maybe we can fix this up, switch | ||
| 563 | to already allocated large buffer? */ | ||
| 564 | } else { | ||
| 565 | /* Have first buffer */ | ||
| 566 | mid_entry->resp_buf = | ||
| 567 | smb_buffer; | ||
| 568 | mid_entry->largeBuf = 1; | ||
| 569 | bigbuf = NULL; | ||
| 570 | } | ||
| 571 | } | ||
| 572 | break; | ||
| 573 | } | ||
| 574 | mid_entry->resp_buf = smb_buffer; | ||
| 575 | if(isLargeBuf) | ||
| 576 | mid_entry->largeBuf = 1; | ||
| 577 | else | ||
| 578 | mid_entry->largeBuf = 0; | ||
| 579 | multi_t2_fnd: | ||
| 580 | task_to_wake = mid_entry->tsk; | ||
| 581 | mid_entry->midState = MID_RESPONSE_RECEIVED; | ||
| 582 | break; | ||
| 583 | } | ||
| 584 | } | ||
| 585 | spin_unlock(&GlobalMid_Lock); | ||
| 586 | if (task_to_wake) { | ||
| 587 | /* Was previous buf put in mpx struct for multi-rsp? */ | ||
| 588 | if(!isMultiRsp) { | ||
| 589 | /* smb buffer will be freed by user thread */ | ||
| 590 | if(isLargeBuf) { | ||
| 591 | bigbuf = NULL; | ||
| 592 | } else | ||
| 593 | smallbuf = NULL; | ||
| 594 | } | ||
| 595 | wake_up_process(task_to_wake); | ||
| 596 | } else if ((is_valid_oplock_break(smb_buffer) == FALSE) | ||
| 597 | && (isMultiRsp == FALSE)) { | ||
| 598 | cERROR(1, ("No task to wake, unknown frame rcvd!")); | ||
| 599 | cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)); | ||
| 600 | } | ||
| 601 | } /* end while !EXITING */ | ||
| 602 | |||
| 391 | spin_lock(&GlobalMid_Lock); | 603 | spin_lock(&GlobalMid_Lock); |
| 392 | server->tcpStatus = CifsExiting; | 604 | server->tcpStatus = CifsExiting; |
| 393 | server->tsk = NULL; | 605 | server->tsk = NULL; |
| 394 | atomic_set(&server->inFlight, 0); | 606 | /* check if we have blocked requests that need to free */ |
| 607 | /* Note that cifs_max_pending is normally 50, but | ||
| 608 | can be set at module install time to as little as two */ | ||
| 609 | if(atomic_read(&server->inFlight) >= cifs_max_pending) | ||
| 610 | atomic_set(&server->inFlight, cifs_max_pending - 1); | ||
| 611 | /* We do not want to set the max_pending too low or we | ||
| 612 | could end up with the counter going negative */ | ||
| 395 | spin_unlock(&GlobalMid_Lock); | 613 | spin_unlock(&GlobalMid_Lock); |
| 396 | /* Although there should not be any requests blocked on | 614 | /* Although there should not be any requests blocked on |
| 397 | this queue it can not hurt to be paranoid and try to wake up requests | 615 | this queue it can not hurt to be paranoid and try to wake up requests |
| 398 | that may haven been blocked when more than 50 at time were on the wire | 616 | that may haven been blocked when more than 50 at time were on the wire |
| 399 | to the same server - they now will see the session is in exit state | 617 | to the same server - they now will see the session is in exit state |
| 400 | and get out of SendReceive. */ | 618 | and get out of SendReceive. */ |
| 401 | wake_up_all(&server->request_q); | 619 | wake_up_all(&server->request_q); |
| 402 | /* give those requests time to exit */ | 620 | /* give those requests time to exit */ |
| 403 | set_current_state(TASK_INTERRUPTIBLE); | 621 | msleep(125); |
| 404 | schedule_timeout(HZ/8); | 622 | |
| 405 | |||
| 406 | if(server->ssocket) { | 623 | if(server->ssocket) { |
| 407 | sock_release(csocket); | 624 | sock_release(csocket); |
| 408 | server->ssocket = NULL; | 625 | server->ssocket = NULL; |
| 409 | } | 626 | } |
| 410 | if (smb_buffer) /* buffer usually freed in free_mid - need to free it on error or exit */ | 627 | /* buffer usuallly freed in free_mid - need to free it here on exit */ |
| 411 | cifs_buf_release(smb_buffer); | 628 | if (bigbuf != NULL) |
| 629 | cifs_buf_release(bigbuf); | ||
| 630 | if (smallbuf != NULL) | ||
| 631 | cifs_small_buf_release(smallbuf); | ||
| 412 | 632 | ||
| 413 | read_lock(&GlobalSMBSeslock); | 633 | read_lock(&GlobalSMBSeslock); |
| 414 | if (list_empty(&server->pending_mid_q)) { | 634 | if (list_empty(&server->pending_mid_q)) { |
| 415 | /* loop through server session structures attached to this and mark them dead */ | 635 | /* loop through server session structures attached to this and |
| 636 | mark them dead */ | ||
| 416 | list_for_each(tmp, &GlobalSMBSessionList) { | 637 | list_for_each(tmp, &GlobalSMBSessionList) { |
| 417 | ses = | 638 | ses = |
| 418 | list_entry(tmp, struct cifsSesInfo, | 639 | list_entry(tmp, struct cifsSesInfo, |
| @@ -424,12 +645,23 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
| 424 | } | 645 | } |
| 425 | read_unlock(&GlobalSMBSeslock); | 646 | read_unlock(&GlobalSMBSeslock); |
| 426 | } else { | 647 | } else { |
| 648 | /* although we can not zero the server struct pointer yet, | ||
| 649 | since there are active requests which may depnd on them, | ||
| 650 | mark the corresponding SMB sessions as exiting too */ | ||
| 651 | list_for_each(tmp, &GlobalSMBSessionList) { | ||
| 652 | ses = list_entry(tmp, struct cifsSesInfo, | ||
| 653 | cifsSessionList); | ||
| 654 | if (ses->server == server) { | ||
| 655 | ses->status = CifsExiting; | ||
| 656 | } | ||
| 657 | } | ||
| 658 | |||
| 427 | spin_lock(&GlobalMid_Lock); | 659 | spin_lock(&GlobalMid_Lock); |
| 428 | list_for_each(tmp, &server->pending_mid_q) { | 660 | list_for_each(tmp, &server->pending_mid_q) { |
| 429 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); | 661 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); |
| 430 | if (mid_entry->midState == MID_REQUEST_SUBMITTED) { | 662 | if (mid_entry->midState == MID_REQUEST_SUBMITTED) { |
| 431 | cFYI(1, | 663 | cFYI(1, |
| 432 | (" Clearing Mid 0x%x - waking up ",mid_entry->mid)); | 664 | ("Clearing Mid 0x%x - waking up ",mid_entry->mid)); |
| 433 | task_to_wake = mid_entry->tsk; | 665 | task_to_wake = mid_entry->tsk; |
| 434 | if(task_to_wake) { | 666 | if(task_to_wake) { |
| 435 | wake_up_process(task_to_wake); | 667 | wake_up_process(task_to_wake); |
| @@ -438,47 +670,51 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
| 438 | } | 670 | } |
| 439 | spin_unlock(&GlobalMid_Lock); | 671 | spin_unlock(&GlobalMid_Lock); |
| 440 | read_unlock(&GlobalSMBSeslock); | 672 | read_unlock(&GlobalSMBSeslock); |
| 441 | set_current_state(TASK_INTERRUPTIBLE); | ||
| 442 | /* 1/8th of sec is more than enough time for them to exit */ | 673 | /* 1/8th of sec is more than enough time for them to exit */ |
| 443 | schedule_timeout(HZ/8); | 674 | msleep(125); |
| 444 | } | 675 | } |
| 445 | 676 | ||
| 446 | if (list_empty(&server->pending_mid_q)) { | 677 | if (list_empty(&server->pending_mid_q)) { |
| 447 | /* mpx threads have not exited yet give them | 678 | /* mpx threads have not exited yet give them |
| 448 | at least the smb send timeout time for long ops */ | 679 | at least the smb send timeout time for long ops */ |
| 680 | /* due to delays on oplock break requests, we need | ||
| 681 | to wait at least 45 seconds before giving up | ||
| 682 | on a request getting a response and going ahead | ||
| 683 | and killing cifsd */ | ||
| 449 | cFYI(1, ("Wait for exit from demultiplex thread")); | 684 | cFYI(1, ("Wait for exit from demultiplex thread")); |
| 450 | set_current_state(TASK_INTERRUPTIBLE); | 685 | msleep(46000); |
| 451 | schedule_timeout(46 * HZ); | ||
| 452 | /* if threads still have not exited they are probably never | 686 | /* if threads still have not exited they are probably never |
| 453 | coming home not much else we can do but free the memory */ | 687 | coming home not much else we can do but free the memory */ |
| 454 | } | 688 | } |
| 455 | kfree(server); | ||
| 456 | 689 | ||
| 457 | write_lock(&GlobalSMBSeslock); | 690 | write_lock(&GlobalSMBSeslock); |
| 458 | atomic_dec(&tcpSesAllocCount); | 691 | atomic_dec(&tcpSesAllocCount); |
| 459 | length = tcpSesAllocCount.counter; | 692 | length = tcpSesAllocCount.counter; |
| 693 | |||
| 694 | /* last chance to mark ses pointers invalid | ||
| 695 | if there are any pointing to this (e.g | ||
| 696 | if a crazy root user tried to kill cifsd | ||
| 697 | kernel thread explicitly this might happen) */ | ||
| 698 | list_for_each(tmp, &GlobalSMBSessionList) { | ||
| 699 | ses = list_entry(tmp, struct cifsSesInfo, | ||
| 700 | cifsSessionList); | ||
| 701 | if (ses->server == server) { | ||
| 702 | ses->server = NULL; | ||
| 703 | } | ||
| 704 | } | ||
| 460 | write_unlock(&GlobalSMBSeslock); | 705 | write_unlock(&GlobalSMBSeslock); |
| 706 | |||
| 707 | kfree(server); | ||
| 461 | if(length > 0) { | 708 | if(length > 0) { |
| 462 | mempool_resize(cifs_req_poolp, | 709 | mempool_resize(cifs_req_poolp, |
| 463 | length + cifs_min_rcv, | 710 | length + cifs_min_rcv, |
| 464 | GFP_KERNEL); | 711 | GFP_KERNEL); |
| 465 | } | 712 | } |
| 466 | 713 | ||
| 467 | set_current_state(TASK_INTERRUPTIBLE); | 714 | msleep(250); |
| 468 | schedule_timeout(HZ/4); | ||
| 469 | return 0; | 715 | return 0; |
| 470 | } | 716 | } |
| 471 | 717 | ||
| 472 | static void * | ||
| 473 | cifs_kcalloc(size_t size, unsigned int __nocast type) | ||
| 474 | { | ||
| 475 | void *addr; | ||
| 476 | addr = kmalloc(size, type); | ||
| 477 | if (addr) | ||
| 478 | memset(addr, 0, size); | ||
| 479 | return addr; | ||
| 480 | } | ||
| 481 | |||
| 482 | static int | 718 | static int |
| 483 | cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) | 719 | cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) |
| 484 | { | 720 | { |
| @@ -495,7 +731,8 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) | |||
| 495 | /* does not have to be a perfect mapping since the field is | 731 | /* does not have to be a perfect mapping since the field is |
| 496 | informational, only used for servers that do not support | 732 | informational, only used for servers that do not support |
| 497 | port 445 and it can be overridden at mount time */ | 733 | port 445 and it can be overridden at mount time */ |
| 498 | vol->source_rfc1001_name[i] = toupper(system_utsname.nodename[i]); | 734 | vol->source_rfc1001_name[i] = |
| 735 | toupper(system_utsname.nodename[i]); | ||
| 499 | } | 736 | } |
| 500 | vol->source_rfc1001_name[15] = 0; | 737 | vol->source_rfc1001_name[15] = 0; |
| 501 | 738 | ||
| @@ -570,14 +807,17 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) | |||
| 570 | /* NB: password legally can have multiple commas and | 807 | /* NB: password legally can have multiple commas and |
| 571 | the only illegal character in a password is null */ | 808 | the only illegal character in a password is null */ |
| 572 | 809 | ||
| 573 | if ((value[temp_len] == 0) && (value[temp_len+1] == separator[0])) { | 810 | if ((value[temp_len] == 0) && |
| 811 | (value[temp_len+1] == separator[0])) { | ||
| 574 | /* reinsert comma */ | 812 | /* reinsert comma */ |
| 575 | value[temp_len] = separator[0]; | 813 | value[temp_len] = separator[0]; |
| 576 | temp_len+=2; /* move after the second comma */ | 814 | temp_len+=2; /* move after the second comma */ |
| 577 | while(value[temp_len] != 0) { | 815 | while(value[temp_len] != 0) { |
| 578 | if (value[temp_len] == separator[0]) { | 816 | if (value[temp_len] == separator[0]) { |
| 579 | if (value[temp_len+1] == separator[0]) { | 817 | if (value[temp_len+1] == |
| 580 | temp_len++; /* skip second comma */ | 818 | separator[0]) { |
| 819 | /* skip second comma */ | ||
| 820 | temp_len++; | ||
| 581 | } else { | 821 | } else { |
| 582 | /* single comma indicating start | 822 | /* single comma indicating start |
| 583 | of next parm */ | 823 | of next parm */ |
| @@ -596,17 +836,26 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) | |||
| 596 | /* go from value to value + temp_len condensing | 836 | /* go from value to value + temp_len condensing |
| 597 | double commas to singles. Note that this ends up | 837 | double commas to singles. Note that this ends up |
| 598 | allocating a few bytes too many, which is ok */ | 838 | allocating a few bytes too many, which is ok */ |
| 599 | vol->password = cifs_kcalloc(temp_len, GFP_KERNEL); | 839 | vol->password = kcalloc(1, temp_len, GFP_KERNEL); |
| 840 | if(vol->password == NULL) { | ||
| 841 | printk("CIFS: no memory for pass\n"); | ||
| 842 | return 1; | ||
| 843 | } | ||
| 600 | for(i=0,j=0;i<temp_len;i++,j++) { | 844 | for(i=0,j=0;i<temp_len;i++,j++) { |
| 601 | vol->password[j] = value[i]; | 845 | vol->password[j] = value[i]; |
| 602 | if(value[i] == separator[0] && value[i+1] == separator[0]) { | 846 | if(value[i] == separator[0] |
| 847 | && value[i+1] == separator[0]) { | ||
| 603 | /* skip second comma */ | 848 | /* skip second comma */ |
| 604 | i++; | 849 | i++; |
| 605 | } | 850 | } |
| 606 | } | 851 | } |
| 607 | vol->password[j] = 0; | 852 | vol->password[j] = 0; |
| 608 | } else { | 853 | } else { |
| 609 | vol->password = cifs_kcalloc(temp_len + 1, GFP_KERNEL); | 854 | vol->password = kcalloc(1, temp_len+1, GFP_KERNEL); |
| 855 | if(vol->password == NULL) { | ||
| 856 | printk("CIFS: no memory for pass\n"); | ||
| 857 | return 1; | ||
| 858 | } | ||
| 610 | strcpy(vol->password, value); | 859 | strcpy(vol->password, value); |
| 611 | } | 860 | } |
| 612 | } else if (strnicmp(data, "ip", 2) == 0) { | 861 | } else if (strnicmp(data, "ip", 2) == 0) { |
| @@ -770,6 +1019,10 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) | |||
| 770 | vol->noperm = 0; | 1019 | vol->noperm = 0; |
| 771 | } else if (strnicmp(data, "noperm", 6) == 0) { | 1020 | } else if (strnicmp(data, "noperm", 6) == 0) { |
| 772 | vol->noperm = 1; | 1021 | vol->noperm = 1; |
| 1022 | } else if (strnicmp(data, "mapchars", 8) == 0) { | ||
| 1023 | vol->remap = 1; | ||
| 1024 | } else if (strnicmp(data, "nomapchars", 10) == 0) { | ||
| 1025 | vol->remap = 0; | ||
| 773 | } else if (strnicmp(data, "setuids", 7) == 0) { | 1026 | } else if (strnicmp(data, "setuids", 7) == 0) { |
| 774 | vol->setuids = 1; | 1027 | vol->setuids = 1; |
| 775 | } else if (strnicmp(data, "nosetuids", 9) == 0) { | 1028 | } else if (strnicmp(data, "nosetuids", 9) == 0) { |
| @@ -918,14 +1171,15 @@ find_unc(__be32 new_target_ip_addr, char *uncName, char *userName) | |||
| 918 | 1171 | ||
| 919 | int | 1172 | int |
| 920 | connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, | 1173 | connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, |
| 921 | const char *old_path, const struct nls_table *nls_codepage) | 1174 | const char *old_path, const struct nls_table *nls_codepage, |
| 1175 | int remap) | ||
| 922 | { | 1176 | { |
| 923 | unsigned char *referrals = NULL; | 1177 | unsigned char *referrals = NULL; |
| 924 | unsigned int num_referrals; | 1178 | unsigned int num_referrals; |
| 925 | int rc = 0; | 1179 | int rc = 0; |
| 926 | 1180 | ||
| 927 | rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage, | 1181 | rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage, |
| 928 | &num_referrals, &referrals); | 1182 | &num_referrals, &referrals, remap); |
| 929 | 1183 | ||
| 930 | /* BB Add in code to: if valid refrl, if not ip address contact | 1184 | /* BB Add in code to: if valid refrl, if not ip address contact |
| 931 | the helper that resolves tcp names, mount to it, try to | 1185 | the helper that resolves tcp names, mount to it, try to |
| @@ -940,7 +1194,8 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, | |||
| 940 | int | 1194 | int |
| 941 | get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, | 1195 | get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, |
| 942 | const char *old_path, const struct nls_table *nls_codepage, | 1196 | const char *old_path, const struct nls_table *nls_codepage, |
| 943 | unsigned int *pnum_referrals, unsigned char ** preferrals) | 1197 | unsigned int *pnum_referrals, |
| 1198 | unsigned char ** preferrals, int remap) | ||
| 944 | { | 1199 | { |
| 945 | char *temp_unc; | 1200 | char *temp_unc; |
| 946 | int rc = 0; | 1201 | int rc = 0; |
| @@ -965,7 +1220,7 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, | |||
| 965 | } | 1220 | } |
| 966 | if (rc == 0) | 1221 | if (rc == 0) |
| 967 | rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals, | 1222 | rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals, |
| 968 | pnum_referrals, nls_codepage); | 1223 | pnum_referrals, nls_codepage, remap); |
| 969 | 1224 | ||
| 970 | return rc; | 1225 | return rc; |
| 971 | } | 1226 | } |
| @@ -1062,7 +1317,7 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, | |||
| 1062 | sessinit is sent but no second negprot */ | 1317 | sessinit is sent but no second negprot */ |
| 1063 | struct rfc1002_session_packet * ses_init_buf; | 1318 | struct rfc1002_session_packet * ses_init_buf; |
| 1064 | struct smb_hdr * smb_buf; | 1319 | struct smb_hdr * smb_buf; |
| 1065 | ses_init_buf = cifs_kcalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL); | 1320 | ses_init_buf = kcalloc(1, sizeof(struct rfc1002_session_packet), GFP_KERNEL); |
| 1066 | if(ses_init_buf) { | 1321 | if(ses_init_buf) { |
| 1067 | ses_init_buf->trailer.session_req.called_len = 32; | 1322 | ses_init_buf->trailer.session_req.called_len = 32; |
| 1068 | rfc1002mangle(ses_init_buf->trailer.session_req.called_name, | 1323 | rfc1002mangle(ses_init_buf->trailer.session_req.called_name, |
| @@ -1352,6 +1607,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 1352 | } else | 1607 | } else |
| 1353 | rc = 0; | 1608 | rc = 0; |
| 1354 | memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16); | 1609 | memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16); |
| 1610 | srvTcp->sequence_number = 0; | ||
| 1355 | } | 1611 | } |
| 1356 | } | 1612 | } |
| 1357 | 1613 | ||
| @@ -1419,6 +1675,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 1419 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID; | 1675 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID; |
| 1420 | if(volume_info.server_ino) | 1676 | if(volume_info.server_ino) |
| 1421 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM; | 1677 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM; |
| 1678 | if(volume_info.remap) | ||
| 1679 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR; | ||
| 1422 | if(volume_info.no_xattr) | 1680 | if(volume_info.no_xattr) |
| 1423 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR; | 1681 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR; |
| 1424 | if(volume_info.direct_io) { | 1682 | if(volume_info.direct_io) { |
| @@ -1447,11 +1705,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 1447 | if ((strchr(volume_info.UNC + 3, '\\') == NULL) | 1705 | if ((strchr(volume_info.UNC + 3, '\\') == NULL) |
| 1448 | && (strchr(volume_info.UNC + 3, '/') == | 1706 | && (strchr(volume_info.UNC + 3, '/') == |
| 1449 | NULL)) { | 1707 | NULL)) { |
| 1450 | rc = connect_to_dfs_path(xid, | 1708 | rc = connect_to_dfs_path(xid, pSesInfo, |
| 1451 | pSesInfo, | 1709 | "", cifs_sb->local_nls, |
| 1452 | "", | 1710 | cifs_sb->mnt_cifs_flags & |
| 1453 | cifs_sb-> | 1711 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 1454 | local_nls); | ||
| 1455 | if(volume_info.UNC) | 1712 | if(volume_info.UNC) |
| 1456 | kfree(volume_info.UNC); | 1713 | kfree(volume_info.UNC); |
| 1457 | FreeXid(xid); | 1714 | FreeXid(xid); |
| @@ -1514,10 +1771,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 1514 | tcon->ses = pSesInfo; | 1771 | tcon->ses = pSesInfo; |
| 1515 | 1772 | ||
| 1516 | /* do not care if following two calls succeed - informational only */ | 1773 | /* do not care if following two calls succeed - informational only */ |
| 1517 | CIFSSMBQFSDeviceInfo(xid, tcon, cifs_sb->local_nls); | 1774 | CIFSSMBQFSDeviceInfo(xid, tcon); |
| 1518 | CIFSSMBQFSAttributeInfo(xid, tcon, cifs_sb->local_nls); | 1775 | CIFSSMBQFSAttributeInfo(xid, tcon); |
| 1519 | if (tcon->ses->capabilities & CAP_UNIX) { | 1776 | if (tcon->ses->capabilities & CAP_UNIX) { |
| 1520 | if(!CIFSSMBQFSUnixInfo(xid, tcon, cifs_sb->local_nls)) { | 1777 | if(!CIFSSMBQFSUnixInfo(xid, tcon)) { |
| 1521 | if(!volume_info.no_psx_acl) { | 1778 | if(!volume_info.no_psx_acl) { |
| 1522 | if(CIFS_UNIX_POSIX_ACL_CAP & | 1779 | if(CIFS_UNIX_POSIX_ACL_CAP & |
| 1523 | le64_to_cpu(tcon->fsUnixInfo.Capability)) | 1780 | le64_to_cpu(tcon->fsUnixInfo.Capability)) |
| @@ -1707,7 +1964,9 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 1707 | /* We look for obvious messed up bcc or strings in response so we do not go off | 1964 | /* We look for obvious messed up bcc or strings in response so we do not go off |
| 1708 | the end since (at least) WIN2K and Windows XP have a major bug in not null | 1965 | the end since (at least) WIN2K and Windows XP have a major bug in not null |
| 1709 | terminating last Unicode string in response */ | 1966 | terminating last Unicode string in response */ |
| 1710 | ses->serverOS = cifs_kcalloc(2 * (len + 1), GFP_KERNEL); | 1967 | ses->serverOS = kcalloc(1, 2 * (len + 1), GFP_KERNEL); |
| 1968 | if(ses->serverOS == NULL) | ||
| 1969 | goto sesssetup_nomem; | ||
| 1711 | cifs_strfromUCS_le(ses->serverOS, | 1970 | cifs_strfromUCS_le(ses->serverOS, |
| 1712 | (wchar_t *)bcc_ptr, len,nls_codepage); | 1971 | (wchar_t *)bcc_ptr, len,nls_codepage); |
| 1713 | bcc_ptr += 2 * (len + 1); | 1972 | bcc_ptr += 2 * (len + 1); |
| @@ -1717,7 +1976,9 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 1717 | if (remaining_words > 0) { | 1976 | if (remaining_words > 0) { |
| 1718 | len = UniStrnlen((wchar_t *)bcc_ptr, | 1977 | len = UniStrnlen((wchar_t *)bcc_ptr, |
| 1719 | remaining_words-1); | 1978 | remaining_words-1); |
| 1720 | ses->serverNOS =cifs_kcalloc(2 * (len + 1),GFP_KERNEL); | 1979 | ses->serverNOS = kcalloc(1, 2 * (len + 1),GFP_KERNEL); |
| 1980 | if(ses->serverNOS == NULL) | ||
| 1981 | goto sesssetup_nomem; | ||
| 1721 | cifs_strfromUCS_le(ses->serverNOS, | 1982 | cifs_strfromUCS_le(ses->serverNOS, |
| 1722 | (wchar_t *)bcc_ptr,len,nls_codepage); | 1983 | (wchar_t *)bcc_ptr,len,nls_codepage); |
| 1723 | bcc_ptr += 2 * (len + 1); | 1984 | bcc_ptr += 2 * (len + 1); |
| @@ -1730,10 +1991,12 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 1730 | } | 1991 | } |
| 1731 | remaining_words -= len + 1; | 1992 | remaining_words -= len + 1; |
| 1732 | if (remaining_words > 0) { | 1993 | if (remaining_words > 0) { |
| 1733 | len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); | 1994 | len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); |
| 1734 | /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ | 1995 | /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ |
| 1735 | ses->serverDomain = | 1996 | ses->serverDomain = |
| 1736 | cifs_kcalloc(2*(len+1),GFP_KERNEL); | 1997 | kcalloc(1, 2*(len+1),GFP_KERNEL); |
| 1998 | if(ses->serverDomain == NULL) | ||
| 1999 | goto sesssetup_nomem; | ||
| 1737 | cifs_strfromUCS_le(ses->serverDomain, | 2000 | cifs_strfromUCS_le(ses->serverDomain, |
| 1738 | (wchar_t *)bcc_ptr,len,nls_codepage); | 2001 | (wchar_t *)bcc_ptr,len,nls_codepage); |
| 1739 | bcc_ptr += 2 * (len + 1); | 2002 | bcc_ptr += 2 * (len + 1); |
| @@ -1741,21 +2004,25 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 1741 | ses->serverDomain[1+(2*len)] = 0; | 2004 | ses->serverDomain[1+(2*len)] = 0; |
| 1742 | } /* else no more room so create dummy domain string */ | 2005 | } /* else no more room so create dummy domain string */ |
| 1743 | else | 2006 | else |
| 1744 | ses->serverDomain = | 2007 | ses->serverDomain = |
| 1745 | cifs_kcalloc(2, | 2008 | kcalloc(1, 2, GFP_KERNEL); |
| 1746 | GFP_KERNEL); | ||
| 1747 | } else { /* no room so create dummy domain and NOS string */ | 2009 | } else { /* no room so create dummy domain and NOS string */ |
| 2010 | /* if these kcallocs fail not much we | ||
| 2011 | can do, but better to not fail the | ||
| 2012 | sesssetup itself */ | ||
| 1748 | ses->serverDomain = | 2013 | ses->serverDomain = |
| 1749 | cifs_kcalloc(2, GFP_KERNEL); | 2014 | kcalloc(1, 2, GFP_KERNEL); |
| 1750 | ses->serverNOS = | 2015 | ses->serverNOS = |
| 1751 | cifs_kcalloc(2, GFP_KERNEL); | 2016 | kcalloc(1, 2, GFP_KERNEL); |
| 1752 | } | 2017 | } |
| 1753 | } else { /* ASCII */ | 2018 | } else { /* ASCII */ |
| 1754 | len = strnlen(bcc_ptr, 1024); | 2019 | len = strnlen(bcc_ptr, 1024); |
| 1755 | if (((long) bcc_ptr + len) - (long) | 2020 | if (((long) bcc_ptr + len) - (long) |
| 1756 | pByteArea(smb_buffer_response) | 2021 | pByteArea(smb_buffer_response) |
| 1757 | <= BCC(smb_buffer_response)) { | 2022 | <= BCC(smb_buffer_response)) { |
| 1758 | ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL); | 2023 | ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL); |
| 2024 | if(ses->serverOS == NULL) | ||
| 2025 | goto sesssetup_nomem; | ||
| 1759 | strncpy(ses->serverOS,bcc_ptr, len); | 2026 | strncpy(ses->serverOS,bcc_ptr, len); |
| 1760 | 2027 | ||
| 1761 | bcc_ptr += len; | 2028 | bcc_ptr += len; |
| @@ -1763,14 +2030,18 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 1763 | bcc_ptr++; | 2030 | bcc_ptr++; |
| 1764 | 2031 | ||
| 1765 | len = strnlen(bcc_ptr, 1024); | 2032 | len = strnlen(bcc_ptr, 1024); |
| 1766 | ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL); | 2033 | ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL); |
| 2034 | if(ses->serverNOS == NULL) | ||
| 2035 | goto sesssetup_nomem; | ||
| 1767 | strncpy(ses->serverNOS, bcc_ptr, len); | 2036 | strncpy(ses->serverNOS, bcc_ptr, len); |
| 1768 | bcc_ptr += len; | 2037 | bcc_ptr += len; |
| 1769 | bcc_ptr[0] = 0; | 2038 | bcc_ptr[0] = 0; |
| 1770 | bcc_ptr++; | 2039 | bcc_ptr++; |
| 1771 | 2040 | ||
| 1772 | len = strnlen(bcc_ptr, 1024); | 2041 | len = strnlen(bcc_ptr, 1024); |
| 1773 | ses->serverDomain = cifs_kcalloc(len + 1,GFP_KERNEL); | 2042 | ses->serverDomain = kcalloc(1, len + 1,GFP_KERNEL); |
| 2043 | if(ses->serverDomain == NULL) | ||
| 2044 | goto sesssetup_nomem; | ||
| 1774 | strncpy(ses->serverDomain, bcc_ptr, len); | 2045 | strncpy(ses->serverDomain, bcc_ptr, len); |
| 1775 | bcc_ptr += len; | 2046 | bcc_ptr += len; |
| 1776 | bcc_ptr[0] = 0; | 2047 | bcc_ptr[0] = 0; |
| @@ -1790,7 +2061,9 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 1790 | smb_buffer_response->WordCount)); | 2061 | smb_buffer_response->WordCount)); |
| 1791 | rc = -EIO; | 2062 | rc = -EIO; |
| 1792 | } | 2063 | } |
| 1793 | 2064 | sesssetup_nomem: /* do not return an error on nomem for the info strings, | |
| 2065 | since that could make reconnection harder, and | ||
| 2066 | reconnection might be needed to free memory */ | ||
| 1794 | if (smb_buffer) | 2067 | if (smb_buffer) |
| 1795 | cifs_buf_release(smb_buffer); | 2068 | cifs_buf_release(smb_buffer); |
| 1796 | 2069 | ||
| @@ -1967,7 +2240,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 1967 | the end since (at least) WIN2K and Windows XP have a major bug in not null | 2240 | the end since (at least) WIN2K and Windows XP have a major bug in not null |
| 1968 | terminating last Unicode string in response */ | 2241 | terminating last Unicode string in response */ |
| 1969 | ses->serverOS = | 2242 | ses->serverOS = |
| 1970 | cifs_kcalloc(2 * (len + 1), GFP_KERNEL); | 2243 | kcalloc(1, 2 * (len + 1), GFP_KERNEL); |
| 1971 | cifs_strfromUCS_le(ses->serverOS, | 2244 | cifs_strfromUCS_le(ses->serverOS, |
| 1972 | (wchar_t *) | 2245 | (wchar_t *) |
| 1973 | bcc_ptr, len, | 2246 | bcc_ptr, len, |
| @@ -1981,7 +2254,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 1981 | remaining_words | 2254 | remaining_words |
| 1982 | - 1); | 2255 | - 1); |
| 1983 | ses->serverNOS = | 2256 | ses->serverNOS = |
| 1984 | cifs_kcalloc(2 * (len + 1), | 2257 | kcalloc(1, 2 * (len + 1), |
| 1985 | GFP_KERNEL); | 2258 | GFP_KERNEL); |
| 1986 | cifs_strfromUCS_le(ses->serverNOS, | 2259 | cifs_strfromUCS_le(ses->serverNOS, |
| 1987 | (wchar_t *)bcc_ptr, | 2260 | (wchar_t *)bcc_ptr, |
| @@ -1994,7 +2267,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 1994 | if (remaining_words > 0) { | 2267 | if (remaining_words > 0) { |
| 1995 | len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); | 2268 | len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); |
| 1996 | /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ | 2269 | /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ |
| 1997 | ses->serverDomain = cifs_kcalloc(2*(len+1),GFP_KERNEL); | 2270 | ses->serverDomain = kcalloc(1, 2*(len+1),GFP_KERNEL); |
| 1998 | cifs_strfromUCS_le(ses->serverDomain, | 2271 | cifs_strfromUCS_le(ses->serverDomain, |
| 1999 | (wchar_t *)bcc_ptr, | 2272 | (wchar_t *)bcc_ptr, |
| 2000 | len, | 2273 | len, |
| @@ -2005,10 +2278,10 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 2005 | } /* else no more room so create dummy domain string */ | 2278 | } /* else no more room so create dummy domain string */ |
| 2006 | else | 2279 | else |
| 2007 | ses->serverDomain = | 2280 | ses->serverDomain = |
| 2008 | cifs_kcalloc(2,GFP_KERNEL); | 2281 | kcalloc(1, 2,GFP_KERNEL); |
| 2009 | } else { /* no room so create dummy domain and NOS string */ | 2282 | } else { /* no room so create dummy domain and NOS string */ |
| 2010 | ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL); | 2283 | ses->serverDomain = kcalloc(1, 2, GFP_KERNEL); |
| 2011 | ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL); | 2284 | ses->serverNOS = kcalloc(1, 2, GFP_KERNEL); |
| 2012 | } | 2285 | } |
| 2013 | } else { /* ASCII */ | 2286 | } else { /* ASCII */ |
| 2014 | 2287 | ||
| @@ -2016,7 +2289,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 2016 | if (((long) bcc_ptr + len) - (long) | 2289 | if (((long) bcc_ptr + len) - (long) |
| 2017 | pByteArea(smb_buffer_response) | 2290 | pByteArea(smb_buffer_response) |
| 2018 | <= BCC(smb_buffer_response)) { | 2291 | <= BCC(smb_buffer_response)) { |
| 2019 | ses->serverOS = cifs_kcalloc(len + 1, GFP_KERNEL); | 2292 | ses->serverOS = kcalloc(1, len + 1, GFP_KERNEL); |
| 2020 | strncpy(ses->serverOS, bcc_ptr, len); | 2293 | strncpy(ses->serverOS, bcc_ptr, len); |
| 2021 | 2294 | ||
| 2022 | bcc_ptr += len; | 2295 | bcc_ptr += len; |
| @@ -2024,14 +2297,14 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 2024 | bcc_ptr++; | 2297 | bcc_ptr++; |
| 2025 | 2298 | ||
| 2026 | len = strnlen(bcc_ptr, 1024); | 2299 | len = strnlen(bcc_ptr, 1024); |
| 2027 | ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL); | 2300 | ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL); |
| 2028 | strncpy(ses->serverNOS, bcc_ptr, len); | 2301 | strncpy(ses->serverNOS, bcc_ptr, len); |
| 2029 | bcc_ptr += len; | 2302 | bcc_ptr += len; |
| 2030 | bcc_ptr[0] = 0; | 2303 | bcc_ptr[0] = 0; |
| 2031 | bcc_ptr++; | 2304 | bcc_ptr++; |
| 2032 | 2305 | ||
| 2033 | len = strnlen(bcc_ptr, 1024); | 2306 | len = strnlen(bcc_ptr, 1024); |
| 2034 | ses->serverDomain = cifs_kcalloc(len + 1, GFP_KERNEL); | 2307 | ses->serverDomain = kcalloc(1, len + 1, GFP_KERNEL); |
| 2035 | strncpy(ses->serverDomain, bcc_ptr, len); | 2308 | strncpy(ses->serverDomain, bcc_ptr, len); |
| 2036 | bcc_ptr += len; | 2309 | bcc_ptr += len; |
| 2037 | bcc_ptr[0] = 0; | 2310 | bcc_ptr[0] = 0; |
| @@ -2281,7 +2554,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, | |||
| 2281 | the end since (at least) WIN2K and Windows XP have a major bug in not null | 2554 | the end since (at least) WIN2K and Windows XP have a major bug in not null |
| 2282 | terminating last Unicode string in response */ | 2555 | terminating last Unicode string in response */ |
| 2283 | ses->serverOS = | 2556 | ses->serverOS = |
| 2284 | cifs_kcalloc(2 * (len + 1), GFP_KERNEL); | 2557 | kcalloc(1, 2 * (len + 1), GFP_KERNEL); |
| 2285 | cifs_strfromUCS_le(ses->serverOS, | 2558 | cifs_strfromUCS_le(ses->serverOS, |
| 2286 | (wchar_t *) | 2559 | (wchar_t *) |
| 2287 | bcc_ptr, len, | 2560 | bcc_ptr, len, |
| @@ -2296,7 +2569,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, | |||
| 2296 | remaining_words | 2569 | remaining_words |
| 2297 | - 1); | 2570 | - 1); |
| 2298 | ses->serverNOS = | 2571 | ses->serverNOS = |
| 2299 | cifs_kcalloc(2 * (len + 1), | 2572 | kcalloc(1, 2 * (len + 1), |
| 2300 | GFP_KERNEL); | 2573 | GFP_KERNEL); |
| 2301 | cifs_strfromUCS_le(ses-> | 2574 | cifs_strfromUCS_le(ses-> |
| 2302 | serverNOS, | 2575 | serverNOS, |
| @@ -2313,7 +2586,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, | |||
| 2313 | len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); | 2586 | len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); |
| 2314 | /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ | 2587 | /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ |
| 2315 | ses->serverDomain = | 2588 | ses->serverDomain = |
| 2316 | cifs_kcalloc(2 * | 2589 | kcalloc(1, 2 * |
| 2317 | (len + | 2590 | (len + |
| 2318 | 1), | 2591 | 1), |
| 2319 | GFP_KERNEL); | 2592 | GFP_KERNEL); |
| @@ -2339,13 +2612,13 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, | |||
| 2339 | } /* else no more room so create dummy domain string */ | 2612 | } /* else no more room so create dummy domain string */ |
| 2340 | else | 2613 | else |
| 2341 | ses->serverDomain = | 2614 | ses->serverDomain = |
| 2342 | cifs_kcalloc(2, | 2615 | kcalloc(1, 2, |
| 2343 | GFP_KERNEL); | 2616 | GFP_KERNEL); |
| 2344 | } else { /* no room so create dummy domain and NOS string */ | 2617 | } else { /* no room so create dummy domain and NOS string */ |
| 2345 | ses->serverDomain = | 2618 | ses->serverDomain = |
| 2346 | cifs_kcalloc(2, GFP_KERNEL); | 2619 | kcalloc(1, 2, GFP_KERNEL); |
| 2347 | ses->serverNOS = | 2620 | ses->serverNOS = |
| 2348 | cifs_kcalloc(2, GFP_KERNEL); | 2621 | kcalloc(1, 2, GFP_KERNEL); |
| 2349 | } | 2622 | } |
| 2350 | } else { /* ASCII */ | 2623 | } else { /* ASCII */ |
| 2351 | len = strnlen(bcc_ptr, 1024); | 2624 | len = strnlen(bcc_ptr, 1024); |
| @@ -2353,7 +2626,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, | |||
| 2353 | pByteArea(smb_buffer_response) | 2626 | pByteArea(smb_buffer_response) |
| 2354 | <= BCC(smb_buffer_response)) { | 2627 | <= BCC(smb_buffer_response)) { |
| 2355 | ses->serverOS = | 2628 | ses->serverOS = |
| 2356 | cifs_kcalloc(len + 1, | 2629 | kcalloc(1, len + 1, |
| 2357 | GFP_KERNEL); | 2630 | GFP_KERNEL); |
| 2358 | strncpy(ses->serverOS, | 2631 | strncpy(ses->serverOS, |
| 2359 | bcc_ptr, len); | 2632 | bcc_ptr, len); |
| @@ -2364,7 +2637,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, | |||
| 2364 | 2637 | ||
| 2365 | len = strnlen(bcc_ptr, 1024); | 2638 | len = strnlen(bcc_ptr, 1024); |
| 2366 | ses->serverNOS = | 2639 | ses->serverNOS = |
| 2367 | cifs_kcalloc(len + 1, | 2640 | kcalloc(1, len + 1, |
| 2368 | GFP_KERNEL); | 2641 | GFP_KERNEL); |
| 2369 | strncpy(ses->serverNOS, bcc_ptr, len); | 2642 | strncpy(ses->serverNOS, bcc_ptr, len); |
| 2370 | bcc_ptr += len; | 2643 | bcc_ptr += len; |
| @@ -2373,7 +2646,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, | |||
| 2373 | 2646 | ||
| 2374 | len = strnlen(bcc_ptr, 1024); | 2647 | len = strnlen(bcc_ptr, 1024); |
| 2375 | ses->serverDomain = | 2648 | ses->serverDomain = |
| 2376 | cifs_kcalloc(len + 1, | 2649 | kcalloc(1, len + 1, |
| 2377 | GFP_KERNEL); | 2650 | GFP_KERNEL); |
| 2378 | strncpy(ses->serverDomain, bcc_ptr, len); | 2651 | strncpy(ses->serverDomain, bcc_ptr, len); |
| 2379 | bcc_ptr += len; | 2652 | bcc_ptr += len; |
| @@ -2675,7 +2948,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 2675 | the end since (at least) WIN2K and Windows XP have a major bug in not null | 2948 | the end since (at least) WIN2K and Windows XP have a major bug in not null |
| 2676 | terminating last Unicode string in response */ | 2949 | terminating last Unicode string in response */ |
| 2677 | ses->serverOS = | 2950 | ses->serverOS = |
| 2678 | cifs_kcalloc(2 * (len + 1), GFP_KERNEL); | 2951 | kcalloc(1, 2 * (len + 1), GFP_KERNEL); |
| 2679 | cifs_strfromUCS_le(ses->serverOS, | 2952 | cifs_strfromUCS_le(ses->serverOS, |
| 2680 | (wchar_t *) | 2953 | (wchar_t *) |
| 2681 | bcc_ptr, len, | 2954 | bcc_ptr, len, |
| @@ -2690,7 +2963,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 2690 | remaining_words | 2963 | remaining_words |
| 2691 | - 1); | 2964 | - 1); |
| 2692 | ses->serverNOS = | 2965 | ses->serverNOS = |
| 2693 | cifs_kcalloc(2 * (len + 1), | 2966 | kcalloc(1, 2 * (len + 1), |
| 2694 | GFP_KERNEL); | 2967 | GFP_KERNEL); |
| 2695 | cifs_strfromUCS_le(ses-> | 2968 | cifs_strfromUCS_le(ses-> |
| 2696 | serverNOS, | 2969 | serverNOS, |
| @@ -2706,7 +2979,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 2706 | len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); | 2979 | len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); |
| 2707 | /* last string not always null terminated (e.g. for Windows XP & 2000) */ | 2980 | /* last string not always null terminated (e.g. for Windows XP & 2000) */ |
| 2708 | ses->serverDomain = | 2981 | ses->serverDomain = |
| 2709 | cifs_kcalloc(2 * | 2982 | kcalloc(1, 2 * |
| 2710 | (len + | 2983 | (len + |
| 2711 | 1), | 2984 | 1), |
| 2712 | GFP_KERNEL); | 2985 | GFP_KERNEL); |
| @@ -2731,17 +3004,17 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 2731 | = 0; | 3004 | = 0; |
| 2732 | } /* else no more room so create dummy domain string */ | 3005 | } /* else no more room so create dummy domain string */ |
| 2733 | else | 3006 | else |
| 2734 | ses->serverDomain = cifs_kcalloc(2,GFP_KERNEL); | 3007 | ses->serverDomain = kcalloc(1, 2,GFP_KERNEL); |
| 2735 | } else { /* no room so create dummy domain and NOS string */ | 3008 | } else { /* no room so create dummy domain and NOS string */ |
| 2736 | ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL); | 3009 | ses->serverDomain = kcalloc(1, 2, GFP_KERNEL); |
| 2737 | ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL); | 3010 | ses->serverNOS = kcalloc(1, 2, GFP_KERNEL); |
| 2738 | } | 3011 | } |
| 2739 | } else { /* ASCII */ | 3012 | } else { /* ASCII */ |
| 2740 | len = strnlen(bcc_ptr, 1024); | 3013 | len = strnlen(bcc_ptr, 1024); |
| 2741 | if (((long) bcc_ptr + len) - | 3014 | if (((long) bcc_ptr + len) - |
| 2742 | (long) pByteArea(smb_buffer_response) | 3015 | (long) pByteArea(smb_buffer_response) |
| 2743 | <= BCC(smb_buffer_response)) { | 3016 | <= BCC(smb_buffer_response)) { |
| 2744 | ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL); | 3017 | ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL); |
| 2745 | strncpy(ses->serverOS,bcc_ptr, len); | 3018 | strncpy(ses->serverOS,bcc_ptr, len); |
| 2746 | 3019 | ||
| 2747 | bcc_ptr += len; | 3020 | bcc_ptr += len; |
| @@ -2749,14 +3022,14 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 2749 | bcc_ptr++; | 3022 | bcc_ptr++; |
| 2750 | 3023 | ||
| 2751 | len = strnlen(bcc_ptr, 1024); | 3024 | len = strnlen(bcc_ptr, 1024); |
| 2752 | ses->serverNOS = cifs_kcalloc(len+1,GFP_KERNEL); | 3025 | ses->serverNOS = kcalloc(1, len+1,GFP_KERNEL); |
| 2753 | strncpy(ses->serverNOS, bcc_ptr, len); | 3026 | strncpy(ses->serverNOS, bcc_ptr, len); |
| 2754 | bcc_ptr += len; | 3027 | bcc_ptr += len; |
| 2755 | bcc_ptr[0] = 0; | 3028 | bcc_ptr[0] = 0; |
| 2756 | bcc_ptr++; | 3029 | bcc_ptr++; |
| 2757 | 3030 | ||
| 2758 | len = strnlen(bcc_ptr, 1024); | 3031 | len = strnlen(bcc_ptr, 1024); |
| 2759 | ses->serverDomain = cifs_kcalloc(len+1,GFP_KERNEL); | 3032 | ses->serverDomain = kcalloc(1, len+1,GFP_KERNEL); |
| 2760 | strncpy(ses->serverDomain, bcc_ptr, len); | 3033 | strncpy(ses->serverDomain, bcc_ptr, len); |
| 2761 | bcc_ptr += len; | 3034 | bcc_ptr += len; |
| 2762 | bcc_ptr[0] = 0; | 3035 | bcc_ptr[0] = 0; |
| @@ -2868,7 +3141,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
| 2868 | if(tcon->nativeFileSystem) | 3141 | if(tcon->nativeFileSystem) |
| 2869 | kfree(tcon->nativeFileSystem); | 3142 | kfree(tcon->nativeFileSystem); |
| 2870 | tcon->nativeFileSystem = | 3143 | tcon->nativeFileSystem = |
| 2871 | cifs_kcalloc(length + 2, GFP_KERNEL); | 3144 | kcalloc(1, length + 2, GFP_KERNEL); |
| 2872 | cifs_strfromUCS_le(tcon->nativeFileSystem, | 3145 | cifs_strfromUCS_le(tcon->nativeFileSystem, |
| 2873 | (wchar_t *) bcc_ptr, | 3146 | (wchar_t *) bcc_ptr, |
| 2874 | length, nls_codepage); | 3147 | length, nls_codepage); |
| @@ -2886,7 +3159,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
| 2886 | if(tcon->nativeFileSystem) | 3159 | if(tcon->nativeFileSystem) |
| 2887 | kfree(tcon->nativeFileSystem); | 3160 | kfree(tcon->nativeFileSystem); |
| 2888 | tcon->nativeFileSystem = | 3161 | tcon->nativeFileSystem = |
| 2889 | cifs_kcalloc(length + 1, GFP_KERNEL); | 3162 | kcalloc(1, length + 1, GFP_KERNEL); |
| 2890 | strncpy(tcon->nativeFileSystem, bcc_ptr, | 3163 | strncpy(tcon->nativeFileSystem, bcc_ptr, |
| 2891 | length); | 3164 | length); |
| 2892 | } | 3165 | } |
| @@ -2959,6 +3232,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, | |||
| 2959 | int rc = 0; | 3232 | int rc = 0; |
| 2960 | char ntlm_session_key[CIFS_SESSION_KEY_SIZE]; | 3233 | char ntlm_session_key[CIFS_SESSION_KEY_SIZE]; |
| 2961 | int ntlmv2_flag = FALSE; | 3234 | int ntlmv2_flag = FALSE; |
| 3235 | int first_time = 0; | ||
| 2962 | 3236 | ||
| 2963 | /* what if server changes its buffer size after dropping the session? */ | 3237 | /* what if server changes its buffer size after dropping the session? */ |
| 2964 | if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ { | 3238 | if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ { |
| @@ -2977,12 +3251,13 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, | |||
| 2977 | spin_unlock(&GlobalMid_Lock); | 3251 | spin_unlock(&GlobalMid_Lock); |
| 2978 | 3252 | ||
| 2979 | } | 3253 | } |
| 3254 | first_time = 1; | ||
| 2980 | } | 3255 | } |
| 2981 | if (!rc) { | 3256 | if (!rc) { |
| 2982 | pSesInfo->capabilities = pSesInfo->server->capabilities; | 3257 | pSesInfo->capabilities = pSesInfo->server->capabilities; |
| 2983 | if(linuxExtEnabled == 0) | 3258 | if(linuxExtEnabled == 0) |
| 2984 | pSesInfo->capabilities &= (~CAP_UNIX); | 3259 | pSesInfo->capabilities &= (~CAP_UNIX); |
| 2985 | pSesInfo->sequence_number = 0; | 3260 | /* pSesInfo->sequence_number = 0;*/ |
| 2986 | cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d", | 3261 | cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d", |
| 2987 | pSesInfo->server->secMode, | 3262 | pSesInfo->server->secMode, |
| 2988 | pSesInfo->server->capabilities, | 3263 | pSesInfo->server->capabilities, |
| @@ -3015,7 +3290,10 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, | |||
| 3015 | v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL); | 3290 | v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL); |
| 3016 | if(v2_response) { | 3291 | if(v2_response) { |
| 3017 | CalcNTLMv2_response(pSesInfo,v2_response); | 3292 | CalcNTLMv2_response(pSesInfo,v2_response); |
| 3018 | /* cifs_calculate_ntlmv2_mac_key(pSesInfo->mac_signing_key, response, ntlm_session_key, */ | 3293 | /* if(first_time) |
| 3294 | cifs_calculate_ntlmv2_mac_key( | ||
| 3295 | pSesInfo->server->mac_signing_key, | ||
| 3296 | response, ntlm_session_key, */ | ||
| 3019 | kfree(v2_response); | 3297 | kfree(v2_response); |
| 3020 | /* BB Put dummy sig in SessSetup PDU? */ | 3298 | /* BB Put dummy sig in SessSetup PDU? */ |
| 3021 | } else { | 3299 | } else { |
| @@ -3028,9 +3306,11 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, | |||
| 3028 | pSesInfo->server->cryptKey, | 3306 | pSesInfo->server->cryptKey, |
| 3029 | ntlm_session_key); | 3307 | ntlm_session_key); |
| 3030 | 3308 | ||
| 3031 | cifs_calculate_mac_key(pSesInfo->mac_signing_key, | 3309 | if(first_time) |
| 3032 | ntlm_session_key, | 3310 | cifs_calculate_mac_key( |
| 3033 | pSesInfo->password); | 3311 | pSesInfo->server->mac_signing_key, |
| 3312 | ntlm_session_key, | ||
| 3313 | pSesInfo->password); | ||
| 3034 | } | 3314 | } |
| 3035 | /* for better security the weaker lanman hash not sent | 3315 | /* for better security the weaker lanman hash not sent |
| 3036 | in AuthSessSetup so we no longer calculate it */ | 3316 | in AuthSessSetup so we no longer calculate it */ |
| @@ -3046,8 +3326,11 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, | |||
| 3046 | pSesInfo->server->cryptKey, | 3326 | pSesInfo->server->cryptKey, |
| 3047 | ntlm_session_key); | 3327 | ntlm_session_key); |
| 3048 | 3328 | ||
| 3049 | cifs_calculate_mac_key(pSesInfo->mac_signing_key, | 3329 | if(first_time) |
| 3050 | ntlm_session_key, pSesInfo->password); | 3330 | cifs_calculate_mac_key( |
| 3331 | pSesInfo->server->mac_signing_key, | ||
| 3332 | ntlm_session_key, pSesInfo->password); | ||
| 3333 | |||
| 3051 | rc = CIFSSessSetup(xid, pSesInfo, | 3334 | rc = CIFSSessSetup(xid, pSesInfo, |
| 3052 | ntlm_session_key, nls_info); | 3335 | ntlm_session_key, nls_info); |
| 3053 | } | 3336 | } |
