📄 connect.c
字号:
if(csocket != NULL) sock_release(csocket); if(volume_info.UNC) kfree(volume_info.UNC); if(volume_info.password) kfree(volume_info.password); FreeXid(xid); return rc; } srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL); if (srvTcp == NULL) { rc = -ENOMEM; sock_release(csocket); if(volume_info.UNC) kfree(volume_info.UNC); if(volume_info.password) kfree(volume_info.password); FreeXid(xid); return rc; } else { memset(srvTcp, 0, sizeof (struct TCP_Server_Info)); memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in)); atomic_set(&srvTcp->inFlight,0); /* BB Add code for ipv6 case too */ srvTcp->ssocket = csocket; srvTcp->protocolType = IPV4; init_waitqueue_head(&srvTcp->response_q); init_waitqueue_head(&srvTcp->request_q); INIT_LIST_HEAD(&srvTcp->pending_mid_q); /* at this point we are the only ones with the pointer to the struct since the kernel thread not created yet so no need to spinlock this init of tcpStatus */ srvTcp->tcpStatus = CifsNew; init_MUTEX(&srvTcp->tcpSem); rc = (int)kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp, CLONE_FS | CLONE_FILES | CLONE_VM); if(rc < 0) { rc = -ENOMEM; sock_release(csocket); if(volume_info.UNC) kfree(volume_info.UNC); if(volume_info.password) kfree(volume_info.password); FreeXid(xid); return rc; } else rc = 0; memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16); } } if (existingCifsSes) { pSesInfo = existingCifsSes; cFYI(1, ("Existing smb sess found ")); if(volume_info.password) kfree(volume_info.password); /* volume_info.UNC freed at end of function */ } else if (!rc) { cFYI(1, ("Existing smb sess not found ")); pSesInfo = sesInfoAlloc(); if (pSesInfo == NULL) rc = -ENOMEM; else { pSesInfo->server = srvTcp; sprintf(pSesInfo->serverName, "%u.%u.%u.%u", NIPQUAD(sin_server.sin_addr.s_addr)); } if (!rc){ /* volume_info.password freed at unmount */ if (volume_info.password) pSesInfo->password = volume_info.password; if (volume_info.username) strncpy(pSesInfo->userName, volume_info.username,MAX_USERNAME_SIZE); if (volume_info.domainname) strncpy(pSesInfo->domainName, volume_info.domainname,MAX_USERNAME_SIZE); pSesInfo->linux_uid = volume_info.linux_uid; down(&pSesInfo->sesSem); rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls); up(&pSesInfo->sesSem); if(!rc) atomic_inc(&srvTcp->socketUseCount); } else if(volume_info.password) kfree(volume_info.password); } /* search for existing tcon to this server share */ if (!rc) { if((volume_info.rsize) && (volume_info.rsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf)) cifs_sb->rsize = volume_info.rsize; else cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */ if((volume_info.wsize) && (volume_info.wsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf)) cifs_sb->wsize = volume_info.wsize; else cifs_sb->wsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */ if(cifs_sb->rsize < PAGE_CACHE_SIZE) { cifs_sb->rsize = PAGE_CACHE_SIZE; cERROR(1,("Attempt to set readsize for mount to less than one page (4096)")); } cifs_sb->mnt_uid = volume_info.linux_uid; cifs_sb->mnt_gid = volume_info.linux_gid; cifs_sb->mnt_file_mode = volume_info.file_mode; cifs_sb->mnt_dir_mode = volume_info.dir_mode; cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode)); if(volume_info.noperm) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM; if(volume_info.setuids) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID; tcon = find_unc(sin_server.sin_addr.s_addr, volume_info.UNC, volume_info.username); if (tcon) { cFYI(1, ("Found match on UNC path ")); /* we can have only one retry value for a connection to a share so for resources mounted more than once to the same server share the last value passed in for the retry flag is used */ tcon->retry = volume_info.retry; } else { tcon = tconInfoAlloc(); if (tcon == NULL) rc = -ENOMEM; else { /* check for null share name ie connect to dfs root */ /* BB check if this works for exactly length three strings */ if ((strchr(volume_info.UNC + 3, '\\') == NULL) && (strchr(volume_info.UNC + 3, '/') == NULL)) { rc = connect_to_dfs_path(xid, pSesInfo, "", cifs_sb-> local_nls); if(volume_info.UNC) kfree(volume_info.UNC); FreeXid(xid); return -ENODEV; } else { rc = CIFSTCon(xid, pSesInfo, volume_info.UNC, tcon, cifs_sb->local_nls); cFYI(1, ("CIFS Tcon rc = %d", rc)); } if (!rc) { atomic_inc(&pSesInfo->inUse); tcon->retry = volume_info.retry; } } } } if(pSesInfo) { if (pSesInfo->capabilities & CAP_LARGE_FILES) { sb->s_maxbytes = (u64) 1 << 63; } else sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */ }/* on error free sesinfo and tcon struct if needed */ if (rc) { /* if session setup failed, use count is zero but we still need to free cifsd thread */ if(atomic_read(&srvTcp->socketUseCount) == 0) { spin_lock(&GlobalMid_Lock); srvTcp->tcpStatus = CifsExiting; spin_unlock(&GlobalMid_Lock); if(srvTcp->tsk) send_sig(SIGKILL,srvTcp->tsk,1); } /* If find_unc succeeded then rc == 0 so we can not end */ if (tcon) /* up accidently freeing someone elses tcon struct */ tconInfoFree(tcon); if (existingCifsSes == 0) { if (pSesInfo) { if ((pSesInfo->server) && (pSesInfo->status == CifsGood)) { int temp_rc; temp_rc = CIFSSMBLogoff(xid, pSesInfo); /* if the socketUseCount is now zero */ if((temp_rc == -ESHUTDOWN) && (pSesInfo->server->tsk)) send_sig(SIGKILL,pSesInfo->server->tsk,1); } else cFYI(1, ("No session or bad tcon")); sesInfoFree(pSesInfo); /* pSesInfo = NULL; */ } } } else { atomic_inc(&tcon->useCount); cifs_sb->tcon = tcon; tcon->ses = pSesInfo; /* do not care if following two calls succeed - informational only */ CIFSSMBQFSDeviceInfo(xid, tcon, cifs_sb->local_nls); CIFSSMBQFSAttributeInfo(xid, tcon, cifs_sb->local_nls); if (tcon->ses->capabilities & CAP_UNIX) CIFSSMBQFSUnixInfo(xid, tcon, cifs_sb->local_nls); } /* volume_info.password is freed above when existing session found (in which case it is not needed anymore) but when new sesion is created the password ptr is put in the new session structure (in which case the password will be freed at unmount time) */ if(volume_info.UNC) kfree(volume_info.UNC); FreeXid(xid); return rc;}static intCIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, char session_key[CIFS_SESSION_KEY_SIZE], const struct nls_table *nls_codepage){ struct smb_hdr *smb_buffer; struct smb_hdr *smb_buffer_response; SESSION_SETUP_ANDX *pSMB; SESSION_SETUP_ANDX *pSMBr; char *bcc_ptr; char *user; char *domain; int rc = 0; int remaining_words = 0; int bytes_returned = 0; int len; __u32 capabilities; __u16 count; cFYI(1, ("In sesssetup ")); if(ses == NULL) return -EINVAL; user = ses->userName; domain = ses->domainName; smb_buffer = cifs_buf_get(); if (smb_buffer == 0) { return -ENOMEM; } smb_buffer_response = smb_buffer; pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer; /* send SMBsessionSetup here */ header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, NULL /* no tCon exists yet */ , 13 /* wct */ ); pSMB->req_no_secext.AndXCommand = 0xFF; pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq); if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS; if (ses->capabilities & CAP_UNICODE) { smb_buffer->Flags2 |= SMBFLG2_UNICODE; capabilities |= CAP_UNICODE; } if (ses->capabilities & CAP_STATUS32) { smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; capabilities |= CAP_STATUS32; } if (ses->capabilities & CAP_DFS) { smb_buffer->Flags2 |= SMBFLG2_DFS; capabilities |= CAP_DFS; } pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); /* pSMB->req_no_secext.CaseInsensitivePasswordLength = CIFS_SESSION_KEY_SIZE; */ pSMB->req_no_secext.CaseInsensitivePasswordLength = 0; pSMB->req_no_secext.CaseSensitivePasswordLength = cpu_to_le16(CIFS_SESSION_KEY_SIZE); bcc_ptr = pByteArea(smb_buffer); /* memcpy(bcc_ptr, (char *) lm_session_key, CIFS_SESSION_KEY_SIZE); bcc_ptr += CIFS_SESSION_KEY_SIZE; */ memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE); bcc_ptr += CIFS_SESSION_KEY_SIZE; if (ses->capabilities & CAP_UNICODE) { if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */ *bcc_ptr = 0; bcc_ptr++; } if(user == NULL) bytes_returned = 0; /* skill null user */ else bytes_returned = cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage); bcc_ptr += 2 * bytes_returned; /* convert num 16 bit words to bytes */ bcc_ptr += 2; /* trailing null */ if (domain == NULL) bytes_returned = cifs_strtoUCS((wchar_t *) bcc_ptr, "CIFS_LINUX_DOM", 32, nls_codepage); else bytes_returned = cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; bytes_returned = cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ", 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bytes_returned = cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; bytes_returned = cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS, 64, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; } else { if(user != NULL) { strncpy(bcc_ptr, user, 200); bcc_ptr += strnlen(user, 200); } *bcc_ptr = 0; bcc_ptr++; if (domain == NULL) { strcpy(bcc_ptr, "CIFS_LINUX_DOM"); bcc_ptr += strlen("CIFS_LINUX_DOM") + 1; } else { strncpy(bcc_ptr, domain, 64); bcc_ptr += strnlen(domain, 64); *bcc_ptr = 0; bcc_ptr++; } strcpy(bcc_ptr, "Linux version "); bcc_ptr += strlen("Linux version "); strcpy(bcc_ptr, UTS_RELEASE); bcc_ptr += strlen(UTS_RELEASE) + 1; strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; } count = (long) bcc_ptr - (long) pByteArea(smb_buffer); smb_buffer->smb_buf_length += count; pSMB->req_no_secext.ByteCount = cpu_to_le16(count); rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &bytes_returned, 1); if (rc) {/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */ } else if ((smb_buffer_response->WordCount == 3) || (smb_buffer_response->WordCount == 4)) { __u16 action = le16_to_cpu(pSMBr->resp.Action); __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); if (action & GUEST_LOGIN) cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */ ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */ cFYI(1, ("UID = %d ", ses->Suid)); /* response can have either 3 or 4 word count - Samba sends 3 */ bcc_ptr = pByteArea(smb_buffer_response); if ((pSMBr->resp.hdr.WordCount == 3) || ((pSMBr->resp.hdr.WordCount == 4) && (blob_len < pSMBr->resp.ByteCount))) { if (pSMBr->resp.hdr.WordCount == 4) bcc_ptr += blob_len; if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { if ((long) (bcc_ptr) % 2) { remaining_words = (BCC(smb_buffer_response) - 1) /2; bcc_ptr++; /* Unicode strings must be word aligned */ } else { remaining_words = BCC(smb_buffer_response) / 2; } len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words - 1);/* We look for obvious messed up bcc or strings in response so we do not go off the end since (at least) WIN2K and Windows XP have a major bug in not null terminating last Unicode string in response */ ses->serverOS = cifs_kcalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverOS, (wchar_t *)bcc_ptr, len,nls_codepage); bcc_ptr += 2 * (len + 1); remaining_words -= len + 1; ses->serverOS[2 * len] = 0; ses->serverOS[1 + (2 * len)] = 0; if (remaining_words > 0) { len = UniStrnlen((wchar_t *)bcc_ptr, remaining_words-1); ses->serverNOS =cifs_kcalloc(2 * (len + 1),GFP_KERNEL); cifs_strfromUCS_le(ses->serverNOS, (wchar_t *)bcc_ptr,len,nls_codepage); bcc_ptr += 2 * (len + 1); ses->serverNOS[2 * len] = 0; ses->serverNOS[1 + (2 * len)] = 0; remaining_words -= len + 1; if (remaining_words > 0) { len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ ses->serverDomain = cifs_kcalloc(2*(len+1),GFP_KERNEL); cifs_strfromUCS_le(ses->serverDomain, (wchar_t *)bcc_ptr,len,nls_codepage); bcc_ptr += 2 * (len + 1); ses->serverDomain[2*len] = 0; ses->serverDomain[1+(2*len)] = 0; } /* else no more room so create dummy domain string */ else ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL); } else { /* no room so create dummy domain and NOS string */ ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL); ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL); } } else { /* ASCII */ len = strnlen(bcc_ptr, 1024); if (((long) bcc_ptr + len) - (long) pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -