s4-smbtorture: add ndr test for nbt_netlogon_packet to avoid future regressions.
[Samba/gebeck_regimport.git] / source3 / smbd / service.c
blobf41bdb561c8eb7936dc1c782de99480f595fcb4c
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"
33 extern userdom_struct current_user_info;
35 static bool canonicalize_connect_path(connection_struct *conn)
37 bool ret;
38 char *resolved_name = SMB_VFS_REALPATH(conn,conn->connectpath);
39 if (!resolved_name) {
40 return false;
42 ret = set_conn_connectpath(conn,resolved_name);
43 SAFE_FREE(resolved_name);
44 return ret;
47 /****************************************************************************
48 Ensure when setting connectpath it is a canonicalized (no ./ // or ../)
49 absolute path stating in / and not ending in /.
50 Observent people will notice a similarity between this and check_path_syntax :-).
51 ****************************************************************************/
53 bool set_conn_connectpath(connection_struct *conn, const char *connectpath)
55 char *destname;
56 char *d;
57 const char *s = connectpath;
58 bool start_of_name_component = true;
60 if (connectpath == NULL || connectpath[0] == '\0') {
61 return false;
64 /* Allocate for strlen + '\0' + possible leading '/' */
65 destname = (char *)SMB_MALLOC(strlen(connectpath) + 2);
66 if (!destname) {
67 return false;
69 d = destname;
71 *d++ = '/'; /* Always start with root. */
73 while (*s) {
74 if (*s == '/') {
75 /* Eat multiple '/' */
76 while (*s == '/') {
77 s++;
79 if ((d > destname + 1) && (*s != '\0')) {
80 *d++ = '/';
82 start_of_name_component = True;
83 continue;
86 if (start_of_name_component) {
87 if ((s[0] == '.') && (s[1] == '.') && (s[2] == '/' || s[2] == '\0')) {
88 /* Uh oh - "/../" or "/..\0" ! */
90 /* Go past the ../ or .. */
91 if (s[2] == '/') {
92 s += 3;
93 } else {
94 s += 2; /* Go past the .. */
97 /* If we just added a '/' - delete it */
98 if ((d > destname) && (*(d-1) == '/')) {
99 *(d-1) = '\0';
100 d--;
103 /* Are we at the start ? Can't go back further if so. */
104 if (d <= destname) {
105 *d++ = '/'; /* Can't delete root */
106 continue;
108 /* Go back one level... */
109 /* Decrement d first as d points to the *next* char to write into. */
110 for (d--; d > destname; d--) {
111 if (*d == '/') {
112 break;
115 /* We're still at the start of a name component, just the previous one. */
116 continue;
117 } else if ((s[0] == '.') && ((s[1] == '\0') || s[1] == '/')) {
118 /* Component of pathname can't be "." only - skip the '.' . */
119 if (s[1] == '/') {
120 s += 2;
121 } else {
122 s++;
124 continue;
128 if (!(*s & 0x80)) {
129 *d++ = *s++;
130 } else {
131 size_t siz;
132 /* Get the size of the next MB character. */
133 next_codepoint(s,&siz);
134 switch(siz) {
135 case 5:
136 *d++ = *s++;
137 /*fall through*/
138 case 4:
139 *d++ = *s++;
140 /*fall through*/
141 case 3:
142 *d++ = *s++;
143 /*fall through*/
144 case 2:
145 *d++ = *s++;
146 /*fall through*/
147 case 1:
148 *d++ = *s++;
149 break;
150 default:
151 break;
154 start_of_name_component = false;
156 *d = '\0';
158 /* And must not end in '/' */
159 if (d > destname + 1 && (*(d-1) == '/')) {
160 *(d-1) = '\0';
163 DEBUG(10,("set_conn_connectpath: service %s, connectpath = %s\n",
164 lp_servicename(SNUM(conn)), destname ));
166 string_set(&conn->connectpath, destname);
167 SAFE_FREE(destname);
168 return true;
171 /****************************************************************************
172 Load parameters specific to a connection/service.
173 ****************************************************************************/
175 bool set_current_service(connection_struct *conn, uint16 flags, bool do_chdir)
177 int snum;
179 if (!conn) {
180 last_conn = NULL;
181 return(False);
184 conn->lastused_count++;
186 snum = SNUM(conn);
188 if (do_chdir &&
189 vfs_ChDir(conn,conn->connectpath) != 0 &&
190 vfs_ChDir(conn,conn->origpath) != 0) {
191 DEBUG(((errno!=EACCES)?0:3),("chdir (%s) failed, reason: %s\n",
192 conn->connectpath, strerror(errno)));
193 return(False);
196 if ((conn == last_conn) && (last_flags == flags)) {
197 return(True);
200 last_conn = conn;
201 last_flags = flags;
203 /* Obey the client case sensitivity requests - only for clients that support it. */
204 switch (lp_casesensitive(snum)) {
205 case Auto:
207 /* We need this uglyness due to DOS/Win9x clients that lie about case insensitivity. */
208 enum remote_arch_types ra_type = get_remote_arch();
209 if ((ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
210 /* Client can't support per-packet case sensitive pathnames. */
211 conn->case_sensitive = False;
212 } else {
213 conn->case_sensitive = !(flags & FLAG_CASELESS_PATHNAMES);
216 break;
217 case True:
218 conn->case_sensitive = True;
219 break;
220 default:
221 conn->case_sensitive = False;
222 break;
224 return(True);
227 /****************************************************************************
228 do some basic sainity checks on the share.
229 This function modifies dev, ecode.
230 ****************************************************************************/
232 static NTSTATUS share_sanity_checks(const struct tsocket_address *remote_address,
233 const char *rhost,
234 int snum,
235 fstring dev)
237 char *raddr;
239 raddr = tsocket_address_inet_addr_string(remote_address,
240 talloc_tos());
241 if (raddr == NULL) {
242 return NT_STATUS_NO_MEMORY;
245 if (!lp_snum_ok(snum) ||
246 !allow_access(lp_hostsdeny(snum), lp_hostsallow(snum),
247 rhost, raddr)) {
248 return NT_STATUS_ACCESS_DENIED;
251 if (dev[0] == '?' || !dev[0]) {
252 if (lp_print_ok(snum)) {
253 fstrcpy(dev,"LPT1:");
254 } else if (strequal(lp_fstype(snum), "IPC")) {
255 fstrcpy(dev, "IPC");
256 } else {
257 fstrcpy(dev,"A:");
261 strupper_m(dev);
263 if (lp_print_ok(snum)) {
264 if (!strequal(dev, "LPT1:")) {
265 return NT_STATUS_BAD_DEVICE_TYPE;
267 } else if (strequal(lp_fstype(snum), "IPC")) {
268 if (!strequal(dev, "IPC")) {
269 return NT_STATUS_BAD_DEVICE_TYPE;
271 } else if (!strequal(dev, "A:")) {
272 return NT_STATUS_BAD_DEVICE_TYPE;
275 /* Behave as a printer if we are supposed to */
276 if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) {
277 fstrcpy(dev, "LPT1:");
280 return NT_STATUS_OK;
284 * Go through lookup_name etc to find the force'd group.
286 * Create a new token from src_token, replacing the primary group sid with the
287 * one found.
290 static NTSTATUS find_forced_group(bool force_user,
291 int snum, const char *username,
292 struct dom_sid *pgroup_sid,
293 gid_t *pgid)
295 NTSTATUS result = NT_STATUS_NO_SUCH_GROUP;
296 TALLOC_CTX *frame = talloc_stackframe();
297 struct dom_sid group_sid;
298 enum lsa_SidType type;
299 char *groupname;
300 bool user_must_be_member = False;
301 gid_t gid;
303 groupname = talloc_strdup(talloc_tos(), lp_force_group(snum));
304 if (groupname == NULL) {
305 DEBUG(1, ("talloc_strdup failed\n"));
306 result = NT_STATUS_NO_MEMORY;
307 goto done;
310 if (groupname[0] == '+') {
311 user_must_be_member = True;
312 groupname += 1;
315 groupname = talloc_string_sub(talloc_tos(), groupname,
316 "%S", lp_servicename(snum));
317 if (groupname == NULL) {
318 DEBUG(1, ("talloc_string_sub failed\n"));
319 result = NT_STATUS_NO_MEMORY;
320 goto done;
323 if (!lookup_name_smbconf(talloc_tos(), groupname,
324 LOOKUP_NAME_ALL|LOOKUP_NAME_GROUP,
325 NULL, NULL, &group_sid, &type)) {
326 DEBUG(10, ("lookup_name_smbconf(%s) failed\n",
327 groupname));
328 goto done;
331 if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
332 (type != SID_NAME_WKN_GRP)) {
333 DEBUG(10, ("%s is a %s, not a group\n", groupname,
334 sid_type_lookup(type)));
335 goto done;
338 if (!sid_to_gid(&group_sid, &gid)) {
339 DEBUG(10, ("sid_to_gid(%s) for %s failed\n",
340 sid_string_dbg(&group_sid), groupname));
341 goto done;
345 * If the user has been forced and the forced group starts with a '+',
346 * then we only set the group to be the forced group if the forced
347 * user is a member of that group. Otherwise, the meaning of the '+'
348 * would be ignored.
351 if (force_user && user_must_be_member) {
352 if (user_in_group_sid(username, &group_sid)) {
353 sid_copy(pgroup_sid, &group_sid);
354 *pgid = gid;
355 DEBUG(3,("Forced group %s for member %s\n",
356 groupname, username));
357 } else {
358 DEBUG(0,("find_forced_group: forced user %s is not a member "
359 "of forced group %s. Disallowing access.\n",
360 username, groupname ));
361 result = NT_STATUS_MEMBER_NOT_IN_GROUP;
362 goto done;
364 } else {
365 sid_copy(pgroup_sid, &group_sid);
366 *pgid = gid;
367 DEBUG(3,("Forced group %s\n", groupname));
370 result = NT_STATUS_OK;
371 done:
372 TALLOC_FREE(frame);
373 return result;
376 /****************************************************************************
377 Create an auth_session_info structure for a connection_struct
378 ****************************************************************************/
380 static NTSTATUS create_connection_session_info(struct smbd_server_connection *sconn,
381 TALLOC_CTX *mem_ctx, int snum,
382 struct auth_session_info *vuid_serverinfo,
383 DATA_BLOB password,
384 struct auth_session_info **presult)
386 if (lp_guest_only(snum)) {
387 return make_session_info_guest(mem_ctx, presult);
390 if (vuid_serverinfo != NULL) {
392 struct auth_session_info *result;
395 * This is the normal security != share case where we have a
396 * valid vuid from the session setup. */
398 if (security_session_user_level(vuid_serverinfo, NULL) < SECURITY_USER) {
399 if (!lp_guest_ok(snum)) {
400 DEBUG(2, ("guest user (from session setup) "
401 "not permitted to access this share "
402 "(%s)\n", lp_servicename(snum)));
403 return NT_STATUS_ACCESS_DENIED;
405 } else {
406 if (!user_ok_token(vuid_serverinfo->unix_info->unix_name,
407 vuid_serverinfo->info->domain_name,
408 vuid_serverinfo->security_token, snum)) {
409 DEBUG(2, ("user '%s' (from session setup) not "
410 "permitted to access this share "
411 "(%s)\n",
412 vuid_serverinfo->unix_info->unix_name,
413 lp_servicename(snum)));
414 return NT_STATUS_ACCESS_DENIED;
418 result = copy_session_info(mem_ctx, vuid_serverinfo);
419 if (result == NULL) {
420 return NT_STATUS_NO_MEMORY;
423 *presult = result;
424 return NT_STATUS_OK;
427 if (lp_security() == SEC_SHARE) {
429 fstring user;
430 bool guest;
432 /* add the sharename as a possible user name if we
433 are in share mode security */
435 add_session_user(sconn, lp_servicename(snum));
437 /* shall we let them in? */
439 if (!authorise_login(sconn, snum,user,password,&guest)) {
440 DEBUG( 2, ( "Invalid username/password for [%s]\n",
441 lp_servicename(snum)) );
442 return NT_STATUS_WRONG_PASSWORD;
445 return make_session_info_from_username(mem_ctx, user, guest,
446 presult);
449 DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
450 return NT_STATUS_ACCESS_DENIED;
453 /****************************************************************************
454 set relavent user and group settings corresponding to force user/group
455 configuration for the given snum.
456 ****************************************************************************/
458 NTSTATUS set_conn_force_user_group(connection_struct *conn, int snum)
460 NTSTATUS status;
462 if (*lp_force_user(snum)) {
465 * Replace conn->session_info with a completely faked up one
466 * from the username we are forced into :-)
469 char *fuser;
470 struct auth_session_info *forced_serverinfo;
471 bool guest;
473 fuser = talloc_string_sub(conn, lp_force_user(snum), "%S",
474 lp_const_servicename(snum));
475 if (fuser == NULL) {
476 return NT_STATUS_NO_MEMORY;
479 guest = security_session_user_level(conn->session_info, NULL) < SECURITY_USER;
481 status = make_session_info_from_username(
482 conn, fuser,
483 guest,
484 &forced_serverinfo);
485 if (!NT_STATUS_IS_OK(status)) {
486 return status;
489 TALLOC_FREE(conn->session_info);
490 conn->session_info = forced_serverinfo;
492 conn->force_user = true;
493 DEBUG(3,("Forced user %s\n", fuser));
497 * If force group is true, then override
498 * any groupid stored for the connecting user.
501 if (*lp_force_group(snum)) {
503 status = find_forced_group(
504 conn->force_user, snum, conn->session_info->unix_info->unix_name,
505 &conn->session_info->security_token->sids[1],
506 &conn->session_info->unix_token->gid);
508 if (!NT_STATUS_IS_OK(status)) {
509 return status;
513 * We need to cache this gid, to use within
514 * change_to_user() separately from the conn->session_info
515 * struct. We only use conn->session_info directly if
516 * "force_user" was set.
518 conn->force_group_gid = conn->session_info->unix_token->gid;
521 return NT_STATUS_OK;
524 /****************************************************************************
525 Make a connection, given the snum to connect to, and the vuser of the
526 connecting user if appropriate.
527 ****************************************************************************/
529 connection_struct *make_connection_snum(struct smbd_server_connection *sconn,
530 int snum, user_struct *vuser,
531 DATA_BLOB password,
532 const char *pdev,
533 NTSTATUS *pstatus)
535 connection_struct *conn = NULL;
536 struct smb_filename *smb_fname_cpath = NULL;
537 fstring dev;
538 int ret;
539 bool on_err_call_dis_hook = false;
540 bool claimed_connection = false;
541 uid_t effuid;
542 gid_t effgid;
543 NTSTATUS status;
545 fstrcpy(dev, pdev);
547 *pstatus = share_sanity_checks(sconn->remote_address,
548 sconn->remote_hostname,
549 snum,
550 dev);
551 if (NT_STATUS_IS_ERR(*pstatus)) {
552 goto err_root_exit;
555 conn = conn_new(sconn);
556 if (!conn) {
557 DEBUG(0,("Couldn't find free connection.\n"));
558 *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
559 goto err_root_exit;
562 conn->params->service = snum;
564 status = create_connection_session_info(sconn,
565 conn, snum, vuser ? vuser->session_info : NULL, password,
566 &conn->session_info);
568 if (!NT_STATUS_IS_OK(status)) {
569 DEBUG(1, ("create_connection_session_info failed: %s\n",
570 nt_errstr(status)));
571 *pstatus = status;
572 goto err_root_exit;
575 if ((lp_guest_only(snum)) || (lp_security() == SEC_SHARE)) {
576 conn->force_user = true;
579 add_session_user(sconn, conn->session_info->unix_info->unix_name);
581 conn->num_files_open = 0;
582 conn->lastused = conn->lastused_count = time(NULL);
583 conn->used = True;
584 conn->printer = (strncmp(dev,"LPT",3) == 0);
585 conn->ipc = ( (strncmp(dev,"IPC",3) == 0) ||
586 ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) );
588 /* Case options for the share. */
589 if (lp_casesensitive(snum) == Auto) {
590 /* We will be setting this per packet. Set to be case
591 * insensitive for now. */
592 conn->case_sensitive = False;
593 } else {
594 conn->case_sensitive = (bool)lp_casesensitive(snum);
597 conn->case_preserve = lp_preservecase(snum);
598 conn->short_case_preserve = lp_shortpreservecase(snum);
600 conn->encrypt_level = lp_smb_encrypt(snum);
602 conn->veto_list = NULL;
603 conn->hide_list = NULL;
604 conn->veto_oplock_list = NULL;
605 conn->aio_write_behind_list = NULL;
607 conn->read_only = lp_readonly(SNUM(conn));
609 status = set_conn_force_user_group(conn, snum);
610 if (!NT_STATUS_IS_OK(status)) {
611 conn_free(conn);
612 *pstatus = status;
613 return NULL;
616 conn->vuid = (vuser != NULL) ? vuser->vuid : UID_FIELD_INVALID;
619 char *s = talloc_sub_advanced(talloc_tos(),
620 lp_servicename(SNUM(conn)),
621 conn->session_info->unix_info->unix_name,
622 conn->connectpath,
623 conn->session_info->unix_token->gid,
624 conn->session_info->unix_info->sanitized_username,
625 conn->session_info->info->domain_name,
626 lp_pathname(snum));
627 if (!s) {
628 *pstatus = NT_STATUS_NO_MEMORY;
629 goto err_root_exit;
632 if (!set_conn_connectpath(conn,s)) {
633 TALLOC_FREE(s);
634 *pstatus = NT_STATUS_NO_MEMORY;
635 goto err_root_exit;
637 DEBUG(3,("Connect path is '%s' for service [%s]\n",s,
638 lp_servicename(snum)));
639 TALLOC_FREE(s);
643 * New code to check if there's a share security descripter
644 * added from NT server manager. This is done after the
645 * smb.conf checks are done as we need a uid and token. JRA.
649 share_access_check(conn->session_info->security_token,
650 lp_servicename(snum), MAXIMUM_ALLOWED_ACCESS,
651 &conn->share_access);
653 if ((conn->share_access & FILE_WRITE_DATA) == 0) {
654 if ((conn->share_access & FILE_READ_DATA) == 0) {
655 /* No access, read or write. */
656 DEBUG(0,("make_connection: connection to %s "
657 "denied due to security "
658 "descriptor.\n",
659 lp_servicename(snum)));
660 *pstatus = NT_STATUS_ACCESS_DENIED;
661 goto err_root_exit;
662 } else {
663 conn->read_only = True;
666 /* Initialise VFS function pointers */
668 if (!smbd_vfs_init(conn)) {
669 DEBUG(0, ("vfs_init failed for service %s\n",
670 lp_servicename(snum)));
671 *pstatus = NT_STATUS_BAD_NETWORK_NAME;
672 goto err_root_exit;
675 /* ROOT Activities: */
676 /* explicitly check widelinks here so that we can correctly warn
677 * in the logs. */
678 widelinks_warning(snum);
681 * Enforce the max connections parameter.
684 if ((lp_max_connections(snum) > 0)
685 && (count_current_connections(lp_servicename(SNUM(conn)), True) >=
686 lp_max_connections(snum))) {
688 DEBUG(1, ("Max connections (%d) exceeded for %s\n",
689 lp_max_connections(snum), lp_servicename(snum)));
690 *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
691 goto err_root_exit;
695 * Get us an entry in the connections db
697 if (!claim_connection(conn, lp_servicename(snum))) {
698 DEBUG(1, ("Could not store connections entry\n"));
699 *pstatus = NT_STATUS_INTERNAL_DB_ERROR;
700 goto err_root_exit;
702 claimed_connection = true;
704 /* Invoke VFS make connection hook - this must be the first
705 filesystem operation that we do. */
707 if (SMB_VFS_CONNECT(conn, lp_servicename(snum),
708 conn->session_info->unix_info->unix_name) < 0) {
709 DEBUG(0,("make_connection: VFS make connection failed!\n"));
710 *pstatus = NT_STATUS_UNSUCCESSFUL;
711 goto err_root_exit;
714 /* Any error exit after here needs to call the disconnect hook. */
715 on_err_call_dis_hook = true;
717 if ((!conn->printer) && (!conn->ipc)) {
718 conn->notify_ctx = notify_init(conn,
719 sconn_server_id(sconn),
720 sconn->msg_ctx,
721 server_event_context(),
722 conn);
726 * Fix compatibility issue pointed out by Volker.
727 * We pass the conn->connectpath to the preexec
728 * scripts as a parameter, so attempt to canonicalize
729 * it here before calling the preexec scripts.
730 * We ignore errors here, as it is possible that
731 * the conn->connectpath doesn't exist yet and
732 * the preexec scripts will create them.
735 (void)canonicalize_connect_path(conn);
737 /* Preexecs are done here as they might make the dir we are to ChDir
738 * to below */
739 /* execute any "root preexec = " line */
740 if (*lp_rootpreexec(snum)) {
741 char *cmd = talloc_sub_advanced(talloc_tos(),
742 lp_servicename(SNUM(conn)),
743 conn->session_info->unix_info->unix_name,
744 conn->connectpath,
745 conn->session_info->unix_token->gid,
746 conn->session_info->unix_info->sanitized_username,
747 conn->session_info->info->domain_name,
748 lp_rootpreexec(snum));
749 DEBUG(5,("cmd=%s\n",cmd));
750 ret = smbrun(cmd,NULL);
751 TALLOC_FREE(cmd);
752 if (ret != 0 && lp_rootpreexec_close(snum)) {
753 DEBUG(1,("root preexec gave %d - failing "
754 "connection\n", ret));
755 *pstatus = NT_STATUS_ACCESS_DENIED;
756 goto err_root_exit;
760 /* USER Activites: */
761 if (!change_to_user(conn, conn->vuid)) {
762 /* No point continuing if they fail the basic checks */
763 DEBUG(0,("Can't become connected user!\n"));
764 *pstatus = NT_STATUS_LOGON_FAILURE;
765 goto err_root_exit;
768 effuid = geteuid();
769 effgid = getegid();
771 /* Remember that a different vuid can connect later without these
772 * checks... */
774 /* Preexecs are done here as they might make the dir we are to ChDir
775 * to below */
777 /* execute any "preexec = " line */
778 if (*lp_preexec(snum)) {
779 char *cmd = talloc_sub_advanced(talloc_tos(),
780 lp_servicename(SNUM(conn)),
781 conn->session_info->unix_info->unix_name,
782 conn->connectpath,
783 conn->session_info->unix_token->gid,
784 conn->session_info->unix_info->sanitized_username,
785 conn->session_info->info->domain_name,
786 lp_preexec(snum));
787 ret = smbrun(cmd,NULL);
788 TALLOC_FREE(cmd);
789 if (ret != 0 && lp_preexec_close(snum)) {
790 DEBUG(1,("preexec gave %d - failing connection\n",
791 ret));
792 *pstatus = NT_STATUS_ACCESS_DENIED;
793 goto err_root_exit;
797 #ifdef WITH_FAKE_KASERVER
798 if (lp_afs_share(snum)) {
799 afs_login(conn);
801 #endif
804 * we've finished with the user stuff - go back to root
805 * so the SMB_VFS_STAT call will only fail on path errors,
806 * not permission problems.
808 change_to_root_user();
809 /* ROOT Activites: */
812 * If widelinks are disallowed we need to canonicalise the connect
813 * path here to ensure we don't have any symlinks in the
814 * connectpath. We will be checking all paths on this connection are
815 * below this directory. We must do this after the VFS init as we
816 * depend on the realpath() pointer in the vfs table. JRA.
818 if (!lp_widelinks(snum)) {
819 if (!canonicalize_connect_path(conn)) {
820 DEBUG(0, ("canonicalize_connect_path failed "
821 "for service %s, path %s\n",
822 lp_servicename(snum),
823 conn->connectpath));
824 *pstatus = NT_STATUS_BAD_NETWORK_NAME;
825 goto err_root_exit;
829 /* Add veto/hide lists */
830 if (!IS_IPC(conn) && !IS_PRINT(conn)) {
831 set_namearray( &conn->veto_list, lp_veto_files(snum));
832 set_namearray( &conn->hide_list, lp_hide_files(snum));
833 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(snum));
834 set_namearray( &conn->aio_write_behind_list,
835 lp_aio_write_behind(snum));
837 status = create_synthetic_smb_fname(talloc_tos(), conn->connectpath,
838 NULL, NULL, &smb_fname_cpath);
839 if (!NT_STATUS_IS_OK(status)) {
840 *pstatus = status;
841 goto err_root_exit;
844 /* win2000 does not check the permissions on the directory
845 during the tree connect, instead relying on permission
846 check during individual operations. To match this behaviour
847 I have disabled this chdir check (tridge) */
848 /* the alternative is just to check the directory exists */
850 if ((ret = SMB_VFS_STAT(conn, smb_fname_cpath)) != 0 ||
851 !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
852 if (ret == 0 && !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
853 DEBUG(0,("'%s' is not a directory, when connecting to "
854 "[%s]\n", conn->connectpath,
855 lp_servicename(snum)));
856 } else {
857 DEBUG(0,("'%s' does not exist or permission denied "
858 "when connecting to [%s] Error was %s\n",
859 conn->connectpath, lp_servicename(snum),
860 strerror(errno) ));
862 *pstatus = NT_STATUS_BAD_NETWORK_NAME;
863 goto err_root_exit;
865 conn->base_share_dev = smb_fname_cpath->st.st_ex_dev;
867 string_set(&conn->origpath,conn->connectpath);
869 /* Figure out the characteristics of the underlying filesystem. This
870 * assumes that all the filesystem mounted withing a share path have
871 * the same characteristics, which is likely but not guaranteed.
874 conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
877 * Print out the 'connected as' stuff here as we need
878 * to know the effective uid and gid we will be using
879 * (at least initially).
882 if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
883 dbgtext( "%s (%s) ", get_remote_machine_name(),
884 tsocket_address_string(conn->sconn->remote_address,
885 talloc_tos()) );
886 dbgtext( "%s", srv_is_signing_active(sconn) ? "signed " : "");
887 dbgtext( "connect to service %s ", lp_servicename(snum) );
888 dbgtext( "initially as user %s ",
889 conn->session_info->unix_info->unix_name );
890 dbgtext( "(uid=%d, gid=%d) ", (int)effuid, (int)effgid );
891 dbgtext( "(pid %d)\n", (int)sys_getpid() );
894 return(conn);
896 err_root_exit:
897 TALLOC_FREE(smb_fname_cpath);
898 /* We must exit this function as root. */
899 if (geteuid() != 0) {
900 change_to_root_user();
902 if (on_err_call_dis_hook) {
903 /* Call VFS disconnect hook */
904 SMB_VFS_DISCONNECT(conn);
906 if (claimed_connection) {
907 yield_connection(conn, lp_servicename(snum));
909 if (conn) {
910 conn_free(conn);
912 return NULL;
915 /****************************************************************************
916 Make a connection to a service.
918 * @param service
919 ****************************************************************************/
921 connection_struct *make_connection(struct smbd_server_connection *sconn,
922 const char *service_in, DATA_BLOB password,
923 const char *pdev, uint16 vuid,
924 NTSTATUS *status)
926 uid_t euid;
927 user_struct *vuser = NULL;
928 char *service = NULL;
929 fstring dev;
930 int snum = -1;
932 fstrcpy(dev, pdev);
934 /* This must ONLY BE CALLED AS ROOT. As it exits this function as
935 * root. */
936 if (!non_root_mode() && (euid = geteuid()) != 0) {
937 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot "
938 "(%u)\n", (unsigned int)euid ));
939 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
942 if (conn_num_open(sconn) > 2047) {
943 *status = NT_STATUS_INSUFF_SERVER_RESOURCES;
944 return NULL;
947 if(lp_security() != SEC_SHARE) {
948 vuser = get_valid_user_struct(sconn, vuid);
949 if (!vuser) {
950 DEBUG(1,("make_connection: refusing to connect with "
951 "no session setup\n"));
952 *status = NT_STATUS_ACCESS_DENIED;
953 return NULL;
957 /* Logic to try and connect to the correct [homes] share, preferably
958 without too many getpwnam() lookups. This is particulary nasty for
959 winbind usernames, where the share name isn't the same as unix
960 username.
962 The snum of the homes share is stored on the vuser at session setup
963 time.
966 if (strequal(service_in,HOMES_NAME)) {
967 if(lp_security() != SEC_SHARE) {
968 DATA_BLOB no_pw = data_blob_null;
969 if (vuser->homes_snum == -1) {
970 DEBUG(2, ("[homes] share not available for "
971 "this user because it was not found "
972 "or created at session setup "
973 "time\n"));
974 *status = NT_STATUS_BAD_NETWORK_NAME;
975 return NULL;
977 DEBUG(5, ("making a connection to [homes] service "
978 "created at session setup time\n"));
979 return make_connection_snum(sconn,
980 vuser->homes_snum,
981 vuser, no_pw,
982 dev, status);
983 } else {
984 /* Security = share. Try with
985 * current_user_info.smb_name as the username. */
986 if (*current_user_info.smb_name) {
987 char *unix_username = NULL;
988 (void)map_username(talloc_tos(),
989 current_user_info.smb_name,
990 &unix_username);
991 snum = find_service(talloc_tos(),
992 unix_username,
993 &unix_username);
994 if (!unix_username) {
995 *status = NT_STATUS_NO_MEMORY;
997 return NULL;
999 if (snum != -1) {
1000 DEBUG(5, ("making a connection to 'homes' "
1001 "service %s based on "
1002 "security=share\n", service_in));
1003 return make_connection_snum(sconn,
1004 snum, NULL,
1005 password,
1006 dev, status);
1009 } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
1010 && strequal(service_in,
1011 lp_servicename(vuser->homes_snum))) {
1012 DATA_BLOB no_pw = data_blob_null;
1013 DEBUG(5, ("making a connection to 'homes' service [%s] "
1014 "created at session setup time\n", service_in));
1015 return make_connection_snum(sconn,
1016 vuser->homes_snum,
1017 vuser, no_pw,
1018 dev, status);
1021 service = talloc_strdup(talloc_tos(), service_in);
1022 if (!service) {
1023 *status = NT_STATUS_NO_MEMORY;
1024 return NULL;
1027 strlower_m(service);
1029 snum = find_service(talloc_tos(), service, &service);
1030 if (!service) {
1031 *status = NT_STATUS_NO_MEMORY;
1032 return NULL;
1035 if (snum < 0) {
1036 if (strequal(service,"IPC$") ||
1037 (lp_enable_asu_support() && strequal(service,"ADMIN$"))) {
1038 DEBUG(3,("refusing IPC connection to %s\n", service));
1039 *status = NT_STATUS_ACCESS_DENIED;
1040 return NULL;
1043 DEBUG(3,("%s (%s) couldn't find service %s\n",
1044 get_remote_machine_name(),
1045 tsocket_address_string(
1046 sconn->remote_address, talloc_tos()),
1047 service));
1048 *status = NT_STATUS_BAD_NETWORK_NAME;
1049 return NULL;
1052 /* Handle non-Dfs clients attempting connections to msdfs proxy */
1053 if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0')) {
1054 DEBUG(3, ("refusing connection to dfs proxy share '%s' "
1055 "(pointing to %s)\n",
1056 service, lp_msdfs_proxy(snum)));
1057 *status = NT_STATUS_BAD_NETWORK_NAME;
1058 return NULL;
1061 DEBUG(5, ("making a connection to 'normal' service %s\n", service));
1063 return make_connection_snum(sconn, snum, vuser,
1064 password,
1065 dev, status);
1068 /****************************************************************************
1069 Close a cnum.
1070 ****************************************************************************/
1072 void close_cnum(connection_struct *conn, uint16 vuid)
1074 file_close_conn(conn);
1076 if (!IS_IPC(conn)) {
1077 dptr_closecnum(conn);
1080 change_to_root_user();
1082 DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
1083 get_remote_machine_name(),
1084 tsocket_address_string(conn->sconn->remote_address,
1085 talloc_tos()),
1086 lp_servicename(SNUM(conn))));
1088 /* Call VFS disconnect hook */
1089 SMB_VFS_DISCONNECT(conn);
1091 yield_connection(conn, lp_servicename(SNUM(conn)));
1093 /* make sure we leave the directory available for unmount */
1094 vfs_ChDir(conn, "/");
1096 /* execute any "postexec = " line */
1097 if (*lp_postexec(SNUM(conn)) &&
1098 change_to_user(conn, vuid)) {
1099 char *cmd = talloc_sub_advanced(talloc_tos(),
1100 lp_servicename(SNUM(conn)),
1101 conn->session_info->unix_info->unix_name,
1102 conn->connectpath,
1103 conn->session_info->unix_token->gid,
1104 conn->session_info->unix_info->sanitized_username,
1105 conn->session_info->info->domain_name,
1106 lp_postexec(SNUM(conn)));
1107 smbrun(cmd,NULL);
1108 TALLOC_FREE(cmd);
1109 change_to_root_user();
1112 change_to_root_user();
1113 /* execute any "root postexec = " line */
1114 if (*lp_rootpostexec(SNUM(conn))) {
1115 char *cmd = talloc_sub_advanced(talloc_tos(),
1116 lp_servicename(SNUM(conn)),
1117 conn->session_info->unix_info->unix_name,
1118 conn->connectpath,
1119 conn->session_info->unix_token->gid,
1120 conn->session_info->unix_info->sanitized_username,
1121 conn->session_info->info->domain_name,
1122 lp_rootpostexec(SNUM(conn)));
1123 smbrun(cmd,NULL);
1124 TALLOC_FREE(cmd);
1127 conn_free(conn);