s3: libsmb: In cli_qpathinfo_send() (SMBtrans2:TRANSACT2_QPATHINFO) check for DFS...
[Samba.git] / source3 / smbd / smb2_service.c
blob5affea6b3e4267e370a57e786ed437705989b1e0
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 /****************************************************************************
94 Load parameters specific to a connection/service.
95 ****************************************************************************/
97 void set_current_case_sensitive(connection_struct *conn, uint16_t flags)
99 int snum;
100 enum remote_arch_types ra_type;
102 SMB_ASSERT(conn != NULL);
104 snum = SNUM(conn);
106 if ((conn == last_conn) && (last_flags == flags)) {
107 return;
110 last_conn = conn;
111 last_flags = flags;
114 * Obey the client case sensitivity requests - only for clients that
115 * support it. */
116 switch (lp_case_sensitive(snum)) {
117 case Auto:
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
127 * pathnames. */
128 conn->case_sensitive = false;
129 } else {
130 conn->case_sensitive =
131 !(flags & FLAG_CASELESS_PATHNAMES);
133 break;
134 case True:
135 conn->case_sensitive = true;
136 break;
137 default:
138 conn->case_sensitive = false;
139 break;
141 return;
144 bool chdir_current_service(connection_struct *conn)
146 const struct smb_filename connectpath_fname = {
147 .base_name = conn->connectpath,
149 int saved_errno = 0;
150 char *utok_str = NULL;
151 int ret;
153 conn->lastused_count++;
155 ret = vfs_ChDir(conn, &connectpath_fname);
156 if (ret == 0) {
157 return true;
159 saved_errno = errno;
161 utok_str = utok_string(talloc_tos(),
162 conn->session_info->unix_token);
163 if (utok_str == NULL) {
164 errno = saved_errno;
165 return false;
168 DBG_ERR("vfs_ChDir(%s) failed: %s. Current token: %s\n",
169 conn->connectpath,
170 strerror(saved_errno),
171 utok_str);
173 if (saved_errno != 0) {
174 errno = saved_errno;
176 return false;
179 /****************************************************************************
180 do some basic sainity checks on the share.
181 This function modifies dev, ecode.
182 ****************************************************************************/
184 static NTSTATUS share_sanity_checks(const struct tsocket_address *remote_address,
185 const char *rhost,
186 int snum,
187 fstring dev)
189 char *raddr;
191 raddr = tsocket_address_inet_addr_string(remote_address,
192 talloc_tos());
193 if (raddr == NULL) {
194 return NT_STATUS_NO_MEMORY;
197 if (!lp_snum_ok(snum) ||
198 !allow_access(lp_hosts_deny(snum), lp_hosts_allow(snum),
199 rhost, raddr)) {
200 return NT_STATUS_ACCESS_DENIED;
203 if (dev[0] == '?' || !dev[0]) {
204 if (lp_printable(snum)) {
205 fstrcpy(dev,"LPT1:");
206 } else if (strequal(lp_fstype(snum), "IPC")) {
207 fstrcpy(dev, "IPC");
208 } else {
209 fstrcpy(dev,"A:");
213 if (!strupper_m(dev)) {
214 DEBUG(2,("strupper_m %s failed\n", dev));
215 return NT_STATUS_INVALID_PARAMETER;
218 if (lp_printable(snum)) {
219 if (!strequal(dev, "LPT1:")) {
220 return NT_STATUS_BAD_DEVICE_TYPE;
222 } else if (strequal(lp_fstype(snum), "IPC")) {
223 if (!strequal(dev, "IPC")) {
224 return NT_STATUS_BAD_DEVICE_TYPE;
226 } else if (!strequal(dev, "A:")) {
227 return NT_STATUS_BAD_DEVICE_TYPE;
230 /* Behave as a printer if we are supposed to */
231 if (lp_printable(snum) && (strcmp(dev, "A:") == 0)) {
232 fstrcpy(dev, "LPT1:");
235 return NT_STATUS_OK;
239 * Go through lookup_name etc to find the force'd group.
241 * Create a new token from src_token, replacing the primary group sid with the
242 * one found.
245 static NTSTATUS find_forced_group(bool force_user,
246 int snum, const char *username,
247 struct dom_sid *pgroup_sid,
248 gid_t *pgid)
250 NTSTATUS result = NT_STATUS_NO_SUCH_GROUP;
251 TALLOC_CTX *frame = talloc_stackframe();
252 const struct loadparm_substitution *lp_sub =
253 loadparm_s3_global_substitution();
254 struct dom_sid group_sid;
255 enum lsa_SidType type;
256 char *groupname;
257 bool user_must_be_member = False;
258 gid_t gid;
260 groupname = lp_force_group(talloc_tos(), lp_sub, snum);
261 if (groupname == NULL) {
262 DEBUG(1, ("talloc_strdup failed\n"));
263 result = NT_STATUS_NO_MEMORY;
264 goto done;
267 if (groupname[0] == '+') {
268 user_must_be_member = True;
269 groupname += 1;
272 groupname = talloc_string_sub(talloc_tos(), groupname,
273 "%S", lp_const_servicename(snum));
274 if (groupname == NULL) {
275 DEBUG(1, ("talloc_string_sub failed\n"));
276 result = NT_STATUS_NO_MEMORY;
277 goto done;
280 if (!lookup_name_smbconf(talloc_tos(), groupname,
281 LOOKUP_NAME_ALL|LOOKUP_NAME_GROUP,
282 NULL, NULL, &group_sid, &type)) {
283 DEBUG(10, ("lookup_name_smbconf(%s) failed\n",
284 groupname));
285 goto done;
288 if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
289 (type != SID_NAME_WKN_GRP)) {
290 DEBUG(10, ("%s is a %s, not a group\n", groupname,
291 sid_type_lookup(type)));
292 goto done;
295 if (!sid_to_gid(&group_sid, &gid)) {
296 struct dom_sid_buf buf;
297 DEBUG(10, ("sid_to_gid(%s) for %s failed\n",
298 dom_sid_str_buf(&group_sid, &buf), groupname));
299 goto done;
303 * If the user has been forced and the forced group starts with a '+',
304 * then we only set the group to be the forced group if the forced
305 * user is a member of that group. Otherwise, the meaning of the '+'
306 * would be ignored.
309 if (force_user && user_must_be_member) {
310 if (user_in_group_sid(username, &group_sid)) {
311 sid_copy(pgroup_sid, &group_sid);
312 *pgid = gid;
313 DEBUG(3,("Forced group %s for member %s\n",
314 groupname, username));
315 } else {
316 DEBUG(0,("find_forced_group: forced user %s is not a member "
317 "of forced group %s. Disallowing access.\n",
318 username, groupname ));
319 result = NT_STATUS_MEMBER_NOT_IN_GROUP;
320 goto done;
322 } else {
323 sid_copy(pgroup_sid, &group_sid);
324 *pgid = gid;
325 DEBUG(3,("Forced group %s\n", groupname));
328 result = NT_STATUS_OK;
329 done:
330 TALLOC_FREE(frame);
331 return result;
334 /****************************************************************************
335 Create an auth_session_info structure for a connection_struct
336 ****************************************************************************/
338 static NTSTATUS create_connection_session_info(struct smbd_server_connection *sconn,
339 TALLOC_CTX *mem_ctx, int snum,
340 struct auth_session_info *session_info,
341 struct auth_session_info **presult)
343 struct auth_session_info *result;
345 if (lp_guest_only(snum)) {
346 return make_session_info_guest(mem_ctx, presult);
350 * This is the normal security != share case where we have a
351 * valid vuid from the session setup. */
353 if (security_session_user_level(session_info, NULL) < SECURITY_USER) {
354 if (!lp_guest_ok(snum)) {
355 DBG_WARNING("guest user (from session setup) "
356 "not permitted to access this share "
357 "(%s)\n", lp_const_servicename(snum));
358 return NT_STATUS_ACCESS_DENIED;
360 } else {
361 if (!user_ok_token(session_info->unix_info->unix_name,
362 session_info->info->domain_name,
363 session_info->security_token, snum)) {
364 DBG_WARNING("user '%s' (from session setup) not "
365 "permitted to access this share "
366 "(%s)\n",
367 session_info->unix_info->unix_name,
368 lp_const_servicename(snum));
369 return NT_STATUS_ACCESS_DENIED;
373 result = copy_session_info(mem_ctx, session_info);
374 if (result == NULL) {
375 return NT_STATUS_NO_MEMORY;
378 *presult = result;
379 return NT_STATUS_OK;
382 /****************************************************************************
383 Set relevant user and group settings corresponding to force user/group
384 configuration for the given snum.
385 ****************************************************************************/
387 NTSTATUS set_conn_force_user_group(connection_struct *conn, int snum)
389 const struct loadparm_substitution *lp_sub =
390 loadparm_s3_global_substitution();
391 NTSTATUS status;
393 if (*lp_force_user(talloc_tos(), lp_sub, snum)) {
396 * Replace conn->session_info with a completely faked up one
397 * from the username we are forced into :-)
400 char *fuser;
401 char *sanitized_username;
402 struct auth_session_info *forced_serverinfo;
403 bool guest;
405 fuser = talloc_string_sub(conn, lp_force_user(talloc_tos(), lp_sub, snum), "%S",
406 lp_const_servicename(snum));
407 if (fuser == NULL) {
408 return NT_STATUS_NO_MEMORY;
411 guest = security_session_user_level(conn->session_info, NULL) < SECURITY_USER;
413 status = make_session_info_from_username(
414 conn, fuser,
415 guest,
416 &forced_serverinfo);
417 if (!NT_STATUS_IS_OK(status)) {
418 return status;
421 /* We don't want to replace the original sanitized_username
422 as it is the original user given in the connect attempt.
423 This is used in '%U' substitutions. */
424 sanitized_username = discard_const_p(char,
425 forced_serverinfo->unix_info->sanitized_username);
426 TALLOC_FREE(sanitized_username);
427 forced_serverinfo->unix_info->sanitized_username =
428 talloc_move(forced_serverinfo->unix_info,
429 &conn->session_info->unix_info->sanitized_username);
431 TALLOC_FREE(conn->session_info);
432 conn->session_info = forced_serverinfo;
434 conn->force_user = true;
435 DEBUG(3,("Forced user %s\n", fuser));
439 * If force group is true, then override
440 * any groupid stored for the connecting user.
443 if (*lp_force_group(talloc_tos(), lp_sub, snum)) {
445 status = find_forced_group(
446 conn->force_user, snum, conn->session_info->unix_info->unix_name,
447 &conn->session_info->security_token->sids[1],
448 &conn->session_info->unix_token->gid);
450 if (!NT_STATUS_IS_OK(status)) {
451 return status;
455 * We need to cache this gid, to use within
456 * change_to_user() separately from the conn->session_info
457 * struct. We only use conn->session_info directly if
458 * "force_user" was set.
460 conn->force_group_gid = conn->session_info->unix_token->gid;
463 return NT_STATUS_OK;
466 static NTSTATUS notify_init_sconn(struct smbd_server_connection *sconn)
468 NTSTATUS status;
470 if (sconn->notify_ctx != NULL) {
471 return NT_STATUS_OK;
474 sconn->notify_ctx = notify_init(sconn, sconn->msg_ctx,
475 sconn, notify_callback);
476 if (sconn->notify_ctx == NULL) {
477 return NT_STATUS_NO_MEMORY;
480 status = messaging_register(sconn->msg_ctx, sconn,
481 MSG_SMB_NOTIFY_CANCEL_DELETED,
482 smbd_notify_cancel_deleted);
483 if (!NT_STATUS_IS_OK(status)) {
484 DBG_DEBUG("messaging_register failed: %s\n",
485 nt_errstr(status));
486 TALLOC_FREE(sconn->notify_ctx);
487 return status;
490 status = messaging_register(sconn->msg_ctx, sconn,
491 MSG_SMB_NOTIFY_STARTED,
492 smbd_notifyd_restarted);
493 if (!NT_STATUS_IS_OK(status)) {
494 DBG_DEBUG("messaging_register failed: %s\n",
495 nt_errstr(status));
496 messaging_deregister(sconn->msg_ctx,
497 MSG_SMB_NOTIFY_CANCEL_DELETED, sconn);
498 TALLOC_FREE(sconn->notify_ctx);
499 return status;
502 return NT_STATUS_OK;
505 /****************************************************************************
506 Make a connection, given the snum to connect to, and the vuser of the
507 connecting user if appropriate.
508 ****************************************************************************/
510 NTSTATUS make_connection_snum(struct smbXsrv_connection *xconn,
511 connection_struct *conn,
512 int snum,
513 struct smbXsrv_session *session,
514 const char *pdev)
516 struct smbd_server_connection *sconn = xconn->client->sconn;
517 const struct loadparm_substitution *lp_sub =
518 loadparm_s3_global_substitution();
519 struct smb_filename *smb_fname_cpath = NULL;
520 fstring dev;
521 int ret;
522 bool on_err_call_dis_hook = false;
523 uid_t effuid;
524 gid_t effgid;
525 NTSTATUS status;
526 bool ok;
528 fstrcpy(dev, pdev);
530 status = share_sanity_checks(sconn->remote_address,
531 sconn->remote_hostname,
532 snum,
533 dev);
534 if (NT_STATUS_IS_ERR(status)) {
535 goto err_root_exit;
538 conn->params->service = snum;
540 status = create_connection_session_info(sconn,
541 conn, snum, session->global->auth_session_info,
542 &conn->session_info);
544 if (!NT_STATUS_IS_OK(status)) {
545 DEBUG(1, ("create_connection_session_info failed: %s\n",
546 nt_errstr(status)));
547 goto err_root_exit;
550 if (lp_guest_only(snum)) {
551 conn->force_user = true;
554 conn->num_files_open = 0;
555 conn->lastused = conn->lastused_count = time(NULL);
556 conn->printer = (strncmp(dev,"LPT",3) == 0);
557 conn->ipc = ( (strncmp(dev,"IPC",3) == 0) ||
558 ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) );
560 /* Case options for the share. */
561 conn_setup_case_options(conn);
563 conn->encrypt_level = lp_server_smb_encrypt(snum);
564 if (conn->encrypt_level > SMB_ENCRYPTION_OFF) {
565 if (lp_server_smb_encrypt(-1) == SMB_ENCRYPTION_OFF) {
566 if (conn->encrypt_level == SMB_ENCRYPTION_REQUIRED) {
567 DBG_ERR("Service [%s] requires encryption, but "
568 "it is disabled globally!\n",
569 lp_const_servicename(snum));
570 status = NT_STATUS_ACCESS_DENIED;
571 goto err_root_exit;
573 conn->encrypt_level = SMB_ENCRYPTION_OFF;
577 conn->veto_list = NULL;
578 conn->hide_list = NULL;
579 conn->veto_oplock_list = NULL;
580 conn->aio_write_behind_list = NULL;
582 conn->read_only = lp_read_only(SNUM(conn));
584 status = set_conn_force_user_group(conn, snum);
585 if (!NT_STATUS_IS_OK(status)) {
586 goto err_root_exit;
589 conn->vuid = session->global->session_wire_id;
592 char *s = talloc_sub_full(talloc_tos(),
593 lp_const_servicename(SNUM(conn)),
594 conn->session_info->unix_info->unix_name,
595 conn->connectpath,
596 conn->session_info->unix_token->gid,
597 conn->session_info->unix_info->sanitized_username,
598 conn->session_info->info->domain_name,
599 lp_path(talloc_tos(), lp_sub, snum));
600 if (!s) {
601 status = NT_STATUS_NO_MEMORY;
602 goto err_root_exit;
605 if (!set_conn_connectpath(conn,s)) {
606 TALLOC_FREE(s);
607 status = NT_STATUS_NO_MEMORY;
608 goto err_root_exit;
610 DBG_NOTICE("Connect path is '%s' for service [%s]\n", s,
611 lp_const_servicename(snum));
612 TALLOC_FREE(s);
616 * Set up the share security descriptor.
617 * NOTE - we use the *INCOMING USER* session_info
618 * here, as does (indirectly) change_to_user(),
619 * which can be called on any incoming packet.
620 * This way we set up the share access based
621 * on the authenticated user, not the forced
622 * user. See bug:
624 * https://bugzilla.samba.org/show_bug.cgi?id=9878
627 status = check_user_share_access(conn,
628 session->global->auth_session_info,
629 &conn->share_access,
630 &conn->read_only);
631 if (!NT_STATUS_IS_OK(status)) {
632 goto err_root_exit;
635 /* Initialise VFS function pointers */
637 if (!smbd_vfs_init(conn)) {
638 DBG_ERR("vfs_init failed for service %s\n",
639 lp_const_servicename(snum));
640 status = NT_STATUS_BAD_NETWORK_NAME;
641 goto err_root_exit;
644 /* ROOT Activities: */
645 /* explicitly check widelinks here so that we can correctly warn
646 * in the logs. */
647 widelinks_warning(snum);
650 * Enforce the max connections parameter.
653 if ((lp_max_connections(snum) > 0)
654 && (count_current_connections(lp_const_servicename(SNUM(conn)), true) >=
655 lp_max_connections(snum))) {
657 DBG_WARNING("Max connections (%d) exceeded for %s\n",
658 lp_max_connections(snum),
659 lp_const_servicename(snum));
660 status = NT_STATUS_INSUFFICIENT_RESOURCES;
661 goto err_root_exit;
664 /* Invoke VFS make connection hook - this must be the first
665 filesystem operation that we do. */
667 if (SMB_VFS_CONNECT(conn, lp_const_servicename(snum),
668 conn->session_info->unix_info->unix_name) < 0) {
669 DBG_WARNING("SMB_VFS_CONNECT for service '%s' at '%s' failed: %s\n",
670 lp_const_servicename(snum), conn->connectpath,
671 strerror(errno));
672 status = NT_STATUS_UNSUCCESSFUL;
673 goto err_root_exit;
676 /* Any error exit after here needs to call the disconnect hook. */
677 on_err_call_dis_hook = true;
679 if ((!conn->printer) && (!conn->ipc) &&
680 lp_change_notify()) {
682 status = notify_init_sconn(sconn);
683 if (!NT_STATUS_IS_OK(status)) {
684 goto err_root_exit;
688 if (lp_kernel_oplocks(snum)) {
689 init_kernel_oplocks(conn->sconn);
693 * Fix compatibility issue pointed out by Volker.
694 * We pass the conn->connectpath to the preexec
695 * scripts as a parameter, so attempt to canonicalize
696 * it here before calling the preexec scripts.
697 * We ignore errors here, as it is possible that
698 * the conn->connectpath doesn't exist yet and
699 * the preexec scripts will create them.
702 (void)canonicalize_connect_path(conn);
704 /* Preexecs are done here as they might make the dir we are to ChDir
705 * to below */
706 /* execute any "root preexec = " line */
707 if (*lp_root_preexec(talloc_tos(), lp_sub, snum)) {
708 char *cmd = talloc_sub_full(talloc_tos(),
709 lp_const_servicename(SNUM(conn)),
710 conn->session_info->unix_info->unix_name,
711 conn->connectpath,
712 conn->session_info->unix_token->gid,
713 conn->session_info->unix_info->sanitized_username,
714 conn->session_info->info->domain_name,
715 lp_root_preexec(talloc_tos(), lp_sub, snum));
716 DEBUG(5,("cmd=%s\n",cmd));
717 ret = smbrun(cmd, NULL, NULL);
718 TALLOC_FREE(cmd);
719 if (ret != 0 && lp_root_preexec_close(snum)) {
720 DEBUG(1,("root preexec gave %d - failing "
721 "connection\n", ret));
722 status = NT_STATUS_ACCESS_DENIED;
723 goto err_root_exit;
727 /* USER Activites: */
728 if (!change_to_user_and_service(conn, conn->vuid)) {
729 /* No point continuing if they fail the basic checks */
730 DEBUG(0,("Can't become connected user!\n"));
731 status = NT_STATUS_LOGON_FAILURE;
732 goto err_root_exit;
735 effuid = geteuid();
736 effgid = getegid();
738 /* Remember that a different vuid can connect later without these
739 * checks... */
741 /* Preexecs are done here as they might make the dir we are to ChDir
742 * to below */
744 /* execute any "preexec = " line */
745 if (*lp_preexec(talloc_tos(), lp_sub, snum)) {
746 char *cmd = talloc_sub_full(talloc_tos(),
747 lp_const_servicename(SNUM(conn)),
748 conn->session_info->unix_info->unix_name,
749 conn->connectpath,
750 conn->session_info->unix_token->gid,
751 conn->session_info->unix_info->sanitized_username,
752 conn->session_info->info->domain_name,
753 lp_preexec(talloc_tos(), lp_sub, snum));
754 ret = smbrun(cmd, NULL, NULL);
755 TALLOC_FREE(cmd);
756 if (ret != 0 && lp_preexec_close(snum)) {
757 DEBUG(1,("preexec gave %d - failing connection\n",
758 ret));
759 status = NT_STATUS_ACCESS_DENIED;
760 goto err_root_exit;
764 #ifdef WITH_FAKE_KASERVER
765 if (lp_afs_share(snum)) {
766 afs_login(conn);
768 #endif
771 * we've finished with the user stuff - go back to root
772 * so the SMB_VFS_STAT call will only fail on path errors,
773 * not permission problems.
775 change_to_root_user();
776 /* ROOT Activites: */
779 * Canonicalise the connect
780 * path here to ensure we don't have any symlinks in the
781 * connectpath. We will be checking all paths on this connection are
782 * below this directory. We must do this after the VFS init as we
783 * depend on the realpath() pointer in the vfs table. JRA.
785 ok = canonicalize_connect_path(conn);
786 if (!ok) {
787 DBG_ERR("canonicalize_connect_path failed "
788 "for service %s, path %s\n",
789 lp_const_servicename(snum),
790 conn->connectpath);
791 status = NT_STATUS_BAD_NETWORK_NAME;
792 goto err_root_exit;
795 /* Add veto/hide lists */
796 if (!IS_IPC(conn) && !IS_PRINT(conn)) {
797 set_namearray( &conn->veto_list,
798 lp_veto_files(talloc_tos(), lp_sub, snum));
799 set_namearray( &conn->hide_list,
800 lp_hide_files(talloc_tos(), lp_sub, snum));
801 set_namearray( &conn->veto_oplock_list,
802 lp_veto_oplock_files(talloc_tos(), lp_sub, snum));
803 set_namearray( &conn->aio_write_behind_list,
804 lp_aio_write_behind(talloc_tos(), lp_sub, snum));
806 smb_fname_cpath = synthetic_smb_fname(talloc_tos(),
807 conn->connectpath,
808 NULL,
809 NULL,
812 if (smb_fname_cpath == NULL) {
813 status = NT_STATUS_NO_MEMORY;
814 goto err_root_exit;
817 /* win2000 does not check the permissions on the directory
818 during the tree connect, instead relying on permission
819 check during individual operations. To match this behaviour
820 I have disabled this chdir check (tridge) */
821 /* the alternative is just to check the directory exists */
823 if ((ret = SMB_VFS_STAT(conn, smb_fname_cpath)) != 0 ||
824 !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
825 if (ret == 0 && !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
826 DBG_ERR("'%s' is not a directory, when connecting to "
827 "[%s]\n", conn->connectpath,
828 lp_const_servicename(snum));
829 } else {
830 DBG_ERR("'%s' does not exist or permission denied "
831 "when connecting to [%s] Error was %s\n",
832 conn->connectpath,
833 lp_const_servicename(snum),
834 strerror(errno));
836 status = NT_STATUS_BAD_NETWORK_NAME;
837 goto err_root_exit;
839 conn->base_share_dev = smb_fname_cpath->st.st_ex_dev;
841 /* Figure out the characteristics of the underlying filesystem. This
842 * assumes that all the filesystem mounted within a share path have
843 * the same characteristics, which is likely but not guaranteed.
846 if(!IS_IPC(conn) ){
847 conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
850 * Print out the 'connected as' stuff here as we need
851 * to know the effective uid and gid we will be using
852 * (at least initially).
855 if( DEBUGLVL( IS_IPC(conn) ? 3 : 2 ) ) {
856 bool signing_active;
858 dbgtext( "%s (%s) ", get_remote_machine_name(),
859 tsocket_address_string(conn->sconn->remote_address,
860 talloc_tos()) );
861 #if defined(WITH_SMB1SERVER)
862 if (sconn->using_smb2) {
863 #endif
864 signing_active = smb2_signing_key_valid(
865 session->global->encryption_key);
866 #if defined(WITH_SMB1SERVER)
867 } else {
868 signing_active = smb1_srv_is_signing_active(xconn);
870 #endif
871 dbgtext( "%s", signing_active ? "signed " : "");
872 dbgtext( "connect to service %s ",
873 lp_const_servicename(snum) );
874 dbgtext( "initially as user %s ",
875 conn->session_info->unix_info->unix_name );
876 dbgtext( "(uid=%d, gid=%d) ", (int)effuid, (int)effgid );
877 dbgtext( "(pid %d)\n", (int)getpid() );
880 conn->tcon_done = true;
881 return NT_STATUS_OK;
883 err_root_exit:
885 TALLOC_FREE(smb_fname_cpath);
886 /* We must exit this function as root. */
887 if (geteuid() != 0) {
888 change_to_root_user();
890 if (on_err_call_dis_hook) {
891 /* Call VFS disconnect hook */
892 SMB_VFS_DISCONNECT(conn);
894 return status;
897 /****************************************************************************
898 Make a connection to a service from SMB2. External SMB2 interface.
899 We must set cnum before claiming connection.
900 ****************************************************************************/
902 connection_struct *make_connection_smb2(struct smbd_smb2_request *req,
903 struct smbXsrv_tcon *tcon,
904 int snum,
905 const char *pdev,
906 NTSTATUS *pstatus)
908 struct smbd_server_connection *sconn = req->sconn;
909 connection_struct *conn = conn_new(sconn);
910 if (!conn) {
911 DEBUG(0,("make_connection_smb2: Couldn't find free connection.\n"));
912 *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
913 return NULL;
916 conn->cnum = tcon->global->tcon_wire_id;
917 conn->tcon = tcon;
919 *pstatus = make_connection_snum(req->xconn,
920 conn,
921 snum,
922 req->session,
923 pdev);
924 if (!NT_STATUS_IS_OK(*pstatus)) {
925 conn_free(conn);
926 return NULL;
928 return conn;
931 /****************************************************************************
932 Close a cnum.
933 ****************************************************************************/
935 void close_cnum(connection_struct *conn,
936 uint64_t vuid,
937 enum file_close_type close_type)
939 char rootpath[2] = { '/', '\0'};
940 struct smb_filename root_fname = { .base_name = rootpath };
941 const struct loadparm_substitution *lp_sub =
942 loadparm_s3_global_substitution();
944 file_close_conn(conn, close_type);
946 change_to_root_user();
948 DEBUG(IS_IPC(conn)?3:2, ("%s (%s) closed connection to service %s\n",
949 get_remote_machine_name(),
950 tsocket_address_string(conn->sconn->remote_address,
951 talloc_tos()),
952 lp_const_servicename(SNUM(conn))));
954 /* make sure we leave the directory available for unmount */
955 vfs_ChDir(conn, &root_fname);
957 /* Call VFS disconnect hook */
958 SMB_VFS_DISCONNECT(conn);
960 /* execute any "postexec = " line */
961 if (*lp_postexec(talloc_tos(), lp_sub, SNUM(conn)) &&
962 change_to_user_and_service(conn, vuid)) {
963 char *cmd = talloc_sub_full(talloc_tos(),
964 lp_const_servicename(SNUM(conn)),
965 conn->session_info->unix_info->unix_name,
966 conn->connectpath,
967 conn->session_info->unix_token->gid,
968 conn->session_info->unix_info->sanitized_username,
969 conn->session_info->info->domain_name,
970 lp_postexec(talloc_tos(), lp_sub, SNUM(conn)));
971 smbrun(cmd, NULL, NULL);
972 TALLOC_FREE(cmd);
973 change_to_root_user();
976 change_to_root_user();
977 /* execute any "root postexec = " line */
978 if (*lp_root_postexec(talloc_tos(), lp_sub, SNUM(conn))) {
979 char *cmd = talloc_sub_full(talloc_tos(),
980 lp_const_servicename(SNUM(conn)),
981 conn->session_info->unix_info->unix_name,
982 conn->connectpath,
983 conn->session_info->unix_token->gid,
984 conn->session_info->unix_info->sanitized_username,
985 conn->session_info->info->domain_name,
986 lp_root_postexec(talloc_tos(), lp_sub, SNUM(conn)));
987 smbrun(cmd, NULL, NULL);
988 TALLOC_FREE(cmd);
991 conn_free(conn);