1/* 2 Unix SMB/CIFS implementation. 3 service (connection) handling 4 Copyright (C) Andrew Tridgell 1992-2003 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18*/ 19 20#include "includes.h" 21#include "smb_server/smb_server.h" 22#include "smbd/service_stream.h" 23#include "ntvfs/ntvfs.h" 24#include "param/param.h" 25 26/**************************************************************************** 27 Make a connection, given the snum to connect to, and the vuser of the 28 connecting user if appropriate. 29 Does note invoke the NTVFS connection hook 30****************************************************************************/ 31static NTSTATUS make_connection_scfg(struct smbsrv_request *req, 32 struct share_config *scfg, 33 enum ntvfs_type type, 34 DATA_BLOB password, 35 const char *dev) 36{ 37 struct smbsrv_tcon *tcon; 38 NTSTATUS status; 39 uint64_t ntvfs_caps = 0; 40 41 tcon = smbsrv_smb_tcon_new(req->smb_conn, scfg->name); 42 if (!tcon) { 43 DEBUG(0,("Couldn't find free connection.\n")); 44 return NT_STATUS_INSUFFICIENT_RESOURCES; 45 } 46 req->tcon = tcon; 47 48 if (req->smb_conn->negotiate.client_caps & CAP_LEVEL_II_OPLOCKS) { 49 ntvfs_caps |= NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS; 50 } 51 52 /* init ntvfs function pointers */ 53 status = ntvfs_init_connection(tcon, scfg, type, 54 req->smb_conn->negotiate.protocol, 55 ntvfs_caps, 56 req->smb_conn->connection->event.ctx, 57 req->smb_conn->connection->msg_ctx, 58 req->smb_conn->lp_ctx, 59 req->smb_conn->connection->server_id, 60 &tcon->ntvfs); 61 if (!NT_STATUS_IS_OK(status)) { 62 DEBUG(0, ("make_connection_scfg: connection failed for service %s\n", 63 scfg->name)); 64 goto failed; 65 } 66 67 status = ntvfs_set_oplock_handler(tcon->ntvfs, smbsrv_send_oplock_break, tcon); 68 if (!NT_STATUS_IS_OK(status)) { 69 DEBUG(0,("make_connection: NTVFS failed to set the oplock handler!\n")); 70 goto failed; 71 } 72 73 status = ntvfs_set_addr_callbacks(tcon->ntvfs, smbsrv_get_my_addr, smbsrv_get_peer_addr, req->smb_conn); 74 if (!NT_STATUS_IS_OK(status)) { 75 DEBUG(0,("make_connection: NTVFS failed to set the addr callbacks!\n")); 76 goto failed; 77 } 78 79 status = ntvfs_set_handle_callbacks(tcon->ntvfs, 80 smbsrv_handle_create_new, 81 smbsrv_handle_make_valid, 82 smbsrv_handle_destroy, 83 smbsrv_handle_search_by_wire_key, 84 smbsrv_handle_get_wire_key, 85 tcon); 86 if (!NT_STATUS_IS_OK(status)) { 87 DEBUG(0,("make_connection: NTVFS failed to set the handle callbacks!\n")); 88 goto failed; 89 } 90 91 return NT_STATUS_OK; 92 93failed: 94 req->tcon = NULL; 95 talloc_free(tcon); 96 return status; 97} 98 99/**************************************************************************** 100 Make a connection to a service. 101 * 102 * @param service 103****************************************************************************/ 104static NTSTATUS make_connection(struct smbsrv_request *req, 105 const char *service, DATA_BLOB password, 106 const char *dev) 107{ 108 NTSTATUS status; 109 enum ntvfs_type type; 110 const char *type_str; 111 struct share_config *scfg; 112 const char *sharetype; 113 114 /* the service might be of the form \\SERVER\SHARE. Should we put 115 the server name we get from this somewhere? */ 116 if (strncmp(service, "\\\\", 2) == 0) { 117 char *p = strchr(service+2, '\\'); 118 if (p) { 119 service = p + 1; 120 } 121 } 122 123 status = share_get_config(req, req->smb_conn->share_context, service, &scfg); 124 if (!NT_STATUS_IS_OK(status)) { 125 DEBUG(0,("make_connection: couldn't find service %s\n", service)); 126 return NT_STATUS_BAD_NETWORK_NAME; 127 } 128 129 /* TODO: check the password, when it's share level security! */ 130 131 if (!socket_check_access(req->smb_conn->connection->socket, 132 scfg->name, 133 share_string_list_option(req, scfg, SHARE_HOSTS_ALLOW), 134 share_string_list_option(req, scfg, SHARE_HOSTS_DENY))) { 135 return NT_STATUS_ACCESS_DENIED; 136 } 137 138 /* work out what sort of connection this is */ 139 sharetype = share_string_option(scfg, "type", "DISK"); 140 if (sharetype && strcmp(sharetype, "IPC") == 0) { 141 type = NTVFS_IPC; 142 type_str = "IPC"; 143 } else if (sharetype && strcmp(sharetype, "PRINTER") == 0) { 144 type = NTVFS_PRINT; 145 type_str = "LPT:"; 146 } else { 147 type = NTVFS_DISK; 148 type_str = "A:"; 149 } 150 151 if (strcmp(dev, "?????") != 0 && strcasecmp(type_str, dev) != 0) { 152 /* the client gave us the wrong device type */ 153 return NT_STATUS_BAD_DEVICE_TYPE; 154 } 155 156 return make_connection_scfg(req, scfg, type, password, dev); 157} 158 159/* 160 backend for tree connect call, in preparation for calling ntvfs_connect() 161*/ 162NTSTATUS smbsrv_tcon_backend(struct smbsrv_request *req, union smb_tcon *con) 163{ 164 NTSTATUS status; 165 166 if (con->generic.level == RAW_TCON_TCON) { 167 DATA_BLOB password; 168 password = data_blob_string_const(con->tcon.in.password); 169 170 status = make_connection(req, con->tcon.in.service, password, con->tcon.in.dev); 171 172 if (!NT_STATUS_IS_OK(status)) { 173 return status; 174 } 175 176 con->tcon.out.max_xmit = req->smb_conn->negotiate.max_recv; 177 con->tcon.out.tid = req->tcon->tid; 178 179 return status; 180 } 181 182 /* TODO: take a look at tconx.in.flags! */ 183 184 status = make_connection(req, con->tconx.in.path, con->tconx.in.password, 185 con->tconx.in.device); 186 if (!NT_STATUS_IS_OK(status)) { 187 return status; 188 } 189 190 con->tconx.out.tid = req->tcon->tid; 191 con->tconx.out.options = SMB_SUPPORT_SEARCH_BITS | (share_int_option(req->tcon->ntvfs->config, SHARE_CSC_POLICY, SHARE_CSC_POLICY_DEFAULT) << 2); 192 if (share_bool_option(req->tcon->ntvfs->config, SHARE_MSDFS_ROOT, SHARE_MSDFS_ROOT_DEFAULT) && lp_host_msdfs(req->smb_conn->lp_ctx)) { 193 con->tconx.out.options |= SMB_SHARE_IN_DFS; 194 } 195 196 return status; 197} 198