s3: smbd: Remove 'is_dfs' parameter to check_path_syntax_smb2().
[Samba.git] / source3 / smbd / smb2_service.c
blob6670b8a5a13a55cc013e5f9152b50f4bba5d83a4
1 /*
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/>.
20 #include "includes.h"
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"
30 #include "auth.h"
31 #include "../auth/auth_util.h"
32 #include "lib/param/loadparm.h"
33 #include "messages.h"
34 #include "lib/afs/afs_funcs.h"
35 #include "lib/util_path.h"
36 #include "lib/util/string_wrappers.h"
37 #include "source3/lib/substitute.h"
39 bool canonicalize_connect_path(connection_struct *conn)
41 bool ret;
42 struct smb_filename con_fname = { .base_name = conn->connectpath };
43 struct smb_filename *resolved_fname = SMB_VFS_REALPATH(conn, talloc_tos(),
44 &con_fname);
45 if (resolved_fname == NULL) {
46 return false;
48 ret = set_conn_connectpath(conn,resolved_fname->base_name);
49 TALLOC_FREE(resolved_fname);
50 return ret;
53 /****************************************************************************
54 Ensure when setting connectpath it is a canonicalized (no ./ // or ../)
55 absolute path stating in / and not ending in /.
56 ****************************************************************************/
58 bool set_conn_connectpath(connection_struct *conn, const char *connectpath)
60 char *destname;
62 if (connectpath == NULL || connectpath[0] == '\0') {
63 return false;
66 destname = canonicalize_absolute_path(conn, connectpath);
67 if (destname == NULL) {
68 return false;
71 DBG_DEBUG("service %s, connectpath = %s\n",
72 lp_const_servicename(SNUM(conn)), destname);
74 talloc_free(conn->connectpath);
75 conn->connectpath = destname;
77 * Ensure conn->cwd_fsp->fsp_name is initialized.
78 * start as conn->connectpath.
80 TALLOC_FREE(conn->cwd_fsp->fsp_name);
81 conn->cwd_fsp->fsp_name = synthetic_smb_fname(conn,
82 conn->connectpath,
83 NULL,
84 NULL,
86 0);
87 if (conn->cwd_fsp->fsp_name == NULL) {
88 return false;
90 return true;
93 bool chdir_current_service(connection_struct *conn)
95 const struct smb_filename connectpath_fname = {
96 .base_name = conn->connectpath,
98 int saved_errno = 0;
99 char *utok_str = NULL;
100 int ret;
102 conn->lastused_count++;
104 ret = vfs_ChDir(conn, &connectpath_fname);
105 if (ret == 0) {
106 return true;
108 saved_errno = errno;
110 utok_str = utok_string(talloc_tos(),
111 conn->session_info->unix_token);
112 if (utok_str == NULL) {
113 errno = saved_errno;
114 return false;
117 DBG_ERR("vfs_ChDir(%s) failed: %s. Current token: %s\n",
118 conn->connectpath,
119 strerror(saved_errno),
120 utok_str);
122 if (saved_errno != 0) {
123 errno = saved_errno;
125 return false;
128 /****************************************************************************
129 do some basic sainity checks on the share.
130 This function modifies dev, ecode.
131 ****************************************************************************/
133 static NTSTATUS share_sanity_checks(const struct tsocket_address *local_address,
134 const struct tsocket_address *remote_address,
135 const char *rhost,
136 int snum,
137 fstring dev)
139 char *raddr;
141 if (!lp_allow_local_address(snum, local_address)) {
142 char *laddr = NULL;
144 laddr = tsocket_address_inet_addr_string(
145 local_address, talloc_tos());
146 if (laddr == NULL) {
147 return NT_STATUS_NO_MEMORY;
150 raddr = tsocket_address_inet_addr_string(
151 remote_address, laddr);
152 if (raddr == NULL) {
153 TALLOC_FREE(laddr);
154 return NT_STATUS_NO_MEMORY;
157 DBG_ERR("Denied connection from %s (%s) to \\\\%s\\%s\n",
158 rhost, raddr, laddr, lp_const_servicename(snum));
159 TALLOC_FREE(laddr);
161 return NT_STATUS_BAD_NETWORK_NAME;
164 raddr = tsocket_address_inet_addr_string(remote_address,
165 talloc_tos());
166 if (raddr == NULL) {
167 return NT_STATUS_NO_MEMORY;
170 if (!lp_snum_ok(snum) ||
171 !allow_access(lp_hosts_deny(snum), lp_hosts_allow(snum),
172 rhost, raddr)) {
173 return NT_STATUS_ACCESS_DENIED;
176 if (dev[0] == '?' || !dev[0]) {
177 if (lp_printable(snum)) {
178 fstrcpy(dev,"LPT1:");
179 } else if (strequal(lp_fstype(snum), "IPC")) {
180 fstrcpy(dev, "IPC");
181 } else {
182 fstrcpy(dev,"A:");
186 if (!strupper_m(dev)) {
187 DEBUG(2,("strupper_m %s failed\n", dev));
188 return NT_STATUS_INVALID_PARAMETER;
191 if (lp_printable(snum)) {
192 if (!strequal(dev, "LPT1:")) {
193 return NT_STATUS_BAD_DEVICE_TYPE;
195 } else if (strequal(lp_fstype(snum), "IPC")) {
196 if (!strequal(dev, "IPC")) {
197 return NT_STATUS_BAD_DEVICE_TYPE;
199 } else if (!strequal(dev, "A:")) {
200 return NT_STATUS_BAD_DEVICE_TYPE;
203 /* Behave as a printer if we are supposed to */
204 if (lp_printable(snum) && (strcmp(dev, "A:") == 0)) {
205 fstrcpy(dev, "LPT1:");
208 return NT_STATUS_OK;
212 * Go through lookup_name etc to find the force'd group.
214 * Create a new token from src_token, replacing the primary group sid with the
215 * one found.
218 static NTSTATUS find_forced_group(bool force_user,
219 int snum, const char *username,
220 struct dom_sid *pgroup_sid,
221 gid_t *pgid)
223 NTSTATUS result = NT_STATUS_NO_SUCH_GROUP;
224 TALLOC_CTX *frame = talloc_stackframe();
225 const struct loadparm_substitution *lp_sub =
226 loadparm_s3_global_substitution();
227 struct dom_sid group_sid;
228 enum lsa_SidType type;
229 char *groupname;
230 bool user_must_be_member = False;
231 gid_t gid;
233 groupname = lp_force_group(talloc_tos(), lp_sub, snum);
234 if (groupname == NULL) {
235 DEBUG(1, ("talloc_strdup failed\n"));
236 result = NT_STATUS_NO_MEMORY;
237 goto done;
240 if (groupname[0] == '+') {
241 user_must_be_member = True;
242 groupname += 1;
245 groupname = talloc_string_sub(talloc_tos(), groupname,
246 "%S", lp_const_servicename(snum));
247 if (groupname == NULL) {
248 DEBUG(1, ("talloc_string_sub failed\n"));
249 result = NT_STATUS_NO_MEMORY;
250 goto done;
253 if (!lookup_name_smbconf(talloc_tos(), groupname,
254 LOOKUP_NAME_ALL|LOOKUP_NAME_GROUP,
255 NULL, NULL, &group_sid, &type)) {
256 DEBUG(10, ("lookup_name_smbconf(%s) failed\n",
257 groupname));
258 goto done;
261 if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
262 (type != SID_NAME_WKN_GRP)) {
263 DEBUG(10, ("%s is a %s, not a group\n", groupname,
264 sid_type_lookup(type)));
265 goto done;
268 if (!sid_to_gid(&group_sid, &gid)) {
269 struct dom_sid_buf buf;
270 DEBUG(10, ("sid_to_gid(%s) for %s failed\n",
271 dom_sid_str_buf(&group_sid, &buf), groupname));
272 goto done;
276 * If the user has been forced and the forced group starts with a '+',
277 * then we only set the group to be the forced group if the forced
278 * user is a member of that group. Otherwise, the meaning of the '+'
279 * would be ignored.
282 if (force_user && user_must_be_member) {
283 if (user_in_group_sid(username, &group_sid)) {
284 sid_copy(pgroup_sid, &group_sid);
285 *pgid = gid;
286 DEBUG(3,("Forced group %s for member %s\n",
287 groupname, username));
288 } else {
289 DEBUG(0,("find_forced_group: forced user %s is not a member "
290 "of forced group %s. Disallowing access.\n",
291 username, groupname ));
292 result = NT_STATUS_MEMBER_NOT_IN_GROUP;
293 goto done;
295 } else {
296 sid_copy(pgroup_sid, &group_sid);
297 *pgid = gid;
298 DEBUG(3,("Forced group %s\n", groupname));
301 result = NT_STATUS_OK;
302 done:
303 TALLOC_FREE(frame);
304 return result;
307 /****************************************************************************
308 Create an auth_session_info structure for a connection_struct
309 ****************************************************************************/
311 static NTSTATUS create_connection_session_info(struct smbd_server_connection *sconn,
312 TALLOC_CTX *mem_ctx, int snum,
313 struct auth_session_info *session_info,
314 struct auth_session_info **presult)
316 struct auth_session_info *result;
318 if (lp_guest_only(snum)) {
319 return make_session_info_guest(mem_ctx, presult);
323 * This is the normal security != share case where we have a
324 * valid vuid from the session setup. */
326 if (security_session_user_level(session_info, NULL) < SECURITY_USER) {
327 if (!lp_guest_ok(snum)) {
328 DBG_WARNING("guest user (from session setup) "
329 "not permitted to access this share "
330 "(%s)\n", lp_const_servicename(snum));
331 return NT_STATUS_ACCESS_DENIED;
333 } else {
334 if (!user_ok_token(session_info->unix_info->unix_name,
335 session_info->info->domain_name,
336 session_info->security_token, snum)) {
337 DBG_WARNING("user '%s' (from session setup) not "
338 "permitted to access this share "
339 "(%s)\n",
340 session_info->unix_info->unix_name,
341 lp_const_servicename(snum));
342 return NT_STATUS_ACCESS_DENIED;
346 result = copy_session_info(mem_ctx, session_info);
347 if (result == NULL) {
348 return NT_STATUS_NO_MEMORY;
351 *presult = result;
352 return NT_STATUS_OK;
355 /****************************************************************************
356 Set relevant user and group settings corresponding to force user/group
357 configuration for the given snum.
358 ****************************************************************************/
360 NTSTATUS set_conn_force_user_group(connection_struct *conn, int snum)
362 const struct loadparm_substitution *lp_sub =
363 loadparm_s3_global_substitution();
364 NTSTATUS status;
366 if (*lp_force_user(talloc_tos(), lp_sub, snum)) {
369 * Replace conn->session_info with a completely faked up one
370 * from the username we are forced into :-)
373 char *fuser;
374 char *sanitized_username;
375 struct auth_session_info *forced_serverinfo;
376 bool guest;
378 fuser = talloc_string_sub(conn, lp_force_user(talloc_tos(), lp_sub, snum), "%S",
379 lp_const_servicename(snum));
380 if (fuser == NULL) {
381 return NT_STATUS_NO_MEMORY;
384 guest = security_session_user_level(conn->session_info, NULL) < SECURITY_USER;
386 status = make_session_info_from_username(
387 conn, fuser,
388 guest,
389 &forced_serverinfo);
390 if (!NT_STATUS_IS_OK(status)) {
391 return status;
394 /* We don't want to replace the original sanitized_username
395 as it is the original user given in the connect attempt.
396 This is used in '%U' substitutions. */
397 sanitized_username = discard_const_p(char,
398 forced_serverinfo->unix_info->sanitized_username);
399 TALLOC_FREE(sanitized_username);
400 forced_serverinfo->unix_info->sanitized_username =
401 talloc_move(forced_serverinfo->unix_info,
402 &conn->session_info->unix_info->sanitized_username);
404 TALLOC_FREE(conn->session_info);
405 conn->session_info = forced_serverinfo;
407 conn->force_user = true;
408 DEBUG(3,("Forced user %s\n", fuser));
412 * If force group is true, then override
413 * any groupid stored for the connecting user.
416 if (*lp_force_group(talloc_tos(), lp_sub, snum)) {
418 status = find_forced_group(
419 conn->force_user, snum, conn->session_info->unix_info->unix_name,
420 &conn->session_info->security_token->sids[1],
421 &conn->session_info->unix_token->gid);
423 if (!NT_STATUS_IS_OK(status)) {
424 return status;
428 * We need to cache this gid, to use within
429 * change_to_user() separately from the conn->session_info
430 * struct. We only use conn->session_info directly if
431 * "force_user" was set.
433 conn->force_group_gid = conn->session_info->unix_token->gid;
436 return NT_STATUS_OK;
439 static NTSTATUS notify_init_sconn(struct smbd_server_connection *sconn)
441 NTSTATUS status;
443 if (sconn->notify_ctx != NULL) {
444 return NT_STATUS_OK;
447 sconn->notify_ctx = notify_init(sconn, sconn->msg_ctx,
448 sconn, notify_callback);
449 if (sconn->notify_ctx == NULL) {
450 return NT_STATUS_NO_MEMORY;
453 status = messaging_register(sconn->msg_ctx, sconn,
454 MSG_SMB_NOTIFY_CANCEL_DELETED,
455 smbd_notify_cancel_deleted);
456 if (!NT_STATUS_IS_OK(status)) {
457 DBG_DEBUG("messaging_register failed: %s\n",
458 nt_errstr(status));
459 TALLOC_FREE(sconn->notify_ctx);
460 return status;
463 status = messaging_register(sconn->msg_ctx, sconn,
464 MSG_SMB_NOTIFY_STARTED,
465 smbd_notifyd_restarted);
466 if (!NT_STATUS_IS_OK(status)) {
467 DBG_DEBUG("messaging_register failed: %s\n",
468 nt_errstr(status));
469 messaging_deregister(sconn->msg_ctx,
470 MSG_SMB_NOTIFY_CANCEL_DELETED, sconn);
471 TALLOC_FREE(sconn->notify_ctx);
472 return status;
475 return NT_STATUS_OK;
478 /****************************************************************************
479 Make a connection, given the snum to connect to, and the vuser of the
480 connecting user if appropriate.
481 ****************************************************************************/
483 NTSTATUS make_connection_snum(struct smbXsrv_connection *xconn,
484 connection_struct *conn,
485 int snum,
486 struct smbXsrv_session *session,
487 const char *pdev)
489 struct smbd_server_connection *sconn = xconn->client->sconn;
490 const struct loadparm_substitution *lp_sub =
491 loadparm_s3_global_substitution();
492 struct smb_filename *smb_fname_cpath = NULL;
493 fstring dev;
494 int ret;
495 bool on_err_call_dis_hook = false;
496 uid_t effuid;
497 gid_t effgid;
498 NTSTATUS status;
499 bool ok;
501 fstrcpy(dev, pdev);
503 status = share_sanity_checks(sconn->local_address,
504 sconn->remote_address,
505 sconn->remote_hostname,
506 snum,
507 dev);
508 if (NT_STATUS_IS_ERR(status)) {
509 goto err_root_exit;
512 conn->params->service = snum;
514 status = create_connection_session_info(sconn,
515 conn, snum, session->global->auth_session_info,
516 &conn->session_info);
518 if (!NT_STATUS_IS_OK(status)) {
519 DEBUG(1, ("create_connection_session_info failed: %s\n",
520 nt_errstr(status)));
521 goto err_root_exit;
524 if (lp_guest_only(snum)) {
525 conn->force_user = true;
528 conn->num_files_open = 0;
529 conn->lastused = conn->lastused_count = time(NULL);
530 conn->printer = (strncmp(dev,"LPT",3) == 0);
531 conn->ipc = ( (strncmp(dev,"IPC",3) == 0) ||
532 ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) );
534 /* Case options for the share. */
535 conn_setup_case_options(conn);
537 conn->encrypt_level = lp_server_smb_encrypt(snum);
538 if (conn->encrypt_level > SMB_ENCRYPTION_OFF) {
539 if (lp_server_smb_encrypt(-1) == SMB_ENCRYPTION_OFF) {
540 if (conn->encrypt_level == SMB_ENCRYPTION_REQUIRED) {
541 DBG_ERR("Service [%s] requires encryption, but "
542 "it is disabled globally!\n",
543 lp_const_servicename(snum));
544 status = NT_STATUS_ACCESS_DENIED;
545 goto err_root_exit;
547 conn->encrypt_level = SMB_ENCRYPTION_OFF;
551 conn->veto_list = NULL;
552 conn->hide_list = NULL;
553 conn->veto_oplock_list = NULL;
554 conn->aio_write_behind_list = NULL;
556 conn->read_only = lp_read_only(SNUM(conn));
558 status = set_conn_force_user_group(conn, snum);
559 if (!NT_STATUS_IS_OK(status)) {
560 goto err_root_exit;
563 conn->vuid = session->global->session_wire_id;
566 char *s = talloc_sub_full(talloc_tos(),
567 lp_const_servicename(SNUM(conn)),
568 conn->session_info->unix_info->unix_name,
569 conn->connectpath,
570 conn->session_info->unix_token->gid,
571 conn->session_info->unix_info->sanitized_username,
572 conn->session_info->info->domain_name,
573 lp_path(talloc_tos(), lp_sub, snum));
574 if (!s) {
575 status = NT_STATUS_NO_MEMORY;
576 goto err_root_exit;
579 if (!set_conn_connectpath(conn,s)) {
580 TALLOC_FREE(s);
581 status = NT_STATUS_NO_MEMORY;
582 goto err_root_exit;
584 DBG_NOTICE("Connect path is '%s' for service [%s]\n", s,
585 lp_const_servicename(snum));
586 TALLOC_FREE(s);
590 * Set up the share security descriptor.
591 * NOTE - we use the *INCOMING USER* session_info
592 * here, as does (indirectly) change_to_user(),
593 * which can be called on any incoming packet.
594 * This way we set up the share access based
595 * on the authenticated user, not the forced
596 * user. See bug:
598 * https://bugzilla.samba.org/show_bug.cgi?id=9878
601 status = check_user_share_access(conn,
602 session->global->auth_session_info,
603 &conn->share_access,
604 &conn->read_only);
605 if (!NT_STATUS_IS_OK(status)) {
606 goto err_root_exit;
609 /* Initialise VFS function pointers */
611 if (!smbd_vfs_init(conn)) {
612 DBG_ERR("vfs_init failed for service %s\n",
613 lp_const_servicename(snum));
614 status = NT_STATUS_BAD_NETWORK_NAME;
615 goto err_root_exit;
618 /* ROOT Activities: */
619 /* explicitly check widelinks here so that we can correctly warn
620 * in the logs. */
621 widelinks_warning(snum);
624 * Enforce the max connections parameter.
627 if ((lp_max_connections(snum) > 0)
628 && (count_current_connections(lp_const_servicename(SNUM(conn)), true) >=
629 lp_max_connections(snum))) {
631 DBG_WARNING("Max connections (%d) exceeded for %s\n",
632 lp_max_connections(snum),
633 lp_const_servicename(snum));
634 status = NT_STATUS_INSUFFICIENT_RESOURCES;
635 goto err_root_exit;
638 /* Invoke VFS make connection hook - this must be the first
639 filesystem operation that we do. */
641 if (SMB_VFS_CONNECT(conn, lp_const_servicename(snum),
642 conn->session_info->unix_info->unix_name) < 0) {
643 DBG_WARNING("SMB_VFS_CONNECT for service '%s' at '%s' failed: %s\n",
644 lp_const_servicename(snum), conn->connectpath,
645 strerror(errno));
646 status = NT_STATUS_UNSUCCESSFUL;
647 goto err_root_exit;
650 /* Any error exit after here needs to call the disconnect hook. */
651 on_err_call_dis_hook = true;
653 if ((!conn->printer) && (!conn->ipc) &&
654 lp_change_notify()) {
656 status = notify_init_sconn(sconn);
657 if (!NT_STATUS_IS_OK(status)) {
658 goto err_root_exit;
662 if (lp_kernel_oplocks(snum)) {
663 init_kernel_oplocks(conn->sconn);
667 * Fix compatibility issue pointed out by Volker.
668 * We pass the conn->connectpath to the preexec
669 * scripts as a parameter, so attempt to canonicalize
670 * it here before calling the preexec scripts.
671 * We ignore errors here, as it is possible that
672 * the conn->connectpath doesn't exist yet and
673 * the preexec scripts will create them.
676 (void)canonicalize_connect_path(conn);
678 /* Preexecs are done here as they might make the dir we are to ChDir
679 * to below */
680 /* execute any "root preexec = " line */
681 if (*lp_root_preexec(talloc_tos(), lp_sub, snum)) {
682 char *cmd = talloc_sub_full(talloc_tos(),
683 lp_const_servicename(SNUM(conn)),
684 conn->session_info->unix_info->unix_name,
685 conn->connectpath,
686 conn->session_info->unix_token->gid,
687 conn->session_info->unix_info->sanitized_username,
688 conn->session_info->info->domain_name,
689 lp_root_preexec(talloc_tos(), lp_sub, snum));
690 DEBUG(5,("cmd=%s\n",cmd));
691 ret = smbrun(cmd, NULL, NULL);
692 TALLOC_FREE(cmd);
693 if (ret != 0 && lp_root_preexec_close(snum)) {
694 DEBUG(1,("root preexec gave %d - failing "
695 "connection\n", ret));
696 status = NT_STATUS_ACCESS_DENIED;
697 goto err_root_exit;
701 /* USER Activites: */
702 if (!change_to_user_and_service(conn, conn->vuid)) {
703 /* No point continuing if they fail the basic checks */
704 DEBUG(0,("Can't become connected user!\n"));
705 status = NT_STATUS_LOGON_FAILURE;
706 goto err_root_exit;
709 effuid = geteuid();
710 effgid = getegid();
712 /* Remember that a different vuid can connect later without these
713 * checks... */
715 /* Preexecs are done here as they might make the dir we are to ChDir
716 * to below */
718 /* execute any "preexec = " line */
719 if (*lp_preexec(talloc_tos(), lp_sub, snum)) {
720 char *cmd = talloc_sub_full(talloc_tos(),
721 lp_const_servicename(SNUM(conn)),
722 conn->session_info->unix_info->unix_name,
723 conn->connectpath,
724 conn->session_info->unix_token->gid,
725 conn->session_info->unix_info->sanitized_username,
726 conn->session_info->info->domain_name,
727 lp_preexec(talloc_tos(), lp_sub, snum));
728 ret = smbrun(cmd, NULL, NULL);
729 TALLOC_FREE(cmd);
730 if (ret != 0 && lp_preexec_close(snum)) {
731 DEBUG(1,("preexec gave %d - failing connection\n",
732 ret));
733 status = NT_STATUS_ACCESS_DENIED;
734 goto err_root_exit;
738 #ifdef WITH_FAKE_KASERVER
739 if (lp_afs_share(snum)) {
740 afs_login(conn);
742 #endif
745 * we've finished with the user stuff - go back to root
746 * so the SMB_VFS_STAT call will only fail on path errors,
747 * not permission problems.
749 change_to_root_user();
750 /* ROOT Activites: */
753 * Canonicalise the connect
754 * path here to ensure we don't have any symlinks in the
755 * connectpath. We will be checking all paths on this connection are
756 * below this directory. We must do this after the VFS init as we
757 * depend on the realpath() pointer in the vfs table. JRA.
759 ok = canonicalize_connect_path(conn);
760 if (!ok) {
761 DBG_ERR("canonicalize_connect_path failed "
762 "for service %s, path %s\n",
763 lp_const_servicename(snum),
764 conn->connectpath);
765 status = NT_STATUS_BAD_NETWORK_NAME;
766 goto err_root_exit;
769 /* Add veto/hide lists */
770 if (!IS_IPC(conn) && !IS_PRINT(conn)) {
771 set_namearray( &conn->veto_list,
772 lp_veto_files(talloc_tos(), lp_sub, snum));
773 set_namearray( &conn->hide_list,
774 lp_hide_files(talloc_tos(), lp_sub, snum));
775 set_namearray( &conn->veto_oplock_list,
776 lp_veto_oplock_files(talloc_tos(), lp_sub, snum));
777 set_namearray( &conn->aio_write_behind_list,
778 lp_aio_write_behind(talloc_tos(), lp_sub, snum));
780 smb_fname_cpath = synthetic_smb_fname(talloc_tos(),
781 conn->connectpath,
782 NULL,
783 NULL,
786 if (smb_fname_cpath == NULL) {
787 status = NT_STATUS_NO_MEMORY;
788 goto err_root_exit;
791 /* win2000 does not check the permissions on the directory
792 during the tree connect, instead relying on permission
793 check during individual operations. To match this behaviour
794 I have disabled this chdir check (tridge) */
795 /* the alternative is just to check the directory exists */
797 if ((ret = SMB_VFS_STAT(conn, smb_fname_cpath)) != 0 ||
798 !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
799 if (ret == 0 && !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
800 DBG_ERR("'%s' is not a directory, when connecting to "
801 "[%s]\n", conn->connectpath,
802 lp_const_servicename(snum));
803 } else {
804 DBG_ERR("'%s' does not exist or permission denied "
805 "when connecting to [%s] Error was %s\n",
806 conn->connectpath,
807 lp_const_servicename(snum),
808 strerror(errno));
810 status = NT_STATUS_BAD_NETWORK_NAME;
811 goto err_root_exit;
813 conn->base_share_dev = smb_fname_cpath->st.st_ex_dev;
815 /* Figure out the characteristics of the underlying filesystem. This
816 * assumes that all the filesystem mounted within a share path have
817 * the same characteristics, which is likely but not guaranteed.
820 if(!IS_IPC(conn) ){
821 conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
824 * Print out the 'connected as' stuff here as we need
825 * to know the effective uid and gid we will be using
826 * (at least initially).
829 if( DEBUGLVL( IS_IPC(conn) ? 3 : 2 ) ) {
830 bool signing_active;
832 dbgtext( "%s (%s) ", get_remote_machine_name(),
833 tsocket_address_string(conn->sconn->remote_address,
834 talloc_tos()) );
835 #if defined(WITH_SMB1SERVER)
836 if (sconn->using_smb2) {
837 #endif
838 signing_active = smb2_signing_key_valid(
839 session->global->encryption_key);
840 #if defined(WITH_SMB1SERVER)
841 } else {
842 signing_active = smb1_srv_is_signing_active(xconn);
844 #endif
845 dbgtext( "%s", signing_active ? "signed " : "");
846 dbgtext( "connect to service %s ",
847 lp_const_servicename(snum) );
848 dbgtext( "initially as user %s ",
849 conn->session_info->unix_info->unix_name );
850 dbgtext( "(uid=%d, gid=%d) ", (int)effuid, (int)effgid );
851 dbgtext( "(pid %d)\n", (int)getpid() );
854 conn->tcon_done = true;
855 return NT_STATUS_OK;
857 err_root_exit:
859 TALLOC_FREE(smb_fname_cpath);
860 /* We must exit this function as root. */
861 if (geteuid() != 0) {
862 change_to_root_user();
864 if (on_err_call_dis_hook) {
865 /* Call VFS disconnect hook */
866 SMB_VFS_DISCONNECT(conn);
868 return status;
871 /****************************************************************************
872 Make a connection to a service from SMB2. External SMB2 interface.
873 We must set cnum before claiming connection.
874 ****************************************************************************/
876 connection_struct *make_connection_smb2(struct smbd_smb2_request *req,
877 struct smbXsrv_tcon *tcon,
878 int snum,
879 const char *pdev,
880 NTSTATUS *pstatus)
882 struct smbd_server_connection *sconn = req->sconn;
883 connection_struct *conn = conn_new(sconn);
884 if (!conn) {
885 DEBUG(0,("make_connection_smb2: Couldn't find free connection.\n"));
886 *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
887 return NULL;
890 conn->cnum = tcon->global->tcon_wire_id;
891 conn->tcon = tcon;
893 *pstatus = make_connection_snum(req->xconn,
894 conn,
895 snum,
896 req->session,
897 pdev);
898 if (!NT_STATUS_IS_OK(*pstatus)) {
899 conn_free(conn);
900 return NULL;
902 return conn;
905 /****************************************************************************
906 Close a cnum.
907 ****************************************************************************/
909 void close_cnum(connection_struct *conn,
910 uint64_t vuid,
911 enum file_close_type close_type)
913 char rootpath[2] = { '/', '\0'};
914 struct smb_filename root_fname = { .base_name = rootpath };
915 const struct loadparm_substitution *lp_sub =
916 loadparm_s3_global_substitution();
918 file_close_conn(conn, close_type);
920 change_to_root_user();
922 DEBUG(IS_IPC(conn)?3:2, ("%s (%s) closed connection to service %s\n",
923 get_remote_machine_name(),
924 tsocket_address_string(conn->sconn->remote_address,
925 talloc_tos()),
926 lp_const_servicename(SNUM(conn))));
928 /* make sure we leave the directory available for unmount */
929 vfs_ChDir(conn, &root_fname);
931 /* Call VFS disconnect hook */
932 SMB_VFS_DISCONNECT(conn);
934 /* execute any "postexec = " line */
935 if (*lp_postexec(talloc_tos(), lp_sub, SNUM(conn)) &&
936 change_to_user_and_service(conn, vuid)) {
937 char *cmd = talloc_sub_full(talloc_tos(),
938 lp_const_servicename(SNUM(conn)),
939 conn->session_info->unix_info->unix_name,
940 conn->connectpath,
941 conn->session_info->unix_token->gid,
942 conn->session_info->unix_info->sanitized_username,
943 conn->session_info->info->domain_name,
944 lp_postexec(talloc_tos(), lp_sub, SNUM(conn)));
945 smbrun(cmd, NULL, NULL);
946 TALLOC_FREE(cmd);
947 change_to_root_user();
950 change_to_root_user();
951 /* execute any "root postexec = " line */
952 if (*lp_root_postexec(talloc_tos(), lp_sub, SNUM(conn))) {
953 char *cmd = talloc_sub_full(talloc_tos(),
954 lp_const_servicename(SNUM(conn)),
955 conn->session_info->unix_info->unix_name,
956 conn->connectpath,
957 conn->session_info->unix_token->gid,
958 conn->session_info->unix_info->sanitized_username,
959 conn->session_info->info->domain_name,
960 lp_root_postexec(talloc_tos(), lp_sub, SNUM(conn)));
961 smbrun(cmd, NULL, NULL);
962 TALLOC_FREE(cmd);
965 conn_free(conn);