2 Unix SMB/CIFS implementation.
3 service (connection) opening and closing
4 Copyright (C) Andrew Tridgell 1992-1998
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.
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.
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/>.
21 #include "system/filesys.h"
22 #include "system/passwd.h" /* uid_wrapper */
23 #include "../lib/tsocket/tsocket.h"
24 #include "smbd/smbd.h"
25 #include "smbd/globals.h"
26 #include "../librpc/gen_ndr/netlogon.h"
27 #include "../libcli/security/security.h"
28 #include "printing/pcap.h"
29 #include "passdb/lookup_sid.h"
31 #include "lib/param/loadparm.h"
33 #include "lib/afs/afs_funcs.h"
34 #include "lib/util_path.h"
36 static bool canonicalize_connect_path(connection_struct *conn)
39 char *resolved_name = SMB_VFS_REALPATH(conn,conn->connectpath);
43 ret = set_conn_connectpath(conn,resolved_name);
44 SAFE_FREE(resolved_name);
48 /****************************************************************************
49 Ensure when setting connectpath it is a canonicalized (no ./ // or ../)
50 absolute path stating in / and not ending in /.
51 ****************************************************************************/
53 bool set_conn_connectpath(connection_struct *conn, const char *connectpath)
57 if (connectpath == NULL || connectpath[0] == '\0') {
61 destname = canonicalize_absolute_path(conn, connectpath);
62 if (destname == NULL) {
66 DEBUG(10,("set_conn_connectpath: service %s, connectpath = %s\n",
67 lp_servicename(talloc_tos(), SNUM(conn)), destname ));
69 talloc_free(conn->connectpath);
70 conn->connectpath = destname;
72 * Ensure conn->cwd_fname is initialized.
73 * start as conn->connectpath.
75 TALLOC_FREE(conn->cwd_fname);
76 conn->cwd_fname = synthetic_smb_fname(conn,
81 if (conn->cwd_fname == NULL) {
87 /****************************************************************************
88 Load parameters specific to a connection/service.
89 ****************************************************************************/
91 bool set_current_service(connection_struct *conn, uint16_t flags, bool do_chdir)
94 enum remote_arch_types ra_type;
101 conn->lastused_count++;
106 struct smb_filename connectpath_fname = {
107 .base_name = conn->connectpath
109 struct smb_filename origpath_fname = {
110 .base_name = conn->origpath
114 vfs_ChDir(conn, &connectpath_fname) != 0 &&
115 vfs_ChDir(conn, &origpath_fname) != 0) {
116 DEBUG(((errno!=EACCES)?0:3),
117 ("chdir (%s) failed, reason: %s\n",
118 conn->connectpath, strerror(errno)));
123 if ((conn == last_conn) && (last_flags == flags)) {
131 * Obey the client case sensitivity requests - only for clients that
133 switch (lp_case_sensitive(snum)) {
136 * We need this uglyness due to DOS/Win9x clients that lie
137 * about case insensitivity. */
138 ra_type = get_remote_arch();
139 if (conn->sconn->using_smb2) {
140 conn->case_sensitive = false;
141 } else if ((ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
143 * Client can't support per-packet case sensitive
145 conn->case_sensitive = false;
147 conn->case_sensitive =
148 !(flags & FLAG_CASELESS_PATHNAMES);
152 conn->case_sensitive = true;
155 conn->case_sensitive = false;
161 /****************************************************************************
162 do some basic sainity checks on the share.
163 This function modifies dev, ecode.
164 ****************************************************************************/
166 static NTSTATUS share_sanity_checks(const struct tsocket_address *remote_address,
173 raddr = tsocket_address_inet_addr_string(remote_address,
176 return NT_STATUS_NO_MEMORY;
179 if (!lp_snum_ok(snum) ||
180 !allow_access(lp_hosts_deny(snum), lp_hosts_allow(snum),
182 return NT_STATUS_ACCESS_DENIED;
185 if (dev[0] == '?' || !dev[0]) {
186 if (lp_printable(snum)) {
187 fstrcpy(dev,"LPT1:");
188 } else if (strequal(lp_fstype(snum), "IPC")) {
195 if (!strupper_m(dev)) {
196 DEBUG(2,("strupper_m %s failed\n", dev));
197 return NT_STATUS_INVALID_PARAMETER;
200 if (lp_printable(snum)) {
201 if (!strequal(dev, "LPT1:")) {
202 return NT_STATUS_BAD_DEVICE_TYPE;
204 } else if (strequal(lp_fstype(snum), "IPC")) {
205 if (!strequal(dev, "IPC")) {
206 return NT_STATUS_BAD_DEVICE_TYPE;
208 } else if (!strequal(dev, "A:")) {
209 return NT_STATUS_BAD_DEVICE_TYPE;
212 /* Behave as a printer if we are supposed to */
213 if (lp_printable(snum) && (strcmp(dev, "A:") == 0)) {
214 fstrcpy(dev, "LPT1:");
221 * Go through lookup_name etc to find the force'd group.
223 * Create a new token from src_token, replacing the primary group sid with the
227 static NTSTATUS find_forced_group(bool force_user,
228 int snum, const char *username,
229 struct dom_sid *pgroup_sid,
232 NTSTATUS result = NT_STATUS_NO_SUCH_GROUP;
233 TALLOC_CTX *frame = talloc_stackframe();
234 struct dom_sid group_sid;
235 enum lsa_SidType type;
237 bool user_must_be_member = False;
240 groupname = lp_force_group(talloc_tos(), snum);
241 if (groupname == NULL) {
242 DEBUG(1, ("talloc_strdup failed\n"));
243 result = NT_STATUS_NO_MEMORY;
247 if (groupname[0] == '+') {
248 user_must_be_member = True;
252 groupname = talloc_string_sub(talloc_tos(), groupname,
253 "%S", lp_servicename(talloc_tos(), snum));
254 if (groupname == NULL) {
255 DEBUG(1, ("talloc_string_sub failed\n"));
256 result = NT_STATUS_NO_MEMORY;
260 if (!lookup_name_smbconf(talloc_tos(), groupname,
261 LOOKUP_NAME_ALL|LOOKUP_NAME_GROUP,
262 NULL, NULL, &group_sid, &type)) {
263 DEBUG(10, ("lookup_name_smbconf(%s) failed\n",
268 if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
269 (type != SID_NAME_WKN_GRP)) {
270 DEBUG(10, ("%s is a %s, not a group\n", groupname,
271 sid_type_lookup(type)));
275 if (!sid_to_gid(&group_sid, &gid)) {
276 DEBUG(10, ("sid_to_gid(%s) for %s failed\n",
277 sid_string_dbg(&group_sid), groupname));
282 * If the user has been forced and the forced group starts with a '+',
283 * then we only set the group to be the forced group if the forced
284 * user is a member of that group. Otherwise, the meaning of the '+'
288 if (force_user && user_must_be_member) {
289 if (user_in_group_sid(username, &group_sid)) {
290 sid_copy(pgroup_sid, &group_sid);
292 DEBUG(3,("Forced group %s for member %s\n",
293 groupname, username));
295 DEBUG(0,("find_forced_group: forced user %s is not a member "
296 "of forced group %s. Disallowing access.\n",
297 username, groupname ));
298 result = NT_STATUS_MEMBER_NOT_IN_GROUP;
302 sid_copy(pgroup_sid, &group_sid);
304 DEBUG(3,("Forced group %s\n", groupname));
307 result = NT_STATUS_OK;
313 /****************************************************************************
314 Create an auth_session_info structure for a connection_struct
315 ****************************************************************************/
317 static NTSTATUS create_connection_session_info(struct smbd_server_connection *sconn,
318 TALLOC_CTX *mem_ctx, int snum,
319 struct auth_session_info *session_info,
320 struct auth_session_info **presult)
322 struct auth_session_info *result;
324 if (lp_guest_only(snum)) {
325 return make_session_info_guest(mem_ctx, presult);
329 * This is the normal security != share case where we have a
330 * valid vuid from the session setup. */
332 if (security_session_user_level(session_info, NULL) < SECURITY_USER) {
333 if (!lp_guest_ok(snum)) {
334 DEBUG(2, ("guest user (from session setup) "
335 "not permitted to access this share "
336 "(%s)\n", lp_servicename(talloc_tos(), snum)));
337 return NT_STATUS_ACCESS_DENIED;
340 if (!user_ok_token(session_info->unix_info->unix_name,
341 session_info->info->domain_name,
342 session_info->security_token, snum)) {
343 DEBUG(2, ("user '%s' (from session setup) not "
344 "permitted to access this share "
346 session_info->unix_info->unix_name,
347 lp_servicename(talloc_tos(), snum)));
348 return NT_STATUS_ACCESS_DENIED;
352 result = copy_session_info(mem_ctx, session_info);
353 if (result == NULL) {
354 return NT_STATUS_NO_MEMORY;
361 /****************************************************************************
362 Set relevant user and group settings corresponding to force user/group
363 configuration for the given snum.
364 ****************************************************************************/
366 NTSTATUS set_conn_force_user_group(connection_struct *conn, int snum)
370 if (*lp_force_user(talloc_tos(), snum)) {
373 * Replace conn->session_info with a completely faked up one
374 * from the username we are forced into :-)
378 char *sanitized_username;
379 struct auth_session_info *forced_serverinfo;
382 fuser = talloc_string_sub(conn, lp_force_user(talloc_tos(), snum), "%S",
383 lp_const_servicename(snum));
385 return NT_STATUS_NO_MEMORY;
388 guest = security_session_user_level(conn->session_info, NULL) < SECURITY_USER;
390 status = make_session_info_from_username(
394 if (!NT_STATUS_IS_OK(status)) {
398 /* We don't want to replace the original sanitized_username
399 as it is the original user given in the connect attempt.
400 This is used in '%U' substitutions. */
401 sanitized_username = discard_const_p(char,
402 forced_serverinfo->unix_info->sanitized_username);
403 TALLOC_FREE(sanitized_username);
404 forced_serverinfo->unix_info->sanitized_username =
405 talloc_move(forced_serverinfo->unix_info,
406 &conn->session_info->unix_info->sanitized_username);
408 TALLOC_FREE(conn->session_info);
409 conn->session_info = forced_serverinfo;
411 conn->force_user = true;
412 DEBUG(3,("Forced user %s\n", fuser));
416 * If force group is true, then override
417 * any groupid stored for the connecting user.
420 if (*lp_force_group(talloc_tos(), snum)) {
422 status = find_forced_group(
423 conn->force_user, snum, conn->session_info->unix_info->unix_name,
424 &conn->session_info->security_token->sids[1],
425 &conn->session_info->unix_token->gid);
427 if (!NT_STATUS_IS_OK(status)) {
432 * We need to cache this gid, to use within
433 * change_to_user() separately from the conn->session_info
434 * struct. We only use conn->session_info directly if
435 * "force_user" was set.
437 conn->force_group_gid = conn->session_info->unix_token->gid;
443 static NTSTATUS notify_init_sconn(struct smbd_server_connection *sconn)
447 if (sconn->notify_ctx != NULL) {
451 sconn->notify_ctx = notify_init(sconn, sconn->msg_ctx, sconn->ev_ctx,
452 sconn, notify_callback);
453 if (sconn->notify_ctx == NULL) {
454 return NT_STATUS_NO_MEMORY;
457 status = messaging_register(sconn->msg_ctx, sconn,
458 MSG_SMB_NOTIFY_CANCEL_DELETED,
459 smbd_notify_cancel_deleted);
460 if (!NT_STATUS_IS_OK(status)) {
461 DBG_DEBUG("messaging_register failed: %s\n",
463 TALLOC_FREE(sconn->notify_ctx);
467 status = messaging_register(sconn->msg_ctx, sconn,
468 MSG_SMB_NOTIFY_STARTED,
469 smbd_notifyd_restarted);
470 if (!NT_STATUS_IS_OK(status)) {
471 DBG_DEBUG("messaging_register failed: %s\n",
473 messaging_deregister(sconn->msg_ctx,
474 MSG_SMB_NOTIFY_CANCEL_DELETED, sconn);
475 TALLOC_FREE(sconn->notify_ctx);
482 /****************************************************************************
483 Make a connection, given the snum to connect to, and the vuser of the
484 connecting user if appropriate.
485 ****************************************************************************/
487 static NTSTATUS make_connection_snum(struct smbXsrv_connection *xconn,
488 connection_struct *conn,
489 int snum, struct user_struct *vuser,
492 struct smbd_server_connection *sconn = xconn->client->sconn;
493 struct smb_filename *smb_fname_cpath = NULL;
496 bool on_err_call_dis_hook = false;
503 status = share_sanity_checks(sconn->remote_address,
504 sconn->remote_hostname,
507 if (NT_STATUS_IS_ERR(status)) {
511 conn->params->service = snum;
513 status = create_connection_session_info(sconn,
514 conn, snum, vuser->session_info,
515 &conn->session_info);
517 if (!NT_STATUS_IS_OK(status)) {
518 DEBUG(1, ("create_connection_session_info failed: %s\n",
523 if (lp_guest_only(snum)) {
524 conn->force_user = true;
527 conn->num_files_open = 0;
528 conn->lastused = conn->lastused_count = time(NULL);
529 conn->printer = (strncmp(dev,"LPT",3) == 0);
530 conn->ipc = ( (strncmp(dev,"IPC",3) == 0) ||
531 ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) );
533 /* Case options for the share. */
534 if (lp_case_sensitive(snum) == Auto) {
535 /* We will be setting this per packet. Set to be case
536 * insensitive for now. */
537 conn->case_sensitive = False;
539 conn->case_sensitive = (bool)lp_case_sensitive(snum);
542 conn->case_preserve = lp_preserve_case(snum);
543 conn->short_case_preserve = lp_short_preserve_case(snum);
545 conn->encrypt_level = lp_smb_encrypt(snum);
546 if (conn->encrypt_level > SMB_SIGNING_OFF) {
547 if (lp_smb_encrypt(-1) == SMB_SIGNING_OFF) {
548 if (conn->encrypt_level == SMB_SIGNING_REQUIRED) {
549 DBG_ERR("Service [%s] requires encryption, but "
550 "it is disabled globally!\n",
551 lp_servicename(talloc_tos(), snum));
552 status = NT_STATUS_ACCESS_DENIED;
555 conn->encrypt_level = SMB_SIGNING_OFF;
559 conn->veto_list = NULL;
560 conn->hide_list = NULL;
561 conn->veto_oplock_list = NULL;
562 conn->aio_write_behind_list = NULL;
564 conn->read_only = lp_read_only(SNUM(conn));
566 status = set_conn_force_user_group(conn, snum);
567 if (!NT_STATUS_IS_OK(status)) {
571 conn->vuid = vuser->vuid;
574 char *s = talloc_sub_advanced(talloc_tos(),
575 lp_servicename(talloc_tos(), SNUM(conn)),
576 conn->session_info->unix_info->unix_name,
578 conn->session_info->unix_token->gid,
579 conn->session_info->unix_info->sanitized_username,
580 conn->session_info->info->domain_name,
581 lp_path(talloc_tos(), snum));
583 status = NT_STATUS_NO_MEMORY;
587 if (!set_conn_connectpath(conn,s)) {
589 status = NT_STATUS_NO_MEMORY;
592 DEBUG(3,("Connect path is '%s' for service [%s]\n",s,
593 lp_servicename(talloc_tos(), snum)));
598 * Set up the share security descriptor.
599 * NOTE - we use the *INCOMING USER* session_info
600 * here, as does (indirectly) change_to_user(),
601 * which can be called on any incoming packet.
602 * This way we set up the share access based
603 * on the authenticated user, not the forced
606 * https://bugzilla.samba.org/show_bug.cgi?id=9878
609 status = check_user_share_access(conn,
613 if (!NT_STATUS_IS_OK(status)) {
617 /* Initialise VFS function pointers */
619 if (!smbd_vfs_init(conn)) {
620 DEBUG(0, ("vfs_init failed for service %s\n",
621 lp_servicename(talloc_tos(), snum)));
622 status = NT_STATUS_BAD_NETWORK_NAME;
626 /* ROOT Activities: */
627 /* explicitly check widelinks here so that we can correctly warn
629 widelinks_warning(snum);
632 * Enforce the max connections parameter.
635 if ((lp_max_connections(snum) > 0)
636 && (count_current_connections(lp_servicename(talloc_tos(), SNUM(conn)), True) >=
637 lp_max_connections(snum))) {
639 DEBUG(1, ("Max connections (%d) exceeded for %s\n",
640 lp_max_connections(snum),
641 lp_servicename(talloc_tos(), snum)));
642 status = NT_STATUS_INSUFFICIENT_RESOURCES;
646 /* Invoke VFS make connection hook - this must be the first
647 filesystem operation that we do. */
649 if (SMB_VFS_CONNECT(conn, lp_servicename(talloc_tos(), snum),
650 conn->session_info->unix_info->unix_name) < 0) {
651 DBG_WARNING("SMB_VFS_CONNECT for service '%s' at '%s' failed: %s\n",
652 lp_servicename(talloc_tos(), snum), conn->connectpath,
654 status = NT_STATUS_UNSUCCESSFUL;
658 /* Any error exit after here needs to call the disconnect hook. */
659 on_err_call_dis_hook = true;
661 if ((!conn->printer) && (!conn->ipc) &&
662 lp_change_notify()) {
664 status = notify_init_sconn(sconn);
665 if (!NT_STATUS_IS_OK(status)) {
670 if (lp_kernel_oplocks(snum)) {
671 init_kernel_oplocks(conn->sconn);
675 * Fix compatibility issue pointed out by Volker.
676 * We pass the conn->connectpath to the preexec
677 * scripts as a parameter, so attempt to canonicalize
678 * it here before calling the preexec scripts.
679 * We ignore errors here, as it is possible that
680 * the conn->connectpath doesn't exist yet and
681 * the preexec scripts will create them.
684 (void)canonicalize_connect_path(conn);
686 /* Preexecs are done here as they might make the dir we are to ChDir
688 /* execute any "root preexec = " line */
689 if (*lp_root_preexec(talloc_tos(), snum)) {
690 char *cmd = talloc_sub_advanced(talloc_tos(),
691 lp_servicename(talloc_tos(), SNUM(conn)),
692 conn->session_info->unix_info->unix_name,
694 conn->session_info->unix_token->gid,
695 conn->session_info->unix_info->sanitized_username,
696 conn->session_info->info->domain_name,
697 lp_root_preexec(talloc_tos(), snum));
698 DEBUG(5,("cmd=%s\n",cmd));
699 ret = smbrun(cmd, NULL, NULL);
701 if (ret != 0 && lp_root_preexec_close(snum)) {
702 DEBUG(1,("root preexec gave %d - failing "
703 "connection\n", ret));
704 status = NT_STATUS_ACCESS_DENIED;
709 /* USER Activites: */
710 if (!change_to_user(conn, conn->vuid)) {
711 /* No point continuing if they fail the basic checks */
712 DEBUG(0,("Can't become connected user!\n"));
713 status = NT_STATUS_LOGON_FAILURE;
720 /* Remember that a different vuid can connect later without these
723 /* Preexecs are done here as they might make the dir we are to ChDir
726 /* execute any "preexec = " line */
727 if (*lp_preexec(talloc_tos(), snum)) {
728 char *cmd = talloc_sub_advanced(talloc_tos(),
729 lp_servicename(talloc_tos(), SNUM(conn)),
730 conn->session_info->unix_info->unix_name,
732 conn->session_info->unix_token->gid,
733 conn->session_info->unix_info->sanitized_username,
734 conn->session_info->info->domain_name,
735 lp_preexec(talloc_tos(), snum));
736 ret = smbrun(cmd, NULL, NULL);
738 if (ret != 0 && lp_preexec_close(snum)) {
739 DEBUG(1,("preexec gave %d - failing connection\n",
741 status = NT_STATUS_ACCESS_DENIED;
746 #ifdef WITH_FAKE_KASERVER
747 if (lp_afs_share(snum)) {
753 * we've finished with the user stuff - go back to root
754 * so the SMB_VFS_STAT call will only fail on path errors,
755 * not permission problems.
757 change_to_root_user();
758 /* ROOT Activites: */
761 * If widelinks are disallowed we need to canonicalise the connect
762 * path here to ensure we don't have any symlinks in the
763 * connectpath. We will be checking all paths on this connection are
764 * below this directory. We must do this after the VFS init as we
765 * depend on the realpath() pointer in the vfs table. JRA.
767 if (!lp_widelinks(snum)) {
768 if (!canonicalize_connect_path(conn)) {
769 DEBUG(0, ("canonicalize_connect_path failed "
770 "for service %s, path %s\n",
771 lp_servicename(talloc_tos(), snum),
773 status = NT_STATUS_BAD_NETWORK_NAME;
778 /* Add veto/hide lists */
779 if (!IS_IPC(conn) && !IS_PRINT(conn)) {
780 set_namearray( &conn->veto_list,
781 lp_veto_files(talloc_tos(), snum));
782 set_namearray( &conn->hide_list,
783 lp_hide_files(talloc_tos(), snum));
784 set_namearray( &conn->veto_oplock_list,
785 lp_veto_oplock_files(talloc_tos(), snum));
786 set_namearray( &conn->aio_write_behind_list,
787 lp_aio_write_behind(talloc_tos(), snum));
789 smb_fname_cpath = synthetic_smb_fname(talloc_tos(),
794 if (smb_fname_cpath == NULL) {
795 status = NT_STATUS_NO_MEMORY;
799 /* win2000 does not check the permissions on the directory
800 during the tree connect, instead relying on permission
801 check during individual operations. To match this behaviour
802 I have disabled this chdir check (tridge) */
803 /* the alternative is just to check the directory exists */
805 if ((ret = SMB_VFS_STAT(conn, smb_fname_cpath)) != 0 ||
806 !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
807 if (ret == 0 && !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
808 DEBUG(0,("'%s' is not a directory, when connecting to "
809 "[%s]\n", conn->connectpath,
810 lp_servicename(talloc_tos(), snum)));
812 DEBUG(0,("'%s' does not exist or permission denied "
813 "when connecting to [%s] Error was %s\n",
815 lp_servicename(talloc_tos(), snum),
818 status = NT_STATUS_BAD_NETWORK_NAME;
821 conn->base_share_dev = smb_fname_cpath->st.st_ex_dev;
823 talloc_free(conn->origpath);
824 conn->origpath = talloc_strdup(conn, conn->connectpath);
826 /* Figure out the characteristics of the underlying filesystem. This
827 * assumes that all the filesystem mounted withing a share path have
828 * the same characteristics, which is likely but not guaranteed.
831 conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
834 * Print out the 'connected as' stuff here as we need
835 * to know the effective uid and gid we will be using
836 * (at least initially).
839 if( DEBUGLVL( IS_IPC(conn) ? 3 : 2 ) ) {
840 dbgtext( "%s (%s) ", get_remote_machine_name(),
841 tsocket_address_string(conn->sconn->remote_address,
843 dbgtext( "%s", srv_is_signing_active(xconn) ? "signed " : "");
844 dbgtext( "connect to service %s ",
845 lp_servicename(talloc_tos(), snum) );
846 dbgtext( "initially as user %s ",
847 conn->session_info->unix_info->unix_name );
848 dbgtext( "(uid=%d, gid=%d) ", (int)effuid, (int)effgid );
849 dbgtext( "(pid %d)\n", (int)getpid() );
856 TALLOC_FREE(smb_fname_cpath);
857 /* We must exit this function as root. */
858 if (geteuid() != 0) {
859 change_to_root_user();
861 if (on_err_call_dis_hook) {
862 /* Call VFS disconnect hook */
863 SMB_VFS_DISCONNECT(conn);
868 /****************************************************************************
869 Make a connection to a service from SMB1. Internal interface.
870 ****************************************************************************/
872 static connection_struct *make_connection_smb1(struct smb_request *req,
874 int snum, struct user_struct *vuser,
878 struct smbXsrv_tcon *tcon;
880 struct connection_struct *conn;
882 status = smb1srv_tcon_create(req->xconn, now, &tcon);
883 if (!NT_STATUS_IS_OK(status)) {
884 DEBUG(0,("make_connection_smb1: Couldn't find free tcon %s.\n",
890 conn = conn_new(req->sconn);
894 DEBUG(0,("make_connection_smb1: Couldn't find free connection.\n"));
895 *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
899 conn->cnum = tcon->global->tcon_wire_id;
902 *pstatus = make_connection_snum(req->xconn,
907 if (!NT_STATUS_IS_OK(*pstatus)) {
913 tcon->global->share_name = lp_servicename(tcon->global, SNUM(conn));
914 if (tcon->global->share_name == NULL) {
917 *pstatus = NT_STATUS_NO_MEMORY;
920 tcon->global->session_global_id =
921 vuser->session->global->session_global_id;
923 tcon->compat = talloc_move(tcon, &conn);
924 tcon->status = NT_STATUS_OK;
926 *pstatus = smbXsrv_tcon_update(tcon);
927 if (!NT_STATUS_IS_OK(*pstatus)) {
935 /****************************************************************************
936 Make a connection to a service from SMB2. External SMB2 interface.
937 We must set cnum before claiming connection.
938 ****************************************************************************/
940 connection_struct *make_connection_smb2(struct smbd_smb2_request *req,
941 struct smbXsrv_tcon *tcon,
943 struct user_struct *vuser,
947 struct smbd_server_connection *sconn = req->sconn;
948 connection_struct *conn = conn_new(sconn);
950 DEBUG(0,("make_connection_smb2: Couldn't find free connection.\n"));
951 *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
955 conn->cnum = tcon->global->tcon_wire_id;
958 *pstatus = make_connection_snum(req->xconn,
963 if (!NT_STATUS_IS_OK(*pstatus)) {
970 /****************************************************************************
971 Make a connection to a service. External SMB1 interface.
974 ****************************************************************************/
976 connection_struct *make_connection(struct smb_request *req,
978 const char *service_in,
979 const char *pdev, uint64_t vuid,
982 struct smbd_server_connection *sconn = req->sconn;
984 struct user_struct *vuser = NULL;
985 char *service = NULL;
991 /* This must ONLY BE CALLED AS ROOT. As it exits this function as
993 if (!non_root_mode() && (euid = geteuid()) != 0) {
994 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot "
995 "(%u)\n", (unsigned int)euid ));
996 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
999 if (conn_num_open(sconn) > 2047) {
1000 *status = NT_STATUS_INSUFF_SERVER_RESOURCES;
1004 vuser = get_valid_user_struct(sconn, vuid);
1006 DEBUG(1,("make_connection: refusing to connect with "
1007 "no session setup\n"));
1008 *status = NT_STATUS_ACCESS_DENIED;
1012 /* Logic to try and connect to the correct [homes] share, preferably
1013 without too many getpwnam() lookups. This is particulary nasty for
1014 winbind usernames, where the share name isn't the same as unix
1017 The snum of the homes share is stored on the vuser at session setup
1021 if (strequal(service_in,HOMES_NAME)) {
1022 if (vuser->homes_snum == -1) {
1023 DEBUG(2, ("[homes] share not available for "
1024 "this user because it was not found "
1025 "or created at session setup "
1027 *status = NT_STATUS_BAD_NETWORK_NAME;
1030 DEBUG(5, ("making a connection to [homes] service "
1031 "created at session setup time\n"));
1032 return make_connection_smb1(req, now,
1036 } else if ((vuser->homes_snum != -1)
1037 && strequal(service_in,
1038 lp_servicename(talloc_tos(), vuser->homes_snum))) {
1039 DEBUG(5, ("making a connection to 'homes' service [%s] "
1040 "created at session setup time\n", service_in));
1041 return make_connection_smb1(req, now,
1047 service = talloc_strdup(talloc_tos(), service_in);
1049 *status = NT_STATUS_NO_MEMORY;
1053 if (!strlower_m(service)) {
1054 DEBUG(2, ("strlower_m %s failed\n", service));
1055 *status = NT_STATUS_INVALID_PARAMETER;
1059 snum = find_service(talloc_tos(), service, &service);
1061 *status = NT_STATUS_NO_MEMORY;
1066 if (strequal(service,"IPC$") ||
1067 (lp_enable_asu_support() && strequal(service,"ADMIN$"))) {
1068 DEBUG(3,("refusing IPC connection to %s\n", service));
1069 *status = NT_STATUS_ACCESS_DENIED;
1073 DEBUG(3,("%s (%s) couldn't find service %s\n",
1074 get_remote_machine_name(),
1075 tsocket_address_string(
1076 sconn->remote_address, talloc_tos()),
1078 *status = NT_STATUS_BAD_NETWORK_NAME;
1082 /* Handle non-Dfs clients attempting connections to msdfs proxy */
1083 if (lp_host_msdfs() && (*lp_msdfs_proxy(talloc_tos(), snum) != '\0')) {
1084 DEBUG(3, ("refusing connection to dfs proxy share '%s' "
1085 "(pointing to %s)\n",
1086 service, lp_msdfs_proxy(talloc_tos(), snum)));
1087 *status = NT_STATUS_BAD_NETWORK_NAME;
1091 DEBUG(5, ("making a connection to 'normal' service %s\n", service));
1093 return make_connection_smb1(req, now, snum, vuser,
1097 /****************************************************************************
1099 ****************************************************************************/
1101 void close_cnum(connection_struct *conn, uint64_t vuid)
1103 char rootpath[2] = { '/', '\0'};
1104 struct smb_filename root_fname = { .base_name = rootpath };
1106 file_close_conn(conn);
1108 if (!IS_IPC(conn)) {
1109 dptr_closecnum(conn);
1112 change_to_root_user();
1114 DEBUG(IS_IPC(conn)?3:2, ("%s (%s) closed connection to service %s\n",
1115 get_remote_machine_name(),
1116 tsocket_address_string(conn->sconn->remote_address,
1118 lp_servicename(talloc_tos(), SNUM(conn))));
1120 /* make sure we leave the directory available for unmount */
1121 vfs_ChDir(conn, &root_fname);
1123 /* Call VFS disconnect hook */
1124 SMB_VFS_DISCONNECT(conn);
1126 /* execute any "postexec = " line */
1127 if (*lp_postexec(talloc_tos(), SNUM(conn)) &&
1128 change_to_user(conn, vuid)) {
1129 char *cmd = talloc_sub_advanced(talloc_tos(),
1130 lp_servicename(talloc_tos(), SNUM(conn)),
1131 conn->session_info->unix_info->unix_name,
1133 conn->session_info->unix_token->gid,
1134 conn->session_info->unix_info->sanitized_username,
1135 conn->session_info->info->domain_name,
1136 lp_postexec(talloc_tos(), SNUM(conn)));
1137 smbrun(cmd, NULL, NULL);
1139 change_to_root_user();
1142 change_to_root_user();
1143 /* execute any "root postexec = " line */
1144 if (*lp_root_postexec(talloc_tos(), SNUM(conn))) {
1145 char *cmd = talloc_sub_advanced(talloc_tos(),
1146 lp_servicename(talloc_tos(), SNUM(conn)),
1147 conn->session_info->unix_info->unix_name,
1149 conn->session_info->unix_token->gid,
1150 conn->session_info->unix_info->sanitized_username,
1151 conn->session_info->info->domain_name,
1152 lp_root_postexec(talloc_tos(), SNUM(conn)));
1153 smbrun(cmd, NULL, NULL);