Fix for CVE-2009-2813.
[Samba.git] / source / smbd / service.c
blob390e606f3ce94bb4b3a1fbdf7842c85914f76bfa
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 2 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, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "includes.h"
23 extern userdom_struct current_user_info;
25 static BOOL canonicalize_path(connection_struct *conn, pstring path)
27 #ifdef REALPATH_TAKES_NULL
28 char *resolved_name = SMB_VFS_REALPATH(conn,path,NULL);
29 if (!resolved_name) {
30 return False;
32 pstrcpy(path, resolved_name);
33 SAFE_FREE(resolved_name);
34 return True;
35 #else
36 #ifdef PATH_MAX
37 char resolved_name_buf[PATH_MAX+1];
38 #else
39 pstring resolved_name_buf;
40 #endif
41 char *resolved_name = SMB_VFS_REALPATH(conn,path,resolved_name_buf);
42 if (!resolved_name) {
43 return False;
45 pstrcpy(path, resolved_name);
46 return True;
47 #endif /* REALPATH_TAKES_NULL */
50 /****************************************************************************
51 Ensure when setting connectpath it is a canonicalized (no ./ // or ../)
52 absolute path stating in / and not ending in /.
53 Observent people will notice a similarity between this and check_path_syntax :-).
54 ****************************************************************************/
56 void set_conn_connectpath(connection_struct *conn, const pstring connectpath)
58 pstring destname;
59 char *d = destname;
60 const char *s = connectpath;
61 BOOL start_of_name_component = True;
63 *d++ = '/'; /* Always start with root. */
65 while (*s) {
66 if (*s == '/') {
67 /* Eat multiple '/' */
68 while (*s == '/') {
69 s++;
71 if ((d > destname + 1) && (*s != '\0')) {
72 *d++ = '/';
74 start_of_name_component = True;
75 continue;
78 if (start_of_name_component) {
79 if ((s[0] == '.') && (s[1] == '.') && (s[2] == '/' || s[2] == '\0')) {
80 /* Uh oh - "/../" or "/..\0" ! */
82 /* Go past the ../ or .. */
83 if (s[2] == '/') {
84 s += 3;
85 } else {
86 s += 2; /* Go past the .. */
89 /* If we just added a '/' - delete it */
90 if ((d > destname) && (*(d-1) == '/')) {
91 *(d-1) = '\0';
92 d--;
95 /* Are we at the start ? Can't go back further if so. */
96 if (d <= destname) {
97 *d++ = '/'; /* Can't delete root */
98 continue;
100 /* Go back one level... */
101 /* Decrement d first as d points to the *next* char to write into. */
102 for (d--; d > destname; d--) {
103 if (*d == '/') {
104 break;
107 /* We're still at the start of a name component, just the previous one. */
108 continue;
109 } else if ((s[0] == '.') && ((s[1] == '\0') || s[1] == '/')) {
110 /* Component of pathname can't be "." only - skip the '.' . */
111 if (s[1] == '/') {
112 s += 2;
113 } else {
114 s++;
116 continue;
120 if (!(*s & 0x80)) {
121 *d++ = *s++;
122 } else {
123 size_t siz;
124 /* Get the size of the next MB character. */
125 next_codepoint(s,&siz);
126 switch(siz) {
127 case 5:
128 *d++ = *s++;
129 /*fall through*/
130 case 4:
131 *d++ = *s++;
132 /*fall through*/
133 case 3:
134 *d++ = *s++;
135 /*fall through*/
136 case 2:
137 *d++ = *s++;
138 /*fall through*/
139 case 1:
140 *d++ = *s++;
141 break;
142 default:
143 break;
146 start_of_name_component = False;
148 *d = '\0';
150 /* And must not end in '/' */
151 if (d > destname + 1 && (*(d-1) == '/')) {
152 *(d-1) = '\0';
155 DEBUG(10,("set_conn_connectpath: service %s, connectpath = %s\n",
156 lp_servicename(SNUM(conn)), destname ));
158 string_set(&conn->connectpath, destname);
161 /****************************************************************************
162 Load parameters specific to a connection/service.
163 ****************************************************************************/
165 BOOL set_current_service(connection_struct *conn, uint16 flags, BOOL do_chdir)
167 static connection_struct *last_conn;
168 static uint16 last_flags;
169 int snum;
171 if (!conn) {
172 last_conn = NULL;
173 return(False);
176 conn->lastused_count++;
178 snum = SNUM(conn);
180 if (do_chdir &&
181 vfs_ChDir(conn,conn->connectpath) != 0 &&
182 vfs_ChDir(conn,conn->origpath) != 0) {
183 DEBUG(0,("chdir (%s) failed\n",
184 conn->connectpath));
185 return(False);
188 if ((conn == last_conn) && (last_flags == flags)) {
189 return(True);
192 last_conn = conn;
193 last_flags = flags;
195 /* Obey the client case sensitivity requests - only for clients that support it. */
196 switch (lp_casesensitive(snum)) {
197 case Auto:
199 /* We need this uglyness due to DOS/Win9x clients that lie about case insensitivity. */
200 enum remote_arch_types ra_type = get_remote_arch();
201 if ((ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
202 /* Client can't support per-packet case sensitive pathnames. */
203 conn->case_sensitive = False;
204 } else {
205 conn->case_sensitive = !(flags & FLAG_CASELESS_PATHNAMES);
208 break;
209 case True:
210 conn->case_sensitive = True;
211 break;
212 default:
213 conn->case_sensitive = False;
214 break;
216 return(True);
219 /****************************************************************************
220 Add a home service. Returns the new service number or -1 if fail.
221 ****************************************************************************/
223 int add_home_service(const char *service, const char *username, const char *homedir)
225 int iHomeService;
227 if (!service || !homedir || homedir[0] == '\0')
228 return -1;
230 if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0)
231 return -1;
234 * If this is a winbindd provided username, remove
235 * the domain component before adding the service.
236 * Log a warning if the "path=" parameter does not
237 * include any macros.
241 const char *p = strchr(service,*lp_winbind_separator());
243 /* We only want the 'user' part of the string */
244 if (p) {
245 service = p + 1;
249 if (!lp_add_home(service, iHomeService, username, homedir)) {
250 return -1;
253 return lp_servicenumber(service);
259 * Find a service entry.
261 * @param service is modified (to canonical form??)
264 int find_service(fstring service)
266 int iService;
268 all_string_sub(service,"\\","/",0);
270 iService = lp_servicenumber(service);
272 /* now handle the special case of a home directory */
273 if (iService < 0) {
274 char *phome_dir = get_user_home_dir(service);
276 if(!phome_dir) {
278 * Try mapping the servicename, it may
279 * be a Windows to unix mapped user name.
281 if(map_username(service))
282 phome_dir = get_user_home_dir(service);
285 DEBUG(3,("checking for home directory %s gave %s\n",service,
286 phome_dir?phome_dir:"(NULL)"));
288 iService = add_home_service(service,service /* 'username' */, phome_dir);
291 /* If we still don't have a service, attempt to add it as a printer. */
292 if (iService < 0) {
293 int iPrinterService;
295 if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) >= 0) {
296 DEBUG(3,("checking whether %s is a valid printer name...\n", service));
297 if (pcap_printername_ok(service)) {
298 DEBUG(3,("%s is a valid printer name\n", service));
299 DEBUG(3,("adding %s as a printer service\n", service));
300 lp_add_printer(service, iPrinterService);
301 iService = lp_servicenumber(service);
302 if (iService < 0) {
303 DEBUG(0,("failed to add %s as a printer service!\n", service));
305 } else {
306 DEBUG(3,("%s is not a valid printer name\n", service));
311 /* Check for default vfs service? Unsure whether to implement this */
312 if (iService < 0) {
315 /* Is it a usershare service ? */
316 if (iService < 0 && *lp_usershare_path()) {
317 /* Ensure the name is canonicalized. */
318 strlower_m(service);
319 iService = load_usershare_service(service);
322 /* just possibly it's a default service? */
323 if (iService < 0) {
324 char *pdefservice = lp_defaultservice();
325 if (pdefservice && *pdefservice && !strequal(pdefservice,service) && !strstr_m(service,"..")) {
327 * We need to do a local copy here as lp_defaultservice()
328 * returns one of the rotating lp_string buffers that
329 * could get overwritten by the recursive find_service() call
330 * below. Fix from Josef Hinteregger <joehtg@joehtg.co.at>.
332 pstring defservice;
333 pstrcpy(defservice, pdefservice);
335 /* Disallow anything except explicit share names. */
336 if (strequal(defservice,HOMES_NAME) ||
337 strequal(defservice, PRINTERS_NAME) ||
338 strequal(defservice, "IPC$")) {
339 goto fail;
342 iService = find_service(defservice);
343 if (iService >= 0) {
344 all_string_sub(service, "_","/",0);
345 iService = lp_add_service(service, iService);
350 if (iService >= 0) {
351 if (!VALID_SNUM(iService)) {
352 DEBUG(0,("Invalid snum %d for %s\n",iService, service));
353 iService = -1;
357 fail:
359 if (iService < 0)
360 DEBUG(3,("find_service() failed to find service %s\n", service));
362 return (iService);
366 /****************************************************************************
367 do some basic sainity checks on the share.
368 This function modifies dev, ecode.
369 ****************************************************************************/
371 static NTSTATUS share_sanity_checks(int snum, fstring dev)
374 if (!lp_snum_ok(snum) ||
375 !check_access(smbd_server_fd(),
376 lp_hostsallow(snum), lp_hostsdeny(snum))) {
377 return NT_STATUS_ACCESS_DENIED;
380 if (dev[0] == '?' || !dev[0]) {
381 if (lp_print_ok(snum)) {
382 fstrcpy(dev,"LPT1:");
383 } else if (strequal(lp_fstype(snum), "IPC")) {
384 fstrcpy(dev, "IPC");
385 } else {
386 fstrcpy(dev,"A:");
390 strupper_m(dev);
392 if (lp_print_ok(snum)) {
393 if (!strequal(dev, "LPT1:")) {
394 return NT_STATUS_BAD_DEVICE_TYPE;
396 } else if (strequal(lp_fstype(snum), "IPC")) {
397 if (!strequal(dev, "IPC")) {
398 return NT_STATUS_BAD_DEVICE_TYPE;
400 } else if (!strequal(dev, "A:")) {
401 return NT_STATUS_BAD_DEVICE_TYPE;
404 /* Behave as a printer if we are supposed to */
405 if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) {
406 fstrcpy(dev, "LPT1:");
409 return NT_STATUS_OK;
412 static NTSTATUS find_forced_user(connection_struct *conn, BOOL vuser_is_guest, fstring username)
414 int snum = conn->params->service;
415 char *fuser, *found_username;
416 NTSTATUS result;
418 if (!(fuser = talloc_string_sub(conn->mem_ctx, lp_force_user(snum), "%S",
419 lp_servicename(snum)))) {
420 return NT_STATUS_NO_MEMORY;
423 result = create_token_from_username(conn->mem_ctx, fuser, vuser_is_guest,
424 &conn->uid, &conn->gid, &found_username,
425 &conn->nt_user_token);
426 if (!NT_STATUS_IS_OK(result)) {
427 return result;
430 fstrcpy(username, found_username);
432 TALLOC_FREE(fuser);
433 TALLOC_FREE(found_username);
434 return NT_STATUS_OK;
438 * Go through lookup_name etc to find the force'd group.
440 * Create a new token from src_token, replacing the primary group sid with the
441 * one found.
444 static NTSTATUS find_forced_group(BOOL force_user,
445 int snum, const char *username,
446 DOM_SID *pgroup_sid,
447 gid_t *pgid)
449 NTSTATUS result = NT_STATUS_NO_SUCH_GROUP;
450 TALLOC_CTX *mem_ctx;
451 DOM_SID group_sid;
452 enum lsa_SidType type;
453 char *groupname;
454 BOOL user_must_be_member = False;
455 gid_t gid;
457 ZERO_STRUCTP(pgroup_sid);
458 *pgid = (gid_t)-1;
460 mem_ctx = talloc_new(NULL);
461 if (mem_ctx == NULL) {
462 DEBUG(0, ("talloc_new failed\n"));
463 return NT_STATUS_NO_MEMORY;
466 groupname = talloc_strdup(mem_ctx, lp_force_group(snum));
467 if (groupname == NULL) {
468 DEBUG(1, ("talloc_strdup failed\n"));
469 result = NT_STATUS_NO_MEMORY;
470 goto done;
473 if (groupname[0] == '+') {
474 user_must_be_member = True;
475 groupname += 1;
478 groupname = talloc_string_sub(mem_ctx, groupname,
479 "%S", lp_servicename(snum));
481 if (!lookup_name_smbconf(mem_ctx, groupname,
482 LOOKUP_NAME_ALL|LOOKUP_NAME_GROUP,
483 NULL, NULL, &group_sid, &type)) {
484 DEBUG(10, ("lookup_name_smbconf(%s) failed\n",
485 groupname));
486 goto done;
489 if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
490 (type != SID_NAME_WKN_GRP)) {
491 DEBUG(10, ("%s is a %s, not a group\n", groupname,
492 sid_type_lookup(type)));
493 goto done;
496 if (!sid_to_gid(&group_sid, &gid)) {
497 DEBUG(10, ("sid_to_gid(%s) for %s failed\n",
498 sid_string_static(&group_sid), groupname));
499 goto done;
503 * If the user has been forced and the forced group starts with a '+',
504 * then we only set the group to be the forced group if the forced
505 * user is a member of that group. Otherwise, the meaning of the '+'
506 * would be ignored.
509 if (force_user && user_must_be_member) {
510 if (user_in_group_sid(username, &group_sid)) {
511 sid_copy(pgroup_sid, &group_sid);
512 *pgid = gid;
513 DEBUG(3,("Forced group %s for member %s\n",
514 groupname, username));
515 } else {
516 DEBUG(0,("find_forced_group: forced user %s is not a member "
517 "of forced group %s. Disallowing access.\n",
518 username, groupname ));
519 result = NT_STATUS_MEMBER_NOT_IN_GROUP;
520 goto done;
522 } else {
523 sid_copy(pgroup_sid, &group_sid);
524 *pgid = gid;
525 DEBUG(3,("Forced group %s\n", groupname));
528 result = NT_STATUS_OK;
529 done:
530 TALLOC_FREE(mem_ctx);
531 return result;
534 /****************************************************************************
535 Make a connection, given the snum to connect to, and the vuser of the
536 connecting user if appropriate.
537 ****************************************************************************/
539 static connection_struct *make_connection_snum(int snum, user_struct *vuser,
540 DATA_BLOB password,
541 const char *pdev,
542 NTSTATUS *status)
544 struct passwd *pass = NULL;
545 BOOL guest = False;
546 connection_struct *conn;
547 SMB_STRUCT_STAT st;
548 fstring user;
549 fstring dev;
550 int ret;
552 *user = 0;
553 fstrcpy(dev, pdev);
554 SET_STAT_INVALID(st);
556 if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, dev))) {
557 return NULL;
560 conn = conn_new();
561 if (!conn) {
562 DEBUG(0,("Couldn't find free connection.\n"));
563 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
564 return NULL;
567 conn->params->service = snum;
568 conn->nt_user_token = NULL;
570 if (lp_guest_only(snum)) {
571 const char *guestname = lp_guestaccount();
572 NTSTATUS status2;
573 char *found_username = NULL;
575 guest = True;
576 pass = getpwnam_alloc(NULL, guestname);
577 if (!pass) {
578 DEBUG(0,("make_connection_snum: Invalid guest "
579 "account %s??\n",guestname));
580 conn_free(conn);
581 *status = NT_STATUS_NO_SUCH_USER;
582 return NULL;
584 status2 = create_token_from_username(conn->mem_ctx, pass->pw_name, True,
585 &conn->uid, &conn->gid,
586 &found_username,
587 &conn->nt_user_token);
588 if (!NT_STATUS_IS_OK(status2)) {
589 TALLOC_FREE(pass);
590 conn_free(conn);
591 *status = status2;
592 return NULL;
594 fstrcpy(user, found_username);
595 string_set(&conn->user,user);
596 conn->force_user = True;
597 TALLOC_FREE(found_username);
598 TALLOC_FREE(pass);
599 DEBUG(3,("Guest only user %s\n",user));
600 } else if (vuser) {
601 if (vuser->guest) {
602 if (!lp_guest_ok(snum)) {
603 DEBUG(2, ("guest user (from session setup) "
604 "not permitted to access this share "
605 "(%s)\n", lp_servicename(snum)));
606 conn_free(conn);
607 *status = NT_STATUS_ACCESS_DENIED;
608 return NULL;
610 } else {
611 if (!user_ok_token(vuser->user.unix_name,
612 vuser->nt_user_token, snum)) {
613 DEBUG(2, ("user '%s' (from session setup) not "
614 "permitted to access this share "
615 "(%s)\n", vuser->user.unix_name,
616 lp_servicename(snum)));
617 conn_free(conn);
618 *status = NT_STATUS_ACCESS_DENIED;
619 return NULL;
622 conn->vuid = vuser->vuid;
623 conn->uid = vuser->uid;
624 conn->gid = vuser->gid;
625 string_set(&conn->user,vuser->user.unix_name);
626 fstrcpy(user,vuser->user.unix_name);
627 guest = vuser->guest;
628 } else if (lp_security() == SEC_SHARE) {
629 NTSTATUS status2;
630 char *found_username = NULL;
632 /* add it as a possible user name if we
633 are in share mode security */
634 add_session_user(lp_servicename(snum));
635 /* shall we let them in? */
636 if (!authorise_login(snum,user,password,&guest)) {
637 DEBUG( 2, ( "Invalid username/password for [%s]\n",
638 lp_servicename(snum)) );
639 conn_free(conn);
640 *status = NT_STATUS_WRONG_PASSWORD;
641 return NULL;
643 pass = Get_Pwnam(user);
644 status2 = create_token_from_username(conn->mem_ctx, pass->pw_name, True,
645 &conn->uid, &conn->gid,
646 &found_username,
647 &conn->nt_user_token);
648 if (!NT_STATUS_IS_OK(status2)) {
649 conn_free(conn);
650 *status = status2;
651 return NULL;
653 fstrcpy(user, found_username);
654 string_set(&conn->user,user);
655 TALLOC_FREE(found_username);
656 conn->force_user = True;
657 } else {
658 DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
659 conn_free(conn);
660 *status = NT_STATUS_ACCESS_DENIED;
661 return NULL;
664 add_session_user(user);
666 safe_strcpy(conn->client_address, client_addr(),
667 sizeof(conn->client_address)-1);
668 conn->num_files_open = 0;
669 conn->lastused = conn->lastused_count = time(NULL);
670 conn->used = True;
671 conn->printer = (strncmp(dev,"LPT",3) == 0);
672 conn->ipc = ( (strncmp(dev,"IPC",3) == 0) ||
673 ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) );
674 conn->dirptr = NULL;
676 /* Case options for the share. */
677 if (lp_casesensitive(snum) == Auto) {
678 /* We will be setting this per packet. Set to be case
679 * insensitive for now. */
680 conn->case_sensitive = False;
681 } else {
682 conn->case_sensitive = (BOOL)lp_casesensitive(snum);
685 conn->case_preserve = lp_preservecase(snum);
686 conn->short_case_preserve = lp_shortpreservecase(snum);
688 conn->veto_list = NULL;
689 conn->hide_list = NULL;
690 conn->veto_oplock_list = NULL;
691 conn->aio_write_behind_list = NULL;
692 string_set(&conn->dirpath,"");
693 string_set(&conn->user,user);
695 conn->read_only = lp_readonly(SNUM(conn));
696 conn->admin_user = False;
699 * If force user is true, then store the given userid and the gid of
700 * the user we're forcing.
701 * For auxiliary groups see below.
704 if (*lp_force_user(snum)) {
705 NTSTATUS status2;
707 status2 = find_forced_user(conn,
708 (vuser != NULL) && vuser->guest,
709 user);
710 if (!NT_STATUS_IS_OK(status2)) {
711 conn_free(conn);
712 *status = status2;
713 return NULL;
715 string_set(&conn->user,user);
716 conn->force_user = True;
717 DEBUG(3,("Forced user %s\n",user));
721 * If force group is true, then override
722 * any groupid stored for the connecting user.
725 if (*lp_force_group(snum)) {
726 NTSTATUS status2;
727 DOM_SID group_sid;
729 status2 = find_forced_group(conn->force_user,
730 snum, user,
731 &group_sid, &conn->gid);
732 if (!NT_STATUS_IS_OK(status2)) {
733 conn_free(conn);
734 *status = status2;
735 return NULL;
738 if ((conn->nt_user_token == NULL) && (vuser != NULL)) {
740 /* Not force user and not security=share, but force
741 * group. vuser has a token to copy */
743 conn->nt_user_token = dup_nt_token(
744 NULL, vuser->nt_user_token);
745 if (conn->nt_user_token == NULL) {
746 DEBUG(0, ("dup_nt_token failed\n"));
747 conn_free(conn);
748 *status = NT_STATUS_NO_MEMORY;
749 return NULL;
753 /* If conn->nt_user_token is still NULL, we have
754 * security=share. This means ignore the SID, as we had no
755 * vuser to copy from */
757 if (conn->nt_user_token != NULL) {
758 /* Overwrite the primary group sid */
759 sid_copy(&conn->nt_user_token->user_sids[1],
760 &group_sid);
763 conn->force_group = True;
766 if (conn->nt_user_token != NULL) {
767 size_t i;
769 /* We have a share-specific token from force [user|group].
770 * This means we have to create the list of unix groups from
771 * the list of sids. */
773 conn->ngroups = 0;
774 conn->groups = NULL;
776 for (i=0; i<conn->nt_user_token->num_sids; i++) {
777 gid_t gid;
778 DOM_SID *sid = &conn->nt_user_token->user_sids[i];
780 if (!sid_to_gid(sid, &gid)) {
781 DEBUG(10, ("Could not convert SID %s to gid, "
782 "ignoring it\n",
783 sid_string_static(sid)));
784 continue;
786 if (!add_gid_to_array_unique(conn->mem_ctx, gid, &conn->groups,
787 &conn->ngroups)) {
788 DEBUG(0, ("add_gid_to_array_unique failed\n"));
789 conn_free(conn);
790 *status = NT_STATUS_NO_MEMORY;
791 return NULL;
797 pstring s;
798 pstrcpy(s,lp_pathname(snum));
799 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
800 conn->connectpath, conn->gid,
801 get_current_username(),
802 current_user_info.domain,
803 s, sizeof(s));
805 if (s[0] == '\0') {
806 DEBUG(6, ("service [%s] did not resolve to a path\n",
807 lp_servicename(snum)));
808 conn_free(conn);
809 *status = NT_STATUS_BAD_NETWORK_NAME;
810 return NULL;
813 set_conn_connectpath(conn,s);
814 DEBUG(3,("Connect path is '%s' for service [%s]\n",s,
815 lp_servicename(snum)));
819 * New code to check if there's a share security descripter
820 * added from NT server manager. This is done after the
821 * smb.conf checks are done as we need a uid and token. JRA.
826 BOOL can_write = False;
827 NT_USER_TOKEN *token = conn->nt_user_token ?
828 conn->nt_user_token :
829 (vuser ? vuser->nt_user_token : NULL);
832 * I don't believe this can happen. But the
833 * logic above is convoluted enough to confuse
834 * automated checkers, so be sure. JRA.
837 if (token == NULL) {
838 DEBUG(0,("make_connection: connection to %s "
839 "denied due to missing "
840 "NT token.\n",
841 lp_servicename(snum)));
842 conn_free(conn);
843 *status = NT_STATUS_ACCESS_DENIED;
844 return NULL;
847 can_write = share_access_check(token,
848 lp_servicename(snum),
849 FILE_WRITE_DATA);
851 if (!can_write) {
852 if (!share_access_check(token,
853 lp_servicename(snum),
854 FILE_READ_DATA)) {
855 /* No access, read or write. */
856 DEBUG(0,("make_connection: connection to %s "
857 "denied due to security "
858 "descriptor.\n",
859 lp_servicename(snum)));
860 conn_free(conn);
861 *status = NT_STATUS_ACCESS_DENIED;
862 return NULL;
863 } else {
864 conn->read_only = True;
868 /* Initialise VFS function pointers */
870 if (!smbd_vfs_init(conn)) {
871 DEBUG(0, ("vfs_init failed for service %s\n",
872 lp_servicename(snum)));
873 conn_free(conn);
874 *status = NT_STATUS_BAD_NETWORK_NAME;
875 return NULL;
879 * If widelinks are disallowed we need to canonicalise the connect
880 * path here to ensure we don't have any symlinks in the
881 * connectpath. We will be checking all paths on this connection are
882 * below this directory. We must do this after the VFS init as we
883 * depend on the realpath() pointer in the vfs table. JRA.
885 if (!lp_widelinks(snum)) {
886 pstring s;
887 pstrcpy(s,conn->connectpath);
888 canonicalize_path(conn, s);
889 set_conn_connectpath(conn,s);
892 if ((!conn->printer) && (!conn->ipc)) {
893 conn->notify_ctx = notify_init(conn->mem_ctx, server_id_self(),
894 smbd_messaging_context(),
895 smbd_event_context(),
896 conn);
899 /* ROOT Activities: */
900 /* check number of connections */
901 if (!claim_connection(conn,
902 lp_servicename(snum),
903 lp_max_connections(snum),
904 False,0)) {
905 DEBUG(1,("too many connections - rejected\n"));
906 conn_free(conn);
907 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
908 return NULL;
911 /* Preexecs are done here as they might make the dir we are to ChDir
912 * to below */
913 /* execute any "root preexec = " line */
914 if (*lp_rootpreexec(snum)) {
915 pstring cmd;
916 pstrcpy(cmd,lp_rootpreexec(snum));
917 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
918 conn->connectpath, conn->gid,
919 get_current_username(),
920 current_user_info.domain,
921 cmd, sizeof(cmd));
922 DEBUG(5,("cmd=%s\n",cmd));
923 ret = smbrun(cmd,NULL);
924 if (ret != 0 && lp_rootpreexec_close(snum)) {
925 DEBUG(1,("root preexec gave %d - failing "
926 "connection\n", ret));
927 yield_connection(conn, lp_servicename(snum));
928 conn_free(conn);
929 *status = NT_STATUS_ACCESS_DENIED;
930 return NULL;
934 /* USER Activites: */
935 if (!change_to_user(conn, conn->vuid)) {
936 /* No point continuing if they fail the basic checks */
937 DEBUG(0,("Can't become connected user!\n"));
938 yield_connection(conn, lp_servicename(snum));
939 conn_free(conn);
940 *status = NT_STATUS_LOGON_FAILURE;
941 return NULL;
944 /* Remember that a different vuid can connect later without these
945 * checks... */
947 /* Preexecs are done here as they might make the dir we are to ChDir
948 * to below */
950 /* execute any "preexec = " line */
951 if (*lp_preexec(snum)) {
952 pstring cmd;
953 pstrcpy(cmd,lp_preexec(snum));
954 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
955 conn->connectpath, conn->gid,
956 get_current_username(),
957 current_user_info.domain,
958 cmd, sizeof(cmd));
959 ret = smbrun(cmd,NULL);
960 if (ret != 0 && lp_preexec_close(snum)) {
961 DEBUG(1,("preexec gave %d - failing connection\n",
962 ret));
963 change_to_root_user();
964 yield_connection(conn, lp_servicename(snum));
965 conn_free(conn);
966 *status = NT_STATUS_ACCESS_DENIED;
967 return NULL;
971 #ifdef WITH_FAKE_KASERVER
972 if (lp_afs_share(snum)) {
973 afs_login(conn);
975 #endif
977 /* Add veto/hide lists */
978 if (!IS_IPC(conn) && !IS_PRINT(conn)) {
979 set_namearray( &conn->veto_list, lp_veto_files(snum));
980 set_namearray( &conn->hide_list, lp_hide_files(snum));
981 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(snum));
984 /* Invoke VFS make connection hook - do this before the VFS_STAT call
985 to allow any filesystems needing user credentials to initialize
986 themselves. */
988 if (SMB_VFS_CONNECT(conn, lp_servicename(snum), user) < 0) {
989 DEBUG(0,("make_connection: VFS make connection failed!\n"));
990 change_to_root_user();
991 yield_connection(conn, lp_servicename(snum));
992 conn_free(conn);
993 *status = NT_STATUS_UNSUCCESSFUL;
994 return NULL;
997 /* win2000 does not check the permissions on the directory
998 during the tree connect, instead relying on permission
999 check during individual operations. To match this behaviour
1000 I have disabled this chdir check (tridge) */
1001 /* the alternative is just to check the directory exists */
1002 if ((ret = SMB_VFS_STAT(conn, conn->connectpath, &st)) != 0 ||
1003 !S_ISDIR(st.st_mode)) {
1004 if (ret == 0 && !S_ISDIR(st.st_mode)) {
1005 DEBUG(0,("'%s' is not a directory, when connecting to "
1006 "[%s]\n", conn->connectpath,
1007 lp_servicename(snum)));
1008 } else {
1009 DEBUG(0,("'%s' does not exist or permission denied "
1010 "when connecting to [%s] Error was %s\n",
1011 conn->connectpath, lp_servicename(snum),
1012 strerror(errno) ));
1014 change_to_root_user();
1015 /* Call VFS disconnect hook */
1016 SMB_VFS_DISCONNECT(conn);
1017 yield_connection(conn, lp_servicename(snum));
1018 conn_free(conn);
1019 *status = NT_STATUS_BAD_NETWORK_NAME;
1020 return NULL;
1023 string_set(&conn->origpath,conn->connectpath);
1025 #if SOFTLINK_OPTIMISATION
1026 /* resolve any soft links early if possible */
1027 if (vfs_ChDir(conn,conn->connectpath) == 0) {
1028 pstring s;
1029 pstrcpy(s,conn->connectpath);
1030 vfs_GetWd(conn,s);
1031 set_conn_connectpath(conn,s);
1032 vfs_ChDir(conn,conn->connectpath);
1034 #endif
1037 * Print out the 'connected as' stuff here as we need
1038 * to know the effective uid and gid we will be using
1039 * (at least initially).
1042 if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
1043 dbgtext( "%s (%s) ", get_remote_machine_name(),
1044 conn->client_address );
1045 dbgtext( "%s", srv_is_signing_active() ? "signed " : "");
1046 dbgtext( "connect to service %s ", lp_servicename(snum) );
1047 dbgtext( "initially as user %s ", user );
1048 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
1049 dbgtext( "(pid %d)\n", (int)sys_getpid() );
1052 /* we've finished with the user stuff - go back to root */
1053 change_to_root_user();
1054 return(conn);
1057 /***************************************************************************************
1058 Simple wrapper function for make_connection() to include a call to
1059 vfs_chdir()
1060 **************************************************************************************/
1062 connection_struct *make_connection_with_chdir(const char *service_in,
1063 DATA_BLOB password,
1064 const char *dev, uint16 vuid,
1065 NTSTATUS *status)
1067 connection_struct *conn = NULL;
1069 conn = make_connection(service_in, password, dev, vuid, status);
1072 * make_connection() does not change the directory for us any more
1073 * so we have to do it as a separate step --jerry
1076 if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) {
1077 DEBUG(0,("move_driver_to_download_area: Can't change "
1078 "directory to %s for [print$] (%s)\n",
1079 conn->connectpath,strerror(errno)));
1080 yield_connection(conn, lp_servicename(SNUM(conn)));
1081 conn_free(conn);
1082 *status = NT_STATUS_UNSUCCESSFUL;
1083 return NULL;
1086 return conn;
1089 /****************************************************************************
1090 Make a connection to a service.
1092 * @param service
1093 ****************************************************************************/
1095 connection_struct *make_connection(const char *service_in, DATA_BLOB password,
1096 const char *pdev, uint16 vuid,
1097 NTSTATUS *status)
1099 uid_t euid;
1100 user_struct *vuser = NULL;
1101 fstring service;
1102 fstring dev;
1103 int snum = -1;
1105 fstrcpy(dev, pdev);
1107 /* This must ONLY BE CALLED AS ROOT. As it exits this function as
1108 * root. */
1109 if (!non_root_mode() && (euid = geteuid()) != 0) {
1110 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot "
1111 "(%u)\n", (unsigned int)euid ));
1112 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
1115 if (conn_num_open() > 2047) {
1116 *status = NT_STATUS_INSUFF_SERVER_RESOURCES;
1117 return NULL;
1120 if(lp_security() != SEC_SHARE) {
1121 vuser = get_valid_user_struct(vuid);
1122 if (!vuser) {
1123 DEBUG(1,("make_connection: refusing to connect with "
1124 "no session setup\n"));
1125 *status = NT_STATUS_ACCESS_DENIED;
1126 return NULL;
1130 /* Logic to try and connect to the correct [homes] share, preferably
1131 without too many getpwnam() lookups. This is particulary nasty for
1132 winbind usernames, where the share name isn't the same as unix
1133 username.
1135 The snum of the homes share is stored on the vuser at session setup
1136 time.
1139 if (strequal(service_in,HOMES_NAME)) {
1140 if(lp_security() != SEC_SHARE) {
1141 DATA_BLOB no_pw = data_blob(NULL, 0);
1142 if (vuser->homes_snum == -1) {
1143 DEBUG(2, ("[homes] share not available for "
1144 "this user because it was not found "
1145 "or created at session setup "
1146 "time\n"));
1147 *status = NT_STATUS_BAD_NETWORK_NAME;
1148 return NULL;
1150 DEBUG(5, ("making a connection to [homes] service "
1151 "created at session setup time\n"));
1152 return make_connection_snum(vuser->homes_snum,
1153 vuser, no_pw,
1154 dev, status);
1155 } else {
1156 /* Security = share. Try with
1157 * current_user_info.smb_name as the username. */
1158 if (*current_user_info.smb_name) {
1159 fstring unix_username;
1160 fstrcpy(unix_username,
1161 current_user_info.smb_name);
1162 map_username(unix_username);
1163 snum = find_service(unix_username);
1165 if (snum != -1) {
1166 DEBUG(5, ("making a connection to 'homes' "
1167 "service %s based on "
1168 "security=share\n", service_in));
1169 return make_connection_snum(snum, NULL,
1170 password,
1171 dev, status);
1174 } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
1175 && strequal(service_in,
1176 lp_servicename(vuser->homes_snum))) {
1177 DATA_BLOB no_pw = data_blob(NULL, 0);
1178 DEBUG(5, ("making a connection to 'homes' service [%s] "
1179 "created at session setup time\n", service_in));
1180 return make_connection_snum(vuser->homes_snum,
1181 vuser, no_pw,
1182 dev, status);
1185 fstrcpy(service, service_in);
1187 strlower_m(service);
1189 snum = find_service(service);
1191 if (snum < 0) {
1192 if (strequal(service,"IPC$") ||
1193 (lp_enable_asu_support() && strequal(service,"ADMIN$"))) {
1194 DEBUG(3,("refusing IPC connection to %s\n", service));
1195 *status = NT_STATUS_ACCESS_DENIED;
1196 return NULL;
1199 DEBUG(0,("%s (%s) couldn't find service %s\n",
1200 get_remote_machine_name(), client_addr(), service));
1201 *status = NT_STATUS_BAD_NETWORK_NAME;
1202 return NULL;
1205 /* Handle non-Dfs clients attempting connections to msdfs proxy */
1206 if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0')) {
1207 DEBUG(3, ("refusing connection to dfs proxy share '%s' "
1208 "(pointing to %s)\n",
1209 service, lp_msdfs_proxy(snum)));
1210 *status = NT_STATUS_BAD_NETWORK_NAME;
1211 return NULL;
1214 DEBUG(5, ("making a connection to 'normal' service %s\n", service));
1216 return make_connection_snum(snum, vuser,
1217 password,
1218 dev, status);
1221 /****************************************************************************
1222 Close a cnum.
1223 ****************************************************************************/
1225 void close_cnum(connection_struct *conn, uint16 vuid)
1227 if (IS_IPC(conn)) {
1228 pipe_close_conn(conn);
1229 } else {
1230 file_close_conn(conn);
1231 dptr_closecnum(conn);
1234 change_to_root_user();
1236 DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
1237 get_remote_machine_name(),
1238 conn->client_address,
1239 lp_servicename(SNUM(conn))));
1241 /* Call VFS disconnect hook */
1242 SMB_VFS_DISCONNECT(conn);
1244 yield_connection(conn, lp_servicename(SNUM(conn)));
1246 /* make sure we leave the directory available for unmount */
1247 vfs_ChDir(conn, "/");
1249 /* execute any "postexec = " line */
1250 if (*lp_postexec(SNUM(conn)) &&
1251 change_to_user(conn, vuid)) {
1252 pstring cmd;
1253 pstrcpy(cmd,lp_postexec(SNUM(conn)));
1254 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
1255 conn->connectpath, conn->gid,
1256 get_current_username(),
1257 current_user_info.domain,
1258 cmd, sizeof(cmd));
1259 smbrun(cmd,NULL);
1260 change_to_root_user();
1263 change_to_root_user();
1264 /* execute any "root postexec = " line */
1265 if (*lp_rootpostexec(SNUM(conn))) {
1266 pstring cmd;
1267 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
1268 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
1269 conn->connectpath, conn->gid,
1270 get_current_username(),
1271 current_user_info.domain,
1272 cmd, sizeof(cmd));
1273 smbrun(cmd,NULL);
1276 conn_free(conn);