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
;
71 /* Ensure conn->cwd is initialized - start as conn->connectpath. */
72 TALLOC_FREE(conn
->cwd
);
73 conn
->cwd
= talloc_strdup(conn
, conn
->connectpath
);
80 /****************************************************************************
81 Load parameters specific to a connection/service.
82 ****************************************************************************/
84 bool set_current_service(connection_struct
*conn
, uint16_t flags
, bool do_chdir
)
87 enum remote_arch_types ra_type
;
94 conn
->lastused_count
++;
99 vfs_ChDir(conn
,conn
->connectpath
) != 0 &&
100 vfs_ChDir(conn
,conn
->origpath
) != 0) {
101 DEBUG(((errno
!=EACCES
)?0:3),("chdir (%s) failed, reason: %s\n",
102 conn
->connectpath
, strerror(errno
)));
106 if ((conn
== last_conn
) && (last_flags
== flags
)) {
114 * Obey the client case sensitivity requests - only for clients that
116 switch (lp_case_sensitive(snum
)) {
119 * We need this uglyness due to DOS/Win9x clients that lie
120 * about case insensitivity. */
121 ra_type
= get_remote_arch();
122 if (conn
->sconn
->using_smb2
) {
123 conn
->case_sensitive
= false;
124 } else if ((ra_type
!= RA_SAMBA
) && (ra_type
!= RA_CIFSFS
)) {
126 * Client can't support per-packet case sensitive
128 conn
->case_sensitive
= false;
130 conn
->case_sensitive
=
131 !(flags
& FLAG_CASELESS_PATHNAMES
);
135 conn
->case_sensitive
= true;
138 conn
->case_sensitive
= false;
144 /****************************************************************************
145 do some basic sainity checks on the share.
146 This function modifies dev, ecode.
147 ****************************************************************************/
149 static NTSTATUS
share_sanity_checks(const struct tsocket_address
*remote_address
,
156 raddr
= tsocket_address_inet_addr_string(remote_address
,
159 return NT_STATUS_NO_MEMORY
;
162 if (!lp_snum_ok(snum
) ||
163 !allow_access(lp_hosts_deny(snum
), lp_hosts_allow(snum
),
165 return NT_STATUS_ACCESS_DENIED
;
168 if (dev
[0] == '?' || !dev
[0]) {
169 if (lp_printable(snum
)) {
170 fstrcpy(dev
,"LPT1:");
171 } else if (strequal(lp_fstype(snum
), "IPC")) {
178 if (!strupper_m(dev
)) {
179 DEBUG(2,("strupper_m %s failed\n", dev
));
180 return NT_STATUS_INVALID_PARAMETER
;
183 if (lp_printable(snum
)) {
184 if (!strequal(dev
, "LPT1:")) {
185 return NT_STATUS_BAD_DEVICE_TYPE
;
187 } else if (strequal(lp_fstype(snum
), "IPC")) {
188 if (!strequal(dev
, "IPC")) {
189 return NT_STATUS_BAD_DEVICE_TYPE
;
191 } else if (!strequal(dev
, "A:")) {
192 return NT_STATUS_BAD_DEVICE_TYPE
;
195 /* Behave as a printer if we are supposed to */
196 if (lp_printable(snum
) && (strcmp(dev
, "A:") == 0)) {
197 fstrcpy(dev
, "LPT1:");
204 * Go through lookup_name etc to find the force'd group.
206 * Create a new token from src_token, replacing the primary group sid with the
210 static NTSTATUS
find_forced_group(bool force_user
,
211 int snum
, const char *username
,
212 struct dom_sid
*pgroup_sid
,
215 NTSTATUS result
= NT_STATUS_NO_SUCH_GROUP
;
216 TALLOC_CTX
*frame
= talloc_stackframe();
217 struct dom_sid group_sid
;
218 enum lsa_SidType type
;
220 bool user_must_be_member
= False
;
223 groupname
= lp_force_group(talloc_tos(), snum
);
224 if (groupname
== NULL
) {
225 DEBUG(1, ("talloc_strdup failed\n"));
226 result
= NT_STATUS_NO_MEMORY
;
230 if (groupname
[0] == '+') {
231 user_must_be_member
= True
;
235 groupname
= talloc_string_sub(talloc_tos(), groupname
,
236 "%S", lp_servicename(talloc_tos(), snum
));
237 if (groupname
== NULL
) {
238 DEBUG(1, ("talloc_string_sub failed\n"));
239 result
= NT_STATUS_NO_MEMORY
;
243 if (!lookup_name_smbconf(talloc_tos(), groupname
,
244 LOOKUP_NAME_ALL
|LOOKUP_NAME_GROUP
,
245 NULL
, NULL
, &group_sid
, &type
)) {
246 DEBUG(10, ("lookup_name_smbconf(%s) failed\n",
251 if ((type
!= SID_NAME_DOM_GRP
) && (type
!= SID_NAME_ALIAS
) &&
252 (type
!= SID_NAME_WKN_GRP
)) {
253 DEBUG(10, ("%s is a %s, not a group\n", groupname
,
254 sid_type_lookup(type
)));
258 if (!sid_to_gid(&group_sid
, &gid
)) {
259 DEBUG(10, ("sid_to_gid(%s) for %s failed\n",
260 sid_string_dbg(&group_sid
), groupname
));
265 * If the user has been forced and the forced group starts with a '+',
266 * then we only set the group to be the forced group if the forced
267 * user is a member of that group. Otherwise, the meaning of the '+'
271 if (force_user
&& user_must_be_member
) {
272 if (user_in_group_sid(username
, &group_sid
)) {
273 sid_copy(pgroup_sid
, &group_sid
);
275 DEBUG(3,("Forced group %s for member %s\n",
276 groupname
, username
));
278 DEBUG(0,("find_forced_group: forced user %s is not a member "
279 "of forced group %s. Disallowing access.\n",
280 username
, groupname
));
281 result
= NT_STATUS_MEMBER_NOT_IN_GROUP
;
285 sid_copy(pgroup_sid
, &group_sid
);
287 DEBUG(3,("Forced group %s\n", groupname
));
290 result
= NT_STATUS_OK
;
296 /****************************************************************************
297 Create an auth_session_info structure for a connection_struct
298 ****************************************************************************/
300 static NTSTATUS
create_connection_session_info(struct smbd_server_connection
*sconn
,
301 TALLOC_CTX
*mem_ctx
, int snum
,
302 struct auth_session_info
*session_info
,
303 struct auth_session_info
**presult
)
305 struct auth_session_info
*result
;
307 if (lp_guest_only(snum
)) {
308 return make_session_info_guest(mem_ctx
, presult
);
312 * This is the normal security != share case where we have a
313 * valid vuid from the session setup. */
315 if (security_session_user_level(session_info
, NULL
) < SECURITY_USER
) {
316 if (!lp_guest_ok(snum
)) {
317 DEBUG(2, ("guest user (from session setup) "
318 "not permitted to access this share "
319 "(%s)\n", lp_servicename(talloc_tos(), snum
)));
320 return NT_STATUS_ACCESS_DENIED
;
323 if (!user_ok_token(session_info
->unix_info
->unix_name
,
324 session_info
->info
->domain_name
,
325 session_info
->security_token
, snum
)) {
326 DEBUG(2, ("user '%s' (from session setup) not "
327 "permitted to access this share "
329 session_info
->unix_info
->unix_name
,
330 lp_servicename(talloc_tos(), snum
)));
331 return NT_STATUS_ACCESS_DENIED
;
335 result
= copy_session_info(mem_ctx
, session_info
);
336 if (result
== NULL
) {
337 return NT_STATUS_NO_MEMORY
;
344 /****************************************************************************
345 Set relevant user and group settings corresponding to force user/group
346 configuration for the given snum.
347 ****************************************************************************/
349 NTSTATUS
set_conn_force_user_group(connection_struct
*conn
, int snum
)
353 if (*lp_force_user(talloc_tos(), snum
)) {
356 * Replace conn->session_info with a completely faked up one
357 * from the username we are forced into :-)
361 char *sanitized_username
;
362 struct auth_session_info
*forced_serverinfo
;
365 fuser
= talloc_string_sub(conn
, lp_force_user(talloc_tos(), snum
), "%S",
366 lp_const_servicename(snum
));
368 return NT_STATUS_NO_MEMORY
;
371 guest
= security_session_user_level(conn
->session_info
, NULL
) < SECURITY_USER
;
373 status
= make_session_info_from_username(
377 if (!NT_STATUS_IS_OK(status
)) {
381 /* We don't want to replace the original sanitized_username
382 as it is the original user given in the connect attempt.
383 This is used in '%U' substitutions. */
384 sanitized_username
= discard_const_p(char,
385 forced_serverinfo
->unix_info
->sanitized_username
);
386 TALLOC_FREE(sanitized_username
);
387 forced_serverinfo
->unix_info
->sanitized_username
=
388 talloc_move(forced_serverinfo
->unix_info
,
389 &conn
->session_info
->unix_info
->sanitized_username
);
391 TALLOC_FREE(conn
->session_info
);
392 conn
->session_info
= forced_serverinfo
;
394 conn
->force_user
= true;
395 DEBUG(3,("Forced user %s\n", fuser
));
399 * If force group is true, then override
400 * any groupid stored for the connecting user.
403 if (*lp_force_group(talloc_tos(), snum
)) {
405 status
= find_forced_group(
406 conn
->force_user
, snum
, conn
->session_info
->unix_info
->unix_name
,
407 &conn
->session_info
->security_token
->sids
[1],
408 &conn
->session_info
->unix_token
->gid
);
410 if (!NT_STATUS_IS_OK(status
)) {
415 * We need to cache this gid, to use within
416 * change_to_user() separately from the conn->session_info
417 * struct. We only use conn->session_info directly if
418 * "force_user" was set.
420 conn
->force_group_gid
= conn
->session_info
->unix_token
->gid
;
426 /****************************************************************************
427 Make a connection, given the snum to connect to, and the vuser of the
428 connecting user if appropriate.
429 ****************************************************************************/
431 static NTSTATUS
make_connection_snum(struct smbXsrv_connection
*xconn
,
432 connection_struct
*conn
,
433 int snum
, struct user_struct
*vuser
,
436 struct smbd_server_connection
*sconn
= xconn
->client
->sconn
;
437 struct smb_filename
*smb_fname_cpath
= NULL
;
440 bool on_err_call_dis_hook
= false;
447 status
= share_sanity_checks(sconn
->remote_address
,
448 sconn
->remote_hostname
,
451 if (NT_STATUS_IS_ERR(status
)) {
455 conn
->params
->service
= snum
;
457 status
= create_connection_session_info(sconn
,
458 conn
, snum
, vuser
->session_info
,
459 &conn
->session_info
);
461 if (!NT_STATUS_IS_OK(status
)) {
462 DEBUG(1, ("create_connection_session_info failed: %s\n",
467 if (lp_guest_only(snum
)) {
468 conn
->force_user
= true;
471 conn
->num_files_open
= 0;
472 conn
->lastused
= conn
->lastused_count
= time(NULL
);
473 conn
->printer
= (strncmp(dev
,"LPT",3) == 0);
474 conn
->ipc
= ( (strncmp(dev
,"IPC",3) == 0) ||
475 ( lp_enable_asu_support() && strequal(dev
,"ADMIN$")) );
477 /* Case options for the share. */
478 if (lp_case_sensitive(snum
) == Auto
) {
479 /* We will be setting this per packet. Set to be case
480 * insensitive for now. */
481 conn
->case_sensitive
= False
;
483 conn
->case_sensitive
= (bool)lp_case_sensitive(snum
);
486 conn
->case_preserve
= lp_preserve_case(snum
);
487 conn
->short_case_preserve
= lp_short_preserve_case(snum
);
489 conn
->encrypt_level
= lp_smb_encrypt(snum
);
490 if (conn
->encrypt_level
> SMB_SIGNING_OFF
) {
491 if (lp_smb_encrypt(-1) == SMB_SIGNING_OFF
) {
492 if (conn
->encrypt_level
== SMB_SIGNING_REQUIRED
) {
493 DBG_ERR("Service [%s] requires encryption, but "
494 "it is disabled globally!\n",
495 lp_servicename(talloc_tos(), snum
));
496 status
= NT_STATUS_ACCESS_DENIED
;
499 conn
->encrypt_level
= SMB_SIGNING_OFF
;
503 conn
->veto_list
= NULL
;
504 conn
->hide_list
= NULL
;
505 conn
->veto_oplock_list
= NULL
;
506 conn
->aio_write_behind_list
= NULL
;
508 conn
->read_only
= lp_read_only(SNUM(conn
));
510 status
= set_conn_force_user_group(conn
, snum
);
511 if (!NT_STATUS_IS_OK(status
)) {
515 conn
->vuid
= vuser
->vuid
;
518 char *s
= talloc_sub_advanced(talloc_tos(),
519 lp_servicename(talloc_tos(), SNUM(conn
)),
520 conn
->session_info
->unix_info
->unix_name
,
522 conn
->session_info
->unix_token
->gid
,
523 conn
->session_info
->unix_info
->sanitized_username
,
524 conn
->session_info
->info
->domain_name
,
525 lp_path(talloc_tos(), snum
));
527 status
= NT_STATUS_NO_MEMORY
;
531 if (!set_conn_connectpath(conn
,s
)) {
533 status
= NT_STATUS_NO_MEMORY
;
536 DEBUG(3,("Connect path is '%s' for service [%s]\n",s
,
537 lp_servicename(talloc_tos(), snum
)));
542 * Set up the share security descriptor.
543 * NOTE - we use the *INCOMING USER* session_info
544 * here, as does (indirectly) change_to_user(),
545 * which can be called on any incoming packet.
546 * This way we set up the share access based
547 * on the authenticated user, not the forced
550 * https://bugzilla.samba.org/show_bug.cgi?id=9878
553 status
= check_user_share_access(conn
,
557 if (!NT_STATUS_IS_OK(status
)) {
561 /* Initialise VFS function pointers */
563 if (!smbd_vfs_init(conn
)) {
564 DEBUG(0, ("vfs_init failed for service %s\n",
565 lp_servicename(talloc_tos(), snum
)));
566 status
= NT_STATUS_BAD_NETWORK_NAME
;
570 /* ROOT Activities: */
571 /* explicitly check widelinks here so that we can correctly warn
573 widelinks_warning(snum
);
576 * Enforce the max connections parameter.
579 if ((lp_max_connections(snum
) > 0)
580 && (count_current_connections(lp_servicename(talloc_tos(), SNUM(conn
)), True
) >=
581 lp_max_connections(snum
))) {
583 DEBUG(1, ("Max connections (%d) exceeded for %s\n",
584 lp_max_connections(snum
),
585 lp_servicename(talloc_tos(), snum
)));
586 status
= NT_STATUS_INSUFFICIENT_RESOURCES
;
590 /* Invoke VFS make connection hook - this must be the first
591 filesystem operation that we do. */
593 if (SMB_VFS_CONNECT(conn
, lp_servicename(talloc_tos(), snum
),
594 conn
->session_info
->unix_info
->unix_name
) < 0) {
595 DBG_WARNING("SMB_VFS_CONNECT for service '%s' at '%s' failed: %s\n",
596 lp_servicename(talloc_tos(), snum
), conn
->connectpath
,
598 status
= NT_STATUS_UNSUCCESSFUL
;
602 /* Any error exit after here needs to call the disconnect hook. */
603 on_err_call_dis_hook
= true;
605 if ((!conn
->printer
) && (!conn
->ipc
) &&
606 lp_change_notify()) {
607 if (sconn
->notify_ctx
== NULL
) {
608 sconn
->notify_ctx
= notify_init(
609 sconn
, sconn
->msg_ctx
, sconn
->ev_ctx
);
610 status
= messaging_register(
611 sconn
->msg_ctx
, sconn
,
612 MSG_SMB_NOTIFY_CANCEL_DELETED
,
613 smbd_notify_cancel_deleted
);
615 if (sconn
->sys_notify_ctx
== NULL
) {
616 sconn
->sys_notify_ctx
= sys_notify_context_create(
617 sconn
, sconn
->ev_ctx
);
621 if (lp_kernel_oplocks(snum
)) {
622 init_kernel_oplocks(conn
->sconn
);
626 * Fix compatibility issue pointed out by Volker.
627 * We pass the conn->connectpath to the preexec
628 * scripts as a parameter, so attempt to canonicalize
629 * it here before calling the preexec scripts.
630 * We ignore errors here, as it is possible that
631 * the conn->connectpath doesn't exist yet and
632 * the preexec scripts will create them.
635 (void)canonicalize_connect_path(conn
);
637 /* Preexecs are done here as they might make the dir we are to ChDir
639 /* execute any "root preexec = " line */
640 if (*lp_root_preexec(talloc_tos(), snum
)) {
641 char *cmd
= talloc_sub_advanced(talloc_tos(),
642 lp_servicename(talloc_tos(), SNUM(conn
)),
643 conn
->session_info
->unix_info
->unix_name
,
645 conn
->session_info
->unix_token
->gid
,
646 conn
->session_info
->unix_info
->sanitized_username
,
647 conn
->session_info
->info
->domain_name
,
648 lp_root_preexec(talloc_tos(), snum
));
649 DEBUG(5,("cmd=%s\n",cmd
));
650 ret
= smbrun(cmd
,NULL
);
652 if (ret
!= 0 && lp_root_preexec_close(snum
)) {
653 DEBUG(1,("root preexec gave %d - failing "
654 "connection\n", ret
));
655 status
= NT_STATUS_ACCESS_DENIED
;
660 /* USER Activites: */
661 if (!change_to_user(conn
, conn
->vuid
)) {
662 /* No point continuing if they fail the basic checks */
663 DEBUG(0,("Can't become connected user!\n"));
664 status
= NT_STATUS_LOGON_FAILURE
;
671 /* Remember that a different vuid can connect later without these
674 /* Preexecs are done here as they might make the dir we are to ChDir
677 /* execute any "preexec = " line */
678 if (*lp_preexec(talloc_tos(), snum
)) {
679 char *cmd
= talloc_sub_advanced(talloc_tos(),
680 lp_servicename(talloc_tos(), SNUM(conn
)),
681 conn
->session_info
->unix_info
->unix_name
,
683 conn
->session_info
->unix_token
->gid
,
684 conn
->session_info
->unix_info
->sanitized_username
,
685 conn
->session_info
->info
->domain_name
,
686 lp_preexec(talloc_tos(), snum
));
687 ret
= smbrun(cmd
,NULL
);
689 if (ret
!= 0 && lp_preexec_close(snum
)) {
690 DEBUG(1,("preexec gave %d - failing connection\n",
692 status
= NT_STATUS_ACCESS_DENIED
;
697 #ifdef WITH_FAKE_KASERVER
698 if (lp_afs_share(snum
)) {
704 * we've finished with the user stuff - go back to root
705 * so the SMB_VFS_STAT call will only fail on path errors,
706 * not permission problems.
708 change_to_root_user();
709 /* ROOT Activites: */
712 * If widelinks are disallowed we need to canonicalise the connect
713 * path here to ensure we don't have any symlinks in the
714 * connectpath. We will be checking all paths on this connection are
715 * below this directory. We must do this after the VFS init as we
716 * depend on the realpath() pointer in the vfs table. JRA.
718 if (!lp_widelinks(snum
)) {
719 if (!canonicalize_connect_path(conn
)) {
720 DEBUG(0, ("canonicalize_connect_path failed "
721 "for service %s, path %s\n",
722 lp_servicename(talloc_tos(), snum
),
724 status
= NT_STATUS_BAD_NETWORK_NAME
;
729 /* Add veto/hide lists */
730 if (!IS_IPC(conn
) && !IS_PRINT(conn
)) {
731 set_namearray( &conn
->veto_list
,
732 lp_veto_files(talloc_tos(), snum
));
733 set_namearray( &conn
->hide_list
,
734 lp_hide_files(talloc_tos(), snum
));
735 set_namearray( &conn
->veto_oplock_list
,
736 lp_veto_oplock_files(talloc_tos(), snum
));
737 set_namearray( &conn
->aio_write_behind_list
,
738 lp_aio_write_behind(talloc_tos(), snum
));
740 smb_fname_cpath
= synthetic_smb_fname(talloc_tos(), conn
->connectpath
,
742 if (smb_fname_cpath
== NULL
) {
743 status
= NT_STATUS_NO_MEMORY
;
747 /* win2000 does not check the permissions on the directory
748 during the tree connect, instead relying on permission
749 check during individual operations. To match this behaviour
750 I have disabled this chdir check (tridge) */
751 /* the alternative is just to check the directory exists */
753 if ((ret
= SMB_VFS_STAT(conn
, smb_fname_cpath
)) != 0 ||
754 !S_ISDIR(smb_fname_cpath
->st
.st_ex_mode
)) {
755 if (ret
== 0 && !S_ISDIR(smb_fname_cpath
->st
.st_ex_mode
)) {
756 DEBUG(0,("'%s' is not a directory, when connecting to "
757 "[%s]\n", conn
->connectpath
,
758 lp_servicename(talloc_tos(), snum
)));
760 DEBUG(0,("'%s' does not exist or permission denied "
761 "when connecting to [%s] Error was %s\n",
763 lp_servicename(talloc_tos(), snum
),
766 status
= NT_STATUS_BAD_NETWORK_NAME
;
769 conn
->base_share_dev
= smb_fname_cpath
->st
.st_ex_dev
;
771 talloc_free(conn
->origpath
);
772 conn
->origpath
= talloc_strdup(conn
, conn
->connectpath
);
774 /* Figure out the characteristics of the underlying filesystem. This
775 * assumes that all the filesystem mounted withing a share path have
776 * the same characteristics, which is likely but not guaranteed.
779 conn
->fs_capabilities
= SMB_VFS_FS_CAPABILITIES(conn
, &conn
->ts_res
);
782 * Print out the 'connected as' stuff here as we need
783 * to know the effective uid and gid we will be using
784 * (at least initially).
787 if( DEBUGLVL( IS_IPC(conn
) ? 3 : 2 ) ) {
788 dbgtext( "%s (%s) ", get_remote_machine_name(),
789 tsocket_address_string(conn
->sconn
->remote_address
,
791 dbgtext( "%s", srv_is_signing_active(xconn
) ? "signed " : "");
792 dbgtext( "connect to service %s ",
793 lp_servicename(talloc_tos(), snum
) );
794 dbgtext( "initially as user %s ",
795 conn
->session_info
->unix_info
->unix_name
);
796 dbgtext( "(uid=%d, gid=%d) ", (int)effuid
, (int)effgid
);
797 dbgtext( "(pid %d)\n", (int)getpid() );
804 TALLOC_FREE(smb_fname_cpath
);
805 /* We must exit this function as root. */
806 if (geteuid() != 0) {
807 change_to_root_user();
809 if (on_err_call_dis_hook
) {
810 /* Call VFS disconnect hook */
811 SMB_VFS_DISCONNECT(conn
);
816 /****************************************************************************
817 Make a connection to a service from SMB1. Internal interface.
818 ****************************************************************************/
820 static connection_struct
*make_connection_smb1(struct smb_request
*req
,
822 int snum
, struct user_struct
*vuser
,
826 struct smbXsrv_tcon
*tcon
;
828 struct connection_struct
*conn
;
830 status
= smb1srv_tcon_create(req
->xconn
, now
, &tcon
);
831 if (!NT_STATUS_IS_OK(status
)) {
832 DEBUG(0,("make_connection_smb1: Couldn't find free tcon %s.\n",
838 conn
= conn_new(req
->sconn
);
842 DEBUG(0,("make_connection_smb1: Couldn't find free connection.\n"));
843 *pstatus
= NT_STATUS_INSUFFICIENT_RESOURCES
;
847 conn
->cnum
= tcon
->global
->tcon_wire_id
;
850 *pstatus
= make_connection_snum(req
->xconn
,
855 if (!NT_STATUS_IS_OK(*pstatus
)) {
861 tcon
->global
->share_name
= lp_servicename(tcon
->global
, SNUM(conn
));
862 if (tcon
->global
->share_name
== NULL
) {
865 *pstatus
= NT_STATUS_NO_MEMORY
;
868 tcon
->global
->session_global_id
=
869 vuser
->session
->global
->session_global_id
;
871 tcon
->compat
= talloc_move(tcon
, &conn
);
872 tcon
->status
= NT_STATUS_OK
;
874 *pstatus
= smbXsrv_tcon_update(tcon
);
875 if (!NT_STATUS_IS_OK(*pstatus
)) {
883 /****************************************************************************
884 Make a connection to a service from SMB2. External SMB2 interface.
885 We must set cnum before claiming connection.
886 ****************************************************************************/
888 connection_struct
*make_connection_smb2(struct smbd_smb2_request
*req
,
889 struct smbXsrv_tcon
*tcon
,
891 struct user_struct
*vuser
,
895 struct smbd_server_connection
*sconn
= req
->sconn
;
896 connection_struct
*conn
= conn_new(sconn
);
898 DEBUG(0,("make_connection_smb2: Couldn't find free connection.\n"));
899 *pstatus
= NT_STATUS_INSUFFICIENT_RESOURCES
;
903 conn
->cnum
= tcon
->global
->tcon_wire_id
;
906 *pstatus
= make_connection_snum(req
->xconn
,
911 if (!NT_STATUS_IS_OK(*pstatus
)) {
918 /****************************************************************************
919 Make a connection to a service. External SMB1 interface.
922 ****************************************************************************/
924 connection_struct
*make_connection(struct smb_request
*req
,
926 const char *service_in
,
927 const char *pdev
, uint64_t vuid
,
930 struct smbd_server_connection
*sconn
= req
->sconn
;
932 struct user_struct
*vuser
= NULL
;
933 char *service
= NULL
;
939 /* This must ONLY BE CALLED AS ROOT. As it exits this function as
941 if (!non_root_mode() && (euid
= geteuid()) != 0) {
942 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot "
943 "(%u)\n", (unsigned int)euid
));
944 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
947 if (conn_num_open(sconn
) > 2047) {
948 *status
= NT_STATUS_INSUFF_SERVER_RESOURCES
;
952 vuser
= get_valid_user_struct(sconn
, vuid
);
954 DEBUG(1,("make_connection: refusing to connect with "
955 "no session setup\n"));
956 *status
= NT_STATUS_ACCESS_DENIED
;
960 /* Logic to try and connect to the correct [homes] share, preferably
961 without too many getpwnam() lookups. This is particulary nasty for
962 winbind usernames, where the share name isn't the same as unix
965 The snum of the homes share is stored on the vuser at session setup
969 if (strequal(service_in
,HOMES_NAME
)) {
970 if (vuser
->homes_snum
== -1) {
971 DEBUG(2, ("[homes] share not available for "
972 "this user because it was not found "
973 "or created at session setup "
975 *status
= NT_STATUS_BAD_NETWORK_NAME
;
978 DEBUG(5, ("making a connection to [homes] service "
979 "created at session setup time\n"));
980 return make_connection_smb1(req
, now
,
984 } else if ((vuser
->homes_snum
!= -1)
985 && strequal(service_in
,
986 lp_servicename(talloc_tos(), vuser
->homes_snum
))) {
987 DEBUG(5, ("making a connection to 'homes' service [%s] "
988 "created at session setup time\n", service_in
));
989 return make_connection_smb1(req
, now
,
995 service
= talloc_strdup(talloc_tos(), service_in
);
997 *status
= NT_STATUS_NO_MEMORY
;
1001 if (!strlower_m(service
)) {
1002 DEBUG(2, ("strlower_m %s failed\n", service
));
1003 *status
= NT_STATUS_INVALID_PARAMETER
;
1007 snum
= find_service(talloc_tos(), service
, &service
);
1009 *status
= NT_STATUS_NO_MEMORY
;
1014 if (strequal(service
,"IPC$") ||
1015 (lp_enable_asu_support() && strequal(service
,"ADMIN$"))) {
1016 DEBUG(3,("refusing IPC connection to %s\n", service
));
1017 *status
= NT_STATUS_ACCESS_DENIED
;
1021 DEBUG(3,("%s (%s) couldn't find service %s\n",
1022 get_remote_machine_name(),
1023 tsocket_address_string(
1024 sconn
->remote_address
, talloc_tos()),
1026 *status
= NT_STATUS_BAD_NETWORK_NAME
;
1030 /* Handle non-Dfs clients attempting connections to msdfs proxy */
1031 if (lp_host_msdfs() && (*lp_msdfs_proxy(talloc_tos(), snum
) != '\0')) {
1032 DEBUG(3, ("refusing connection to dfs proxy share '%s' "
1033 "(pointing to %s)\n",
1034 service
, lp_msdfs_proxy(talloc_tos(), snum
)));
1035 *status
= NT_STATUS_BAD_NETWORK_NAME
;
1039 DEBUG(5, ("making a connection to 'normal' service %s\n", service
));
1041 return make_connection_smb1(req
, now
, snum
, vuser
,
1045 /****************************************************************************
1047 ****************************************************************************/
1049 void close_cnum(connection_struct
*conn
, uint64_t vuid
)
1051 file_close_conn(conn
);
1053 if (!IS_IPC(conn
)) {
1054 dptr_closecnum(conn
);
1057 change_to_root_user();
1059 DEBUG(IS_IPC(conn
)?3:2, ("%s (%s) closed connection to service %s\n",
1060 get_remote_machine_name(),
1061 tsocket_address_string(conn
->sconn
->remote_address
,
1063 lp_servicename(talloc_tos(), SNUM(conn
))));
1065 /* make sure we leave the directory available for unmount */
1066 vfs_ChDir(conn
, "/");
1068 /* Call VFS disconnect hook */
1069 SMB_VFS_DISCONNECT(conn
);
1071 /* execute any "postexec = " line */
1072 if (*lp_postexec(talloc_tos(), SNUM(conn
)) &&
1073 change_to_user(conn
, vuid
)) {
1074 char *cmd
= talloc_sub_advanced(talloc_tos(),
1075 lp_servicename(talloc_tos(), SNUM(conn
)),
1076 conn
->session_info
->unix_info
->unix_name
,
1078 conn
->session_info
->unix_token
->gid
,
1079 conn
->session_info
->unix_info
->sanitized_username
,
1080 conn
->session_info
->info
->domain_name
,
1081 lp_postexec(talloc_tos(), SNUM(conn
)));
1084 change_to_root_user();
1087 change_to_root_user();
1088 /* execute any "root postexec = " line */
1089 if (*lp_root_postexec(talloc_tos(), SNUM(conn
))) {
1090 char *cmd
= talloc_sub_advanced(talloc_tos(),
1091 lp_servicename(talloc_tos(), SNUM(conn
)),
1092 conn
->session_info
->unix_info
->unix_name
,
1094 conn
->session_info
->unix_token
->gid
,
1095 conn
->session_info
->unix_info
->sanitized_username
,
1096 conn
->session_info
->info
->domain_name
,
1097 lp_root_postexec(talloc_tos(), SNUM(conn
)));