diff options
Diffstat (limited to '')
-rw-r--r-- | source4/smb_server/smb/service.c | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/source4/smb_server/smb/service.c b/source4/smb_server/smb/service.c new file mode 100644 index 0000000..eb1874c --- /dev/null +++ b/source4/smb_server/smb/service.c @@ -0,0 +1,202 @@ +/* + Unix SMB/CIFS implementation. + service (connection) handling + Copyright (C) Andrew Tridgell 1992-2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "smb_server/smb_server.h" +#include "samba/service_stream.h" +#include "ntvfs/ntvfs.h" +#include "param/param.h" + +#undef strcasecmp + +/**************************************************************************** + Make a connection, given the snum to connect to, and the vuser of the + connecting user if appropriate. + Does note invoke the NTVFS connection hook +****************************************************************************/ +static NTSTATUS make_connection_scfg(struct smbsrv_request *req, + struct share_config *scfg, + enum ntvfs_type type, + DATA_BLOB password, + const char *dev) +{ + struct smbsrv_tcon *tcon; + NTSTATUS status; + uint64_t ntvfs_caps = 0; + + tcon = smbsrv_smb_tcon_new(req->smb_conn, scfg->name); + if (!tcon) { + DEBUG(0,("Couldn't find free connection.\n")); + return NT_STATUS_INSUFFICIENT_RESOURCES; + } + req->tcon = tcon; + + if (req->smb_conn->negotiate.client_caps & CAP_LEVEL_II_OPLOCKS) { + ntvfs_caps |= NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS; + } + + /* init ntvfs function pointers */ + status = ntvfs_init_connection(tcon, scfg, type, + req->smb_conn->negotiate.protocol, + ntvfs_caps, + req->smb_conn->connection->event.ctx, + req->smb_conn->connection->msg_ctx, + req->smb_conn->lp_ctx, + req->smb_conn->connection->server_id, + &tcon->ntvfs); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("make_connection_scfg: connection failed for service %s\n", + scfg->name)); + goto failed; + } + + status = ntvfs_set_oplock_handler(tcon->ntvfs, smbsrv_send_oplock_break, tcon); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("make_connection: NTVFS failed to set the oplock handler!\n")); + goto failed; + } + + status = ntvfs_set_addresses(tcon->ntvfs, + req->smb_conn->connection->local_address, + req->smb_conn->connection->remote_address); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("make_connection: NTVFS failed to set the addresses!\n")); + goto failed; + } + + status = ntvfs_set_handle_callbacks(tcon->ntvfs, + smbsrv_handle_create_new, + smbsrv_handle_make_valid, + smbsrv_handle_destroy, + smbsrv_handle_search_by_wire_key, + smbsrv_handle_get_wire_key, + tcon); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("make_connection: NTVFS failed to set the handle callbacks!\n")); + goto failed; + } + + return NT_STATUS_OK; + +failed: + req->tcon = NULL; + talloc_free(tcon); + return status; +} + +/**************************************************************************** + Make a connection to a service. + * + * @param service +****************************************************************************/ +static NTSTATUS make_connection(struct smbsrv_request *req, + const char *service, DATA_BLOB password, + const char *dev) +{ + NTSTATUS status; + enum ntvfs_type type; + const char *type_str; + struct share_config *scfg; + char *sharetype; + + /* the service might be of the form \\SERVER\SHARE. Should we put + the server name we get from this somewhere? */ + if (strncmp(service, "\\\\", 2) == 0) { + char *p = strchr(service+2, '\\'); + if (p) { + service = p + 1; + } + } + + status = share_get_config(req, req->smb_conn->share_context, service, &scfg); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("make_connection: couldn't find service %s: %s\n", service, nt_errstr(status))); + return NT_STATUS_BAD_NETWORK_NAME; + } + + /* TODO: check the password, when it's share level security! */ + + if (!socket_check_access(req->smb_conn->connection->socket, + scfg->name, + share_string_list_option(req, scfg, SHARE_HOSTS_ALLOW), + share_string_list_option(req, scfg, SHARE_HOSTS_DENY))) { + return NT_STATUS_ACCESS_DENIED; + } + + /* work out what sort of connection this is */ + sharetype = share_string_option(req, scfg, "type", "DISK"); + if (sharetype && strcmp(sharetype, "IPC") == 0) { + type = NTVFS_IPC; + type_str = "IPC"; + } else if (sharetype && strcmp(sharetype, "PRINTER") == 0) { + type = NTVFS_PRINT; + type_str = "LPT:"; + } else { + type = NTVFS_DISK; + type_str = "A:"; + } + TALLOC_FREE(sharetype); + + if (strcmp(dev, "?????") != 0 && strcasecmp(type_str, dev) != 0) { + /* the client gave us the wrong device type */ + return NT_STATUS_BAD_DEVICE_TYPE; + } + + return make_connection_scfg(req, scfg, type, password, dev); +} + +/* + backend for tree connect call, in preparation for calling ntvfs_connect() +*/ +NTSTATUS smbsrv_tcon_backend(struct smbsrv_request *req, union smb_tcon *con) +{ + NTSTATUS status; + + if (con->generic.level == RAW_TCON_TCON) { + DATA_BLOB password; + password = data_blob_string_const(con->tcon.in.password); + + status = make_connection(req, con->tcon.in.service, password, con->tcon.in.dev); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + con->tcon.out.max_xmit = req->smb_conn->negotiate.max_recv; + con->tcon.out.tid = req->tcon->tid; + + return status; + } + + /* TODO: take a look at tconx.in.flags! */ + + status = make_connection(req, con->tconx.in.path, con->tconx.in.password, + con->tconx.in.device); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + con->tconx.out.tid = req->tcon->tid; + con->tconx.out.options = SMB_SUPPORT_SEARCH_BITS | (share_int_option(req->tcon->ntvfs->config, SHARE_CSC_POLICY, SHARE_CSC_POLICY_DEFAULT) << 2); + if (share_bool_option(req->tcon->ntvfs->config, SHARE_MSDFS_ROOT, SHARE_MSDFS_ROOT_DEFAULT) && lpcfg_host_msdfs(req->smb_conn->lp_ctx)) { + con->tconx.out.options |= SMB_SHARE_IN_DFS; + } + + return status; +} |