Samba 3: added Samba 3.0.24 sources
[tomato.git] / release / src / router / samba3 / source / smbd / service.c
blob1cad6fb136a7089af86a1f8c469a1bcf75e4b523
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 /****************************************************************************
26 Ensure when setting connectpath it is a canonicalized (no ./ // or ../)
27 absolute path stating in / and not ending in /.
28 Observent people will notice a similarity between this and check_path_syntax :-).
29 ****************************************************************************/
31 void set_conn_connectpath(connection_struct *conn, const pstring connectpath)
33 pstring destname;
34 char *d = destname;
35 const char *s = connectpath;
36 BOOL start_of_name_component = True;
38 *d++ = '/'; /* Always start with root. */
40 while (*s) {
41 if (*s == '/') {
42 /* Eat multiple '/' */
43 while (*s == '/') {
44 s++;
46 if ((d > destname + 1) && (*s != '\0')) {
47 *d++ = '/';
49 start_of_name_component = True;
50 continue;
53 if (start_of_name_component) {
54 if ((s[0] == '.') && (s[1] == '.') && (s[2] == '/' || s[2] == '\0')) {
55 /* Uh oh - "/../" or "/..\0" ! */
57 /* Go past the ../ or .. */
58 if (s[2] == '/') {
59 s += 3;
60 } else {
61 s += 2; /* Go past the .. */
64 /* If we just added a '/' - delete it */
65 if ((d > destname) && (*(d-1) == '/')) {
66 *(d-1) = '\0';
67 d--;
70 /* Are we at the start ? Can't go back further if so. */
71 if (d <= destname) {
72 *d++ = '/'; /* Can't delete root */
73 continue;
75 /* Go back one level... */
76 /* Decrement d first as d points to the *next* char to write into. */
77 for (d--; d > destname; d--) {
78 if (*d == '/') {
79 break;
82 /* We're still at the start of a name component, just the previous one. */
83 continue;
84 } else if ((s[0] == '.') && ((s[1] == '\0') || s[1] == '/')) {
85 /* Component of pathname can't be "." only - skip the '.' . */
86 if (s[1] == '/') {
87 s += 2;
88 } else {
89 s++;
91 continue;
95 if (!(*s & 0x80)) {
96 *d++ = *s++;
97 } else {
98 switch(next_mb_char_size(s)) {
99 case 4:
100 *d++ = *s++;
101 case 3:
102 *d++ = *s++;
103 case 2:
104 *d++ = *s++;
105 case 1:
106 *d++ = *s++;
107 break;
108 default:
109 break;
112 start_of_name_component = False;
114 *d = '\0';
116 /* And must not end in '/' */
117 if (d > destname + 1 && (*(d-1) == '/')) {
118 *(d-1) = '\0';
121 DEBUG(10,("set_conn_connectpath: service %s, connectpath = %s\n",
122 lp_servicename(SNUM(conn)), destname ));
124 string_set(&conn->connectpath, destname);
127 /****************************************************************************
128 Load parameters specific to a connection/service.
129 ****************************************************************************/
131 BOOL set_current_service(connection_struct *conn, uint16 flags, BOOL do_chdir)
133 static connection_struct *last_conn;
134 static uint16 last_flags;
135 int snum;
137 if (!conn) {
138 last_conn = NULL;
139 return(False);
142 conn->lastused_count++;
144 snum = SNUM(conn);
146 if (do_chdir &&
147 vfs_ChDir(conn,conn->connectpath) != 0 &&
148 vfs_ChDir(conn,conn->origpath) != 0) {
149 DEBUG(0,("chdir (%s) failed\n",
150 conn->connectpath));
151 return(False);
154 if ((conn == last_conn) && (last_flags == flags)) {
155 return(True);
158 last_conn = conn;
159 last_flags = flags;
161 /* Obey the client case sensitivity requests - only for clients that support it. */
162 switch (lp_casesensitive(snum)) {
163 case Auto:
165 /* We need this uglyness due to DOS/Win9x clients that lie about case insensitivity. */
166 enum remote_arch_types ra_type = get_remote_arch();
167 if ((ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
168 /* Client can't support per-packet case sensitive pathnames. */
169 conn->case_sensitive = False;
170 } else {
171 conn->case_sensitive = !(flags & FLAG_CASELESS_PATHNAMES);
174 break;
175 case True:
176 conn->case_sensitive = True;
177 break;
178 default:
179 conn->case_sensitive = False;
180 break;
182 return(True);
185 /****************************************************************************
186 Add a home service. Returns the new service number or -1 if fail.
187 ****************************************************************************/
189 int add_home_service(const char *service, const char *username, const char *homedir)
191 int iHomeService;
193 if (!service || !homedir)
194 return -1;
196 if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0)
197 return -1;
200 * If this is a winbindd provided username, remove
201 * the domain component before adding the service.
202 * Log a warning if the "path=" parameter does not
203 * include any macros.
207 const char *p = strchr(service,*lp_winbind_separator());
209 /* We only want the 'user' part of the string */
210 if (p) {
211 service = p + 1;
215 if (!lp_add_home(service, iHomeService, username, homedir)) {
216 return -1;
219 return lp_servicenumber(service);
225 * Find a service entry.
227 * @param service is modified (to canonical form??)
230 int find_service(fstring service)
232 int iService;
234 all_string_sub(service,"\\","/",0);
236 iService = lp_servicenumber(service);
238 /* now handle the special case of a home directory */
239 if (iService < 0) {
240 char *phome_dir = get_user_home_dir(service);
242 if(!phome_dir) {
244 * Try mapping the servicename, it may
245 * be a Windows to unix mapped user name.
247 if(map_username(service))
248 phome_dir = get_user_home_dir(service);
251 DEBUG(3,("checking for home directory %s gave %s\n",service,
252 phome_dir?phome_dir:"(NULL)"));
254 iService = add_home_service(service,service /* 'username' */, phome_dir);
257 /* If we still don't have a service, attempt to add it as a printer. */
258 if (iService < 0) {
259 int iPrinterService;
261 if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) >= 0) {
262 DEBUG(3,("checking whether %s is a valid printer name...\n", service));
263 if (pcap_printername_ok(service)) {
264 DEBUG(3,("%s is a valid printer name\n", service));
265 DEBUG(3,("adding %s as a printer service\n", service));
266 lp_add_printer(service, iPrinterService);
267 iService = lp_servicenumber(service);
268 if (iService < 0) {
269 DEBUG(0,("failed to add %s as a printer service!\n", service));
271 } else {
272 DEBUG(3,("%s is not a valid printer name\n", service));
277 /* Check for default vfs service? Unsure whether to implement this */
278 if (iService < 0) {
281 /* just possibly it's a default service? */
282 if (iService < 0) {
283 char *pdefservice = lp_defaultservice();
284 if (pdefservice && *pdefservice && !strequal(pdefservice,service) && !strstr_m(service,"..")) {
286 * We need to do a local copy here as lp_defaultservice()
287 * returns one of the rotating lp_string buffers that
288 * could get overwritten by the recursive find_service() call
289 * below. Fix from Josef Hinteregger <joehtg@joehtg.co.at>.
291 pstring defservice;
292 pstrcpy(defservice, pdefservice);
293 iService = find_service(defservice);
294 if (iService >= 0) {
295 all_string_sub(service, "_","/",0);
296 iService = lp_add_service(service, iService);
301 /* Is it a usershare service ? */
302 if (iService < 0 && *lp_usershare_path()) {
303 /* Ensure the name is canonicalized. */
304 strlower_m(service);
305 iService = load_usershare_service(service);
308 if (iService >= 0) {
309 if (!VALID_SNUM(iService)) {
310 DEBUG(0,("Invalid snum %d for %s\n",iService, service));
311 iService = -1;
315 if (iService < 0)
316 DEBUG(3,("find_service() failed to find service %s\n", service));
318 return (iService);
322 /****************************************************************************
323 do some basic sainity checks on the share.
324 This function modifies dev, ecode.
325 ****************************************************************************/
327 static NTSTATUS share_sanity_checks(int snum, fstring dev)
330 if (!lp_snum_ok(snum) ||
331 !check_access(smbd_server_fd(),
332 lp_hostsallow(snum), lp_hostsdeny(snum))) {
333 return NT_STATUS_ACCESS_DENIED;
336 if (dev[0] == '?' || !dev[0]) {
337 if (lp_print_ok(snum)) {
338 fstrcpy(dev,"LPT1:");
339 } else if (strequal(lp_fstype(snum), "IPC")) {
340 fstrcpy(dev, "IPC");
341 } else {
342 fstrcpy(dev,"A:");
346 strupper_m(dev);
348 if (lp_print_ok(snum)) {
349 if (!strequal(dev, "LPT1:")) {
350 return NT_STATUS_BAD_DEVICE_TYPE;
352 } else if (strequal(lp_fstype(snum), "IPC")) {
353 if (!strequal(dev, "IPC")) {
354 return NT_STATUS_BAD_DEVICE_TYPE;
356 } else if (!strequal(dev, "A:")) {
357 return NT_STATUS_BAD_DEVICE_TYPE;
360 /* Behave as a printer if we are supposed to */
361 if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) {
362 fstrcpy(dev, "LPT1:");
365 return NT_STATUS_OK;
368 static NTSTATUS find_forced_user(int snum, BOOL vuser_is_guest,
369 uid_t *uid, gid_t *gid, fstring username,
370 struct nt_user_token **token)
372 TALLOC_CTX *mem_ctx;
373 char *fuser, *found_username;
374 NTSTATUS result;
376 mem_ctx = talloc_new(NULL);
377 if (mem_ctx == NULL) {
378 DEBUG(0, ("talloc_new failed\n"));
379 return NT_STATUS_NO_MEMORY;
382 fuser = talloc_string_sub(mem_ctx, lp_force_user(snum), "%S",
383 lp_servicename(snum));
384 if (fuser == NULL) {
385 result = NT_STATUS_NO_MEMORY;
386 goto done;
389 result = create_token_from_username(mem_ctx, fuser, vuser_is_guest,
390 uid, gid, &found_username,
391 token);
392 if (!NT_STATUS_IS_OK(result)) {
393 goto done;
396 talloc_steal(NULL, *token);
397 fstrcpy(username, found_username);
399 result = NT_STATUS_OK;
400 done:
401 TALLOC_FREE(mem_ctx);
402 return result;
406 * Go through lookup_name etc to find the force'd group.
408 * Create a new token from src_token, replacing the primary group sid with the
409 * one found.
412 static NTSTATUS find_forced_group(BOOL force_user,
413 int snum, const char *username,
414 DOM_SID *pgroup_sid,
415 gid_t *pgid)
417 NTSTATUS result = NT_STATUS_NO_SUCH_GROUP;
418 TALLOC_CTX *mem_ctx;
419 DOM_SID group_sid;
420 enum SID_NAME_USE type;
421 char *groupname;
422 BOOL user_must_be_member = False;
423 gid_t gid;
425 ZERO_STRUCTP(pgroup_sid);
426 *pgid = (gid_t)-1;
428 mem_ctx = talloc_new(NULL);
429 if (mem_ctx == NULL) {
430 DEBUG(0, ("talloc_new failed\n"));
431 return NT_STATUS_NO_MEMORY;
434 groupname = talloc_strdup(mem_ctx, lp_force_group(snum));
435 if (groupname == NULL) {
436 DEBUG(1, ("talloc_strdup failed\n"));
437 result = NT_STATUS_NO_MEMORY;
438 goto done;
441 if (groupname[0] == '+') {
442 user_must_be_member = True;
443 groupname += 1;
446 groupname = talloc_string_sub(mem_ctx, groupname,
447 "%S", lp_servicename(snum));
449 if (!lookup_name_smbconf(mem_ctx, groupname,
450 LOOKUP_NAME_ALL|LOOKUP_NAME_GROUP,
451 NULL, NULL, &group_sid, &type)) {
452 DEBUG(10, ("lookup_name_smbconf(%s) failed\n",
453 groupname));
454 goto done;
457 if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
458 (type != SID_NAME_WKN_GRP)) {
459 DEBUG(10, ("%s is a %s, not a group\n", groupname,
460 sid_type_lookup(type)));
461 goto done;
464 if (!sid_to_gid(&group_sid, &gid)) {
465 DEBUG(10, ("sid_to_gid(%s) for %s failed\n",
466 sid_string_static(&group_sid), groupname));
467 goto done;
471 * If the user has been forced and the forced group starts with a '+',
472 * then we only set the group to be the forced group if the forced
473 * user is a member of that group. Otherwise, the meaning of the '+'
474 * would be ignored.
477 if (force_user && user_must_be_member) {
478 if (user_in_group_sid(username, &group_sid)) {
479 sid_copy(pgroup_sid, &group_sid);
480 *pgid = gid;
481 DEBUG(3,("Forced group %s for member %s\n",
482 groupname, username));
483 } else {
484 DEBUG(0,("find_forced_group: forced user %s is not a member "
485 "of forced group %s. Disallowing access.\n",
486 username, groupname ));
487 result = NT_STATUS_MEMBER_NOT_IN_GROUP;
488 goto done;
490 } else {
491 sid_copy(pgroup_sid, &group_sid);
492 *pgid = gid;
493 DEBUG(3,("Forced group %s\n", groupname));
496 result = NT_STATUS_OK;
497 done:
498 TALLOC_FREE(mem_ctx);
499 return result;
502 /****************************************************************************
503 Make a connection, given the snum to connect to, and the vuser of the
504 connecting user if appropriate.
505 ****************************************************************************/
507 static connection_struct *make_connection_snum(int snum, user_struct *vuser,
508 DATA_BLOB password,
509 const char *pdev,
510 NTSTATUS *status)
512 struct passwd *pass = NULL;
513 BOOL guest = False;
514 connection_struct *conn;
515 SMB_STRUCT_STAT st;
516 fstring user;
517 fstring dev;
518 int ret;
520 *user = 0;
521 fstrcpy(dev, pdev);
522 SET_STAT_INVALID(st);
524 if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, dev))) {
525 return NULL;
528 conn = conn_new();
529 if (!conn) {
530 DEBUG(0,("Couldn't find free connection.\n"));
531 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
532 return NULL;
535 conn->nt_user_token = NULL;
537 if (lp_guest_only(snum)) {
538 const char *guestname = lp_guestaccount();
539 NTSTATUS status2;
540 char *found_username;
541 guest = True;
542 pass = getpwnam_alloc(NULL, guestname);
543 if (!pass) {
544 DEBUG(0,("make_connection_snum: Invalid guest "
545 "account %s??\n",guestname));
546 conn_free(conn);
547 *status = NT_STATUS_NO_SUCH_USER;
548 return NULL;
550 status2 = create_token_from_username(NULL, pass->pw_name, True,
551 &conn->uid, &conn->gid,
552 &found_username,
553 &conn->nt_user_token);
554 if (!NT_STATUS_IS_OK(status2)) {
555 conn_free(conn);
556 *status = status2;
557 return NULL;
559 fstrcpy(user, found_username);
560 string_set(&conn->user,user);
561 conn->force_user = True;
562 TALLOC_FREE(pass);
563 DEBUG(3,("Guest only user %s\n",user));
564 } else if (vuser) {
565 if (vuser->guest) {
566 if (!lp_guest_ok(snum)) {
567 DEBUG(2, ("guest user (from session setup) "
568 "not permitted to access this share "
569 "(%s)\n", lp_servicename(snum)));
570 conn_free(conn);
571 *status = NT_STATUS_ACCESS_DENIED;
572 return NULL;
574 } else {
575 if (!user_ok_token(vuser->user.unix_name,
576 vuser->nt_user_token, snum)) {
577 DEBUG(2, ("user '%s' (from session setup) not "
578 "permitted to access this share "
579 "(%s)\n", vuser->user.unix_name,
580 lp_servicename(snum)));
581 conn_free(conn);
582 *status = NT_STATUS_ACCESS_DENIED;
583 return NULL;
586 conn->vuid = vuser->vuid;
587 conn->uid = vuser->uid;
588 conn->gid = vuser->gid;
589 string_set(&conn->user,vuser->user.unix_name);
590 fstrcpy(user,vuser->user.unix_name);
591 guest = vuser->guest;
592 } else if (lp_security() == SEC_SHARE) {
593 NTSTATUS status2;
594 char *found_username;
595 /* add it as a possible user name if we
596 are in share mode security */
597 add_session_user(lp_servicename(snum));
598 /* shall we let them in? */
599 if (!authorise_login(snum,user,password,&guest)) {
600 DEBUG( 2, ( "Invalid username/password for [%s]\n",
601 lp_servicename(snum)) );
602 conn_free(conn);
603 *status = NT_STATUS_WRONG_PASSWORD;
604 return NULL;
606 pass = Get_Pwnam(user);
607 status2 = create_token_from_username(NULL, pass->pw_name, True,
608 &conn->uid, &conn->gid,
609 &found_username,
610 &conn->nt_user_token);
611 if (!NT_STATUS_IS_OK(status2)) {
612 conn_free(conn);
613 *status = status2;
614 return NULL;
616 fstrcpy(user, found_username);
617 string_set(&conn->user,user);
618 conn->force_user = True;
619 } else {
620 DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
621 conn_free(conn);
622 *status = NT_STATUS_ACCESS_DENIED;
623 return NULL;
626 add_session_user(user);
628 safe_strcpy(conn->client_address, client_addr(),
629 sizeof(conn->client_address)-1);
630 conn->num_files_open = 0;
631 conn->lastused = conn->lastused_count = time(NULL);
632 conn->service = snum;
633 conn->used = True;
634 conn->printer = (strncmp(dev,"LPT",3) == 0);
635 conn->ipc = ( (strncmp(dev,"IPC",3) == 0) ||
636 ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) );
637 conn->dirptr = NULL;
639 /* Case options for the share. */
640 if (lp_casesensitive(snum) == Auto) {
641 /* We will be setting this per packet. Set to be case
642 * insensitive for now. */
643 conn->case_sensitive = False;
644 } else {
645 conn->case_sensitive = (BOOL)lp_casesensitive(snum);
648 conn->case_preserve = lp_preservecase(snum);
649 conn->short_case_preserve = lp_shortpreservecase(snum);
651 conn->veto_list = NULL;
652 conn->hide_list = NULL;
653 conn->veto_oplock_list = NULL;
654 conn->aio_write_behind_list = NULL;
655 string_set(&conn->dirpath,"");
656 string_set(&conn->user,user);
658 conn->read_only = lp_readonly(conn->service);
659 conn->admin_user = False;
662 * If force user is true, then store the given userid and the gid of
663 * the user we're forcing.
664 * For auxiliary groups see below.
667 if (*lp_force_user(snum)) {
668 NTSTATUS status2;
670 status2 = find_forced_user(snum,
671 (vuser != NULL) && vuser->guest,
672 &conn->uid, &conn->gid, user,
673 &conn->nt_user_token);
674 if (!NT_STATUS_IS_OK(status2)) {
675 conn_free(conn);
676 *status = status2;
677 return NULL;
679 string_set(&conn->user,user);
680 conn->force_user = True;
681 DEBUG(3,("Forced user %s\n",user));
685 * If force group is true, then override
686 * any groupid stored for the connecting user.
689 if (*lp_force_group(snum)) {
690 NTSTATUS status2;
691 DOM_SID group_sid;
693 status2 = find_forced_group(conn->force_user,
694 snum, user,
695 &group_sid, &conn->gid);
696 if (!NT_STATUS_IS_OK(status2)) {
697 conn_free(conn);
698 *status = status2;
699 return NULL;
702 if ((conn->nt_user_token == NULL) && (vuser != NULL)) {
704 /* Not force user and not security=share, but force
705 * group. vuser has a token to copy */
707 conn->nt_user_token = dup_nt_token(
708 NULL, vuser->nt_user_token);
709 if (conn->nt_user_token == NULL) {
710 DEBUG(0, ("dup_nt_token failed\n"));
711 conn_free(conn);
712 *status = NT_STATUS_NO_MEMORY;
713 return NULL;
717 /* If conn->nt_user_token is still NULL, we have
718 * security=share. This means ignore the SID, as we had no
719 * vuser to copy from */
721 if (conn->nt_user_token != NULL) {
722 /* Overwrite the primary group sid */
723 sid_copy(&conn->nt_user_token->user_sids[1],
724 &group_sid);
727 conn->force_group = True;
730 if (conn->nt_user_token != NULL) {
731 size_t i;
733 /* We have a share-specific token from force [user|group].
734 * This means we have to create the list of unix groups from
735 * the list of sids. */
737 conn->ngroups = 0;
738 conn->groups = NULL;
740 for (i=0; i<conn->nt_user_token->num_sids; i++) {
741 gid_t gid;
742 DOM_SID *sid = &conn->nt_user_token->user_sids[i];
744 if (!sid_to_gid(sid, &gid)) {
745 DEBUG(10, ("Could not convert SID %s to gid, "
746 "ignoring it\n",
747 sid_string_static(sid)));
748 continue;
750 add_gid_to_array_unique(NULL, gid, &conn->groups,
751 &conn->ngroups);
756 pstring s;
757 pstrcpy(s,lp_pathname(snum));
758 standard_sub_conn(conn,s,sizeof(s));
759 set_conn_connectpath(conn,s);
760 DEBUG(3,("Connect path is '%s' for service [%s]\n",s,
761 lp_servicename(snum)));
765 * New code to check if there's a share security descripter
766 * added from NT server manager. This is done after the
767 * smb.conf checks are done as we need a uid and token. JRA.
772 BOOL can_write = share_access_check(conn, snum, vuser,
773 FILE_WRITE_DATA);
775 if (!can_write) {
776 if (!share_access_check(conn, snum, vuser,
777 FILE_READ_DATA)) {
778 /* No access, read or write. */
779 DEBUG(0,("make_connection: connection to %s "
780 "denied due to security "
781 "descriptor.\n",
782 lp_servicename(snum)));
783 conn_free(conn);
784 *status = NT_STATUS_ACCESS_DENIED;
785 return NULL;
786 } else {
787 conn->read_only = True;
791 /* Initialise VFS function pointers */
793 if (!smbd_vfs_init(conn)) {
794 DEBUG(0, ("vfs_init failed for service %s\n",
795 lp_servicename(snum)));
796 conn_free(conn);
797 *status = NT_STATUS_BAD_NETWORK_NAME;
798 return NULL;
802 * If widelinks are disallowed we need to canonicalise the connect
803 * path here to ensure we don't have any symlinks in the
804 * connectpath. We will be checking all paths on this connection are
805 * below this directory. We must do this after the VFS init as we
806 * depend on the realpath() pointer in the vfs table. JRA.
808 if (!lp_widelinks(snum)) {
809 pstring s;
810 pstrcpy(s,conn->connectpath);
811 canonicalize_path(conn, s);
812 set_conn_connectpath(conn,s);
815 /* ROOT Activities: */
816 /* check number of connections */
817 if (!claim_connection(conn,
818 lp_servicename(snum),
819 lp_max_connections(snum),
820 False,0)) {
821 DEBUG(1,("too many connections - rejected\n"));
822 conn_free(conn);
823 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
824 return NULL;
827 /* Preexecs are done here as they might make the dir we are to ChDir
828 * to below */
829 /* execute any "root preexec = " line */
830 if (*lp_rootpreexec(snum)) {
831 pstring cmd;
832 pstrcpy(cmd,lp_rootpreexec(snum));
833 standard_sub_conn(conn,cmd,sizeof(cmd));
834 DEBUG(5,("cmd=%s\n",cmd));
835 ret = smbrun(cmd,NULL);
836 if (ret != 0 && lp_rootpreexec_close(snum)) {
837 DEBUG(1,("root preexec gave %d - failing "
838 "connection\n", ret));
839 yield_connection(conn, lp_servicename(snum));
840 conn_free(conn);
841 *status = NT_STATUS_ACCESS_DENIED;
842 return NULL;
846 /* USER Activites: */
847 if (!change_to_user(conn, conn->vuid)) {
848 /* No point continuing if they fail the basic checks */
849 DEBUG(0,("Can't become connected user!\n"));
850 yield_connection(conn, lp_servicename(snum));
851 conn_free(conn);
852 *status = NT_STATUS_LOGON_FAILURE;
853 return NULL;
856 /* Remember that a different vuid can connect later without these
857 * checks... */
859 /* Preexecs are done here as they might make the dir we are to ChDir
860 * to below */
862 /* execute any "preexec = " line */
863 if (*lp_preexec(snum)) {
864 pstring cmd;
865 pstrcpy(cmd,lp_preexec(snum));
866 standard_sub_conn(conn,cmd,sizeof(cmd));
867 ret = smbrun(cmd,NULL);
868 if (ret != 0 && lp_preexec_close(snum)) {
869 DEBUG(1,("preexec gave %d - failing connection\n",
870 ret));
871 change_to_root_user();
872 yield_connection(conn, lp_servicename(snum));
873 conn_free(conn);
874 *status = NT_STATUS_ACCESS_DENIED;
875 return NULL;
879 #ifdef WITH_FAKE_KASERVER
880 if (lp_afs_share(snum)) {
881 afs_login(conn);
883 #endif
885 /* Add veto/hide lists */
886 if (!IS_IPC(conn) && !IS_PRINT(conn)) {
887 set_namearray( &conn->veto_list, lp_veto_files(snum));
888 set_namearray( &conn->hide_list, lp_hide_files(snum));
889 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(snum));
892 /* Invoke VFS make connection hook - do this before the VFS_STAT call
893 to allow any filesystems needing user credentials to initialize
894 themselves. */
896 if (SMB_VFS_CONNECT(conn, lp_servicename(snum), user) < 0) {
897 DEBUG(0,("make_connection: VFS make connection failed!\n"));
898 change_to_root_user();
899 yield_connection(conn, lp_servicename(snum));
900 conn_free(conn);
901 *status = NT_STATUS_UNSUCCESSFUL;
902 return NULL;
905 /* win2000 does not check the permissions on the directory
906 during the tree connect, instead relying on permission
907 check during individual operations. To match this behaviour
908 I have disabled this chdir check (tridge) */
909 /* the alternative is just to check the directory exists */
910 if ((ret = SMB_VFS_STAT(conn, conn->connectpath, &st)) != 0 ||
911 !S_ISDIR(st.st_mode)) {
912 if (ret == 0 && !S_ISDIR(st.st_mode)) {
913 DEBUG(0,("'%s' is not a directory, when connecting to "
914 "[%s]\n", conn->connectpath,
915 lp_servicename(snum)));
916 } else {
917 DEBUG(0,("'%s' does not exist or permission denied "
918 "when connecting to [%s] Error was %s\n",
919 conn->connectpath, lp_servicename(snum),
920 strerror(errno) ));
922 change_to_root_user();
923 /* Call VFS disconnect hook */
924 SMB_VFS_DISCONNECT(conn);
925 yield_connection(conn, lp_servicename(snum));
926 conn_free(conn);
927 *status = NT_STATUS_BAD_NETWORK_NAME;
928 return NULL;
931 string_set(&conn->origpath,conn->connectpath);
933 #if SOFTLINK_OPTIMISATION
934 /* resolve any soft links early if possible */
935 if (vfs_ChDir(conn,conn->connectpath) == 0) {
936 pstring s;
937 pstrcpy(s,conn->connectpath);
938 vfs_GetWd(conn,s);
939 set_conn_connectpath(conn,s);
940 vfs_ChDir(conn,conn->connectpath);
942 #endif
945 * Print out the 'connected as' stuff here as we need
946 * to know the effective uid and gid we will be using
947 * (at least initially).
950 if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
951 dbgtext( "%s (%s) ", get_remote_machine_name(),
952 conn->client_address );
953 dbgtext( "%s", srv_is_signing_active() ? "signed " : "");
954 dbgtext( "connect to service %s ", lp_servicename(snum) );
955 dbgtext( "initially as user %s ", user );
956 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
957 dbgtext( "(pid %d)\n", (int)sys_getpid() );
960 /* Setup the minimum value for a change notify wait time (seconds). */
961 set_change_notify_timeout(lp_change_notify_timeout(snum));
963 /* we've finished with the user stuff - go back to root */
964 change_to_root_user();
965 return(conn);
968 /***************************************************************************************
969 Simple wrapper function for make_connection() to include a call to
970 vfs_chdir()
971 **************************************************************************************/
973 connection_struct *make_connection_with_chdir(const char *service_in,
974 DATA_BLOB password,
975 const char *dev, uint16 vuid,
976 NTSTATUS *status)
978 connection_struct *conn = NULL;
980 conn = make_connection(service_in, password, dev, vuid, status);
983 * make_connection() does not change the directory for us any more
984 * so we have to do it as a separate step --jerry
987 if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) {
988 DEBUG(0,("move_driver_to_download_area: Can't change "
989 "directory to %s for [print$] (%s)\n",
990 conn->connectpath,strerror(errno)));
991 yield_connection(conn, lp_servicename(SNUM(conn)));
992 conn_free(conn);
993 *status = NT_STATUS_UNSUCCESSFUL;
994 return NULL;
997 return conn;
1000 /****************************************************************************
1001 Make a connection to a service.
1003 * @param service
1004 ****************************************************************************/
1006 connection_struct *make_connection(const char *service_in, DATA_BLOB password,
1007 const char *pdev, uint16 vuid,
1008 NTSTATUS *status)
1010 uid_t euid;
1011 user_struct *vuser = NULL;
1012 fstring service;
1013 fstring dev;
1014 int snum = -1;
1016 fstrcpy(dev, pdev);
1018 /* This must ONLY BE CALLED AS ROOT. As it exits this function as
1019 * root. */
1020 if (!non_root_mode() && (euid = geteuid()) != 0) {
1021 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot "
1022 "(%u)\n", (unsigned int)euid ));
1023 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
1026 if (conn_num_open() > 2047) {
1027 *status = NT_STATUS_INSUFF_SERVER_RESOURCES;
1028 return NULL;
1031 if(lp_security() != SEC_SHARE) {
1032 vuser = get_valid_user_struct(vuid);
1033 if (!vuser) {
1034 DEBUG(1,("make_connection: refusing to connect with "
1035 "no session setup\n"));
1036 *status = NT_STATUS_ACCESS_DENIED;
1037 return NULL;
1041 /* Logic to try and connect to the correct [homes] share, preferably
1042 without too many getpwnam() lookups. This is particulary nasty for
1043 winbind usernames, where the share name isn't the same as unix
1044 username.
1046 The snum of the homes share is stored on the vuser at session setup
1047 time.
1050 if (strequal(service_in,HOMES_NAME)) {
1051 if(lp_security() != SEC_SHARE) {
1052 DATA_BLOB no_pw = data_blob(NULL, 0);
1053 if (vuser->homes_snum == -1) {
1054 DEBUG(2, ("[homes] share not available for "
1055 "this user because it was not found "
1056 "or created at session setup "
1057 "time\n"));
1058 *status = NT_STATUS_BAD_NETWORK_NAME;
1059 return NULL;
1061 DEBUG(5, ("making a connection to [homes] service "
1062 "created at session setup time\n"));
1063 return make_connection_snum(vuser->homes_snum,
1064 vuser, no_pw,
1065 dev, status);
1066 } else {
1067 /* Security = share. Try with
1068 * current_user_info.smb_name as the username. */
1069 if (*current_user_info.smb_name) {
1070 fstring unix_username;
1071 fstrcpy(unix_username,
1072 current_user_info.smb_name);
1073 map_username(unix_username);
1074 snum = find_service(unix_username);
1076 if (snum != -1) {
1077 DEBUG(5, ("making a connection to 'homes' "
1078 "service %s based on "
1079 "security=share\n", service_in));
1080 return make_connection_snum(snum, NULL,
1081 password,
1082 dev, status);
1085 } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
1086 && strequal(service_in,
1087 lp_servicename(vuser->homes_snum))) {
1088 DATA_BLOB no_pw = data_blob(NULL, 0);
1089 DEBUG(5, ("making a connection to 'homes' service [%s] "
1090 "created at session setup time\n", service_in));
1091 return make_connection_snum(vuser->homes_snum,
1092 vuser, no_pw,
1093 dev, status);
1096 fstrcpy(service, service_in);
1098 strlower_m(service);
1100 snum = find_service(service);
1102 if (snum < 0) {
1103 if (strequal(service,"IPC$") ||
1104 (lp_enable_asu_support() && strequal(service,"ADMIN$"))) {
1105 DEBUG(3,("refusing IPC connection to %s\n", service));
1106 *status = NT_STATUS_ACCESS_DENIED;
1107 return NULL;
1110 DEBUG(0,("%s (%s) couldn't find service %s\n",
1111 get_remote_machine_name(), client_addr(), service));
1112 *status = NT_STATUS_BAD_NETWORK_NAME;
1113 return NULL;
1116 /* Handle non-Dfs clients attempting connections to msdfs proxy */
1117 if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0')) {
1118 DEBUG(3, ("refusing connection to dfs proxy share '%s' "
1119 "(pointing to %s)\n",
1120 service, lp_msdfs_proxy(snum)));
1121 *status = NT_STATUS_BAD_NETWORK_NAME;
1122 return NULL;
1125 DEBUG(5, ("making a connection to 'normal' service %s\n", service));
1127 return make_connection_snum(snum, vuser,
1128 password,
1129 dev, status);
1132 /****************************************************************************
1133 Close a cnum.
1134 ****************************************************************************/
1136 void close_cnum(connection_struct *conn, uint16 vuid)
1138 if (IS_IPC(conn)) {
1139 pipe_close_conn(conn);
1140 } else {
1141 file_close_conn(conn);
1142 dptr_closecnum(conn);
1145 change_to_root_user();
1147 DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
1148 get_remote_machine_name(),
1149 conn->client_address,
1150 lp_servicename(SNUM(conn))));
1152 /* Call VFS disconnect hook */
1153 SMB_VFS_DISCONNECT(conn);
1155 yield_connection(conn, lp_servicename(SNUM(conn)));
1157 /* make sure we leave the directory available for unmount */
1158 vfs_ChDir(conn, "/");
1160 /* execute any "postexec = " line */
1161 if (*lp_postexec(SNUM(conn)) &&
1162 change_to_user(conn, vuid)) {
1163 pstring cmd;
1164 pstrcpy(cmd,lp_postexec(SNUM(conn)));
1165 standard_sub_conn(conn,cmd,sizeof(cmd));
1166 smbrun(cmd,NULL);
1167 change_to_root_user();
1170 change_to_root_user();
1171 /* execute any "root postexec = " line */
1172 if (*lp_rootpostexec(SNUM(conn))) {
1173 pstring cmd;
1174 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
1175 standard_sub_conn(conn,cmd,sizeof(cmd));
1176 smbrun(cmd,NULL);
1179 conn_free(conn);