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.
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)
35 const char *s = connectpath;
36 BOOL start_of_name_component = True;
38 *d++ = '/'; /* Always start with root. */
42 /* Eat multiple '/' */
46 if ((d > destname + 1) && (*s != '\0')) {
49 start_of_name_component = True;
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 .. */
61 s += 2; /* Go past the .. */
64 /* If we just added a '/' - delete it */
65 if ((d > destname) && (*(d-1) == '/')) {
70 /* Are we at the start ? Can't go back further if so. */
72 *d++ = '/'; /* Can't delete root */
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--) {
82 /* We're still at the start of a name component, just the previous one. */
84 } else if ((s[0] == '.') && ((s[1] == '\0') || s[1] == '/')) {
85 /* Component of pathname can't be "." only - skip the '.' . */
98 switch(next_mb_char_size(s)) {
112 start_of_name_component = False;
116 /* And must not end in '/' */
117 if (d > destname + 1 && (*(d-1) == '/')) {
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;
142 conn->lastused_count++;
147 vfs_ChDir(conn,conn->connectpath) != 0 &&
148 vfs_ChDir(conn,conn->origpath) != 0) {
149 DEBUG(0,("chdir (%s) failed\n",
154 if ((conn == last_conn) && (last_flags == flags)) {
161 /* Obey the client case sensitivity requests - only for clients that support it. */
162 switch (lp_casesensitive(snum)) {
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;
171 conn->case_sensitive = !(flags & FLAG_CASELESS_PATHNAMES);
176 conn->case_sensitive = True;
179 conn->case_sensitive = False;
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)
193 if (!service || !homedir)
196 if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0)
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 */
215 if (!lp_add_home(service, iHomeService, username, homedir)) {
219 return lp_servicenumber(service);
225 * Find a service entry.
227 * @param service is modified (to canonical form??)
230 int find_service(fstring service)
234 all_string_sub(service,"\\","/",0);
236 iService = lp_servicenumber(service);
238 /* now handle the special case of a home directory */
240 char *phome_dir = get_user_home_dir(service);
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. */
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);
269 DEBUG(0,("failed to add %s as a printer service!\n", service));
272 DEBUG(3,("%s is not a valid printer name\n", service));
277 /* Check for default vfs service? Unsure whether to implement this */
281 /* just possibly it's a default service? */
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>.
292 pstrcpy(defservice, pdefservice);
293 iService = find_service(defservice);
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. */
305 iService = load_usershare_service(service);
309 if (!VALID_SNUM(iService)) {
310 DEBUG(0,("Invalid snum %d for %s\n",iService, service));
316 DEBUG(3,("find_service() failed to find service %s\n", service));
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")) {
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:");
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)
373 char *fuser, *found_username;
374 struct nt_user_token *tmp_token;
377 if (!(mem_ctx = talloc_new(NULL))) {
378 DEBUG(0, ("talloc_new failed\n"));
379 return NT_STATUS_NO_MEMORY;
382 if (!(fuser = talloc_string_sub(mem_ctx, lp_force_user(snum), "%S",
383 lp_servicename(snum)))) {
384 TALLOC_FREE(mem_ctx);
385 return NT_STATUS_NO_MEMORY;
389 result = create_token_from_username(mem_ctx, fuser, vuser_is_guest,
390 uid, gid, &found_username,
392 if (!NT_STATUS_IS_OK(result)) {
393 TALLOC_FREE(mem_ctx);
397 if (!(*token = dup_nt_token(NULL, tmp_token))) {
398 TALLOC_FREE(mem_ctx);
399 return NT_STATUS_NO_MEMORY;
402 fstrcpy(username, found_username);
404 TALLOC_FREE(mem_ctx);
409 * Go through lookup_name etc to find the force'd group.
411 * Create a new token from src_token, replacing the primary group sid with the
415 static NTSTATUS find_forced_group(BOOL force_user,
416 int snum, const char *username,
420 NTSTATUS result = NT_STATUS_NO_SUCH_GROUP;
423 enum SID_NAME_USE type;
425 BOOL user_must_be_member = False;
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;
441 if (groupname[0] == '+') {
442 user_must_be_member = True;
446 groupname = talloc_string_sub(mem_ctx, groupname,
447 "%S", lp_servicename(snum));
449 if (!lookup_name(mem_ctx, groupname,
450 LOOKUP_NAME_ALL|LOOKUP_NAME_GROUP,
451 NULL, NULL, &group_sid, &type)) {
452 DEBUG(10, ("lookup_name(%s) failed\n",
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)));
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));
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 '+'
477 if (force_user && user_must_be_member) {
478 if (user_in_group_sid(username, &group_sid)) {
479 sid_copy(pgroup_sid, &group_sid);
481 DEBUG(3,("Forced group %s for member %s\n",
482 groupname, username));
485 sid_copy(pgroup_sid, &group_sid);
487 DEBUG(3,("Forced group %s\n", groupname));
490 result = NT_STATUS_OK;
492 TALLOC_FREE(mem_ctx);
496 /****************************************************************************
497 Make a connection, given the snum to connect to, and the vuser of the
498 connecting user if appropriate.
499 ****************************************************************************/
501 static connection_struct *make_connection_snum(int snum, user_struct *vuser,
506 struct passwd *pass = NULL;
508 connection_struct *conn;
516 SET_STAT_INVALID(st);
518 if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, dev))) {
524 DEBUG(0,("Couldn't find free connection.\n"));
525 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
529 conn->nt_user_token = NULL;
531 if (lp_guest_only(snum)) {
532 const char *guestname = lp_guestaccount();
534 char *found_username;
536 pass = getpwnam_alloc(NULL, guestname);
538 DEBUG(0,("make_connection_snum: Invalid guest "
539 "account %s??\n",guestname));
541 *status = NT_STATUS_NO_SUCH_USER;
544 status2 = create_token_from_username(NULL, pass->pw_name, True,
545 &conn->uid, &conn->gid,
547 &conn->nt_user_token);
548 if (!NT_STATUS_IS_OK(status2)) {
553 fstrcpy(user, found_username);
554 string_set(&conn->user,user);
555 conn->force_user = True;
557 DEBUG(3,("Guest only user %s\n",user));
560 if (!lp_guest_ok(snum)) {
561 DEBUG(2, ("guest user (from session setup) "
562 "not permitted to access this share "
563 "(%s)\n", lp_servicename(snum)));
565 *status = NT_STATUS_ACCESS_DENIED;
569 if (!user_ok_token(vuser->user.unix_name,
570 vuser->nt_user_token, snum)) {
571 DEBUG(2, ("user '%s' (from session setup) not "
572 "permitted to access this share "
573 "(%s)\n", vuser->user.unix_name,
574 lp_servicename(snum)));
576 *status = NT_STATUS_ACCESS_DENIED;
580 conn->vuid = vuser->vuid;
581 conn->uid = vuser->uid;
582 conn->gid = vuser->gid;
583 string_set(&conn->user,vuser->user.unix_name);
584 fstrcpy(user,vuser->user.unix_name);
585 guest = vuser->guest;
586 } else if (lp_security() == SEC_SHARE) {
588 char *found_username;
589 /* add it as a possible user name if we
590 are in share mode security */
591 add_session_user(lp_servicename(snum));
592 /* shall we let them in? */
593 if (!authorise_login(snum,user,password,&guest)) {
594 DEBUG( 2, ( "Invalid username/password for [%s]\n",
595 lp_servicename(snum)) );
597 *status = NT_STATUS_WRONG_PASSWORD;
600 pass = Get_Pwnam(user);
601 status2 = create_token_from_username(NULL, pass->pw_name, True,
602 &conn->uid, &conn->gid,
604 &conn->nt_user_token);
605 if (!NT_STATUS_IS_OK(status2)) {
610 fstrcpy(user, found_username);
611 string_set(&conn->user,user);
612 conn->force_user = True;
614 DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
616 *status = NT_STATUS_ACCESS_DENIED;
620 add_session_user(user);
622 safe_strcpy(conn->client_address, client_addr(),
623 sizeof(conn->client_address)-1);
624 conn->num_files_open = 0;
625 conn->lastused = conn->lastused_count = time(NULL);
626 conn->params->service = snum;
628 conn->printer = (strncmp(dev,"LPT",3) == 0);
629 conn->ipc = ( (strncmp(dev,"IPC",3) == 0) ||
630 ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) );
633 /* Case options for the share. */
634 if (lp_casesensitive(snum) == Auto) {
635 /* We will be setting this per packet. Set to be case
636 * insensitive for now. */
637 conn->case_sensitive = False;
639 conn->case_sensitive = (BOOL)lp_casesensitive(snum);
642 conn->case_preserve = lp_preservecase(snum);
643 conn->short_case_preserve = lp_shortpreservecase(snum);
645 conn->veto_list = NULL;
646 conn->hide_list = NULL;
647 conn->veto_oplock_list = NULL;
648 conn->aio_write_behind_list = NULL;
649 string_set(&conn->dirpath,"");
650 string_set(&conn->user,user);
652 conn->read_only = lp_readonly(SNUM(conn));
653 conn->admin_user = False;
656 * If force user is true, then store the given userid and the gid of
657 * the user we're forcing.
658 * For auxiliary groups see below.
661 if (*lp_force_user(snum)) {
664 status2 = find_forced_user(snum,
665 (vuser != NULL) && vuser->guest,
666 &conn->uid, &conn->gid, user,
667 &conn->nt_user_token);
668 if (!NT_STATUS_IS_OK(status2)) {
673 string_set(&conn->user,user);
674 conn->force_user = True;
675 DEBUG(3,("Forced user %s\n",user));
679 * If force group is true, then override
680 * any groupid stored for the connecting user.
683 if (*lp_force_group(snum)) {
687 status2 = find_forced_group(conn->force_user,
689 &group_sid, &conn->gid);
690 if (!NT_STATUS_IS_OK(status2)) {
696 if ((conn->nt_user_token == NULL) && (vuser != NULL)) {
698 /* Not force user and not security=share, but force
699 * group. vuser has a token to copy */
701 conn->nt_user_token = dup_nt_token(
702 NULL, vuser->nt_user_token);
703 if (conn->nt_user_token == NULL) {
704 DEBUG(0, ("dup_nt_token failed\n"));
706 *status = NT_STATUS_NO_MEMORY;
711 /* If conn->nt_user_token is still NULL, we have
712 * security=share. This means ignore the SID, as we had no
713 * vuser to copy from */
715 if (conn->nt_user_token != NULL) {
716 /* Overwrite the primary group sid */
717 sid_copy(&conn->nt_user_token->user_sids[1],
721 conn->force_group = True;
724 if (conn->nt_user_token != NULL) {
727 /* We have a share-specific token from force [user|group].
728 * This means we have to create the list of unix groups from
729 * the list of sids. */
734 for (i=0; i<conn->nt_user_token->num_sids; i++) {
736 DOM_SID *sid = &conn->nt_user_token->user_sids[i];
738 if (!sid_to_gid(sid, &gid)) {
739 DEBUG(10, ("Could not convert SID %s to gid, "
741 sid_string_static(sid)));
744 add_gid_to_array_unique(NULL, gid, &conn->groups,
751 pstrcpy(s,lp_pathname(snum));
752 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
753 conn->connectpath, conn->gid,
754 get_current_username(),
755 current_user_info.domain,
757 set_conn_connectpath(conn,s);
758 DEBUG(3,("Connect path is '%s' for service [%s]\n",s,
759 lp_servicename(snum)));
763 * New code to check if there's a share security descripter
764 * added from NT server manager. This is done after the
765 * smb.conf checks are done as we need a uid and token. JRA.
770 BOOL can_write = share_access_check(conn, snum, vuser,
774 if (!share_access_check(conn, snum, vuser,
776 /* No access, read or write. */
777 DEBUG(0,("make_connection: connection to %s "
778 "denied due to security "
780 lp_servicename(snum)));
782 *status = NT_STATUS_ACCESS_DENIED;
785 conn->read_only = True;
789 /* Initialise VFS function pointers */
791 if (!smbd_vfs_init(conn)) {
792 DEBUG(0, ("vfs_init failed for service %s\n",
793 lp_servicename(snum)));
795 *status = NT_STATUS_BAD_NETWORK_NAME;
800 * If widelinks are disallowed we need to canonicalise the connect
801 * path here to ensure we don't have any symlinks in the
802 * connectpath. We will be checking all paths on this connection are
803 * below this directory. We must do this after the VFS init as we
804 * depend on the realpath() pointer in the vfs table. JRA.
806 if (!lp_widelinks(snum)) {
808 pstrcpy(s,conn->connectpath);
809 canonicalize_path(conn, s);
810 set_conn_connectpath(conn,s);
813 /* ROOT Activities: */
814 /* check number of connections */
815 if (!claim_connection(conn,
816 lp_servicename(snum),
817 lp_max_connections(snum),
819 DEBUG(1,("too many connections - rejected\n"));
821 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
825 /* Preexecs are done here as they might make the dir we are to ChDir
827 /* execute any "root preexec = " line */
828 if (*lp_rootpreexec(snum)) {
830 pstrcpy(cmd,lp_rootpreexec(snum));
831 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
832 conn->connectpath, conn->gid,
833 get_current_username(),
834 current_user_info.domain,
836 DEBUG(5,("cmd=%s\n",cmd));
837 ret = smbrun(cmd,NULL);
838 if (ret != 0 && lp_rootpreexec_close(snum)) {
839 DEBUG(1,("root preexec gave %d - failing "
840 "connection\n", ret));
841 yield_connection(conn, lp_servicename(snum));
843 *status = NT_STATUS_ACCESS_DENIED;
848 /* USER Activites: */
849 if (!change_to_user(conn, conn->vuid)) {
850 /* No point continuing if they fail the basic checks */
851 DEBUG(0,("Can't become connected user!\n"));
852 yield_connection(conn, lp_servicename(snum));
854 *status = NT_STATUS_LOGON_FAILURE;
858 /* Remember that a different vuid can connect later without these
861 /* Preexecs are done here as they might make the dir we are to ChDir
864 /* execute any "preexec = " line */
865 if (*lp_preexec(snum)) {
867 pstrcpy(cmd,lp_preexec(snum));
868 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
869 conn->connectpath, conn->gid,
870 get_current_username(),
871 current_user_info.domain,
873 ret = smbrun(cmd,NULL);
874 if (ret != 0 && lp_preexec_close(snum)) {
875 DEBUG(1,("preexec gave %d - failing connection\n",
877 change_to_root_user();
878 yield_connection(conn, lp_servicename(snum));
880 *status = NT_STATUS_ACCESS_DENIED;
885 #ifdef WITH_FAKE_KASERVER
886 if (lp_afs_share(snum)) {
891 /* Add veto/hide lists */
892 if (!IS_IPC(conn) && !IS_PRINT(conn)) {
893 set_namearray( &conn->veto_list, lp_veto_files(snum));
894 set_namearray( &conn->hide_list, lp_hide_files(snum));
895 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(snum));
898 /* Invoke VFS make connection hook - do this before the VFS_STAT call
899 to allow any filesystems needing user credentials to initialize
902 if (SMB_VFS_CONNECT(conn, lp_servicename(snum), user) < 0) {
903 DEBUG(0,("make_connection: VFS make connection failed!\n"));
904 change_to_root_user();
905 yield_connection(conn, lp_servicename(snum));
907 *status = NT_STATUS_UNSUCCESSFUL;
911 /* win2000 does not check the permissions on the directory
912 during the tree connect, instead relying on permission
913 check during individual operations. To match this behaviour
914 I have disabled this chdir check (tridge) */
915 /* the alternative is just to check the directory exists */
916 if ((ret = SMB_VFS_STAT(conn, conn->connectpath, &st)) != 0 ||
917 !S_ISDIR(st.st_mode)) {
918 if (ret == 0 && !S_ISDIR(st.st_mode)) {
919 DEBUG(0,("'%s' is not a directory, when connecting to "
920 "[%s]\n", conn->connectpath,
921 lp_servicename(snum)));
923 DEBUG(0,("'%s' does not exist or permission denied "
924 "when connecting to [%s] Error was %s\n",
925 conn->connectpath, lp_servicename(snum),
928 change_to_root_user();
929 /* Call VFS disconnect hook */
930 SMB_VFS_DISCONNECT(conn);
931 yield_connection(conn, lp_servicename(snum));
933 *status = NT_STATUS_BAD_NETWORK_NAME;
937 string_set(&conn->origpath,conn->connectpath);
939 #if SOFTLINK_OPTIMISATION
940 /* resolve any soft links early if possible */
941 if (vfs_ChDir(conn,conn->connectpath) == 0) {
943 pstrcpy(s,conn->connectpath);
945 set_conn_connectpath(conn,s);
946 vfs_ChDir(conn,conn->connectpath);
951 * Print out the 'connected as' stuff here as we need
952 * to know the effective uid and gid we will be using
953 * (at least initially).
956 if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
957 dbgtext( "%s (%s) ", get_remote_machine_name(),
958 conn->client_address );
959 dbgtext( "%s", srv_is_signing_active() ? "signed " : "");
960 dbgtext( "connect to service %s ", lp_servicename(snum) );
961 dbgtext( "initially as user %s ", user );
962 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
963 dbgtext( "(pid %d)\n", (int)sys_getpid() );
966 /* Setup the minimum value for a change notify wait time (seconds). */
967 set_change_notify_timeout(lp_change_notify_timeout(snum));
969 /* we've finished with the user stuff - go back to root */
970 change_to_root_user();
974 /***************************************************************************************
975 Simple wrapper function for make_connection() to include a call to
977 **************************************************************************************/
979 connection_struct *make_connection_with_chdir(const char *service_in,
981 const char *dev, uint16 vuid,
984 connection_struct *conn = NULL;
986 conn = make_connection(service_in, password, dev, vuid, status);
989 * make_connection() does not change the directory for us any more
990 * so we have to do it as a separate step --jerry
993 if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) {
994 DEBUG(0,("move_driver_to_download_area: Can't change "
995 "directory to %s for [print$] (%s)\n",
996 conn->connectpath,strerror(errno)));
997 yield_connection(conn, lp_servicename(SNUM(conn)));
999 *status = NT_STATUS_UNSUCCESSFUL;
1006 /****************************************************************************
1007 Make a connection to a service.
1010 ****************************************************************************/
1012 connection_struct *make_connection(const char *service_in, DATA_BLOB password,
1013 const char *pdev, uint16 vuid,
1017 user_struct *vuser = NULL;
1024 /* This must ONLY BE CALLED AS ROOT. As it exits this function as
1026 if (!non_root_mode() && (euid = geteuid()) != 0) {
1027 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot "
1028 "(%u)\n", (unsigned int)euid ));
1029 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
1032 if(lp_security() != SEC_SHARE) {
1033 vuser = get_valid_user_struct(vuid);
1035 DEBUG(1,("make_connection: refusing to connect with "
1036 "no session setup\n"));
1037 *status = NT_STATUS_ACCESS_DENIED;
1042 /* Logic to try and connect to the correct [homes] share, preferably
1043 without too many getpwnam() lookups. This is particulary nasty for
1044 winbind usernames, where the share name isn't the same as unix
1047 The snum of the homes share is stored on the vuser at session setup
1051 if (strequal(service_in,HOMES_NAME)) {
1052 if(lp_security() != SEC_SHARE) {
1053 DATA_BLOB no_pw = data_blob(NULL, 0);
1054 if (vuser->homes_snum == -1) {
1055 DEBUG(2, ("[homes] share not available for "
1056 "this user because it was not found "
1057 "or created at session setup "
1059 *status = NT_STATUS_BAD_NETWORK_NAME;
1062 DEBUG(5, ("making a connection to [homes] service "
1063 "created at session setup time\n"));
1064 return make_connection_snum(vuser->homes_snum,
1068 /* Security = share. Try with
1069 * current_user_info.smb_name as the username. */
1070 if (*current_user_info.smb_name) {
1071 fstring unix_username;
1072 fstrcpy(unix_username,
1073 current_user_info.smb_name);
1074 map_username(unix_username);
1075 snum = find_service(unix_username);
1078 DEBUG(5, ("making a connection to 'homes' "
1079 "service %s based on "
1080 "security=share\n", service_in));
1081 return make_connection_snum(snum, NULL,
1086 } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
1087 && strequal(service_in,
1088 lp_servicename(vuser->homes_snum))) {
1089 DATA_BLOB no_pw = data_blob(NULL, 0);
1090 DEBUG(5, ("making a connection to 'homes' service [%s] "
1091 "created at session setup time\n", service_in));
1092 return make_connection_snum(vuser->homes_snum,
1097 fstrcpy(service, service_in);
1099 strlower_m(service);
1101 snum = find_service(service);
1104 if (strequal(service,"IPC$") ||
1105 (lp_enable_asu_support() && strequal(service,"ADMIN$"))) {
1106 DEBUG(3,("refusing IPC connection to %s\n", service));
1107 *status = NT_STATUS_ACCESS_DENIED;
1111 DEBUG(0,("%s (%s) couldn't find service %s\n",
1112 get_remote_machine_name(), client_addr(), service));
1113 *status = NT_STATUS_BAD_NETWORK_NAME;
1117 /* Handle non-Dfs clients attempting connections to msdfs proxy */
1118 if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0')) {
1119 DEBUG(3, ("refusing connection to dfs proxy share '%s' "
1120 "(pointing to %s)\n",
1121 service, lp_msdfs_proxy(snum)));
1122 *status = NT_STATUS_BAD_NETWORK_NAME;
1126 DEBUG(5, ("making a connection to 'normal' service %s\n", service));
1128 return make_connection_snum(snum, vuser,
1133 /****************************************************************************
1135 ****************************************************************************/
1137 void close_cnum(connection_struct *conn, uint16 vuid)
1140 pipe_close_conn(conn);
1142 file_close_conn(conn);
1143 dptr_closecnum(conn);
1146 change_to_root_user();
1148 DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
1149 get_remote_machine_name(),
1150 conn->client_address,
1151 lp_servicename(SNUM(conn))));
1153 /* Call VFS disconnect hook */
1154 SMB_VFS_DISCONNECT(conn);
1156 yield_connection(conn, lp_servicename(SNUM(conn)));
1158 /* make sure we leave the directory available for unmount */
1159 vfs_ChDir(conn, "/");
1161 /* execute any "postexec = " line */
1162 if (*lp_postexec(SNUM(conn)) &&
1163 change_to_user(conn, vuid)) {
1165 pstrcpy(cmd,lp_postexec(SNUM(conn)));
1166 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
1167 conn->connectpath, conn->gid,
1168 get_current_username(),
1169 current_user_info.domain,
1172 change_to_root_user();
1175 change_to_root_user();
1176 /* execute any "root postexec = " line */
1177 if (*lp_rootpostexec(SNUM(conn))) {
1179 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
1180 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
1181 conn->connectpath, conn->gid,
1182 get_current_username(),
1183 current_user_info.domain,