diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:47:29 +0000 |
commit | 4f5791ebd03eaec1c7da0865a383175b05102712 (patch) | |
tree | 8ce7b00f7a76baa386372422adebbe64510812d4 /source3/smbd/smb1_service.c | |
parent | Initial commit. (diff) | |
download | samba-upstream.tar.xz samba-upstream.zip |
Adding upstream version 2:4.17.12+dfsg.upstream/2%4.17.12+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'source3/smbd/smb1_service.c')
-rw-r--r-- | source3/smbd/smb1_service.c | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/source3/smbd/smb1_service.c b/source3/smbd/smb1_service.c new file mode 100644 index 0000000..df26b9f --- /dev/null +++ b/source3/smbd/smb1_service.c @@ -0,0 +1,241 @@ +/* + Unix SMB/CIFS implementation. + service (connection) opening and closing + Copyright (C) Andrew Tridgell 1992-1998 + + 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 "system/filesys.h" +#include "system/passwd.h" /* uid_wrapper */ +#include "../lib/tsocket/tsocket.h" +#include "smbd/smbd.h" +#include "smbd/globals.h" +#include "../librpc/gen_ndr/netlogon.h" +#include "../libcli/security/security.h" +#include "printing/pcap.h" +#include "passdb/lookup_sid.h" +#include "auth.h" +#include "../auth/auth_util.h" +#include "lib/param/loadparm.h" +#include "messages.h" +#include "lib/afs/afs_funcs.h" +#include "lib/util_path.h" +#include "lib/util/string_wrappers.h" +#include "source3/lib/substitute.h" + +/**************************************************************************** + Make a connection to a service from SMB1. Internal interface. +****************************************************************************/ + +static connection_struct *make_connection_smb1(struct smb_request *req, + NTTIME now, + int snum, + const char *pdev, + NTSTATUS *pstatus) +{ + const struct loadparm_substitution *lp_sub = + loadparm_s3_global_substitution(); + uint32_t session_global_id; + char *share_name = NULL; + struct smbXsrv_tcon *tcon; + NTSTATUS status; + struct connection_struct *conn; + + session_global_id = req->session->global->session_global_id; + share_name = lp_servicename(talloc_tos(), lp_sub, snum); + if (share_name == NULL) { + *pstatus = NT_STATUS_NO_MEMORY; + return NULL; + } + + if ((lp_max_connections(snum) > 0) + && (count_current_connections(lp_const_servicename(snum), true) >= + lp_max_connections(snum))) { + + DBG_WARNING("Max connections (%d) exceeded for [%s][%s]\n", + lp_max_connections(snum), + lp_const_servicename(snum), share_name); + TALLOC_FREE(share_name); + *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES; + return NULL; + } + + status = smb1srv_tcon_create(req->xconn, + session_global_id, + share_name, + now, &tcon); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("make_connection_smb1: Couldn't find free tcon for [%s] - %s\n", + share_name, nt_errstr(status))); + TALLOC_FREE(share_name); + *pstatus = status; + return NULL; + } + TALLOC_FREE(share_name); + + conn = conn_new(req->sconn); + if (!conn) { + TALLOC_FREE(tcon); + + DEBUG(0,("make_connection_smb1: Couldn't find free connection.\n")); + *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES; + return NULL; + } + + conn->cnum = tcon->global->tcon_wire_id; + conn->tcon = tcon; + + *pstatus = make_connection_snum(req->xconn, + conn, + snum, + req->session, + pdev); + if (!NT_STATUS_IS_OK(*pstatus)) { + conn_free(conn); + TALLOC_FREE(tcon); + return NULL; + } + + tcon->compat = talloc_move(tcon, &conn); + tcon->status = NT_STATUS_OK; + + *pstatus = NT_STATUS_OK; + + return tcon->compat; +} + +/**************************************************************************** + Make a connection to a service. External SMB1 interface. + * + * @param service +****************************************************************************/ + +connection_struct *make_connection(struct smb_request *req, + NTTIME now, + const char *service_in, + const char *pdev, uint64_t vuid, + NTSTATUS *status) +{ + struct smbd_server_connection *sconn = req->sconn; + struct smbXsrv_session *session = req->session; + const struct loadparm_substitution *lp_sub = + loadparm_s3_global_substitution(); + uid_t euid; + char *service = NULL; + fstring dev; + int snum = -1; + + fstrcpy(dev, pdev); + + /* This must ONLY BE CALLED AS ROOT. As it exits this function as + * root. */ + if (!non_root_mode() && (euid = geteuid()) != 0) { + DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot " + "(%u)\n", (unsigned int)euid )); + smb_panic("make_connection: PANIC ERROR. Called as nonroot\n"); + } + + if (conn_num_open(sconn) > 2047) { + *status = NT_STATUS_INSUFF_SERVER_RESOURCES; + return NULL; + } + + if (session == NULL) { + DEBUG(1,("make_connection: refusing to connect with " + "no session setup\n")); + *status = NT_STATUS_ACCESS_DENIED; + return NULL; + } + + /* Logic to try and connect to the correct [homes] share, preferably + without too many getpwnam() lookups. This is particulary nasty for + winbind usernames, where the share name isn't the same as unix + username. + */ + + if (strequal(service_in,HOMES_NAME)) { + if (session->homes_snum == -1) { + DEBUG(2, ("[homes] share not available for " + "this user because it was not found " + "or created at session setup " + "time\n")); + *status = NT_STATUS_BAD_NETWORK_NAME; + return NULL; + } + DEBUG(5, ("making a connection to [homes] service " + "created at session setup time\n")); + return make_connection_smb1(req, now, + session->homes_snum, + dev, status); + } else if ((session->homes_snum != -1) + && strequal(service_in, + lp_const_servicename(session->homes_snum))) { + DEBUG(5, ("making a connection to 'homes' service [%s] " + "created at session setup time\n", service_in)); + return make_connection_smb1(req, now, + session->homes_snum, + dev, status); + } + + service = talloc_strdup(talloc_tos(), service_in); + if (!service) { + *status = NT_STATUS_NO_MEMORY; + return NULL; + } + + if (!strlower_m(service)) { + DEBUG(2, ("strlower_m %s failed\n", service)); + *status = NT_STATUS_INVALID_PARAMETER; + return NULL; + } + + snum = find_service(talloc_tos(), service, &service); + if (!service) { + *status = NT_STATUS_NO_MEMORY; + return NULL; + } + + if (snum < 0) { + if (strequal(service,"IPC$") || + (lp_enable_asu_support() && strequal(service,"ADMIN$"))) { + DEBUG(3,("refusing IPC connection to %s\n", service)); + *status = NT_STATUS_ACCESS_DENIED; + return NULL; + } + + DEBUG(3,("%s (%s) couldn't find service %s\n", + get_remote_machine_name(), + tsocket_address_string( + sconn->remote_address, talloc_tos()), + service)); + *status = NT_STATUS_BAD_NETWORK_NAME; + return NULL; + } + + /* Handle non-Dfs clients attempting connections to msdfs proxy */ + if (lp_host_msdfs() && (*lp_msdfs_proxy(talloc_tos(), lp_sub, snum) != '\0')) { + DEBUG(3, ("refusing connection to dfs proxy share '%s' " + "(pointing to %s)\n", + service, lp_msdfs_proxy(talloc_tos(), lp_sub, snum))); + *status = NT_STATUS_BAD_NETWORK_NAME; + return NULL; + } + + DEBUG(5, ("making a connection to 'normal' service %s\n", service)); + + return make_connection_smb1(req, now, snum, + dev, status); +} |