Fix bug in SMB_FIND_INFO_STANDARD parsing found by Volker.
[Samba/gebeck_regimport.git] / source3 / smbd / service.c
blob0cd48f895046adbb45e9d13d270d79136a9d74c6
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"
34 static bool canonicalize_connect_path(connection_struct *conn)
36 bool ret;
37 char *resolved_name = SMB_VFS_REALPATH(conn,conn->connectpath);
38 if (!resolved_name) {
39 return false;
41 ret = set_conn_connectpath(conn,resolved_name);
42 SAFE_FREE(resolved_name);
43 return ret;
46 /****************************************************************************
47 Ensure when setting connectpath it is a canonicalized (no ./ // or ../)
48 absolute path stating in / and not ending in /.
49 Observent people will notice a similarity between this and check_path_syntax :-).
50 ****************************************************************************/
52 bool set_conn_connectpath(connection_struct *conn, const char *connectpath)
54 char *destname;
55 char *d;
56 const char *s = connectpath;
57 bool start_of_name_component = true;
59 if (connectpath == NULL || connectpath[0] == '\0') {
60 return false;
63 /* Allocate for strlen + '\0' + possible leading '/' */
64 destname = (char *)talloc_size(conn, strlen(connectpath) + 2);
65 if (!destname) {
66 return false;
68 d = destname;
70 *d++ = '/'; /* Always start with root. */
72 while (*s) {
73 if (*s == '/') {
74 /* Eat multiple '/' */
75 while (*s == '/') {
76 s++;
78 if ((d > destname + 1) && (*s != '\0')) {
79 *d++ = '/';
81 start_of_name_component = True;
82 continue;
85 if (start_of_name_component) {
86 if ((s[0] == '.') && (s[1] == '.') && (s[2] == '/' || s[2] == '\0')) {
87 /* Uh oh - "/../" or "/..\0" ! */
89 /* Go past the ../ or .. */
90 if (s[2] == '/') {
91 s += 3;
92 } else {
93 s += 2; /* Go past the .. */
96 /* If we just added a '/' - delete it */
97 if ((d > destname) && (*(d-1) == '/')) {
98 *(d-1) = '\0';
99 d--;
102 /* Are we at the start ? Can't go back further if so. */
103 if (d <= destname) {
104 *d++ = '/'; /* Can't delete root */
105 continue;
107 /* Go back one level... */
108 /* Decrement d first as d points to the *next* char to write into. */
109 for (d--; d > destname; d--) {
110 if (*d == '/') {
111 break;
114 /* We're still at the start of a name component, just the previous one. */
115 continue;
116 } else if ((s[0] == '.') && ((s[1] == '\0') || s[1] == '/')) {
117 /* Component of pathname can't be "." only - skip the '.' . */
118 if (s[1] == '/') {
119 s += 2;
120 } else {
121 s++;
123 continue;
127 if (!(*s & 0x80)) {
128 *d++ = *s++;
129 } else {
130 size_t siz;
131 /* Get the size of the next MB character. */
132 next_codepoint(s,&siz);
133 switch(siz) {
134 case 5:
135 *d++ = *s++;
136 /*fall through*/
137 case 4:
138 *d++ = *s++;
139 /*fall through*/
140 case 3:
141 *d++ = *s++;
142 /*fall through*/
143 case 2:
144 *d++ = *s++;
145 /*fall through*/
146 case 1:
147 *d++ = *s++;
148 break;
149 default:
150 break;
153 start_of_name_component = false;
155 *d = '\0';
157 /* And must not end in '/' */
158 if (d > destname + 1 && (*(d-1) == '/')) {
159 *(d-1) = '\0';
162 DEBUG(10,("set_conn_connectpath: service %s, connectpath = %s\n",
163 lp_servicename(talloc_tos(), SNUM(conn)), destname ));
165 talloc_free(conn->connectpath);
166 conn->connectpath = destname;
167 return true;
170 /****************************************************************************
171 Load parameters specific to a connection/service.
172 ****************************************************************************/
174 bool set_current_service(connection_struct *conn, uint16 flags, bool do_chdir)
176 int snum;
178 if (!conn) {
179 last_conn = NULL;
180 return(False);
183 conn->lastused_count++;
185 snum = SNUM(conn);
187 if (do_chdir &&
188 vfs_ChDir(conn,conn->connectpath) != 0 &&
189 vfs_ChDir(conn,conn->origpath) != 0) {
190 DEBUG(((errno!=EACCES)?0:3),("chdir (%s) failed, reason: %s\n",
191 conn->connectpath, strerror(errno)));
192 return(False);
195 if ((conn == last_conn) && (last_flags == flags)) {
196 return(True);
199 last_conn = conn;
200 last_flags = flags;
202 /* Obey the client case sensitivity requests - only for clients that support it. */
203 switch (lp_casesensitive(snum)) {
204 case Auto:
206 /* We need this uglyness due to DOS/Win9x clients that lie about case insensitivity. */
207 enum remote_arch_types ra_type = get_remote_arch();
208 if ((ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
209 /* Client can't support per-packet case sensitive pathnames. */
210 conn->case_sensitive = False;
211 } else {
212 conn->case_sensitive = !(flags & FLAG_CASELESS_PATHNAMES);
215 break;
216 case True:
217 conn->case_sensitive = True;
218 break;
219 default:
220 conn->case_sensitive = False;
221 break;
223 return(True);
226 /****************************************************************************
227 do some basic sainity checks on the share.
228 This function modifies dev, ecode.
229 ****************************************************************************/
231 static NTSTATUS share_sanity_checks(const struct tsocket_address *remote_address,
232 const char *rhost,
233 int snum,
234 fstring dev)
236 char *raddr;
238 raddr = tsocket_address_inet_addr_string(remote_address,
239 talloc_tos());
240 if (raddr == NULL) {
241 return NT_STATUS_NO_MEMORY;
244 if (!lp_snum_ok(snum) ||
245 !allow_access(lp_hostsdeny(snum), lp_hostsallow(snum),
246 rhost, raddr)) {
247 return NT_STATUS_ACCESS_DENIED;
250 if (dev[0] == '?' || !dev[0]) {
251 if (lp_print_ok(snum)) {
252 fstrcpy(dev,"LPT1:");
253 } else if (strequal(lp_fstype(talloc_tos(), snum), "IPC")) {
254 fstrcpy(dev, "IPC");
255 } else {
256 fstrcpy(dev,"A:");
260 if (!strupper_m(dev)) {
261 DEBUG(2,("strupper_m %s failed\n", dev));
262 return NT_STATUS_INVALID_PARAMETER;
265 if (lp_print_ok(snum)) {
266 if (!strequal(dev, "LPT1:")) {
267 return NT_STATUS_BAD_DEVICE_TYPE;
269 } else if (strequal(lp_fstype(talloc_tos(), snum), "IPC")) {
270 if (!strequal(dev, "IPC")) {
271 return NT_STATUS_BAD_DEVICE_TYPE;
273 } else if (!strequal(dev, "A:")) {
274 return NT_STATUS_BAD_DEVICE_TYPE;
277 /* Behave as a printer if we are supposed to */
278 if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) {
279 fstrcpy(dev, "LPT1:");
282 return NT_STATUS_OK;
286 * Go through lookup_name etc to find the force'd group.
288 * Create a new token from src_token, replacing the primary group sid with the
289 * one found.
292 static NTSTATUS find_forced_group(bool force_user,
293 int snum, const char *username,
294 struct dom_sid *pgroup_sid,
295 gid_t *pgid)
297 NTSTATUS result = NT_STATUS_NO_SUCH_GROUP;
298 TALLOC_CTX *frame = talloc_stackframe();
299 struct dom_sid group_sid;
300 enum lsa_SidType type;
301 char *groupname;
302 bool user_must_be_member = False;
303 gid_t gid;
305 groupname = lp_force_group(talloc_tos(), snum);
306 if (groupname == NULL) {
307 DEBUG(1, ("talloc_strdup failed\n"));
308 result = NT_STATUS_NO_MEMORY;
309 goto done;
312 if (groupname[0] == '+') {
313 user_must_be_member = True;
314 groupname += 1;
317 groupname = talloc_string_sub(talloc_tos(), groupname,
318 "%S", lp_servicename(talloc_tos(), snum));
319 if (groupname == NULL) {
320 DEBUG(1, ("talloc_string_sub failed\n"));
321 result = NT_STATUS_NO_MEMORY;
322 goto done;
325 if (!lookup_name_smbconf(talloc_tos(), groupname,
326 LOOKUP_NAME_ALL|LOOKUP_NAME_GROUP,
327 NULL, NULL, &group_sid, &type)) {
328 DEBUG(10, ("lookup_name_smbconf(%s) failed\n",
329 groupname));
330 goto done;
333 if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
334 (type != SID_NAME_WKN_GRP)) {
335 DEBUG(10, ("%s is a %s, not a group\n", groupname,
336 sid_type_lookup(type)));
337 goto done;
340 if (!sid_to_gid(&group_sid, &gid)) {
341 DEBUG(10, ("sid_to_gid(%s) for %s failed\n",
342 sid_string_dbg(&group_sid), groupname));
343 goto done;
347 * If the user has been forced and the forced group starts with a '+',
348 * then we only set the group to be the forced group if the forced
349 * user is a member of that group. Otherwise, the meaning of the '+'
350 * would be ignored.
353 if (force_user && user_must_be_member) {
354 if (user_in_group_sid(username, &group_sid)) {
355 sid_copy(pgroup_sid, &group_sid);
356 *pgid = gid;
357 DEBUG(3,("Forced group %s for member %s\n",
358 groupname, username));
359 } else {
360 DEBUG(0,("find_forced_group: forced user %s is not a member "
361 "of forced group %s. Disallowing access.\n",
362 username, groupname ));
363 result = NT_STATUS_MEMBER_NOT_IN_GROUP;
364 goto done;
366 } else {
367 sid_copy(pgroup_sid, &group_sid);
368 *pgid = gid;
369 DEBUG(3,("Forced group %s\n", groupname));
372 result = NT_STATUS_OK;
373 done:
374 TALLOC_FREE(frame);
375 return result;
378 /****************************************************************************
379 Create an auth_session_info structure for a connection_struct
380 ****************************************************************************/
382 static NTSTATUS create_connection_session_info(struct smbd_server_connection *sconn,
383 TALLOC_CTX *mem_ctx, int snum,
384 struct auth_session_info *session_info,
385 struct auth_session_info **presult)
387 struct auth_session_info *result;
389 if (lp_guest_only(snum)) {
390 return make_session_info_guest(mem_ctx, presult);
394 * This is the normal security != share case where we have a
395 * valid vuid from the session setup. */
397 if (security_session_user_level(session_info, NULL) < SECURITY_USER) {
398 if (!lp_guest_ok(snum)) {
399 DEBUG(2, ("guest user (from session setup) "
400 "not permitted to access this share "
401 "(%s)\n", lp_servicename(talloc_tos(), snum)));
402 return NT_STATUS_ACCESS_DENIED;
404 } else {
405 if (!user_ok_token(session_info->unix_info->unix_name,
406 session_info->info->domain_name,
407 session_info->security_token, snum)) {
408 DEBUG(2, ("user '%s' (from session setup) not "
409 "permitted to access this share "
410 "(%s)\n",
411 session_info->unix_info->unix_name,
412 lp_servicename(talloc_tos(), snum)));
413 return NT_STATUS_ACCESS_DENIED;
417 result = copy_session_info(mem_ctx, session_info);
418 if (result == NULL) {
419 return NT_STATUS_NO_MEMORY;
422 *presult = result;
423 return NT_STATUS_OK;
426 /****************************************************************************
427 set relavent user and group settings corresponding to force user/group
428 configuration for the given snum.
429 ****************************************************************************/
431 NTSTATUS set_conn_force_user_group(connection_struct *conn, int snum)
433 NTSTATUS status;
435 if (*lp_force_user(talloc_tos(), snum)) {
438 * Replace conn->session_info with a completely faked up one
439 * from the username we are forced into :-)
442 char *fuser;
443 char *sanitized_username;
444 struct auth_session_info *forced_serverinfo;
445 bool guest;
447 fuser = talloc_string_sub(conn, lp_force_user(talloc_tos(), snum), "%S",
448 lp_const_servicename(snum));
449 if (fuser == NULL) {
450 return NT_STATUS_NO_MEMORY;
453 guest = security_session_user_level(conn->session_info, NULL) < SECURITY_USER;
455 status = make_session_info_from_username(
456 conn, fuser,
457 guest,
458 &forced_serverinfo);
459 if (!NT_STATUS_IS_OK(status)) {
460 return status;
463 /* We don't want to replace the original sanitized_username
464 as it is the original user given in the connect attempt.
465 This is used in '%U' substitutions. */
466 sanitized_username = discard_const_p(char,
467 forced_serverinfo->unix_info->sanitized_username);
468 TALLOC_FREE(sanitized_username);
469 forced_serverinfo->unix_info->sanitized_username =
470 talloc_move(forced_serverinfo->unix_info,
471 &conn->session_info->unix_info->sanitized_username);
473 TALLOC_FREE(conn->session_info);
474 conn->session_info = forced_serverinfo;
476 conn->force_user = true;
477 DEBUG(3,("Forced user %s\n", fuser));
481 * If force group is true, then override
482 * any groupid stored for the connecting user.
485 if (*lp_force_group(talloc_tos(), snum)) {
487 status = find_forced_group(
488 conn->force_user, snum, conn->session_info->unix_info->unix_name,
489 &conn->session_info->security_token->sids[1],
490 &conn->session_info->unix_token->gid);
492 if (!NT_STATUS_IS_OK(status)) {
493 return status;
497 * We need to cache this gid, to use within
498 * change_to_user() separately from the conn->session_info
499 * struct. We only use conn->session_info directly if
500 * "force_user" was set.
502 conn->force_group_gid = conn->session_info->unix_token->gid;
505 return NT_STATUS_OK;
508 /****************************************************************************
509 Setup the share access mask for a connection.
510 ****************************************************************************/
512 static void create_share_access_mask(connection_struct *conn, int snum)
514 const struct security_token *token = conn->session_info->security_token;
516 share_access_check(token,
517 lp_servicename(talloc_tos(), snum),
518 MAXIMUM_ALLOWED_ACCESS,
519 &conn->share_access);
521 if (security_token_has_privilege(token, SEC_PRIV_SECURITY)) {
522 conn->share_access |= SEC_FLAG_SYSTEM_SECURITY;
524 if (security_token_has_privilege(token, SEC_PRIV_RESTORE)) {
525 conn->share_access |= (SEC_RIGHTS_PRIV_RESTORE);
527 if (security_token_has_privilege(token, SEC_PRIV_BACKUP)) {
528 conn->share_access |= (SEC_RIGHTS_PRIV_BACKUP);
530 if (security_token_has_privilege(token, SEC_PRIV_TAKE_OWNERSHIP)) {
531 conn->share_access |= (SEC_STD_WRITE_OWNER);
535 /****************************************************************************
536 Make a connection, given the snum to connect to, and the vuser of the
537 connecting user if appropriate.
538 ****************************************************************************/
540 static NTSTATUS make_connection_snum(struct smbd_server_connection *sconn,
541 connection_struct *conn,
542 int snum, struct user_struct *vuser,
543 const char *pdev)
545 struct smb_filename *smb_fname_cpath = NULL;
546 fstring dev;
547 int ret;
548 bool on_err_call_dis_hook = false;
549 bool claimed_connection = false;
550 uid_t effuid;
551 gid_t effgid;
552 NTSTATUS status;
554 fstrcpy(dev, pdev);
556 status = share_sanity_checks(sconn->remote_address,
557 sconn->remote_hostname,
558 snum,
559 dev);
560 if (NT_STATUS_IS_ERR(status)) {
561 goto err_root_exit;
564 conn->params->service = snum;
566 status = create_connection_session_info(sconn,
567 conn, snum, vuser->session_info,
568 &conn->session_info);
570 if (!NT_STATUS_IS_OK(status)) {
571 DEBUG(1, ("create_connection_session_info failed: %s\n",
572 nt_errstr(status)));
573 goto err_root_exit;
576 if (lp_guest_only(snum)) {
577 conn->force_user = true;
580 conn->num_files_open = 0;
581 conn->lastused = conn->lastused_count = time(NULL);
582 conn->printer = (strncmp(dev,"LPT",3) == 0);
583 conn->ipc = ( (strncmp(dev,"IPC",3) == 0) ||
584 ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) );
586 /* Case options for the share. */
587 if (lp_casesensitive(snum) == Auto) {
588 /* We will be setting this per packet. Set to be case
589 * insensitive for now. */
590 conn->case_sensitive = False;
591 } else {
592 conn->case_sensitive = (bool)lp_casesensitive(snum);
595 conn->case_preserve = lp_preservecase(snum);
596 conn->short_case_preserve = lp_shortpreservecase(snum);
598 conn->encrypt_level = lp_smb_encrypt(snum);
600 conn->veto_list = NULL;
601 conn->hide_list = NULL;
602 conn->veto_oplock_list = NULL;
603 conn->aio_write_behind_list = NULL;
605 conn->read_only = lp_readonly(SNUM(conn));
607 status = set_conn_force_user_group(conn, snum);
608 if (!NT_STATUS_IS_OK(status)) {
609 goto err_root_exit;
612 conn->vuid = vuser->vuid;
615 char *s = talloc_sub_advanced(talloc_tos(),
616 lp_servicename(talloc_tos(), SNUM(conn)),
617 conn->session_info->unix_info->unix_name,
618 conn->connectpath,
619 conn->session_info->unix_token->gid,
620 conn->session_info->unix_info->sanitized_username,
621 conn->session_info->info->domain_name,
622 lp_pathname(talloc_tos(), snum));
623 if (!s) {
624 status = NT_STATUS_NO_MEMORY;
625 goto err_root_exit;
628 if (!set_conn_connectpath(conn,s)) {
629 TALLOC_FREE(s);
630 status = NT_STATUS_NO_MEMORY;
631 goto err_root_exit;
633 DEBUG(3,("Connect path is '%s' for service [%s]\n",s,
634 lp_servicename(talloc_tos(), snum)));
635 TALLOC_FREE(s);
639 * New code to check if there's a share security descripter
640 * added from NT server manager. This is done after the
641 * smb.conf checks are done as we need a uid and token. JRA.
645 create_share_access_mask(conn, snum);
647 if ((conn->share_access & FILE_WRITE_DATA) == 0) {
648 if ((conn->share_access & FILE_READ_DATA) == 0) {
649 /* No access, read or write. */
650 DEBUG(0,("make_connection: connection to %s "
651 "denied due to security "
652 "descriptor.\n",
653 lp_servicename(talloc_tos(), snum)));
654 status = NT_STATUS_ACCESS_DENIED;
655 goto err_root_exit;
656 } else {
657 conn->read_only = True;
660 /* Initialise VFS function pointers */
662 if (!smbd_vfs_init(conn)) {
663 DEBUG(0, ("vfs_init failed for service %s\n",
664 lp_servicename(talloc_tos(), snum)));
665 status = NT_STATUS_BAD_NETWORK_NAME;
666 goto err_root_exit;
669 /* ROOT Activities: */
670 /* explicitly check widelinks here so that we can correctly warn
671 * in the logs. */
672 widelinks_warning(snum);
675 * Enforce the max connections parameter.
678 if ((lp_max_connections(snum) > 0)
679 && (count_current_connections(lp_servicename(talloc_tos(), SNUM(conn)), True) >=
680 lp_max_connections(snum))) {
682 DEBUG(1, ("Max connections (%d) exceeded for %s\n",
683 lp_max_connections(snum),
684 lp_servicename(talloc_tos(), snum)));
685 status = NT_STATUS_INSUFFICIENT_RESOURCES;
686 goto err_root_exit;
690 * Get us an entry in the connections db
692 if (!claim_connection(conn, lp_servicename(talloc_tos(), snum))) {
693 DEBUG(1, ("Could not store connections entry\n"));
694 status = NT_STATUS_INTERNAL_DB_ERROR;
695 goto err_root_exit;
697 claimed_connection = true;
699 /* Invoke VFS make connection hook - this must be the first
700 filesystem operation that we do. */
702 if (SMB_VFS_CONNECT(conn, lp_servicename(talloc_tos(), snum),
703 conn->session_info->unix_info->unix_name) < 0) {
704 DEBUG(0,("make_connection: VFS make connection failed!\n"));
705 status = NT_STATUS_UNSUCCESSFUL;
706 goto err_root_exit;
709 /* Any error exit after here needs to call the disconnect hook. */
710 on_err_call_dis_hook = true;
712 if ((!conn->printer) && (!conn->ipc) &&
713 lp_change_notify(conn->params)) {
714 if (sconn->notify_ctx == NULL) {
715 sconn->notify_ctx = notify_init(
716 sconn, sconn->msg_ctx, sconn->ev_ctx);
718 if (sconn->sys_notify_ctx == NULL) {
719 sconn->sys_notify_ctx = sys_notify_context_create(
720 sconn, sconn->ev_ctx);
724 if (lp_kernel_oplocks(snum)) {
725 init_kernel_oplocks(conn->sconn);
729 * Fix compatibility issue pointed out by Volker.
730 * We pass the conn->connectpath to the preexec
731 * scripts as a parameter, so attempt to canonicalize
732 * it here before calling the preexec scripts.
733 * We ignore errors here, as it is possible that
734 * the conn->connectpath doesn't exist yet and
735 * the preexec scripts will create them.
738 (void)canonicalize_connect_path(conn);
740 /* Preexecs are done here as they might make the dir we are to ChDir
741 * to below */
742 /* execute any "root preexec = " line */
743 if (*lp_rootpreexec(talloc_tos(), snum)) {
744 char *cmd = talloc_sub_advanced(talloc_tos(),
745 lp_servicename(talloc_tos(), SNUM(conn)),
746 conn->session_info->unix_info->unix_name,
747 conn->connectpath,
748 conn->session_info->unix_token->gid,
749 conn->session_info->unix_info->sanitized_username,
750 conn->session_info->info->domain_name,
751 lp_rootpreexec(talloc_tos(), snum));
752 DEBUG(5,("cmd=%s\n",cmd));
753 ret = smbrun(cmd,NULL);
754 TALLOC_FREE(cmd);
755 if (ret != 0 && lp_rootpreexec_close(snum)) {
756 DEBUG(1,("root preexec gave %d - failing "
757 "connection\n", ret));
758 status = NT_STATUS_ACCESS_DENIED;
759 goto err_root_exit;
763 /* USER Activites: */
764 if (!change_to_user(conn, conn->vuid)) {
765 /* No point continuing if they fail the basic checks */
766 DEBUG(0,("Can't become connected user!\n"));
767 status = NT_STATUS_LOGON_FAILURE;
768 goto err_root_exit;
771 effuid = geteuid();
772 effgid = getegid();
774 /* Remember that a different vuid can connect later without these
775 * checks... */
777 /* Preexecs are done here as they might make the dir we are to ChDir
778 * to below */
780 /* execute any "preexec = " line */
781 if (*lp_preexec(talloc_tos(), snum)) {
782 char *cmd = talloc_sub_advanced(talloc_tos(),
783 lp_servicename(talloc_tos(), SNUM(conn)),
784 conn->session_info->unix_info->unix_name,
785 conn->connectpath,
786 conn->session_info->unix_token->gid,
787 conn->session_info->unix_info->sanitized_username,
788 conn->session_info->info->domain_name,
789 lp_preexec(talloc_tos(), snum));
790 ret = smbrun(cmd,NULL);
791 TALLOC_FREE(cmd);
792 if (ret != 0 && lp_preexec_close(snum)) {
793 DEBUG(1,("preexec gave %d - failing connection\n",
794 ret));
795 status = NT_STATUS_ACCESS_DENIED;
796 goto err_root_exit;
800 #ifdef WITH_FAKE_KASERVER
801 if (lp_afs_share(snum)) {
802 afs_login(conn);
804 #endif
807 * we've finished with the user stuff - go back to root
808 * so the SMB_VFS_STAT call will only fail on path errors,
809 * not permission problems.
811 change_to_root_user();
812 /* ROOT Activites: */
815 * If widelinks are disallowed we need to canonicalise the connect
816 * path here to ensure we don't have any symlinks in the
817 * connectpath. We will be checking all paths on this connection are
818 * below this directory. We must do this after the VFS init as we
819 * depend on the realpath() pointer in the vfs table. JRA.
821 if (!lp_widelinks(snum)) {
822 if (!canonicalize_connect_path(conn)) {
823 DEBUG(0, ("canonicalize_connect_path failed "
824 "for service %s, path %s\n",
825 lp_servicename(talloc_tos(), snum),
826 conn->connectpath));
827 status = NT_STATUS_BAD_NETWORK_NAME;
828 goto err_root_exit;
832 /* Add veto/hide lists */
833 if (!IS_IPC(conn) && !IS_PRINT(conn)) {
834 set_namearray( &conn->veto_list,
835 lp_veto_files(talloc_tos(), snum));
836 set_namearray( &conn->hide_list,
837 lp_hide_files(talloc_tos(), snum));
838 set_namearray( &conn->veto_oplock_list,
839 lp_veto_oplocks(talloc_tos(), snum));
840 set_namearray( &conn->aio_write_behind_list,
841 lp_aio_write_behind(talloc_tos(), snum));
843 status = create_synthetic_smb_fname(talloc_tos(), conn->connectpath,
844 NULL, NULL, &smb_fname_cpath);
845 if (!NT_STATUS_IS_OK(status)) {
846 goto err_root_exit;
849 /* win2000 does not check the permissions on the directory
850 during the tree connect, instead relying on permission
851 check during individual operations. To match this behaviour
852 I have disabled this chdir check (tridge) */
853 /* the alternative is just to check the directory exists */
855 if ((ret = SMB_VFS_STAT(conn, smb_fname_cpath)) != 0 ||
856 !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
857 if (ret == 0 && !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
858 DEBUG(0,("'%s' is not a directory, when connecting to "
859 "[%s]\n", conn->connectpath,
860 lp_servicename(talloc_tos(), snum)));
861 } else {
862 DEBUG(0,("'%s' does not exist or permission denied "
863 "when connecting to [%s] Error was %s\n",
864 conn->connectpath,
865 lp_servicename(talloc_tos(), snum),
866 strerror(errno) ));
868 status = NT_STATUS_BAD_NETWORK_NAME;
869 goto err_root_exit;
871 conn->base_share_dev = smb_fname_cpath->st.st_ex_dev;
873 talloc_free(conn->origpath);
874 conn->origpath = talloc_strdup(conn, conn->connectpath);
876 /* Figure out the characteristics of the underlying filesystem. This
877 * assumes that all the filesystem mounted withing a share path have
878 * the same characteristics, which is likely but not guaranteed.
881 conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
884 * Print out the 'connected as' stuff here as we need
885 * to know the effective uid and gid we will be using
886 * (at least initially).
889 if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
890 dbgtext( "%s (%s) ", get_remote_machine_name(),
891 tsocket_address_string(conn->sconn->remote_address,
892 talloc_tos()) );
893 dbgtext( "%s", srv_is_signing_active(sconn) ? "signed " : "");
894 dbgtext( "connect to service %s ",
895 lp_servicename(talloc_tos(), snum) );
896 dbgtext( "initially as user %s ",
897 conn->session_info->unix_info->unix_name );
898 dbgtext( "(uid=%d, gid=%d) ", (int)effuid, (int)effgid );
899 dbgtext( "(pid %d)\n", (int)getpid() );
902 return status;
904 err_root_exit:
906 TALLOC_FREE(smb_fname_cpath);
907 /* We must exit this function as root. */
908 if (geteuid() != 0) {
909 change_to_root_user();
911 if (on_err_call_dis_hook) {
912 /* Call VFS disconnect hook */
913 SMB_VFS_DISCONNECT(conn);
915 if (claimed_connection) {
916 yield_connection(conn, lp_servicename(talloc_tos(), snum));
918 return status;
921 /****************************************************************************
922 Make a connection to a service from SMB1. Internal interface.
923 ****************************************************************************/
925 static connection_struct *make_connection_smb1(struct smbd_server_connection *sconn,
926 int snum, struct user_struct *vuser,
927 const char *pdev,
928 NTSTATUS *pstatus)
930 struct smbXsrv_tcon *tcon;
931 NTSTATUS status;
932 NTTIME now = 0;
933 struct connection_struct *conn;
935 status = smb1srv_tcon_create(sconn->conn, now, &tcon);
936 if (!NT_STATUS_IS_OK(status)) {
937 DEBUG(0,("make_connection_smb1: Couldn't find free tcon %s.\n",
938 nt_errstr(status)));
939 *pstatus = status;
940 return NULL;
943 conn = conn_new(sconn);
944 if (!conn) {
945 TALLOC_FREE(tcon);
947 DEBUG(0,("make_connection_smb1: Couldn't find free connection.\n"));
948 *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
949 return NULL;
952 conn->cnum = tcon->global->tcon_wire_id;
953 conn->tcon = tcon;
955 *pstatus = make_connection_snum(sconn,
956 conn,
957 snum,
958 vuser,
959 pdev);
960 if (!NT_STATUS_IS_OK(*pstatus)) {
961 conn_free(conn);
962 TALLOC_FREE(tcon);
963 return NULL;
966 tcon->global->share_name = lp_servicename(tcon->global, SNUM(conn));
967 if (tcon->global->share_name == NULL) {
968 conn_free(conn);
969 TALLOC_FREE(tcon);
970 *pstatus = NT_STATUS_NO_MEMORY;
971 return NULL;
974 tcon->compat = talloc_move(tcon, &conn);
975 tcon->status = NT_STATUS_OK;
977 *pstatus = smbXsrv_tcon_update(tcon);
978 if (!NT_STATUS_IS_OK(*pstatus)) {
979 TALLOC_FREE(tcon);
980 return NULL;
983 return tcon->compat;
986 /****************************************************************************
987 Make a connection to a service from SMB2. External SMB2 interface.
988 We must set cnum before claiming connection.
989 ****************************************************************************/
991 connection_struct *make_connection_smb2(struct smbd_server_connection *sconn,
992 struct smbXsrv_tcon *tcon,
993 int snum,
994 struct user_struct *vuser,
995 const char *pdev,
996 NTSTATUS *pstatus)
998 connection_struct *conn = conn_new(sconn);
999 if (!conn) {
1000 DEBUG(0,("make_connection_smb2: Couldn't find free connection.\n"));
1001 *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
1002 return NULL;
1005 conn->cnum = tcon->global->tcon_wire_id;
1006 conn->tcon = tcon;
1008 *pstatus = make_connection_snum(sconn,
1009 conn,
1010 snum,
1011 vuser,
1012 pdev);
1013 if (!NT_STATUS_IS_OK(*pstatus)) {
1014 conn_free(conn);
1015 return NULL;
1017 return conn;
1020 /****************************************************************************
1021 Make a connection to a service. External SMB1 interface.
1023 * @param service
1024 ****************************************************************************/
1026 connection_struct *make_connection(struct smbd_server_connection *sconn,
1027 const char *service_in,
1028 const char *pdev, uint64_t vuid,
1029 NTSTATUS *status)
1031 uid_t euid;
1032 struct user_struct *vuser = NULL;
1033 char *service = NULL;
1034 fstring dev;
1035 int snum = -1;
1037 fstrcpy(dev, pdev);
1039 /* This must ONLY BE CALLED AS ROOT. As it exits this function as
1040 * root. */
1041 if (!non_root_mode() && (euid = geteuid()) != 0) {
1042 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot "
1043 "(%u)\n", (unsigned int)euid ));
1044 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
1047 if (conn_num_open(sconn) > 2047) {
1048 *status = NT_STATUS_INSUFF_SERVER_RESOURCES;
1049 return NULL;
1052 vuser = get_valid_user_struct(sconn, vuid);
1053 if (!vuser) {
1054 DEBUG(1,("make_connection: refusing to connect with "
1055 "no session setup\n"));
1056 *status = NT_STATUS_ACCESS_DENIED;
1057 return NULL;
1060 /* Logic to try and connect to the correct [homes] share, preferably
1061 without too many getpwnam() lookups. This is particulary nasty for
1062 winbind usernames, where the share name isn't the same as unix
1063 username.
1065 The snum of the homes share is stored on the vuser at session setup
1066 time.
1069 if (strequal(service_in,HOMES_NAME)) {
1070 if (vuser->homes_snum == -1) {
1071 DEBUG(2, ("[homes] share not available for "
1072 "this user because it was not found "
1073 "or created at session setup "
1074 "time\n"));
1075 *status = NT_STATUS_BAD_NETWORK_NAME;
1076 return NULL;
1078 DEBUG(5, ("making a connection to [homes] service "
1079 "created at session setup time\n"));
1080 return make_connection_smb1(sconn,
1081 vuser->homes_snum,
1082 vuser,
1083 dev, status);
1084 } else if ((vuser->homes_snum != -1)
1085 && strequal(service_in,
1086 lp_servicename(talloc_tos(), vuser->homes_snum))) {
1087 DEBUG(5, ("making a connection to 'homes' service [%s] "
1088 "created at session setup time\n", service_in));
1089 return make_connection_smb1(sconn,
1090 vuser->homes_snum,
1091 vuser,
1092 dev, status);
1095 service = talloc_strdup(talloc_tos(), service_in);
1096 if (!service) {
1097 *status = NT_STATUS_NO_MEMORY;
1098 return NULL;
1101 if (!strlower_m(service)) {
1102 DEBUG(2, ("strlower_m %s failed\n", service));
1103 *status = NT_STATUS_INVALID_PARAMETER;
1104 return NULL;
1107 snum = find_service(talloc_tos(), service, &service);
1108 if (!service) {
1109 *status = NT_STATUS_NO_MEMORY;
1110 return NULL;
1113 if (snum < 0) {
1114 if (strequal(service,"IPC$") ||
1115 (lp_enable_asu_support() && strequal(service,"ADMIN$"))) {
1116 DEBUG(3,("refusing IPC connection to %s\n", service));
1117 *status = NT_STATUS_ACCESS_DENIED;
1118 return NULL;
1121 DEBUG(3,("%s (%s) couldn't find service %s\n",
1122 get_remote_machine_name(),
1123 tsocket_address_string(
1124 sconn->remote_address, talloc_tos()),
1125 service));
1126 *status = NT_STATUS_BAD_NETWORK_NAME;
1127 return NULL;
1130 /* Handle non-Dfs clients attempting connections to msdfs proxy */
1131 if (lp_host_msdfs() && (*lp_msdfs_proxy(talloc_tos(), snum) != '\0')) {
1132 DEBUG(3, ("refusing connection to dfs proxy share '%s' "
1133 "(pointing to %s)\n",
1134 service, lp_msdfs_proxy(talloc_tos(), snum)));
1135 *status = NT_STATUS_BAD_NETWORK_NAME;
1136 return NULL;
1139 DEBUG(5, ("making a connection to 'normal' service %s\n", service));
1141 return make_connection_smb1(sconn, snum, vuser,
1142 dev, status);
1145 /****************************************************************************
1146 Close a cnum.
1147 ****************************************************************************/
1149 void close_cnum(connection_struct *conn, uint64_t vuid)
1151 file_close_conn(conn);
1153 if (!IS_IPC(conn)) {
1154 dptr_closecnum(conn);
1157 change_to_root_user();
1159 DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
1160 get_remote_machine_name(),
1161 tsocket_address_string(conn->sconn->remote_address,
1162 talloc_tos()),
1163 lp_servicename(talloc_tos(), SNUM(conn))));
1165 /* Call VFS disconnect hook */
1166 SMB_VFS_DISCONNECT(conn);
1168 yield_connection(conn, lp_servicename(talloc_tos(), SNUM(conn)));
1170 /* make sure we leave the directory available for unmount */
1171 vfs_ChDir(conn, "/");
1173 /* execute any "postexec = " line */
1174 if (*lp_postexec(talloc_tos(), SNUM(conn)) &&
1175 change_to_user(conn, vuid)) {
1176 char *cmd = talloc_sub_advanced(talloc_tos(),
1177 lp_servicename(talloc_tos(), SNUM(conn)),
1178 conn->session_info->unix_info->unix_name,
1179 conn->connectpath,
1180 conn->session_info->unix_token->gid,
1181 conn->session_info->unix_info->sanitized_username,
1182 conn->session_info->info->domain_name,
1183 lp_postexec(talloc_tos(), SNUM(conn)));
1184 smbrun(cmd,NULL);
1185 TALLOC_FREE(cmd);
1186 change_to_root_user();
1189 change_to_root_user();
1190 /* execute any "root postexec = " line */
1191 if (*lp_rootpostexec(talloc_tos(), SNUM(conn))) {
1192 char *cmd = talloc_sub_advanced(talloc_tos(),
1193 lp_servicename(talloc_tos(), SNUM(conn)),
1194 conn->session_info->unix_info->unix_name,
1195 conn->connectpath,
1196 conn->session_info->unix_token->gid,
1197 conn->session_info->unix_info->sanitized_username,
1198 conn->session_info->info->domain_name,
1199 lp_rootpostexec(talloc_tos(), SNUM(conn)));
1200 smbrun(cmd,NULL);
1201 TALLOC_FREE(cmd);
1204 conn_free(conn);