VERSION: Bump version up to 4.9.2...
[Samba.git] / source3 / smbd / service.c
blob2e4a1136254b56941dd1dfd1374560ec94f21181
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 "lib/param/loadparm.h"
32 #include "messages.h"
33 #include "lib/afs/afs_funcs.h"
34 #include "lib/util_path.h"
36 static bool canonicalize_connect_path(connection_struct *conn)
38 bool ret;
39 struct smb_filename con_fname = { .base_name = conn->connectpath };
40 struct smb_filename *resolved_fname = SMB_VFS_REALPATH(conn, talloc_tos(),
41 &con_fname);
42 if (resolved_fname == NULL) {
43 return false;
45 ret = set_conn_connectpath(conn,resolved_fname->base_name);
46 TALLOC_FREE(resolved_fname);
47 return ret;
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)
57 char *destname;
59 if (connectpath == NULL || connectpath[0] == '\0') {
60 return false;
63 destname = canonicalize_absolute_path(conn, connectpath);
64 if (destname == NULL) {
65 return false;
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,
79 conn->connectpath,
80 NULL,
81 NULL,
82 0);
83 if (conn->cwd_fname == NULL) {
84 return false;
86 return true;
89 /****************************************************************************
90 Load parameters specific to a connection/service.
91 ****************************************************************************/
93 void set_current_case_sensitive(connection_struct *conn, uint16_t flags)
95 int snum;
96 enum remote_arch_types ra_type;
98 SMB_ASSERT(conn != NULL);
100 snum = SNUM(conn);
102 if ((conn == last_conn) && (last_flags == flags)) {
103 return;
106 last_conn = conn;
107 last_flags = flags;
110 * Obey the client case sensitivity requests - only for clients that
111 * support it. */
112 switch (lp_case_sensitive(snum)) {
113 case Auto:
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
123 * pathnames. */
124 conn->case_sensitive = false;
125 } else {
126 conn->case_sensitive =
127 !(flags & FLAG_CASELESS_PATHNAMES);
129 break;
130 case True:
131 conn->case_sensitive = true;
132 break;
133 default:
134 conn->case_sensitive = false;
135 break;
137 return;
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,
148 int ret;
150 conn->lastused_count++;
152 ret = vfs_ChDir(conn, &connectpath_fname);
153 if (ret != 0) {
154 DEBUG(((errno!=EACCES)?0:3),
155 ("chdir (%s) failed, reason: %s\n",
156 conn->connectpath, strerror(errno)));
157 return false;
160 ret = vfs_ChDir(conn, &origpath_fname);
161 if (ret != 0) {
162 DEBUG(((errno!=EACCES)?0:3),
163 ("chdir (%s) failed, reason: %s\n",
164 conn->origpath, strerror(errno)));
165 return false;
168 return true;
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,
177 const char *rhost,
178 int snum,
179 fstring dev)
181 char *raddr;
183 raddr = tsocket_address_inet_addr_string(remote_address,
184 talloc_tos());
185 if (raddr == NULL) {
186 return NT_STATUS_NO_MEMORY;
189 if (!lp_snum_ok(snum) ||
190 !allow_access(lp_hosts_deny(snum), lp_hosts_allow(snum),
191 rhost, raddr)) {
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")) {
199 fstrcpy(dev, "IPC");
200 } else {
201 fstrcpy(dev,"A:");
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:");
227 return NT_STATUS_OK;
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
234 * one found.
237 static NTSTATUS find_forced_group(bool force_user,
238 int snum, const char *username,
239 struct dom_sid *pgroup_sid,
240 gid_t *pgid)
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 char *groupname;
247 bool user_must_be_member = False;
248 gid_t gid;
250 groupname = lp_force_group(talloc_tos(), snum);
251 if (groupname == NULL) {
252 DEBUG(1, ("talloc_strdup failed\n"));
253 result = NT_STATUS_NO_MEMORY;
254 goto done;
257 if (groupname[0] == '+') {
258 user_must_be_member = True;
259 groupname += 1;
262 groupname = talloc_string_sub(talloc_tos(), groupname,
263 "%S", lp_const_servicename(snum));
264 if (groupname == NULL) {
265 DEBUG(1, ("talloc_string_sub failed\n"));
266 result = NT_STATUS_NO_MEMORY;
267 goto done;
270 if (!lookup_name_smbconf(talloc_tos(), groupname,
271 LOOKUP_NAME_ALL|LOOKUP_NAME_GROUP,
272 NULL, NULL, &group_sid, &type)) {
273 DEBUG(10, ("lookup_name_smbconf(%s) failed\n",
274 groupname));
275 goto done;
278 if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
279 (type != SID_NAME_WKN_GRP)) {
280 DEBUG(10, ("%s is a %s, not a group\n", groupname,
281 sid_type_lookup(type)));
282 goto done;
285 if (!sid_to_gid(&group_sid, &gid)) {
286 DEBUG(10, ("sid_to_gid(%s) for %s failed\n",
287 sid_string_dbg(&group_sid), groupname));
288 goto done;
292 * If the user has been forced and the forced group starts with a '+',
293 * then we only set the group to be the forced group if the forced
294 * user is a member of that group. Otherwise, the meaning of the '+'
295 * would be ignored.
298 if (force_user && user_must_be_member) {
299 if (user_in_group_sid(username, &group_sid)) {
300 sid_copy(pgroup_sid, &group_sid);
301 *pgid = gid;
302 DEBUG(3,("Forced group %s for member %s\n",
303 groupname, username));
304 } else {
305 DEBUG(0,("find_forced_group: forced user %s is not a member "
306 "of forced group %s. Disallowing access.\n",
307 username, groupname ));
308 result = NT_STATUS_MEMBER_NOT_IN_GROUP;
309 goto done;
311 } else {
312 sid_copy(pgroup_sid, &group_sid);
313 *pgid = gid;
314 DEBUG(3,("Forced group %s\n", groupname));
317 result = NT_STATUS_OK;
318 done:
319 TALLOC_FREE(frame);
320 return result;
323 /****************************************************************************
324 Create an auth_session_info structure for a connection_struct
325 ****************************************************************************/
327 static NTSTATUS create_connection_session_info(struct smbd_server_connection *sconn,
328 TALLOC_CTX *mem_ctx, int snum,
329 struct auth_session_info *session_info,
330 struct auth_session_info **presult)
332 struct auth_session_info *result;
334 if (lp_guest_only(snum)) {
335 return make_session_info_guest(mem_ctx, presult);
339 * This is the normal security != share case where we have a
340 * valid vuid from the session setup. */
342 if (security_session_user_level(session_info, NULL) < SECURITY_USER) {
343 if (!lp_guest_ok(snum)) {
344 DBG_WARNING("guest user (from session setup) "
345 "not permitted to access this share "
346 "(%s)\n", lp_const_servicename(snum));
347 return NT_STATUS_ACCESS_DENIED;
349 } else {
350 if (!user_ok_token(session_info->unix_info->unix_name,
351 session_info->info->domain_name,
352 session_info->security_token, snum)) {
353 DBG_WARNING("user '%s' (from session setup) not "
354 "permitted to access this share "
355 "(%s)\n",
356 session_info->unix_info->unix_name,
357 lp_const_servicename(snum));
358 return NT_STATUS_ACCESS_DENIED;
362 result = copy_session_info(mem_ctx, session_info);
363 if (result == NULL) {
364 return NT_STATUS_NO_MEMORY;
367 *presult = result;
368 return NT_STATUS_OK;
371 /****************************************************************************
372 Set relevant user and group settings corresponding to force user/group
373 configuration for the given snum.
374 ****************************************************************************/
376 NTSTATUS set_conn_force_user_group(connection_struct *conn, int snum)
378 NTSTATUS status;
380 if (*lp_force_user(talloc_tos(), snum)) {
383 * Replace conn->session_info with a completely faked up one
384 * from the username we are forced into :-)
387 char *fuser;
388 char *sanitized_username;
389 struct auth_session_info *forced_serverinfo;
390 bool guest;
392 fuser = talloc_string_sub(conn, lp_force_user(talloc_tos(), snum), "%S",
393 lp_const_servicename(snum));
394 if (fuser == NULL) {
395 return NT_STATUS_NO_MEMORY;
398 guest = security_session_user_level(conn->session_info, NULL) < SECURITY_USER;
400 status = make_session_info_from_username(
401 conn, fuser,
402 guest,
403 &forced_serverinfo);
404 if (!NT_STATUS_IS_OK(status)) {
405 return status;
408 /* We don't want to replace the original sanitized_username
409 as it is the original user given in the connect attempt.
410 This is used in '%U' substitutions. */
411 sanitized_username = discard_const_p(char,
412 forced_serverinfo->unix_info->sanitized_username);
413 TALLOC_FREE(sanitized_username);
414 forced_serverinfo->unix_info->sanitized_username =
415 talloc_move(forced_serverinfo->unix_info,
416 &conn->session_info->unix_info->sanitized_username);
418 TALLOC_FREE(conn->session_info);
419 conn->session_info = forced_serverinfo;
421 conn->force_user = true;
422 DEBUG(3,("Forced user %s\n", fuser));
426 * If force group is true, then override
427 * any groupid stored for the connecting user.
430 if (*lp_force_group(talloc_tos(), snum)) {
432 status = find_forced_group(
433 conn->force_user, snum, conn->session_info->unix_info->unix_name,
434 &conn->session_info->security_token->sids[1],
435 &conn->session_info->unix_token->gid);
437 if (!NT_STATUS_IS_OK(status)) {
438 return status;
442 * We need to cache this gid, to use within
443 * change_to_user() separately from the conn->session_info
444 * struct. We only use conn->session_info directly if
445 * "force_user" was set.
447 conn->force_group_gid = conn->session_info->unix_token->gid;
450 return NT_STATUS_OK;
453 static NTSTATUS notify_init_sconn(struct smbd_server_connection *sconn)
455 NTSTATUS status;
457 if (sconn->notify_ctx != NULL) {
458 return NT_STATUS_OK;
461 sconn->notify_ctx = notify_init(sconn, sconn->msg_ctx,
462 sconn, notify_callback);
463 if (sconn->notify_ctx == NULL) {
464 return NT_STATUS_NO_MEMORY;
467 status = messaging_register(sconn->msg_ctx, sconn,
468 MSG_SMB_NOTIFY_CANCEL_DELETED,
469 smbd_notify_cancel_deleted);
470 if (!NT_STATUS_IS_OK(status)) {
471 DBG_DEBUG("messaging_register failed: %s\n",
472 nt_errstr(status));
473 TALLOC_FREE(sconn->notify_ctx);
474 return status;
477 status = messaging_register(sconn->msg_ctx, sconn,
478 MSG_SMB_NOTIFY_STARTED,
479 smbd_notifyd_restarted);
480 if (!NT_STATUS_IS_OK(status)) {
481 DBG_DEBUG("messaging_register failed: %s\n",
482 nt_errstr(status));
483 messaging_deregister(sconn->msg_ctx,
484 MSG_SMB_NOTIFY_CANCEL_DELETED, sconn);
485 TALLOC_FREE(sconn->notify_ctx);
486 return status;
489 return NT_STATUS_OK;
492 /****************************************************************************
493 Make a connection, given the snum to connect to, and the vuser of the
494 connecting user if appropriate.
495 ****************************************************************************/
497 static NTSTATUS make_connection_snum(struct smbXsrv_connection *xconn,
498 connection_struct *conn,
499 int snum, struct user_struct *vuser,
500 const char *pdev)
502 struct smbd_server_connection *sconn = xconn->client->sconn;
503 struct smb_filename *smb_fname_cpath = NULL;
504 fstring dev;
505 int ret;
506 bool on_err_call_dis_hook = false;
507 uid_t effuid;
508 gid_t effgid;
509 NTSTATUS status;
511 fstrcpy(dev, pdev);
513 status = share_sanity_checks(sconn->remote_address,
514 sconn->remote_hostname,
515 snum,
516 dev);
517 if (NT_STATUS_IS_ERR(status)) {
518 goto err_root_exit;
521 conn->params->service = snum;
523 status = create_connection_session_info(sconn,
524 conn, snum, vuser->session_info,
525 &conn->session_info);
527 if (!NT_STATUS_IS_OK(status)) {
528 DEBUG(1, ("create_connection_session_info failed: %s\n",
529 nt_errstr(status)));
530 goto err_root_exit;
533 if (lp_guest_only(snum)) {
534 conn->force_user = true;
537 conn->num_files_open = 0;
538 conn->lastused = conn->lastused_count = time(NULL);
539 conn->printer = (strncmp(dev,"LPT",3) == 0);
540 conn->ipc = ( (strncmp(dev,"IPC",3) == 0) ||
541 ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) );
543 /* Case options for the share. */
544 if (lp_case_sensitive(snum) == Auto) {
545 /* We will be setting this per packet. Set to be case
546 * insensitive for now. */
547 conn->case_sensitive = False;
548 } else {
549 conn->case_sensitive = (bool)lp_case_sensitive(snum);
552 conn->case_preserve = lp_preserve_case(snum);
553 conn->short_case_preserve = lp_short_preserve_case(snum);
555 conn->encrypt_level = lp_smb_encrypt(snum);
556 if (conn->encrypt_level > SMB_SIGNING_OFF) {
557 if (lp_smb_encrypt(-1) == SMB_SIGNING_OFF) {
558 if (conn->encrypt_level == SMB_SIGNING_REQUIRED) {
559 DBG_ERR("Service [%s] requires encryption, but "
560 "it is disabled globally!\n",
561 lp_const_servicename(snum));
562 status = NT_STATUS_ACCESS_DENIED;
563 goto err_root_exit;
565 conn->encrypt_level = SMB_SIGNING_OFF;
569 conn->veto_list = NULL;
570 conn->hide_list = NULL;
571 conn->veto_oplock_list = NULL;
572 conn->aio_write_behind_list = NULL;
574 conn->read_only = lp_read_only(SNUM(conn));
576 status = set_conn_force_user_group(conn, snum);
577 if (!NT_STATUS_IS_OK(status)) {
578 goto err_root_exit;
581 conn->vuid = vuser->vuid;
584 char *s = talloc_sub_advanced(talloc_tos(),
585 lp_const_servicename(SNUM(conn)),
586 conn->session_info->unix_info->unix_name,
587 conn->connectpath,
588 conn->session_info->unix_token->gid,
589 conn->session_info->unix_info->sanitized_username,
590 conn->session_info->info->domain_name,
591 lp_path(talloc_tos(), snum));
592 if (!s) {
593 status = NT_STATUS_NO_MEMORY;
594 goto err_root_exit;
597 if (!set_conn_connectpath(conn,s)) {
598 TALLOC_FREE(s);
599 status = NT_STATUS_NO_MEMORY;
600 goto err_root_exit;
602 DBG_NOTICE("Connect path is '%s' for service [%s]\n", s,
603 lp_const_servicename(snum));
604 TALLOC_FREE(s);
608 * Set up the share security descriptor.
609 * NOTE - we use the *INCOMING USER* session_info
610 * here, as does (indirectly) change_to_user(),
611 * which can be called on any incoming packet.
612 * This way we set up the share access based
613 * on the authenticated user, not the forced
614 * user. See bug:
616 * https://bugzilla.samba.org/show_bug.cgi?id=9878
619 status = check_user_share_access(conn,
620 vuser->session_info,
621 &conn->share_access,
622 &conn->read_only);
623 if (!NT_STATUS_IS_OK(status)) {
624 goto err_root_exit;
627 /* Initialise VFS function pointers */
629 if (!smbd_vfs_init(conn)) {
630 DBG_ERR("vfs_init failed for service %s\n",
631 lp_const_servicename(snum));
632 status = NT_STATUS_BAD_NETWORK_NAME;
633 goto err_root_exit;
636 /* ROOT Activities: */
637 /* explicitly check widelinks here so that we can correctly warn
638 * in the logs. */
639 widelinks_warning(snum);
642 * Enforce the max connections parameter.
645 if ((lp_max_connections(snum) > 0)
646 && (count_current_connections(lp_const_servicename(SNUM(conn)), true) >=
647 lp_max_connections(snum))) {
649 DBG_WARNING("Max connections (%d) exceeded for %s\n",
650 lp_max_connections(snum),
651 lp_const_servicename(snum));
652 status = NT_STATUS_INSUFFICIENT_RESOURCES;
653 goto err_root_exit;
656 /* Invoke VFS make connection hook - this must be the first
657 filesystem operation that we do. */
659 if (SMB_VFS_CONNECT(conn, lp_const_servicename(snum),
660 conn->session_info->unix_info->unix_name) < 0) {
661 DBG_WARNING("SMB_VFS_CONNECT for service '%s' at '%s' failed: %s\n",
662 lp_const_servicename(snum), conn->connectpath,
663 strerror(errno));
664 status = NT_STATUS_UNSUCCESSFUL;
665 goto err_root_exit;
668 /* Any error exit after here needs to call the disconnect hook. */
669 on_err_call_dis_hook = true;
671 if ((!conn->printer) && (!conn->ipc) &&
672 lp_change_notify()) {
674 status = notify_init_sconn(sconn);
675 if (!NT_STATUS_IS_OK(status)) {
676 goto err_root_exit;
680 if (lp_kernel_oplocks(snum)) {
681 init_kernel_oplocks(conn->sconn);
685 * Fix compatibility issue pointed out by Volker.
686 * We pass the conn->connectpath to the preexec
687 * scripts as a parameter, so attempt to canonicalize
688 * it here before calling the preexec scripts.
689 * We ignore errors here, as it is possible that
690 * the conn->connectpath doesn't exist yet and
691 * the preexec scripts will create them.
694 (void)canonicalize_connect_path(conn);
696 /* Preexecs are done here as they might make the dir we are to ChDir
697 * to below */
698 /* execute any "root preexec = " line */
699 if (*lp_root_preexec(talloc_tos(), snum)) {
700 char *cmd = talloc_sub_advanced(talloc_tos(),
701 lp_const_servicename(SNUM(conn)),
702 conn->session_info->unix_info->unix_name,
703 conn->connectpath,
704 conn->session_info->unix_token->gid,
705 conn->session_info->unix_info->sanitized_username,
706 conn->session_info->info->domain_name,
707 lp_root_preexec(talloc_tos(), snum));
708 DEBUG(5,("cmd=%s\n",cmd));
709 ret = smbrun(cmd, NULL, NULL);
710 TALLOC_FREE(cmd);
711 if (ret != 0 && lp_root_preexec_close(snum)) {
712 DEBUG(1,("root preexec gave %d - failing "
713 "connection\n", ret));
714 status = NT_STATUS_ACCESS_DENIED;
715 goto err_root_exit;
719 /* USER Activites: */
720 if (!change_to_user(conn, conn->vuid)) {
721 /* No point continuing if they fail the basic checks */
722 DEBUG(0,("Can't become connected user!\n"));
723 status = NT_STATUS_LOGON_FAILURE;
724 goto err_root_exit;
727 effuid = geteuid();
728 effgid = getegid();
730 /* Remember that a different vuid can connect later without these
731 * checks... */
733 /* Preexecs are done here as they might make the dir we are to ChDir
734 * to below */
736 /* execute any "preexec = " line */
737 if (*lp_preexec(talloc_tos(), snum)) {
738 char *cmd = talloc_sub_advanced(talloc_tos(),
739 lp_const_servicename(SNUM(conn)),
740 conn->session_info->unix_info->unix_name,
741 conn->connectpath,
742 conn->session_info->unix_token->gid,
743 conn->session_info->unix_info->sanitized_username,
744 conn->session_info->info->domain_name,
745 lp_preexec(talloc_tos(), snum));
746 ret = smbrun(cmd, NULL, NULL);
747 TALLOC_FREE(cmd);
748 if (ret != 0 && lp_preexec_close(snum)) {
749 DEBUG(1,("preexec gave %d - failing connection\n",
750 ret));
751 status = NT_STATUS_ACCESS_DENIED;
752 goto err_root_exit;
756 #ifdef WITH_FAKE_KASERVER
757 if (lp_afs_share(snum)) {
758 afs_login(conn);
760 #endif
763 * we've finished with the user stuff - go back to root
764 * so the SMB_VFS_STAT call will only fail on path errors,
765 * not permission problems.
767 change_to_root_user();
768 /* ROOT Activites: */
771 * If widelinks are disallowed we need to canonicalise the connect
772 * path here to ensure we don't have any symlinks in the
773 * connectpath. We will be checking all paths on this connection are
774 * below this directory. We must do this after the VFS init as we
775 * depend on the realpath() pointer in the vfs table. JRA.
777 if (!lp_widelinks(snum)) {
778 if (!canonicalize_connect_path(conn)) {
779 DBG_ERR("canonicalize_connect_path failed "
780 "for service %s, path %s\n",
781 lp_const_servicename(snum),
782 conn->connectpath);
783 status = NT_STATUS_BAD_NETWORK_NAME;
784 goto err_root_exit;
788 /* Add veto/hide lists */
789 if (!IS_IPC(conn) && !IS_PRINT(conn)) {
790 set_namearray( &conn->veto_list,
791 lp_veto_files(talloc_tos(), snum));
792 set_namearray( &conn->hide_list,
793 lp_hide_files(talloc_tos(), snum));
794 set_namearray( &conn->veto_oplock_list,
795 lp_veto_oplock_files(talloc_tos(), snum));
796 set_namearray( &conn->aio_write_behind_list,
797 lp_aio_write_behind(talloc_tos(), snum));
799 smb_fname_cpath = synthetic_smb_fname(talloc_tos(),
800 conn->connectpath,
801 NULL,
802 NULL,
804 if (smb_fname_cpath == NULL) {
805 status = NT_STATUS_NO_MEMORY;
806 goto err_root_exit;
809 /* win2000 does not check the permissions on the directory
810 during the tree connect, instead relying on permission
811 check during individual operations. To match this behaviour
812 I have disabled this chdir check (tridge) */
813 /* the alternative is just to check the directory exists */
815 if ((ret = SMB_VFS_STAT(conn, smb_fname_cpath)) != 0 ||
816 !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
817 if (ret == 0 && !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
818 DBG_ERR("'%s' is not a directory, when connecting to "
819 "[%s]\n", conn->connectpath,
820 lp_const_servicename(snum));
821 } else {
822 DBG_ERR("'%s' does not exist or permission denied "
823 "when connecting to [%s] Error was %s\n",
824 conn->connectpath,
825 lp_const_servicename(snum),
826 strerror(errno));
828 status = NT_STATUS_BAD_NETWORK_NAME;
829 goto err_root_exit;
831 conn->base_share_dev = smb_fname_cpath->st.st_ex_dev;
833 talloc_free(conn->origpath);
834 conn->origpath = talloc_strdup(conn, conn->connectpath);
836 /* Figure out the characteristics of the underlying filesystem. This
837 * assumes that all the filesystem mounted withing a share path have
838 * the same characteristics, which is likely but not guaranteed.
841 conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
844 * Print out the 'connected as' stuff here as we need
845 * to know the effective uid and gid we will be using
846 * (at least initially).
849 if( DEBUGLVL( IS_IPC(conn) ? 3 : 2 ) ) {
850 dbgtext( "%s (%s) ", get_remote_machine_name(),
851 tsocket_address_string(conn->sconn->remote_address,
852 talloc_tos()) );
853 dbgtext( "%s", srv_is_signing_active(xconn) ? "signed " : "");
854 dbgtext( "connect to service %s ",
855 lp_const_servicename(snum) );
856 dbgtext( "initially as user %s ",
857 conn->session_info->unix_info->unix_name );
858 dbgtext( "(uid=%d, gid=%d) ", (int)effuid, (int)effgid );
859 dbgtext( "(pid %d)\n", (int)getpid() );
862 conn->tcon_done = true;
863 return NT_STATUS_OK;
865 err_root_exit:
867 TALLOC_FREE(smb_fname_cpath);
868 /* We must exit this function as root. */
869 if (geteuid() != 0) {
870 change_to_root_user();
872 if (on_err_call_dis_hook) {
873 /* Call VFS disconnect hook */
874 SMB_VFS_DISCONNECT(conn);
876 return status;
879 /****************************************************************************
880 Make a connection to a service from SMB1. Internal interface.
881 ****************************************************************************/
883 static connection_struct *make_connection_smb1(struct smb_request *req,
884 NTTIME now,
885 int snum, struct user_struct *vuser,
886 const char *pdev,
887 NTSTATUS *pstatus)
889 struct smbXsrv_tcon *tcon;
890 NTSTATUS status;
891 struct connection_struct *conn;
893 status = smb1srv_tcon_create(req->xconn, now, &tcon);
894 if (!NT_STATUS_IS_OK(status)) {
895 DEBUG(0,("make_connection_smb1: Couldn't find free tcon %s.\n",
896 nt_errstr(status)));
897 *pstatus = status;
898 return NULL;
901 conn = conn_new(req->sconn);
902 if (!conn) {
903 TALLOC_FREE(tcon);
905 DEBUG(0,("make_connection_smb1: Couldn't find free connection.\n"));
906 *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
907 return NULL;
910 conn->cnum = tcon->global->tcon_wire_id;
911 conn->tcon = tcon;
913 *pstatus = make_connection_snum(req->xconn,
914 conn,
915 snum,
916 vuser,
917 pdev);
918 if (!NT_STATUS_IS_OK(*pstatus)) {
919 conn_free(conn);
920 TALLOC_FREE(tcon);
921 return NULL;
924 tcon->global->share_name = lp_servicename(tcon->global, SNUM(conn));
925 if (tcon->global->share_name == NULL) {
926 conn_free(conn);
927 TALLOC_FREE(tcon);
928 *pstatus = NT_STATUS_NO_MEMORY;
929 return NULL;
931 tcon->global->session_global_id =
932 vuser->session->global->session_global_id;
934 tcon->compat = talloc_move(tcon, &conn);
935 tcon->status = NT_STATUS_OK;
937 *pstatus = smbXsrv_tcon_update(tcon);
938 if (!NT_STATUS_IS_OK(*pstatus)) {
939 TALLOC_FREE(tcon);
940 return NULL;
943 return tcon->compat;
946 /****************************************************************************
947 Make a connection to a service from SMB2. External SMB2 interface.
948 We must set cnum before claiming connection.
949 ****************************************************************************/
951 connection_struct *make_connection_smb2(struct smbd_smb2_request *req,
952 struct smbXsrv_tcon *tcon,
953 int snum,
954 struct user_struct *vuser,
955 const char *pdev,
956 NTSTATUS *pstatus)
958 struct smbd_server_connection *sconn = req->sconn;
959 connection_struct *conn = conn_new(sconn);
960 if (!conn) {
961 DEBUG(0,("make_connection_smb2: Couldn't find free connection.\n"));
962 *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
963 return NULL;
966 conn->cnum = tcon->global->tcon_wire_id;
967 conn->tcon = tcon;
969 *pstatus = make_connection_snum(req->xconn,
970 conn,
971 snum,
972 vuser,
973 pdev);
974 if (!NT_STATUS_IS_OK(*pstatus)) {
975 conn_free(conn);
976 return NULL;
978 return conn;
981 /****************************************************************************
982 Make a connection to a service. External SMB1 interface.
984 * @param service
985 ****************************************************************************/
987 connection_struct *make_connection(struct smb_request *req,
988 NTTIME now,
989 const char *service_in,
990 const char *pdev, uint64_t vuid,
991 NTSTATUS *status)
993 struct smbd_server_connection *sconn = req->sconn;
994 uid_t euid;
995 struct user_struct *vuser = NULL;
996 char *service = NULL;
997 fstring dev;
998 int snum = -1;
1000 fstrcpy(dev, pdev);
1002 /* This must ONLY BE CALLED AS ROOT. As it exits this function as
1003 * root. */
1004 if (!non_root_mode() && (euid = geteuid()) != 0) {
1005 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot "
1006 "(%u)\n", (unsigned int)euid ));
1007 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
1010 if (conn_num_open(sconn) > 2047) {
1011 *status = NT_STATUS_INSUFF_SERVER_RESOURCES;
1012 return NULL;
1015 vuser = get_valid_user_struct(sconn, vuid);
1016 if (!vuser) {
1017 DEBUG(1,("make_connection: refusing to connect with "
1018 "no session setup\n"));
1019 *status = NT_STATUS_ACCESS_DENIED;
1020 return NULL;
1023 /* Logic to try and connect to the correct [homes] share, preferably
1024 without too many getpwnam() lookups. This is particulary nasty for
1025 winbind usernames, where the share name isn't the same as unix
1026 username.
1028 The snum of the homes share is stored on the vuser at session setup
1029 time.
1032 if (strequal(service_in,HOMES_NAME)) {
1033 if (vuser->homes_snum == -1) {
1034 DEBUG(2, ("[homes] share not available for "
1035 "this user because it was not found "
1036 "or created at session setup "
1037 "time\n"));
1038 *status = NT_STATUS_BAD_NETWORK_NAME;
1039 return NULL;
1041 DEBUG(5, ("making a connection to [homes] service "
1042 "created at session setup time\n"));
1043 return make_connection_smb1(req, now,
1044 vuser->homes_snum,
1045 vuser,
1046 dev, status);
1047 } else if ((vuser->homes_snum != -1)
1048 && strequal(service_in,
1049 lp_const_servicename(vuser->homes_snum))) {
1050 DEBUG(5, ("making a connection to 'homes' service [%s] "
1051 "created at session setup time\n", service_in));
1052 return make_connection_smb1(req, now,
1053 vuser->homes_snum,
1054 vuser,
1055 dev, status);
1058 service = talloc_strdup(talloc_tos(), service_in);
1059 if (!service) {
1060 *status = NT_STATUS_NO_MEMORY;
1061 return NULL;
1064 if (!strlower_m(service)) {
1065 DEBUG(2, ("strlower_m %s failed\n", service));
1066 *status = NT_STATUS_INVALID_PARAMETER;
1067 return NULL;
1070 snum = find_service(talloc_tos(), service, &service);
1071 if (!service) {
1072 *status = NT_STATUS_NO_MEMORY;
1073 return NULL;
1076 if (snum < 0) {
1077 if (strequal(service,"IPC$") ||
1078 (lp_enable_asu_support() && strequal(service,"ADMIN$"))) {
1079 DEBUG(3,("refusing IPC connection to %s\n", service));
1080 *status = NT_STATUS_ACCESS_DENIED;
1081 return NULL;
1084 DEBUG(3,("%s (%s) couldn't find service %s\n",
1085 get_remote_machine_name(),
1086 tsocket_address_string(
1087 sconn->remote_address, talloc_tos()),
1088 service));
1089 *status = NT_STATUS_BAD_NETWORK_NAME;
1090 return NULL;
1093 /* Handle non-Dfs clients attempting connections to msdfs proxy */
1094 if (lp_host_msdfs() && (*lp_msdfs_proxy(talloc_tos(), snum) != '\0')) {
1095 DEBUG(3, ("refusing connection to dfs proxy share '%s' "
1096 "(pointing to %s)\n",
1097 service, lp_msdfs_proxy(talloc_tos(), snum)));
1098 *status = NT_STATUS_BAD_NETWORK_NAME;
1099 return NULL;
1102 DEBUG(5, ("making a connection to 'normal' service %s\n", service));
1104 return make_connection_smb1(req, now, snum, vuser,
1105 dev, status);
1108 /****************************************************************************
1109 Close a cnum.
1110 ****************************************************************************/
1112 void close_cnum(connection_struct *conn, uint64_t vuid)
1114 char rootpath[2] = { '/', '\0'};
1115 struct smb_filename root_fname = { .base_name = rootpath };
1117 file_close_conn(conn);
1119 if (!IS_IPC(conn)) {
1120 dptr_closecnum(conn);
1123 change_to_root_user();
1125 DEBUG(IS_IPC(conn)?3:2, ("%s (%s) closed connection to service %s\n",
1126 get_remote_machine_name(),
1127 tsocket_address_string(conn->sconn->remote_address,
1128 talloc_tos()),
1129 lp_const_servicename(SNUM(conn))));
1131 /* make sure we leave the directory available for unmount */
1132 vfs_ChDir(conn, &root_fname);
1134 /* Call VFS disconnect hook */
1135 SMB_VFS_DISCONNECT(conn);
1137 /* execute any "postexec = " line */
1138 if (*lp_postexec(talloc_tos(), SNUM(conn)) &&
1139 change_to_user(conn, vuid)) {
1140 char *cmd = talloc_sub_advanced(talloc_tos(),
1141 lp_const_servicename(SNUM(conn)),
1142 conn->session_info->unix_info->unix_name,
1143 conn->connectpath,
1144 conn->session_info->unix_token->gid,
1145 conn->session_info->unix_info->sanitized_username,
1146 conn->session_info->info->domain_name,
1147 lp_postexec(talloc_tos(), SNUM(conn)));
1148 smbrun(cmd, NULL, NULL);
1149 TALLOC_FREE(cmd);
1150 change_to_root_user();
1153 change_to_root_user();
1154 /* execute any "root postexec = " line */
1155 if (*lp_root_postexec(talloc_tos(), SNUM(conn))) {
1156 char *cmd = talloc_sub_advanced(talloc_tos(),
1157 lp_const_servicename(SNUM(conn)),
1158 conn->session_info->unix_info->unix_name,
1159 conn->connectpath,
1160 conn->session_info->unix_token->gid,
1161 conn->session_info->unix_info->sanitized_username,
1162 conn->session_info->info->domain_name,
1163 lp_root_postexec(talloc_tos(), SNUM(conn)));
1164 smbrun(cmd, NULL, NULL);
1165 TALLOC_FREE(cmd);
1168 conn_free(conn);