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 struct smb_filename con_fname = { .base_name = conn->connectpath };
40 struct smb_filename *resolved_fname = SMB_VFS_REALPATH(conn, talloc_tos(),
42 if (resolved_fname == NULL) {
45 ret = set_conn_connectpath(conn,resolved_fname->base_name);
46 TALLOC_FREE(resolved_fname);
50 /****************************************************************************
51 Ensure when setting connectpath it is a canonicalized (no ./ // or ../)
52 absolute path stating in / and not ending in /.
53 ****************************************************************************/
55 bool set_conn_connectpath(connection_struct *conn, const char *connectpath)
59 if (connectpath == NULL || connectpath[0] == '\0') {
63 destname = canonicalize_absolute_path(conn, connectpath);
64 if (destname == NULL) {
68 DBG_DEBUG("service %s, connectpath = %s\n",
69 lp_const_servicename(SNUM(conn)), destname);
71 talloc_free(conn->connectpath);
72 conn->connectpath = destname;
74 * Ensure conn->cwd_fname is initialized.
75 * start as conn->connectpath.
77 TALLOC_FREE(conn->cwd_fname);
78 conn->cwd_fname = synthetic_smb_fname(conn,
83 if (conn->cwd_fname == NULL) {
89 /****************************************************************************
90 Load parameters specific to a connection/service.
91 ****************************************************************************/
93 void set_current_case_sensitive(connection_struct *conn, uint16_t flags)
96 enum remote_arch_types ra_type;
98 SMB_ASSERT(conn != NULL);
102 if ((conn == last_conn) && (last_flags == flags)) {
110 * Obey the client case sensitivity requests - only for clients that
112 switch (lp_case_sensitive(snum)) {
115 * We need this uglyness due to DOS/Win9x clients that lie
116 * about case insensitivity. */
117 ra_type = get_remote_arch();
118 if (conn->sconn->using_smb2) {
119 conn->case_sensitive = false;
120 } else if ((ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
122 * Client can't support per-packet case sensitive
124 conn->case_sensitive = false;
126 conn->case_sensitive =
127 !(flags & FLAG_CASELESS_PATHNAMES);
131 conn->case_sensitive = true;
134 conn->case_sensitive = false;
140 bool chdir_current_service(connection_struct *conn)
142 const struct smb_filename connectpath_fname = {
143 .base_name = conn->connectpath,
145 const struct smb_filename origpath_fname = {
146 .base_name = conn->origpath,
150 conn->lastused_count++;
152 ret = vfs_ChDir(conn, &connectpath_fname);
154 DEBUG(((errno!=EACCES)?0:3),
155 ("chdir (%s) failed, reason: %s\n",
156 conn->connectpath, strerror(errno)));
160 ret = vfs_ChDir(conn, &origpath_fname);
162 DEBUG(((errno!=EACCES)?0:3),
163 ("chdir (%s) failed, reason: %s\n",
164 conn->origpath, strerror(errno)));
171 /****************************************************************************
172 do some basic sainity checks on the share.
173 This function modifies dev, ecode.
174 ****************************************************************************/
176 static NTSTATUS share_sanity_checks(const struct tsocket_address *remote_address,
183 raddr = tsocket_address_inet_addr_string(remote_address,
186 return NT_STATUS_NO_MEMORY;
189 if (!lp_snum_ok(snum) ||
190 !allow_access(lp_hosts_deny(snum), lp_hosts_allow(snum),
192 return NT_STATUS_ACCESS_DENIED;
195 if (dev[0] == '?' || !dev[0]) {
196 if (lp_printable(snum)) {
197 fstrcpy(dev,"LPT1:");
198 } else if (strequal(lp_fstype(snum), "IPC")) {
205 if (!strupper_m(dev)) {
206 DEBUG(2,("strupper_m %s failed\n", dev));
207 return NT_STATUS_INVALID_PARAMETER;
210 if (lp_printable(snum)) {
211 if (!strequal(dev, "LPT1:")) {
212 return NT_STATUS_BAD_DEVICE_TYPE;
214 } else if (strequal(lp_fstype(snum), "IPC")) {
215 if (!strequal(dev, "IPC")) {
216 return NT_STATUS_BAD_DEVICE_TYPE;
218 } else if (!strequal(dev, "A:")) {
219 return NT_STATUS_BAD_DEVICE_TYPE;
222 /* Behave as a printer if we are supposed to */
223 if (lp_printable(snum) && (strcmp(dev, "A:") == 0)) {
224 fstrcpy(dev, "LPT1:");
231 * Go through lookup_name etc to find the force'd group.
233 * Create a new token from src_token, replacing the primary group sid with the
237 static NTSTATUS find_forced_group(bool force_user,
238 int snum, const char *username,
239 struct dom_sid *pgroup_sid,
242 NTSTATUS result = NT_STATUS_NO_SUCH_GROUP;
243 TALLOC_CTX *frame = talloc_stackframe();
244 struct dom_sid group_sid;
245 enum lsa_SidType type;
246 const char *force_group;
248 bool user_must_be_member = False;
251 force_group = lp_force_group(snum);
252 if (force_group[0] == '+') {
253 user_must_be_member = true;
257 groupname = talloc_string_sub(talloc_tos(), force_group,
258 "%S", lp_const_servicename(snum));
259 if (groupname == NULL) {
260 DEBUG(1, ("talloc_string_sub failed\n"));
261 result = NT_STATUS_NO_MEMORY;
265 if (!lookup_name_smbconf(talloc_tos(), groupname,
266 LOOKUP_NAME_ALL|LOOKUP_NAME_GROUP,
267 NULL, NULL, &group_sid, &type)) {
268 DEBUG(10, ("lookup_name_smbconf(%s) failed\n",
273 if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
274 (type != SID_NAME_WKN_GRP)) {
275 DEBUG(10, ("%s is a %s, not a group\n", groupname,
276 sid_type_lookup(type)));
280 if (!sid_to_gid(&group_sid, &gid)) {
281 DEBUG(10, ("sid_to_gid(%s) for %s failed\n",
282 sid_string_dbg(&group_sid), groupname));
287 * If the user has been forced and the forced group starts with a '+',
288 * then we only set the group to be the forced group if the forced
289 * user is a member of that group. Otherwise, the meaning of the '+'
293 if (force_user && user_must_be_member) {
294 if (user_in_group_sid(username, &group_sid)) {
295 sid_copy(pgroup_sid, &group_sid);
297 DEBUG(3,("Forced group %s for member %s\n",
298 groupname, username));
300 DEBUG(0,("find_forced_group: forced user %s is not a member "
301 "of forced group %s. Disallowing access.\n",
302 username, groupname ));
303 result = NT_STATUS_MEMBER_NOT_IN_GROUP;
307 sid_copy(pgroup_sid, &group_sid);
309 DEBUG(3,("Forced group %s\n", groupname));
312 result = NT_STATUS_OK;
318 /****************************************************************************
319 Create an auth_session_info structure for a connection_struct
320 ****************************************************************************/
322 static NTSTATUS create_connection_session_info(struct smbd_server_connection *sconn,
323 TALLOC_CTX *mem_ctx, int snum,
324 struct auth_session_info *session_info,
325 struct auth_session_info **presult)
327 struct auth_session_info *result;
329 if (lp_guest_only(snum)) {
330 return make_session_info_guest(mem_ctx, presult);
334 * This is the normal security != share case where we have a
335 * valid vuid from the session setup. */
337 if (security_session_user_level(session_info, NULL) < SECURITY_USER) {
338 if (!lp_guest_ok(snum)) {
339 DBG_WARNING("guest user (from session setup) "
340 "not permitted to access this share "
341 "(%s)\n", lp_const_servicename(snum));
342 return NT_STATUS_ACCESS_DENIED;
345 if (!user_ok_token(session_info->unix_info->unix_name,
346 session_info->info->domain_name,
347 session_info->security_token, snum)) {
348 DBG_WARNING("user '%s' (from session setup) not "
349 "permitted to access this share "
351 session_info->unix_info->unix_name,
352 lp_const_servicename(snum));
353 return NT_STATUS_ACCESS_DENIED;
357 result = copy_session_info(mem_ctx, session_info);
358 if (result == NULL) {
359 return NT_STATUS_NO_MEMORY;
366 /****************************************************************************
367 Set relevant user and group settings corresponding to force user/group
368 configuration for the given snum.
369 ****************************************************************************/
371 NTSTATUS set_conn_force_user_group(connection_struct *conn, int snum)
375 if (*lp_force_user(talloc_tos(), snum)) {
378 * Replace conn->session_info with a completely faked up one
379 * from the username we are forced into :-)
383 char *sanitized_username;
384 struct auth_session_info *forced_serverinfo;
387 fuser = talloc_string_sub(conn, lp_force_user(talloc_tos(), snum), "%S",
388 lp_const_servicename(snum));
390 return NT_STATUS_NO_MEMORY;
393 guest = security_session_user_level(conn->session_info, NULL) < SECURITY_USER;
395 status = make_session_info_from_username(
399 if (!NT_STATUS_IS_OK(status)) {
403 /* We don't want to replace the original sanitized_username
404 as it is the original user given in the connect attempt.
405 This is used in '%U' substitutions. */
406 sanitized_username = discard_const_p(char,
407 forced_serverinfo->unix_info->sanitized_username);
408 TALLOC_FREE(sanitized_username);
409 forced_serverinfo->unix_info->sanitized_username =
410 talloc_move(forced_serverinfo->unix_info,
411 &conn->session_info->unix_info->sanitized_username);
413 TALLOC_FREE(conn->session_info);
414 conn->session_info = forced_serverinfo;
416 conn->force_user = true;
417 DEBUG(3,("Forced user %s\n", fuser));
421 * If force group is true, then override
422 * any groupid stored for the connecting user.
425 if (*lp_force_group(snum)) {
427 status = find_forced_group(
428 conn->force_user, snum, conn->session_info->unix_info->unix_name,
429 &conn->session_info->security_token->sids[1],
430 &conn->session_info->unix_token->gid);
432 if (!NT_STATUS_IS_OK(status)) {
437 * We need to cache this gid, to use within
438 * change_to_user() separately from the conn->session_info
439 * struct. We only use conn->session_info directly if
440 * "force_user" was set.
442 conn->force_group_gid = conn->session_info->unix_token->gid;
448 static NTSTATUS notify_init_sconn(struct smbd_server_connection *sconn)
452 if (sconn->notify_ctx != NULL) {
456 sconn->notify_ctx = notify_init(sconn, sconn->msg_ctx,
457 sconn, notify_callback);
458 if (sconn->notify_ctx == NULL) {
459 return NT_STATUS_NO_MEMORY;
462 status = messaging_register(sconn->msg_ctx, sconn,
463 MSG_SMB_NOTIFY_CANCEL_DELETED,
464 smbd_notify_cancel_deleted);
465 if (!NT_STATUS_IS_OK(status)) {
466 DBG_DEBUG("messaging_register failed: %s\n",
468 TALLOC_FREE(sconn->notify_ctx);
472 status = messaging_register(sconn->msg_ctx, sconn,
473 MSG_SMB_NOTIFY_STARTED,
474 smbd_notifyd_restarted);
475 if (!NT_STATUS_IS_OK(status)) {
476 DBG_DEBUG("messaging_register failed: %s\n",
478 messaging_deregister(sconn->msg_ctx,
479 MSG_SMB_NOTIFY_CANCEL_DELETED, sconn);
480 TALLOC_FREE(sconn->notify_ctx);
487 /****************************************************************************
488 Make a connection, given the snum to connect to, and the vuser of the
489 connecting user if appropriate.
490 ****************************************************************************/
492 static NTSTATUS make_connection_snum(struct smbXsrv_connection *xconn,
493 connection_struct *conn,
494 int snum, struct user_struct *vuser,
497 struct smbd_server_connection *sconn = xconn->client->sconn;
498 struct smb_filename *smb_fname_cpath = NULL;
501 bool on_err_call_dis_hook = false;
508 status = share_sanity_checks(sconn->remote_address,
509 sconn->remote_hostname,
512 if (NT_STATUS_IS_ERR(status)) {
516 conn->params->service = snum;
518 status = create_connection_session_info(sconn,
519 conn, snum, vuser->session_info,
520 &conn->session_info);
522 if (!NT_STATUS_IS_OK(status)) {
523 DEBUG(1, ("create_connection_session_info failed: %s\n",
528 if (lp_guest_only(snum)) {
529 conn->force_user = true;
532 conn->num_files_open = 0;
533 conn->lastused = conn->lastused_count = time(NULL);
534 conn->printer = (strncmp(dev,"LPT",3) == 0);
535 conn->ipc = ( (strncmp(dev,"IPC",3) == 0) ||
536 ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) );
538 /* Case options for the share. */
539 if (lp_case_sensitive(snum) == Auto) {
540 /* We will be setting this per packet. Set to be case
541 * insensitive for now. */
542 conn->case_sensitive = False;
544 conn->case_sensitive = (bool)lp_case_sensitive(snum);
547 conn->case_preserve = lp_preserve_case(snum);
548 conn->short_case_preserve = lp_short_preserve_case(snum);
550 conn->encrypt_level = lp_smb_encrypt(snum);
551 if (conn->encrypt_level > SMB_SIGNING_OFF) {
552 if (lp_smb_encrypt(-1) == SMB_SIGNING_OFF) {
553 if (conn->encrypt_level == SMB_SIGNING_REQUIRED) {
554 DBG_ERR("Service [%s] requires encryption, but "
555 "it is disabled globally!\n",
556 lp_const_servicename(snum));
557 status = NT_STATUS_ACCESS_DENIED;
560 conn->encrypt_level = SMB_SIGNING_OFF;
564 conn->veto_list = NULL;
565 conn->hide_list = NULL;
566 conn->veto_oplock_list = NULL;
567 conn->aio_write_behind_list = NULL;
569 conn->read_only = lp_read_only(SNUM(conn));
571 status = set_conn_force_user_group(conn, snum);
572 if (!NT_STATUS_IS_OK(status)) {
576 conn->vuid = vuser->vuid;
579 char *s = talloc_sub_advanced(talloc_tos(),
580 lp_const_servicename(SNUM(conn)),
581 conn->session_info->unix_info->unix_name,
583 conn->session_info->unix_token->gid,
584 conn->session_info->unix_info->sanitized_username,
585 conn->session_info->info->domain_name,
586 lp_path(talloc_tos(), snum));
588 status = NT_STATUS_NO_MEMORY;
592 if (!set_conn_connectpath(conn,s)) {
594 status = NT_STATUS_NO_MEMORY;
597 DBG_NOTICE("Connect path is '%s' for service [%s]\n", s,
598 lp_const_servicename(snum));
603 * Set up the share security descriptor.
604 * NOTE - we use the *INCOMING USER* session_info
605 * here, as does (indirectly) change_to_user(),
606 * which can be called on any incoming packet.
607 * This way we set up the share access based
608 * on the authenticated user, not the forced
611 * https://bugzilla.samba.org/show_bug.cgi?id=9878
614 status = check_user_share_access(conn,
618 if (!NT_STATUS_IS_OK(status)) {
622 /* Initialise VFS function pointers */
624 if (!smbd_vfs_init(conn)) {
625 DBG_ERR("vfs_init failed for service %s\n",
626 lp_const_servicename(snum));
627 status = NT_STATUS_BAD_NETWORK_NAME;
631 /* ROOT Activities: */
632 /* explicitly check widelinks here so that we can correctly warn
634 widelinks_warning(snum);
637 * Enforce the max connections parameter.
640 if ((lp_max_connections(snum) > 0)
641 && (count_current_connections(lp_const_servicename(SNUM(conn)), true) >=
642 lp_max_connections(snum))) {
644 DBG_WARNING("Max connections (%d) exceeded for %s\n",
645 lp_max_connections(snum),
646 lp_const_servicename(snum));
647 status = NT_STATUS_INSUFFICIENT_RESOURCES;
651 /* Invoke VFS make connection hook - this must be the first
652 filesystem operation that we do. */
654 if (SMB_VFS_CONNECT(conn, lp_const_servicename(snum),
655 conn->session_info->unix_info->unix_name) < 0) {
656 DBG_WARNING("SMB_VFS_CONNECT for service '%s' at '%s' failed: %s\n",
657 lp_const_servicename(snum), conn->connectpath,
659 status = NT_STATUS_UNSUCCESSFUL;
663 /* Any error exit after here needs to call the disconnect hook. */
664 on_err_call_dis_hook = true;
666 if ((!conn->printer) && (!conn->ipc) &&
667 lp_change_notify()) {
669 status = notify_init_sconn(sconn);
670 if (!NT_STATUS_IS_OK(status)) {
675 if (lp_kernel_oplocks(snum)) {
676 init_kernel_oplocks(conn->sconn);
680 * Fix compatibility issue pointed out by Volker.
681 * We pass the conn->connectpath to the preexec
682 * scripts as a parameter, so attempt to canonicalize
683 * it here before calling the preexec scripts.
684 * We ignore errors here, as it is possible that
685 * the conn->connectpath doesn't exist yet and
686 * the preexec scripts will create them.
689 (void)canonicalize_connect_path(conn);
691 /* Preexecs are done here as they might make the dir we are to ChDir
693 /* execute any "root preexec = " line */
694 if (*lp_root_preexec(talloc_tos(), snum)) {
695 char *cmd = talloc_sub_advanced(talloc_tos(),
696 lp_const_servicename(SNUM(conn)),
697 conn->session_info->unix_info->unix_name,
699 conn->session_info->unix_token->gid,
700 conn->session_info->unix_info->sanitized_username,
701 conn->session_info->info->domain_name,
702 lp_root_preexec(talloc_tos(), snum));
703 DEBUG(5,("cmd=%s\n",cmd));
704 ret = smbrun(cmd, NULL, NULL);
706 if (ret != 0 && lp_root_preexec_close(snum)) {
707 DEBUG(1,("root preexec gave %d - failing "
708 "connection\n", ret));
709 status = NT_STATUS_ACCESS_DENIED;
714 /* USER Activites: */
715 if (!change_to_user(conn, conn->vuid)) {
716 /* No point continuing if they fail the basic checks */
717 DEBUG(0,("Can't become connected user!\n"));
718 status = NT_STATUS_LOGON_FAILURE;
725 /* Remember that a different vuid can connect later without these
728 /* Preexecs are done here as they might make the dir we are to ChDir
731 /* execute any "preexec = " line */
732 if (*lp_preexec(talloc_tos(), snum)) {
733 char *cmd = talloc_sub_advanced(talloc_tos(),
734 lp_const_servicename(SNUM(conn)),
735 conn->session_info->unix_info->unix_name,
737 conn->session_info->unix_token->gid,
738 conn->session_info->unix_info->sanitized_username,
739 conn->session_info->info->domain_name,
740 lp_preexec(talloc_tos(), snum));
741 ret = smbrun(cmd, NULL, NULL);
743 if (ret != 0 && lp_preexec_close(snum)) {
744 DEBUG(1,("preexec gave %d - failing connection\n",
746 status = NT_STATUS_ACCESS_DENIED;
751 #ifdef WITH_FAKE_KASERVER
752 if (lp_afs_share(snum)) {
758 * we've finished with the user stuff - go back to root
759 * so the SMB_VFS_STAT call will only fail on path errors,
760 * not permission problems.
762 change_to_root_user();
763 /* ROOT Activites: */
766 * If widelinks are disallowed we need to canonicalise the connect
767 * path here to ensure we don't have any symlinks in the
768 * connectpath. We will be checking all paths on this connection are
769 * below this directory. We must do this after the VFS init as we
770 * depend on the realpath() pointer in the vfs table. JRA.
772 if (!lp_widelinks(snum)) {
773 if (!canonicalize_connect_path(conn)) {
774 DBG_ERR("canonicalize_connect_path failed "
775 "for service %s, path %s\n",
776 lp_const_servicename(snum),
778 status = NT_STATUS_BAD_NETWORK_NAME;
783 /* Add veto/hide lists */
784 if (!IS_IPC(conn) && !IS_PRINT(conn)) {
785 set_namearray( &conn->veto_list,
786 lp_veto_files(talloc_tos(), snum));
787 set_namearray( &conn->hide_list,
788 lp_hide_files(talloc_tos(), snum));
789 set_namearray( &conn->veto_oplock_list,
790 lp_veto_oplock_files(talloc_tos(), snum));
791 set_namearray( &conn->aio_write_behind_list,
792 lp_aio_write_behind(talloc_tos(), snum));
794 smb_fname_cpath = synthetic_smb_fname(talloc_tos(),
799 if (smb_fname_cpath == NULL) {
800 status = NT_STATUS_NO_MEMORY;
804 /* win2000 does not check the permissions on the directory
805 during the tree connect, instead relying on permission
806 check during individual operations. To match this behaviour
807 I have disabled this chdir check (tridge) */
808 /* the alternative is just to check the directory exists */
810 if ((ret = SMB_VFS_STAT(conn, smb_fname_cpath)) != 0 ||
811 !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
812 if (ret == 0 && !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
813 DBG_ERR("'%s' is not a directory, when connecting to "
814 "[%s]\n", conn->connectpath,
815 lp_const_servicename(snum));
817 DBG_ERR("'%s' does not exist or permission denied "
818 "when connecting to [%s] Error was %s\n",
820 lp_const_servicename(snum),
823 status = NT_STATUS_BAD_NETWORK_NAME;
826 conn->base_share_dev = smb_fname_cpath->st.st_ex_dev;
828 talloc_free(conn->origpath);
829 conn->origpath = talloc_strdup(conn, conn->connectpath);
831 /* Figure out the characteristics of the underlying filesystem. This
832 * assumes that all the filesystem mounted withing a share path have
833 * the same characteristics, which is likely but not guaranteed.
836 conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
839 * Print out the 'connected as' stuff here as we need
840 * to know the effective uid and gid we will be using
841 * (at least initially).
844 if( DEBUGLVL( IS_IPC(conn) ? 3 : 2 ) ) {
845 dbgtext( "%s (%s) ", get_remote_machine_name(),
846 tsocket_address_string(conn->sconn->remote_address,
848 dbgtext( "%s", srv_is_signing_active(xconn) ? "signed " : "");
849 dbgtext( "connect to service %s ",
850 lp_const_servicename(snum) );
851 dbgtext( "initially as user %s ",
852 conn->session_info->unix_info->unix_name );
853 dbgtext( "(uid=%d, gid=%d) ", (int)effuid, (int)effgid );
854 dbgtext( "(pid %d)\n", (int)getpid() );
857 conn->tcon_done = true;
862 TALLOC_FREE(smb_fname_cpath);
863 /* We must exit this function as root. */
864 if (geteuid() != 0) {
865 change_to_root_user();
867 if (on_err_call_dis_hook) {
868 /* Call VFS disconnect hook */
869 SMB_VFS_DISCONNECT(conn);
874 /****************************************************************************
875 Make a connection to a service from SMB1. Internal interface.
876 ****************************************************************************/
878 static connection_struct *make_connection_smb1(struct smb_request *req,
880 int snum, struct user_struct *vuser,
884 struct smbXsrv_tcon *tcon;
886 struct connection_struct *conn;
888 status = smb1srv_tcon_create(req->xconn, now, &tcon);
889 if (!NT_STATUS_IS_OK(status)) {
890 DEBUG(0,("make_connection_smb1: Couldn't find free tcon %s.\n",
896 conn = conn_new(req->sconn);
900 DEBUG(0,("make_connection_smb1: Couldn't find free connection.\n"));
901 *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
905 conn->cnum = tcon->global->tcon_wire_id;
908 *pstatus = make_connection_snum(req->xconn,
913 if (!NT_STATUS_IS_OK(*pstatus)) {
919 tcon->global->share_name = lp_servicename(tcon->global, SNUM(conn));
920 if (tcon->global->share_name == NULL) {
923 *pstatus = NT_STATUS_NO_MEMORY;
926 tcon->global->session_global_id =
927 vuser->session->global->session_global_id;
929 tcon->compat = talloc_move(tcon, &conn);
930 tcon->status = NT_STATUS_OK;
932 *pstatus = smbXsrv_tcon_update(tcon);
933 if (!NT_STATUS_IS_OK(*pstatus)) {
941 /****************************************************************************
942 Make a connection to a service from SMB2. External SMB2 interface.
943 We must set cnum before claiming connection.
944 ****************************************************************************/
946 connection_struct *make_connection_smb2(struct smbd_smb2_request *req,
947 struct smbXsrv_tcon *tcon,
949 struct user_struct *vuser,
953 struct smbd_server_connection *sconn = req->sconn;
954 connection_struct *conn = conn_new(sconn);
956 DEBUG(0,("make_connection_smb2: Couldn't find free connection.\n"));
957 *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
961 conn->cnum = tcon->global->tcon_wire_id;
964 *pstatus = make_connection_snum(req->xconn,
969 if (!NT_STATUS_IS_OK(*pstatus)) {
976 /****************************************************************************
977 Make a connection to a service. External SMB1 interface.
980 ****************************************************************************/
982 connection_struct *make_connection(struct smb_request *req,
984 const char *service_in,
985 const char *pdev, uint64_t vuid,
988 struct smbd_server_connection *sconn = req->sconn;
990 struct user_struct *vuser = NULL;
991 char *service = NULL;
997 /* This must ONLY BE CALLED AS ROOT. As it exits this function as
999 if (!non_root_mode() && (euid = geteuid()) != 0) {
1000 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot "
1001 "(%u)\n", (unsigned int)euid ));
1002 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
1005 if (conn_num_open(sconn) > 2047) {
1006 *status = NT_STATUS_INSUFF_SERVER_RESOURCES;
1010 vuser = get_valid_user_struct(sconn, vuid);
1012 DEBUG(1,("make_connection: refusing to connect with "
1013 "no session setup\n"));
1014 *status = NT_STATUS_ACCESS_DENIED;
1018 /* Logic to try and connect to the correct [homes] share, preferably
1019 without too many getpwnam() lookups. This is particulary nasty for
1020 winbind usernames, where the share name isn't the same as unix
1023 The snum of the homes share is stored on the vuser at session setup
1027 if (strequal(service_in,HOMES_NAME)) {
1028 if (vuser->homes_snum == -1) {
1029 DEBUG(2, ("[homes] share not available for "
1030 "this user because it was not found "
1031 "or created at session setup "
1033 *status = NT_STATUS_BAD_NETWORK_NAME;
1036 DEBUG(5, ("making a connection to [homes] service "
1037 "created at session setup time\n"));
1038 return make_connection_smb1(req, now,
1042 } else if ((vuser->homes_snum != -1)
1043 && strequal(service_in,
1044 lp_const_servicename(vuser->homes_snum))) {
1045 DEBUG(5, ("making a connection to 'homes' service [%s] "
1046 "created at session setup time\n", service_in));
1047 return make_connection_smb1(req, now,
1053 service = talloc_strdup(talloc_tos(), service_in);
1055 *status = NT_STATUS_NO_MEMORY;
1059 if (!strlower_m(service)) {
1060 DEBUG(2, ("strlower_m %s failed\n", service));
1061 *status = NT_STATUS_INVALID_PARAMETER;
1065 snum = find_service(talloc_tos(), service, &service);
1067 *status = NT_STATUS_NO_MEMORY;
1072 if (strequal(service,"IPC$") ||
1073 (lp_enable_asu_support() && strequal(service,"ADMIN$"))) {
1074 DEBUG(3,("refusing IPC connection to %s\n", service));
1075 *status = NT_STATUS_ACCESS_DENIED;
1079 DEBUG(3,("%s (%s) couldn't find service %s\n",
1080 get_remote_machine_name(),
1081 tsocket_address_string(
1082 sconn->remote_address, talloc_tos()),
1084 *status = NT_STATUS_BAD_NETWORK_NAME;
1088 /* Handle non-Dfs clients attempting connections to msdfs proxy */
1089 if (lp_host_msdfs() && (*lp_msdfs_proxy(talloc_tos(), snum) != '\0')) {
1090 DEBUG(3, ("refusing connection to dfs proxy share '%s' "
1091 "(pointing to %s)\n",
1092 service, lp_msdfs_proxy(talloc_tos(), snum)));
1093 *status = NT_STATUS_BAD_NETWORK_NAME;
1097 DEBUG(5, ("making a connection to 'normal' service %s\n", service));
1099 return make_connection_smb1(req, now, snum, vuser,
1103 /****************************************************************************
1105 ****************************************************************************/
1107 void close_cnum(connection_struct *conn, uint64_t vuid)
1109 char rootpath[2] = { '/', '\0'};
1110 struct smb_filename root_fname = { .base_name = rootpath };
1112 file_close_conn(conn);
1114 if (!IS_IPC(conn)) {
1115 dptr_closecnum(conn);
1118 change_to_root_user();
1120 DEBUG(IS_IPC(conn)?3:2, ("%s (%s) closed connection to service %s\n",
1121 get_remote_machine_name(),
1122 tsocket_address_string(conn->sconn->remote_address,
1124 lp_const_servicename(SNUM(conn))));
1126 /* make sure we leave the directory available for unmount */
1127 vfs_ChDir(conn, &root_fname);
1129 /* Call VFS disconnect hook */
1130 SMB_VFS_DISCONNECT(conn);
1132 /* execute any "postexec = " line */
1133 if (*lp_postexec(talloc_tos(), SNUM(conn)) &&
1134 change_to_user(conn, vuid)) {
1135 char *cmd = talloc_sub_advanced(talloc_tos(),
1136 lp_const_servicename(SNUM(conn)),
1137 conn->session_info->unix_info->unix_name,
1139 conn->session_info->unix_token->gid,
1140 conn->session_info->unix_info->sanitized_username,
1141 conn->session_info->info->domain_name,
1142 lp_postexec(talloc_tos(), SNUM(conn)));
1143 smbrun(cmd, NULL, NULL);
1145 change_to_root_user();
1148 change_to_root_user();
1149 /* execute any "root postexec = " line */
1150 if (*lp_root_postexec(talloc_tos(), SNUM(conn))) {
1151 char *cmd = talloc_sub_advanced(talloc_tos(),
1152 lp_const_servicename(SNUM(conn)),
1153 conn->session_info->unix_info->unix_name,
1155 conn->session_info->unix_token->gid,
1156 conn->session_info->unix_info->sanitized_username,
1157 conn->session_info->info->domain_name,
1158 lp_root_postexec(talloc_tos(), SNUM(conn)));
1159 smbrun(cmd, NULL, NULL);