s3-utils/net_rpc_printer.c: print more info on write error
[Samba/gebeck_regimport.git] / source3 / smbd / service.c
blobf1d2ca040d2ce14e11ddac28acfeb651f5f90d12
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 "../lib/tsocket/tsocket.h"
23 #include "smbd/smbd.h"
24 #include "smbd/globals.h"
25 #include "../librpc/gen_ndr/netlogon.h"
26 #include "../libcli/security/security.h"
27 #include "printing/pcap.h"
28 #include "passdb/lookup_sid.h"
29 #include "auth.h"
30 #include "lib/param/loadparm.h"
32 extern userdom_struct current_user_info;
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 *)SMB_MALLOC(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(SNUM(conn)), destname ));
165 string_set(&conn->connectpath, destname);
166 SAFE_FREE(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(snum), "IPC")) {
254 fstrcpy(dev, "IPC");
255 } else {
256 fstrcpy(dev,"A:");
260 strupper_m(dev);
262 if (lp_print_ok(snum)) {
263 if (!strequal(dev, "LPT1:")) {
264 return NT_STATUS_BAD_DEVICE_TYPE;
266 } else if (strequal(lp_fstype(snum), "IPC")) {
267 if (!strequal(dev, "IPC")) {
268 return NT_STATUS_BAD_DEVICE_TYPE;
270 } else if (!strequal(dev, "A:")) {
271 return NT_STATUS_BAD_DEVICE_TYPE;
274 /* Behave as a printer if we are supposed to */
275 if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) {
276 fstrcpy(dev, "LPT1:");
279 return NT_STATUS_OK;
283 * Go through lookup_name etc to find the force'd group.
285 * Create a new token from src_token, replacing the primary group sid with the
286 * one found.
289 static NTSTATUS find_forced_group(bool force_user,
290 int snum, const char *username,
291 struct dom_sid *pgroup_sid,
292 gid_t *pgid)
294 NTSTATUS result = NT_STATUS_NO_SUCH_GROUP;
295 TALLOC_CTX *frame = talloc_stackframe();
296 struct dom_sid group_sid;
297 enum lsa_SidType type;
298 char *groupname;
299 bool user_must_be_member = False;
300 gid_t gid;
302 groupname = talloc_strdup(talloc_tos(), lp_force_group(snum));
303 if (groupname == NULL) {
304 DEBUG(1, ("talloc_strdup failed\n"));
305 result = NT_STATUS_NO_MEMORY;
306 goto done;
309 if (groupname[0] == '+') {
310 user_must_be_member = True;
311 groupname += 1;
314 groupname = talloc_string_sub(talloc_tos(), groupname,
315 "%S", lp_servicename(snum));
316 if (groupname == NULL) {
317 DEBUG(1, ("talloc_string_sub failed\n"));
318 result = NT_STATUS_NO_MEMORY;
319 goto done;
322 if (!lookup_name_smbconf(talloc_tos(), groupname,
323 LOOKUP_NAME_ALL|LOOKUP_NAME_GROUP,
324 NULL, NULL, &group_sid, &type)) {
325 DEBUG(10, ("lookup_name_smbconf(%s) failed\n",
326 groupname));
327 goto done;
330 if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
331 (type != SID_NAME_WKN_GRP)) {
332 DEBUG(10, ("%s is a %s, not a group\n", groupname,
333 sid_type_lookup(type)));
334 goto done;
337 if (!sid_to_gid(&group_sid, &gid)) {
338 DEBUG(10, ("sid_to_gid(%s) for %s failed\n",
339 sid_string_dbg(&group_sid), groupname));
340 goto done;
344 * If the user has been forced and the forced group starts with a '+',
345 * then we only set the group to be the forced group if the forced
346 * user is a member of that group. Otherwise, the meaning of the '+'
347 * would be ignored.
350 if (force_user && user_must_be_member) {
351 if (user_in_group_sid(username, &group_sid)) {
352 sid_copy(pgroup_sid, &group_sid);
353 *pgid = gid;
354 DEBUG(3,("Forced group %s for member %s\n",
355 groupname, username));
356 } else {
357 DEBUG(0,("find_forced_group: forced user %s is not a member "
358 "of forced group %s. Disallowing access.\n",
359 username, groupname ));
360 result = NT_STATUS_MEMBER_NOT_IN_GROUP;
361 goto done;
363 } else {
364 sid_copy(pgroup_sid, &group_sid);
365 *pgid = gid;
366 DEBUG(3,("Forced group %s\n", groupname));
369 result = NT_STATUS_OK;
370 done:
371 TALLOC_FREE(frame);
372 return result;
375 /****************************************************************************
376 Create an auth_session_info structure for a connection_struct
377 ****************************************************************************/
379 static NTSTATUS create_connection_session_info(struct smbd_server_connection *sconn,
380 TALLOC_CTX *mem_ctx, int snum,
381 struct auth_session_info *vuid_serverinfo,
382 DATA_BLOB password,
383 struct auth_session_info **presult)
385 if (lp_guest_only(snum)) {
386 return make_session_info_guest(mem_ctx, presult);
389 if (vuid_serverinfo != NULL) {
391 struct auth_session_info *result;
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(vuid_serverinfo, 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(snum)));
402 return NT_STATUS_ACCESS_DENIED;
404 } else {
405 if (!user_ok_token(vuid_serverinfo->unix_info->unix_name,
406 vuid_serverinfo->info->domain_name,
407 vuid_serverinfo->security_token, snum)) {
408 DEBUG(2, ("user '%s' (from session setup) not "
409 "permitted to access this share "
410 "(%s)\n",
411 vuid_serverinfo->unix_info->unix_name,
412 lp_servicename(snum)));
413 return NT_STATUS_ACCESS_DENIED;
417 result = copy_session_info(mem_ctx, vuid_serverinfo);
418 if (result == NULL) {
419 return NT_STATUS_NO_MEMORY;
422 *presult = result;
423 return NT_STATUS_OK;
426 if (lp_security() == SEC_SHARE) {
428 fstring user;
429 bool guest;
431 /* add the sharename as a possible user name if we
432 are in share mode security */
434 add_session_user(sconn, lp_servicename(snum));
436 /* shall we let them in? */
438 if (!authorise_login(sconn, snum,user,password,&guest)) {
439 DEBUG( 2, ( "Invalid username/password for [%s]\n",
440 lp_servicename(snum)) );
441 return NT_STATUS_WRONG_PASSWORD;
444 return make_session_info_from_username(mem_ctx, user, guest,
445 presult);
448 DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
449 return NT_STATUS_ACCESS_DENIED;
452 /****************************************************************************
453 set relavent user and group settings corresponding to force user/group
454 configuration for the given snum.
455 ****************************************************************************/
457 NTSTATUS set_conn_force_user_group(connection_struct *conn, int snum)
459 NTSTATUS status;
461 if (*lp_force_user(snum)) {
464 * Replace conn->session_info with a completely faked up one
465 * from the username we are forced into :-)
468 char *fuser;
469 struct auth_session_info *forced_serverinfo;
470 bool guest;
472 fuser = talloc_string_sub(conn, lp_force_user(snum), "%S",
473 lp_const_servicename(snum));
474 if (fuser == NULL) {
475 return NT_STATUS_NO_MEMORY;
478 guest = security_session_user_level(conn->session_info, NULL) < SECURITY_USER;
480 status = make_session_info_from_username(
481 conn, fuser,
482 guest,
483 &forced_serverinfo);
484 if (!NT_STATUS_IS_OK(status)) {
485 return status;
488 TALLOC_FREE(conn->session_info);
489 conn->session_info = forced_serverinfo;
491 conn->force_user = true;
492 DEBUG(3,("Forced user %s\n", fuser));
496 * If force group is true, then override
497 * any groupid stored for the connecting user.
500 if (*lp_force_group(snum)) {
502 status = find_forced_group(
503 conn->force_user, snum, conn->session_info->unix_info->unix_name,
504 &conn->session_info->security_token->sids[1],
505 &conn->session_info->unix_token->gid);
507 if (!NT_STATUS_IS_OK(status)) {
508 return status;
512 * We need to cache this gid, to use within
513 * change_to_user() separately from the conn->session_info
514 * struct. We only use conn->session_info directly if
515 * "force_user" was set.
517 conn->force_group_gid = conn->session_info->unix_token->gid;
520 return NT_STATUS_OK;
523 /****************************************************************************
524 Make a connection, given the snum to connect to, and the vuser of the
525 connecting user if appropriate.
526 ****************************************************************************/
528 connection_struct *make_connection_snum(struct smbd_server_connection *sconn,
529 int snum, user_struct *vuser,
530 DATA_BLOB password,
531 const char *pdev,
532 NTSTATUS *pstatus)
534 connection_struct *conn = NULL;
535 struct smb_filename *smb_fname_cpath = NULL;
536 fstring dev;
537 int ret;
538 bool on_err_call_dis_hook = false;
539 bool claimed_connection = false;
540 uid_t effuid;
541 gid_t effgid;
542 NTSTATUS status;
544 fstrcpy(dev, pdev);
546 *pstatus = share_sanity_checks(sconn->remote_address,
547 sconn->remote_hostname,
548 snum,
549 dev);
550 if (NT_STATUS_IS_ERR(*pstatus)) {
551 goto err_root_exit;
554 conn = conn_new(sconn);
555 if (!conn) {
556 DEBUG(0,("Couldn't find free connection.\n"));
557 *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
558 goto err_root_exit;
561 conn->params->service = snum;
563 status = create_connection_session_info(sconn,
564 conn, snum, vuser ? vuser->session_info : NULL, password,
565 &conn->session_info);
567 if (!NT_STATUS_IS_OK(status)) {
568 DEBUG(1, ("create_connection_session_info failed: %s\n",
569 nt_errstr(status)));
570 *pstatus = status;
571 goto err_root_exit;
574 if ((lp_guest_only(snum)) || (lp_security() == SEC_SHARE)) {
575 conn->force_user = true;
578 add_session_user(sconn, conn->session_info->unix_info->unix_name);
580 conn->num_files_open = 0;
581 conn->lastused = conn->lastused_count = time(NULL);
582 conn->used = True;
583 conn->printer = (strncmp(dev,"LPT",3) == 0);
584 conn->ipc = ( (strncmp(dev,"IPC",3) == 0) ||
585 ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) );
587 /* Case options for the share. */
588 if (lp_casesensitive(snum) == Auto) {
589 /* We will be setting this per packet. Set to be case
590 * insensitive for now. */
591 conn->case_sensitive = False;
592 } else {
593 conn->case_sensitive = (bool)lp_casesensitive(snum);
596 conn->case_preserve = lp_preservecase(snum);
597 conn->short_case_preserve = lp_shortpreservecase(snum);
599 conn->encrypt_level = lp_smb_encrypt(snum);
601 conn->veto_list = NULL;
602 conn->hide_list = NULL;
603 conn->veto_oplock_list = NULL;
604 conn->aio_write_behind_list = NULL;
606 conn->read_only = lp_readonly(SNUM(conn));
608 status = set_conn_force_user_group(conn, snum);
609 if (!NT_STATUS_IS_OK(status)) {
610 conn_free(conn);
611 *pstatus = status;
612 return NULL;
615 conn->vuid = (vuser != NULL) ? vuser->vuid : UID_FIELD_INVALID;
618 char *s = talloc_sub_advanced(talloc_tos(),
619 lp_servicename(SNUM(conn)),
620 conn->session_info->unix_info->unix_name,
621 conn->connectpath,
622 conn->session_info->unix_token->gid,
623 conn->session_info->unix_info->sanitized_username,
624 conn->session_info->info->domain_name,
625 lp_pathname(snum));
626 if (!s) {
627 *pstatus = NT_STATUS_NO_MEMORY;
628 goto err_root_exit;
631 if (!set_conn_connectpath(conn,s)) {
632 TALLOC_FREE(s);
633 *pstatus = NT_STATUS_NO_MEMORY;
634 goto err_root_exit;
636 DEBUG(3,("Connect path is '%s' for service [%s]\n",s,
637 lp_servicename(snum)));
638 TALLOC_FREE(s);
642 * New code to check if there's a share security descripter
643 * added from NT server manager. This is done after the
644 * smb.conf checks are done as we need a uid and token. JRA.
648 share_access_check(conn->session_info->security_token,
649 lp_servicename(snum), MAXIMUM_ALLOWED_ACCESS,
650 &conn->share_access);
652 if ((conn->share_access & FILE_WRITE_DATA) == 0) {
653 if ((conn->share_access & FILE_READ_DATA) == 0) {
654 /* No access, read or write. */
655 DEBUG(0,("make_connection: connection to %s "
656 "denied due to security "
657 "descriptor.\n",
658 lp_servicename(snum)));
659 *pstatus = NT_STATUS_ACCESS_DENIED;
660 goto err_root_exit;
661 } else {
662 conn->read_only = True;
665 /* Initialise VFS function pointers */
667 if (!smbd_vfs_init(conn)) {
668 DEBUG(0, ("vfs_init failed for service %s\n",
669 lp_servicename(snum)));
670 *pstatus = NT_STATUS_BAD_NETWORK_NAME;
671 goto err_root_exit;
674 /* ROOT Activities: */
675 /* explicitly check widelinks here so that we can correctly warn
676 * in the logs. */
677 widelinks_warning(snum);
680 * Enforce the max connections parameter.
683 if ((lp_max_connections(snum) > 0)
684 && (count_current_connections(lp_servicename(SNUM(conn)), True) >=
685 lp_max_connections(snum))) {
687 DEBUG(1, ("Max connections (%d) exceeded for %s\n",
688 lp_max_connections(snum), lp_servicename(snum)));
689 *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
690 goto err_root_exit;
694 * Get us an entry in the connections db
696 if (!claim_connection(conn, lp_servicename(snum))) {
697 DEBUG(1, ("Could not store connections entry\n"));
698 *pstatus = NT_STATUS_INTERNAL_DB_ERROR;
699 goto err_root_exit;
701 claimed_connection = true;
703 /* Invoke VFS make connection hook - this must be the first
704 filesystem operation that we do. */
706 if (SMB_VFS_CONNECT(conn, lp_servicename(snum),
707 conn->session_info->unix_info->unix_name) < 0) {
708 DEBUG(0,("make_connection: VFS make connection failed!\n"));
709 *pstatus = NT_STATUS_UNSUCCESSFUL;
710 goto err_root_exit;
713 /* Any error exit after here needs to call the disconnect hook. */
714 on_err_call_dis_hook = true;
716 if ((!conn->printer) && (!conn->ipc)) {
717 conn->notify_ctx = notify_init(conn,
718 sconn_server_id(sconn),
719 sconn->msg_ctx,
720 server_event_context(),
721 conn);
725 * Fix compatibility issue pointed out by Volker.
726 * We pass the conn->connectpath to the preexec
727 * scripts as a parameter, so attempt to canonicalize
728 * it here before calling the preexec scripts.
729 * We ignore errors here, as it is possible that
730 * the conn->connectpath doesn't exist yet and
731 * the preexec scripts will create them.
734 (void)canonicalize_connect_path(conn);
736 /* Preexecs are done here as they might make the dir we are to ChDir
737 * to below */
738 /* execute any "root preexec = " line */
739 if (*lp_rootpreexec(snum)) {
740 char *cmd = talloc_sub_advanced(talloc_tos(),
741 lp_servicename(SNUM(conn)),
742 conn->session_info->unix_info->unix_name,
743 conn->connectpath,
744 conn->session_info->unix_token->gid,
745 conn->session_info->unix_info->sanitized_username,
746 conn->session_info->info->domain_name,
747 lp_rootpreexec(snum));
748 DEBUG(5,("cmd=%s\n",cmd));
749 ret = smbrun(cmd,NULL);
750 TALLOC_FREE(cmd);
751 if (ret != 0 && lp_rootpreexec_close(snum)) {
752 DEBUG(1,("root preexec gave %d - failing "
753 "connection\n", ret));
754 *pstatus = NT_STATUS_ACCESS_DENIED;
755 goto err_root_exit;
759 /* USER Activites: */
760 if (!change_to_user(conn, conn->vuid)) {
761 /* No point continuing if they fail the basic checks */
762 DEBUG(0,("Can't become connected user!\n"));
763 *pstatus = NT_STATUS_LOGON_FAILURE;
764 goto err_root_exit;
767 effuid = geteuid();
768 effgid = getegid();
770 /* Remember that a different vuid can connect later without these
771 * checks... */
773 /* Preexecs are done here as they might make the dir we are to ChDir
774 * to below */
776 /* execute any "preexec = " line */
777 if (*lp_preexec(snum)) {
778 char *cmd = talloc_sub_advanced(talloc_tos(),
779 lp_servicename(SNUM(conn)),
780 conn->session_info->unix_info->unix_name,
781 conn->connectpath,
782 conn->session_info->unix_token->gid,
783 conn->session_info->unix_info->sanitized_username,
784 conn->session_info->info->domain_name,
785 lp_preexec(snum));
786 ret = smbrun(cmd,NULL);
787 TALLOC_FREE(cmd);
788 if (ret != 0 && lp_preexec_close(snum)) {
789 DEBUG(1,("preexec gave %d - failing connection\n",
790 ret));
791 *pstatus = NT_STATUS_ACCESS_DENIED;
792 goto err_root_exit;
796 #ifdef WITH_FAKE_KASERVER
797 if (lp_afs_share(snum)) {
798 afs_login(conn);
800 #endif
803 * we've finished with the user stuff - go back to root
804 * so the SMB_VFS_STAT call will only fail on path errors,
805 * not permission problems.
807 change_to_root_user();
808 /* ROOT Activites: */
811 * If widelinks are disallowed we need to canonicalise the connect
812 * path here to ensure we don't have any symlinks in the
813 * connectpath. We will be checking all paths on this connection are
814 * below this directory. We must do this after the VFS init as we
815 * depend on the realpath() pointer in the vfs table. JRA.
817 if (!lp_widelinks(snum)) {
818 if (!canonicalize_connect_path(conn)) {
819 DEBUG(0, ("canonicalize_connect_path failed "
820 "for service %s, path %s\n",
821 lp_servicename(snum),
822 conn->connectpath));
823 *pstatus = NT_STATUS_BAD_NETWORK_NAME;
824 goto err_root_exit;
828 /* Add veto/hide lists */
829 if (!IS_IPC(conn) && !IS_PRINT(conn)) {
830 set_namearray( &conn->veto_list, lp_veto_files(snum));
831 set_namearray( &conn->hide_list, lp_hide_files(snum));
832 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(snum));
833 set_namearray( &conn->aio_write_behind_list,
834 lp_aio_write_behind(snum));
836 status = create_synthetic_smb_fname(talloc_tos(), conn->connectpath,
837 NULL, NULL, &smb_fname_cpath);
838 if (!NT_STATUS_IS_OK(status)) {
839 *pstatus = status;
840 goto err_root_exit;
843 /* win2000 does not check the permissions on the directory
844 during the tree connect, instead relying on permission
845 check during individual operations. To match this behaviour
846 I have disabled this chdir check (tridge) */
847 /* the alternative is just to check the directory exists */
849 if ((ret = SMB_VFS_STAT(conn, smb_fname_cpath)) != 0 ||
850 !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
851 if (ret == 0 && !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
852 DEBUG(0,("'%s' is not a directory, when connecting to "
853 "[%s]\n", conn->connectpath,
854 lp_servicename(snum)));
855 } else {
856 DEBUG(0,("'%s' does not exist or permission denied "
857 "when connecting to [%s] Error was %s\n",
858 conn->connectpath, lp_servicename(snum),
859 strerror(errno) ));
861 *pstatus = NT_STATUS_BAD_NETWORK_NAME;
862 goto err_root_exit;
864 conn->base_share_dev = smb_fname_cpath->st.st_ex_dev;
866 string_set(&conn->origpath,conn->connectpath);
868 /* Figure out the characteristics of the underlying filesystem. This
869 * assumes that all the filesystem mounted withing a share path have
870 * the same characteristics, which is likely but not guaranteed.
873 conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
876 * Print out the 'connected as' stuff here as we need
877 * to know the effective uid and gid we will be using
878 * (at least initially).
881 if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
882 dbgtext( "%s (%s) ", get_remote_machine_name(),
883 tsocket_address_string(conn->sconn->remote_address,
884 talloc_tos()) );
885 dbgtext( "%s", srv_is_signing_active(sconn) ? "signed " : "");
886 dbgtext( "connect to service %s ", lp_servicename(snum) );
887 dbgtext( "initially as user %s ",
888 conn->session_info->unix_info->unix_name );
889 dbgtext( "(uid=%d, gid=%d) ", (int)effuid, (int)effgid );
890 dbgtext( "(pid %d)\n", (int)sys_getpid() );
893 return(conn);
895 err_root_exit:
896 TALLOC_FREE(smb_fname_cpath);
897 /* We must exit this function as root. */
898 if (geteuid() != 0) {
899 change_to_root_user();
901 if (on_err_call_dis_hook) {
902 /* Call VFS disconnect hook */
903 SMB_VFS_DISCONNECT(conn);
905 if (claimed_connection) {
906 yield_connection(conn, lp_servicename(snum));
908 if (conn) {
909 conn_free(conn);
911 return NULL;
914 /****************************************************************************
915 Make a connection to a service.
917 * @param service
918 ****************************************************************************/
920 connection_struct *make_connection(struct smbd_server_connection *sconn,
921 const char *service_in, DATA_BLOB password,
922 const char *pdev, uint16 vuid,
923 NTSTATUS *status)
925 uid_t euid;
926 user_struct *vuser = NULL;
927 char *service = NULL;
928 fstring dev;
929 int snum = -1;
931 fstrcpy(dev, pdev);
933 /* This must ONLY BE CALLED AS ROOT. As it exits this function as
934 * root. */
935 if (!non_root_mode() && (euid = geteuid()) != 0) {
936 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot "
937 "(%u)\n", (unsigned int)euid ));
938 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
941 if (conn_num_open(sconn) > 2047) {
942 *status = NT_STATUS_INSUFF_SERVER_RESOURCES;
943 return NULL;
946 if(lp_security() != SEC_SHARE) {
947 vuser = get_valid_user_struct(sconn, vuid);
948 if (!vuser) {
949 DEBUG(1,("make_connection: refusing to connect with "
950 "no session setup\n"));
951 *status = NT_STATUS_ACCESS_DENIED;
952 return NULL;
956 /* Logic to try and connect to the correct [homes] share, preferably
957 without too many getpwnam() lookups. This is particulary nasty for
958 winbind usernames, where the share name isn't the same as unix
959 username.
961 The snum of the homes share is stored on the vuser at session setup
962 time.
965 if (strequal(service_in,HOMES_NAME)) {
966 if(lp_security() != SEC_SHARE) {
967 DATA_BLOB no_pw = data_blob_null;
968 if (vuser->homes_snum == -1) {
969 DEBUG(2, ("[homes] share not available for "
970 "this user because it was not found "
971 "or created at session setup "
972 "time\n"));
973 *status = NT_STATUS_BAD_NETWORK_NAME;
974 return NULL;
976 DEBUG(5, ("making a connection to [homes] service "
977 "created at session setup time\n"));
978 return make_connection_snum(sconn,
979 vuser->homes_snum,
980 vuser, no_pw,
981 dev, status);
982 } else {
983 /* Security = share. Try with
984 * current_user_info.smb_name as the username. */
985 if (*current_user_info.smb_name) {
986 char *unix_username = NULL;
987 (void)map_username(talloc_tos(),
988 current_user_info.smb_name,
989 &unix_username);
990 snum = find_service(talloc_tos(),
991 unix_username,
992 &unix_username);
993 if (!unix_username) {
994 *status = NT_STATUS_NO_MEMORY;
996 return NULL;
998 if (snum != -1) {
999 DEBUG(5, ("making a connection to 'homes' "
1000 "service %s based on "
1001 "security=share\n", service_in));
1002 return make_connection_snum(sconn,
1003 snum, NULL,
1004 password,
1005 dev, status);
1008 } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
1009 && strequal(service_in,
1010 lp_servicename(vuser->homes_snum))) {
1011 DATA_BLOB no_pw = data_blob_null;
1012 DEBUG(5, ("making a connection to 'homes' service [%s] "
1013 "created at session setup time\n", service_in));
1014 return make_connection_snum(sconn,
1015 vuser->homes_snum,
1016 vuser, no_pw,
1017 dev, status);
1020 service = talloc_strdup(talloc_tos(), service_in);
1021 if (!service) {
1022 *status = NT_STATUS_NO_MEMORY;
1023 return NULL;
1026 strlower_m(service);
1028 snum = find_service(talloc_tos(), service, &service);
1029 if (!service) {
1030 *status = NT_STATUS_NO_MEMORY;
1031 return NULL;
1034 if (snum < 0) {
1035 if (strequal(service,"IPC$") ||
1036 (lp_enable_asu_support() && strequal(service,"ADMIN$"))) {
1037 DEBUG(3,("refusing IPC connection to %s\n", service));
1038 *status = NT_STATUS_ACCESS_DENIED;
1039 return NULL;
1042 DEBUG(3,("%s (%s) couldn't find service %s\n",
1043 get_remote_machine_name(),
1044 tsocket_address_string(
1045 sconn->remote_address, talloc_tos()),
1046 service));
1047 *status = NT_STATUS_BAD_NETWORK_NAME;
1048 return NULL;
1051 /* Handle non-Dfs clients attempting connections to msdfs proxy */
1052 if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0')) {
1053 DEBUG(3, ("refusing connection to dfs proxy share '%s' "
1054 "(pointing to %s)\n",
1055 service, lp_msdfs_proxy(snum)));
1056 *status = NT_STATUS_BAD_NETWORK_NAME;
1057 return NULL;
1060 DEBUG(5, ("making a connection to 'normal' service %s\n", service));
1062 return make_connection_snum(sconn, snum, vuser,
1063 password,
1064 dev, status);
1067 /****************************************************************************
1068 Close a cnum.
1069 ****************************************************************************/
1071 void close_cnum(connection_struct *conn, uint16 vuid)
1073 file_close_conn(conn);
1075 if (!IS_IPC(conn)) {
1076 dptr_closecnum(conn);
1079 change_to_root_user();
1081 DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
1082 get_remote_machine_name(),
1083 tsocket_address_string(conn->sconn->remote_address,
1084 talloc_tos()),
1085 lp_servicename(SNUM(conn))));
1087 /* Call VFS disconnect hook */
1088 SMB_VFS_DISCONNECT(conn);
1090 yield_connection(conn, lp_servicename(SNUM(conn)));
1092 /* make sure we leave the directory available for unmount */
1093 vfs_ChDir(conn, "/");
1095 /* execute any "postexec = " line */
1096 if (*lp_postexec(SNUM(conn)) &&
1097 change_to_user(conn, vuid)) {
1098 char *cmd = talloc_sub_advanced(talloc_tos(),
1099 lp_servicename(SNUM(conn)),
1100 conn->session_info->unix_info->unix_name,
1101 conn->connectpath,
1102 conn->session_info->unix_token->gid,
1103 conn->session_info->unix_info->sanitized_username,
1104 conn->session_info->info->domain_name,
1105 lp_postexec(SNUM(conn)));
1106 smbrun(cmd,NULL);
1107 TALLOC_FREE(cmd);
1108 change_to_root_user();
1111 change_to_root_user();
1112 /* execute any "root postexec = " line */
1113 if (*lp_rootpostexec(SNUM(conn))) {
1114 char *cmd = talloc_sub_advanced(talloc_tos(),
1115 lp_servicename(SNUM(conn)),
1116 conn->session_info->unix_info->unix_name,
1117 conn->connectpath,
1118 conn->session_info->unix_token->gid,
1119 conn->session_info->unix_info->sanitized_username,
1120 conn->session_info->info->domain_name,
1121 lp_rootpostexec(SNUM(conn)));
1122 smbrun(cmd,NULL);
1123 TALLOC_FREE(cmd);
1126 conn_free(conn);