s3: smbd: Make set_conn_connectpath() call canonicalize_absolute_path().
[Samba.git] / source3 / smbd / service.c
blob2702a2432027e9715bfc38a9fe9cfffffe9e5a8d
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 char *resolved_name = SMB_VFS_REALPATH(conn,conn->connectpath);
40 if (!resolved_name) {
41 return false;
43 ret = set_conn_connectpath(conn,resolved_name);
44 SAFE_FREE(resolved_name);
45 return ret;
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)
55 char *destname;
57 if (connectpath == NULL || connectpath[0] == '\0') {
58 return false;
61 destname = canonicalize_absolute_path(conn, connectpath);
62 if (destname == NULL) {
63 return false;
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);
74 if (!conn->cwd) {
75 return false;
77 return true;
80 /****************************************************************************
81 Load parameters specific to a connection/service.
82 ****************************************************************************/
84 bool set_current_service(connection_struct *conn, uint16_t flags, bool do_chdir)
86 int snum;
87 enum remote_arch_types ra_type;
89 if (!conn) {
90 last_conn = NULL;
91 return(False);
94 conn->lastused_count++;
96 snum = SNUM(conn);
98 if (do_chdir &&
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)));
103 return(False);
106 if ((conn == last_conn) && (last_flags == flags)) {
107 return(True);
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 true;
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,
150 const char *rhost,
151 int snum,
152 fstring dev)
154 char *raddr;
156 raddr = tsocket_address_inet_addr_string(remote_address,
157 talloc_tos());
158 if (raddr == NULL) {
159 return NT_STATUS_NO_MEMORY;
162 if (!lp_snum_ok(snum) ||
163 !allow_access(lp_hosts_deny(snum), lp_hosts_allow(snum),
164 rhost, raddr)) {
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")) {
172 fstrcpy(dev, "IPC");
173 } else {
174 fstrcpy(dev,"A:");
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:");
200 return NT_STATUS_OK;
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
207 * one found.
210 static NTSTATUS find_forced_group(bool force_user,
211 int snum, const char *username,
212 struct dom_sid *pgroup_sid,
213 gid_t *pgid)
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;
219 char *groupname;
220 bool user_must_be_member = False;
221 gid_t gid;
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;
227 goto done;
230 if (groupname[0] == '+') {
231 user_must_be_member = True;
232 groupname += 1;
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;
240 goto done;
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",
247 groupname));
248 goto done;
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)));
255 goto done;
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));
261 goto done;
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 '+'
268 * would be ignored.
271 if (force_user && user_must_be_member) {
272 if (user_in_group_sid(username, &group_sid)) {
273 sid_copy(pgroup_sid, &group_sid);
274 *pgid = gid;
275 DEBUG(3,("Forced group %s for member %s\n",
276 groupname, username));
277 } else {
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;
282 goto done;
284 } else {
285 sid_copy(pgroup_sid, &group_sid);
286 *pgid = gid;
287 DEBUG(3,("Forced group %s\n", groupname));
290 result = NT_STATUS_OK;
291 done:
292 TALLOC_FREE(frame);
293 return result;
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;
322 } else {
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 "
328 "(%s)\n",
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;
340 *presult = result;
341 return NT_STATUS_OK;
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)
351 NTSTATUS status;
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 :-)
360 char *fuser;
361 char *sanitized_username;
362 struct auth_session_info *forced_serverinfo;
363 bool guest;
365 fuser = talloc_string_sub(conn, lp_force_user(talloc_tos(), snum), "%S",
366 lp_const_servicename(snum));
367 if (fuser == NULL) {
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(
374 conn, fuser,
375 guest,
376 &forced_serverinfo);
377 if (!NT_STATUS_IS_OK(status)) {
378 return 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)) {
411 return 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;
423 return NT_STATUS_OK;
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,
434 const char *pdev)
436 struct smbd_server_connection *sconn = xconn->client->sconn;
437 struct smb_filename *smb_fname_cpath = NULL;
438 fstring dev;
439 int ret;
440 bool on_err_call_dis_hook = false;
441 uid_t effuid;
442 gid_t effgid;
443 NTSTATUS status;
445 fstrcpy(dev, pdev);
447 status = share_sanity_checks(sconn->remote_address,
448 sconn->remote_hostname,
449 snum,
450 dev);
451 if (NT_STATUS_IS_ERR(status)) {
452 goto err_root_exit;
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",
463 nt_errstr(status)));
464 goto err_root_exit;
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;
482 } else {
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;
497 goto err_root_exit;
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)) {
512 goto err_root_exit;
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,
521 conn->connectpath,
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));
526 if (!s) {
527 status = NT_STATUS_NO_MEMORY;
528 goto err_root_exit;
531 if (!set_conn_connectpath(conn,s)) {
532 TALLOC_FREE(s);
533 status = NT_STATUS_NO_MEMORY;
534 goto err_root_exit;
536 DEBUG(3,("Connect path is '%s' for service [%s]\n",s,
537 lp_servicename(talloc_tos(), snum)));
538 TALLOC_FREE(s);
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
548 * user. See bug:
550 * https://bugzilla.samba.org/show_bug.cgi?id=9878
553 status = check_user_share_access(conn,
554 vuser->session_info,
555 &conn->share_access,
556 &conn->read_only);
557 if (!NT_STATUS_IS_OK(status)) {
558 goto err_root_exit;
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;
567 goto err_root_exit;
570 /* ROOT Activities: */
571 /* explicitly check widelinks here so that we can correctly warn
572 * in the logs. */
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;
587 goto err_root_exit;
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,
597 strerror(errno));
598 status = NT_STATUS_UNSUCCESSFUL;
599 goto err_root_exit;
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
638 * to below */
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,
644 conn->connectpath,
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);
651 TALLOC_FREE(cmd);
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;
656 goto err_root_exit;
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;
665 goto err_root_exit;
668 effuid = geteuid();
669 effgid = getegid();
671 /* Remember that a different vuid can connect later without these
672 * checks... */
674 /* Preexecs are done here as they might make the dir we are to ChDir
675 * to below */
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,
682 conn->connectpath,
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);
688 TALLOC_FREE(cmd);
689 if (ret != 0 && lp_preexec_close(snum)) {
690 DEBUG(1,("preexec gave %d - failing connection\n",
691 ret));
692 status = NT_STATUS_ACCESS_DENIED;
693 goto err_root_exit;
697 #ifdef WITH_FAKE_KASERVER
698 if (lp_afs_share(snum)) {
699 afs_login(conn);
701 #endif
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),
723 conn->connectpath));
724 status = NT_STATUS_BAD_NETWORK_NAME;
725 goto err_root_exit;
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,
741 NULL, NULL);
742 if (smb_fname_cpath == NULL) {
743 status = NT_STATUS_NO_MEMORY;
744 goto err_root_exit;
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)));
759 } else {
760 DEBUG(0,("'%s' does not exist or permission denied "
761 "when connecting to [%s] Error was %s\n",
762 conn->connectpath,
763 lp_servicename(talloc_tos(), snum),
764 strerror(errno) ));
766 status = NT_STATUS_BAD_NETWORK_NAME;
767 goto err_root_exit;
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,
790 talloc_tos()) );
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() );
800 return status;
802 err_root_exit:
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);
813 return status;
816 /****************************************************************************
817 Make a connection to a service from SMB1. Internal interface.
818 ****************************************************************************/
820 static connection_struct *make_connection_smb1(struct smb_request *req,
821 NTTIME now,
822 int snum, struct user_struct *vuser,
823 const char *pdev,
824 NTSTATUS *pstatus)
826 struct smbXsrv_tcon *tcon;
827 NTSTATUS status;
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",
833 nt_errstr(status)));
834 *pstatus = status;
835 return NULL;
838 conn = conn_new(req->sconn);
839 if (!conn) {
840 TALLOC_FREE(tcon);
842 DEBUG(0,("make_connection_smb1: Couldn't find free connection.\n"));
843 *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
844 return NULL;
847 conn->cnum = tcon->global->tcon_wire_id;
848 conn->tcon = tcon;
850 *pstatus = make_connection_snum(req->xconn,
851 conn,
852 snum,
853 vuser,
854 pdev);
855 if (!NT_STATUS_IS_OK(*pstatus)) {
856 conn_free(conn);
857 TALLOC_FREE(tcon);
858 return NULL;
861 tcon->global->share_name = lp_servicename(tcon->global, SNUM(conn));
862 if (tcon->global->share_name == NULL) {
863 conn_free(conn);
864 TALLOC_FREE(tcon);
865 *pstatus = NT_STATUS_NO_MEMORY;
866 return NULL;
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)) {
876 TALLOC_FREE(tcon);
877 return NULL;
880 return tcon->compat;
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,
890 int snum,
891 struct user_struct *vuser,
892 const char *pdev,
893 NTSTATUS *pstatus)
895 struct smbd_server_connection *sconn = req->sconn;
896 connection_struct *conn = conn_new(sconn);
897 if (!conn) {
898 DEBUG(0,("make_connection_smb2: Couldn't find free connection.\n"));
899 *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
900 return NULL;
903 conn->cnum = tcon->global->tcon_wire_id;
904 conn->tcon = tcon;
906 *pstatus = make_connection_snum(req->xconn,
907 conn,
908 snum,
909 vuser,
910 pdev);
911 if (!NT_STATUS_IS_OK(*pstatus)) {
912 conn_free(conn);
913 return NULL;
915 return conn;
918 /****************************************************************************
919 Make a connection to a service. External SMB1 interface.
921 * @param service
922 ****************************************************************************/
924 connection_struct *make_connection(struct smb_request *req,
925 NTTIME now,
926 const char *service_in,
927 const char *pdev, uint64_t vuid,
928 NTSTATUS *status)
930 struct smbd_server_connection *sconn = req->sconn;
931 uid_t euid;
932 struct user_struct *vuser = NULL;
933 char *service = NULL;
934 fstring dev;
935 int snum = -1;
937 fstrcpy(dev, pdev);
939 /* This must ONLY BE CALLED AS ROOT. As it exits this function as
940 * root. */
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;
949 return NULL;
952 vuser = get_valid_user_struct(sconn, vuid);
953 if (!vuser) {
954 DEBUG(1,("make_connection: refusing to connect with "
955 "no session setup\n"));
956 *status = NT_STATUS_ACCESS_DENIED;
957 return NULL;
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
963 username.
965 The snum of the homes share is stored on the vuser at session setup
966 time.
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 "
974 "time\n"));
975 *status = NT_STATUS_BAD_NETWORK_NAME;
976 return NULL;
978 DEBUG(5, ("making a connection to [homes] service "
979 "created at session setup time\n"));
980 return make_connection_smb1(req, now,
981 vuser->homes_snum,
982 vuser,
983 dev, status);
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,
990 vuser->homes_snum,
991 vuser,
992 dev, status);
995 service = talloc_strdup(talloc_tos(), service_in);
996 if (!service) {
997 *status = NT_STATUS_NO_MEMORY;
998 return NULL;
1001 if (!strlower_m(service)) {
1002 DEBUG(2, ("strlower_m %s failed\n", service));
1003 *status = NT_STATUS_INVALID_PARAMETER;
1004 return NULL;
1007 snum = find_service(talloc_tos(), service, &service);
1008 if (!service) {
1009 *status = NT_STATUS_NO_MEMORY;
1010 return NULL;
1013 if (snum < 0) {
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;
1018 return NULL;
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()),
1025 service));
1026 *status = NT_STATUS_BAD_NETWORK_NAME;
1027 return NULL;
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;
1036 return NULL;
1039 DEBUG(5, ("making a connection to 'normal' service %s\n", service));
1041 return make_connection_smb1(req, now, snum, vuser,
1042 dev, status);
1045 /****************************************************************************
1046 Close a cnum.
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,
1062 talloc_tos()),
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,
1077 conn->connectpath,
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)));
1082 smbrun(cmd,NULL);
1083 TALLOC_FREE(cmd);
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,
1093 conn->connectpath,
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)));
1098 smbrun(cmd,NULL);
1099 TALLOC_FREE(cmd);
1102 conn_free(conn);