static NTSTATUS smbd_smb2_tree_connect(struct smbd_smb2_request *req, const char *in_path, uint8_t *out_share_type, uint32_t *out_share_flags, uint32_t *out_capabilities, uint32_t *out_maximal_access, uint32_t *out_tree_id) { struct smbXsrv_connection *conn = req->sconn->conn; const char *share = in_path; char *service = NULL; int snum = -1; struct smbXsrv_tcon *tcon; NTTIME now = timeval_to_nttime(&req->request_time); connection_struct *compat_conn = NULL; struct user_struct *compat_vuser = req->session->compat; NTSTATUS status; bool encryption_desired = req->session->encryption_desired; bool encryption_required = req->session->global->encryption_required; bool guest_session = false; if (strncmp(share, "\\\\", 2) == 0) { const char *p = strchr(share+2, '\\'); if (p) { share = p + 1; } } DEBUG(10,("smbd_smb2_tree_connect: path[%s] share[%s]\n", in_path, share)); service = talloc_strdup(talloc_tos(), share); if(!service) { return NT_STATUS_NO_MEMORY; } if (!strlower_m(service)) { DEBUG(2, ("strlower_m %s failed\n", service)); return NT_STATUS_INVALID_PARAMETER; } /* TODO: do more things... */ if (strequal(service,HOMES_NAME)) { if (compat_vuser->homes_snum == -1) { DEBUG(2, ("[homes] share not available for " "user %s because it was not found " "or created at session setup " "time\n", compat_vuser->session_info->unix_info->unix_name)); return NT_STATUS_BAD_NETWORK_NAME; } snum = compat_vuser->homes_snum; } else if ((compat_vuser->homes_snum != -1) && strequal(service, lp_servicename(talloc_tos(), compat_vuser->homes_snum))) { snum = compat_vuser->homes_snum; } else { snum = find_service(talloc_tos(), service, &service); if (!service) { return NT_STATUS_NO_MEMORY; } } if (snum < 0) { DEBUG(3,("smbd_smb2_tree_connect: couldn't find service %s\n", service)); return NT_STATUS_BAD_NETWORK_NAME; } if ((lp_smb_encrypt(snum) >= SMB_SIGNING_DESIRED) && (conn->smb2.client.capabilities & SMB2_CAP_ENCRYPTION)) { encryption_desired = true; } if (lp_smb_encrypt(snum) == SMB_SIGNING_REQUIRED) { encryption_desired = true; encryption_required = true; } if (security_session_user_level(compat_vuser->session_info, NULL) < SECURITY_USER) { guest_session = true; } if (guest_session && encryption_required) { DEBUG(1,("reject guest as encryption is required for service %s\n", service)); return NT_STATUS_ACCESS_DENIED; } if (!(conn->smb2.server.capabilities & SMB2_CAP_ENCRYPTION)) { if (encryption_required) { DEBUG(1,("reject tcon with dialect[0x%04X] " "as encryption is required for service %s\n", conn->smb2.server.dialect, service)); return NT_STATUS_ACCESS_DENIED; } } /* create a new tcon as child of the session */ status = smb2srv_tcon_create(req->session, now, &tcon); if (!NT_STATUS_IS_OK(status)) { return status; } tcon->encryption_desired = encryption_desired; tcon->global->encryption_required = encryption_required; compat_conn = make_connection_smb2(req->sconn, tcon, snum, req->session->compat, "???", &status); if (compat_conn == NULL) { TALLOC_FREE(tcon); return status; } tcon->global->share_name = lp_servicename(tcon->global, SNUM(compat_conn)); if (tcon->global->share_name == NULL) { conn_free(compat_conn); TALLOC_FREE(tcon); return NT_STATUS_NO_MEMORY; } tcon->global->session_global_id = req->session->global->session_global_id; tcon->compat = talloc_move(tcon, &compat_conn); tcon->status = NT_STATUS_OK; status = smbXsrv_tcon_update(tcon); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(tcon); return status; } if (IS_PRINT(tcon->compat)) { *out_share_type = SMB2_SHARE_TYPE_PRINT; } else if (IS_IPC(tcon->compat)) { *out_share_type = SMB2_SHARE_TYPE_PIPE; } else { *out_share_type = SMB2_SHARE_TYPE_DISK; } *out_share_flags = 0; if (lp_msdfs_root(SNUM(tcon->compat)) && lp_host_msdfs()) { *out_share_flags |= (SMB2_SHAREFLAG_DFS|SMB2_SHAREFLAG_DFS_ROOT); *out_capabilities = SMB2_SHARE_CAP_DFS; } else { *out_capabilities = 0; } switch(lp_csc_policy(SNUM(tcon->compat))) { case CSC_POLICY_MANUAL: break; case CSC_POLICY_DOCUMENTS: *out_share_flags |= SMB2_SHAREFLAG_AUTO_CACHING; break; case CSC_POLICY_PROGRAMS: *out_share_flags |= SMB2_SHAREFLAG_VDO_CACHING; break; case CSC_POLICY_DISABLE: *out_share_flags |= SMB2_SHAREFLAG_NO_CACHING; break; default: break; } if (lp_hideunreadable(SNUM(tcon->compat)) || lp_hideunwriteable_files(SNUM(tcon->compat))) { *out_share_flags |= SMB2_SHAREFLAG_ACCESS_BASED_DIRECTORY_ENUM; } if (encryption_desired) { *out_share_flags |= SMB2_SHAREFLAG_ENCRYPT_DATA; } *out_maximal_access = tcon->compat->share_access; *out_tree_id = tcon->global->tcon_wire_id; return NT_STATUS_OK; }
static NTSTATUS smbd_smb2_tree_connect(struct smbd_smb2_request *req, const char *in_path, uint8_t *out_share_type, uint32_t *out_share_flags, uint32_t *out_capabilities, uint32_t *out_maximal_access, uint32_t *out_tree_id) { const char *share = in_path; char *service = NULL; int snum = -1; struct smbd_smb2_tcon *tcon; connection_struct *compat_conn = NULL; user_struct *compat_vuser = req->session->compat_vuser; int id; NTSTATUS status; if (strncmp(share, "\\\\", 2) == 0) { const char *p = strchr(share+2, '\\'); if (p) { share = p + 1; } } DEBUG(10,("smbd_smb2_tree_connect: path[%s] share[%s]\n", in_path, share)); service = talloc_strdup(talloc_tos(), share); if(!service) { return NT_STATUS_NO_MEMORY; } strlower_m(service); /* TODO: do more things... */ if (strequal(service,HOMES_NAME)) { if (compat_vuser->homes_snum == -1) { DEBUG(2, ("[homes] share not available for " "user %s because it was not found " "or created at session setup " "time\n", compat_vuser->session_info->unix_info->unix_name)); return NT_STATUS_BAD_NETWORK_NAME; } snum = compat_vuser->homes_snum; } else if ((compat_vuser->homes_snum != -1) && strequal(service, lp_servicename(compat_vuser->homes_snum))) { snum = compat_vuser->homes_snum; } else { snum = find_service(talloc_tos(), service, &service); if (!service) { return NT_STATUS_NO_MEMORY; } } if (snum < 0) { DEBUG(3,("smbd_smb2_tree_connect: couldn't find service %s\n", service)); return NT_STATUS_BAD_NETWORK_NAME; } /* create a new tcon as child of the session */ tcon = talloc_zero(req->session, struct smbd_smb2_tcon); if (tcon == NULL) { return NT_STATUS_NO_MEMORY; } id = idr_get_new_random(req->session->tcons.idtree, tcon, req->session->tcons.limit); if (id == -1) { TALLOC_FREE(tcon); return NT_STATUS_INSUFFICIENT_RESOURCES; } tcon->tid = id; tcon->snum = snum; DLIST_ADD_END(req->session->tcons.list, tcon, struct smbd_smb2_tcon *); tcon->session = req->session; tcon->session->sconn->num_tcons_open++; talloc_set_destructor(tcon, smbd_smb2_tcon_destructor); compat_conn = make_connection_smb2(req->sconn, tcon, req->session->compat_vuser, data_blob_null, "???", &status); if (compat_conn == NULL) { TALLOC_FREE(tcon); return status; } tcon->compat_conn = talloc_move(tcon, &compat_conn); if (IS_PRINT(tcon->compat_conn)) { *out_share_type = SMB2_SHARE_TYPE_PRINT; } else if (IS_IPC(tcon->compat_conn)) { *out_share_type = SMB2_SHARE_TYPE_PIPE; } else { *out_share_type = SMB2_SHARE_TYPE_DISK; } *out_share_flags = 0; if (lp_msdfs_root(SNUM(tcon->compat_conn)) && lp_host_msdfs()) { *out_share_flags |= (SMB2_SHAREFLAG_DFS|SMB2_SHAREFLAG_DFS_ROOT); *out_capabilities = SMB2_SHARE_CAP_DFS; } else { *out_capabilities = 0; } switch(lp_csc_policy(SNUM(tcon->compat_conn))) { case CSC_POLICY_MANUAL: break; case CSC_POLICY_DOCUMENTS: *out_share_flags |= SMB2_SHAREFLAG_AUTO_CACHING; break; case CSC_POLICY_PROGRAMS: *out_share_flags |= SMB2_SHAREFLAG_VDO_CACHING; break; case CSC_POLICY_DISABLE: *out_share_flags |= SMB2_SHAREFLAG_NO_CACHING; break; default: break; } if (lp_hideunreadable(SNUM(tcon->compat_conn)) || lp_hideunwriteable_files(SNUM(tcon->compat_conn))) { *out_share_flags |= SMB2_SHAREFLAG_ACCESS_BASED_DIRECTORY_ENUM; } *out_maximal_access = tcon->compat_conn->share_access; *out_tree_id = tcon->tid; return NT_STATUS_OK; }