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 struct timeval smb_last_time;
24 extern userdom_struct current_user_info;
26 /****************************************************************************
27 Ensure when setting connectpath it is a canonicalized (no ./ // or ../)
28 absolute path stating in / and not ending in /.
29 Observent people will notice a similarity between this and check_path_syntax :-).
30 ****************************************************************************/
32 void set_conn_connectpath(connection_struct *conn, const pstring connectpath)
36 const char *s = connectpath;
37 BOOL start_of_name_component = True;
39 *d++ = '/'; /* Always start with root. */
43 /* Eat multiple '/' */
47 if ((d > destname + 1) && (*s != '\0')) {
50 start_of_name_component = True;
54 if (start_of_name_component) {
55 if ((s[0] == '.') && (s[1] == '.') && (s[2] == '/' || s[2] == '\0')) {
56 /* Uh oh - "/../" or "/..\0" ! */
58 /* Go past the ../ or .. */
62 s += 2; /* Go past the .. */
65 /* If we just added a '/' - delete it */
66 if ((d > destname) && (*(d-1) == '/')) {
71 /* Are we at the start ? Can't go back further if so. */
73 *d++ = '/'; /* Can't delete root */
76 /* Go back one level... */
77 /* Decrement d first as d points to the *next* char to write into. */
78 for (d--; d > destname; d--) {
83 /* We're still at the start of a name component, just the previous one. */
85 } else if ((s[0] == '.') && ((s[1] == '\0') || s[1] == '/')) {
86 /* Component of pathname can't be "." only - skip the '.' . */
99 switch(next_mb_char_size(s)) {
113 start_of_name_component = False;
117 /* And must not end in '/' */
118 if (d > destname + 1 && (*(d-1) == '/')) {
122 DEBUG(10,("set_conn_connectpath: service %s, connectpath = %s\n",
123 lp_servicename(SNUM(conn)), destname ));
125 string_set(&conn->connectpath, destname);
128 /****************************************************************************
129 Load parameters specific to a connection/service.
130 ****************************************************************************/
132 BOOL set_current_service(connection_struct *conn, uint16 flags, BOOL do_chdir)
134 static connection_struct *last_conn;
135 static uint16 last_flags;
143 conn->lastused = smb_last_time.tv_sec;
148 vfs_ChDir(conn,conn->connectpath) != 0 &&
149 vfs_ChDir(conn,conn->origpath) != 0) {
150 DEBUG(0,("chdir (%s) failed\n",
155 if ((conn == last_conn) && (last_flags == flags)) {
162 /* Obey the client case sensitivity requests - only for clients that support it. */
163 switch (lp_casesensitive(snum)) {
166 /* We need this uglyness due to DOS/Win9x clients that lie about case insensitivity. */
167 enum remote_arch_types ra_type = get_remote_arch();
168 if ((ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
169 /* Client can't support per-packet case sensitive pathnames. */
170 conn->case_sensitive = False;
172 conn->case_sensitive = !(flags & FLAG_CASELESS_PATHNAMES);
177 conn->case_sensitive = True;
180 conn->case_sensitive = False;
186 /****************************************************************************
187 Add a home service. Returns the new service number or -1 if fail.
188 ****************************************************************************/
190 int add_home_service(const char *service, const char *username, const char *homedir)
194 if (!service || !homedir)
197 if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0)
201 * If this is a winbindd provided username, remove
202 * the domain component before adding the service.
203 * Log a warning if the "path=" parameter does not
204 * include any macros.
208 const char *p = strchr(service,*lp_winbind_separator());
210 /* We only want the 'user' part of the string */
216 if (!lp_add_home(service, iHomeService, username, homedir)) {
220 return lp_servicenumber(service);
226 * Find a service entry.
228 * @param service is modified (to canonical form??)
231 int find_service(fstring service)
235 all_string_sub(service,"\\","/",0);
237 iService = lp_servicenumber(service);
239 /* now handle the special case of a home directory */
241 char *phome_dir = get_user_home_dir(service);
245 * Try mapping the servicename, it may
246 * be a Windows to unix mapped user name.
248 if(map_username(service))
249 phome_dir = get_user_home_dir(service);
252 DEBUG(3,("checking for home directory %s gave %s\n",service,
253 phome_dir?phome_dir:"(NULL)"));
255 iService = add_home_service(service,service /* 'username' */, phome_dir);
258 /* If we still don't have a service, attempt to add it as a printer. */
262 if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) >= 0) {
263 DEBUG(3,("checking whether %s is a valid printer name...\n", service));
264 if (pcap_printername_ok(service)) {
265 DEBUG(3,("%s is a valid printer name\n", service));
266 DEBUG(3,("adding %s as a printer service\n", service));
267 lp_add_printer(service, iPrinterService);
268 iService = lp_servicenumber(service);
270 DEBUG(0,("failed to add %s as a printer service!\n", service));
273 DEBUG(3,("%s is not a valid printer name\n", service));
278 /* Check for default vfs service? Unsure whether to implement this */
282 /* just possibly it's a default service? */
284 char *pdefservice = lp_defaultservice();
285 if (pdefservice && *pdefservice && !strequal(pdefservice,service) && !strstr_m(service,"..")) {
287 * We need to do a local copy here as lp_defaultservice()
288 * returns one of the rotating lp_string buffers that
289 * could get overwritten by the recursive find_service() call
290 * below. Fix from Josef Hinteregger <joehtg@joehtg.co.at>.
293 pstrcpy(defservice, pdefservice);
294 iService = find_service(defservice);
296 all_string_sub(service, "_","/",0);
297 iService = lp_add_service(service, iService);
303 if (!VALID_SNUM(iService)) {
304 DEBUG(0,("Invalid snum %d for %s\n",iService, service));
310 DEBUG(3,("find_service() failed to find service %s\n", service));
316 /****************************************************************************
317 do some basic sainity checks on the share.
318 This function modifies dev, ecode.
319 ****************************************************************************/
321 static NTSTATUS share_sanity_checks(int snum, fstring dev)
324 if (!lp_snum_ok(snum) ||
325 !check_access(smbd_server_fd(),
326 lp_hostsallow(snum), lp_hostsdeny(snum))) {
327 return NT_STATUS_ACCESS_DENIED;
330 if (dev[0] == '?' || !dev[0]) {
331 if (lp_print_ok(snum)) {
332 fstrcpy(dev,"LPT1:");
333 } else if (strequal(lp_fstype(snum), "IPC")) {
342 if (lp_print_ok(snum)) {
343 if (!strequal(dev, "LPT1:")) {
344 return NT_STATUS_BAD_DEVICE_TYPE;
346 } else if (strequal(lp_fstype(snum), "IPC")) {
347 if (!strequal(dev, "IPC")) {
348 return NT_STATUS_BAD_DEVICE_TYPE;
350 } else if (!strequal(dev, "A:")) {
351 return NT_STATUS_BAD_DEVICE_TYPE;
354 /* Behave as a printer if we are supposed to */
355 if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) {
356 fstrcpy(dev, "LPT1:");
362 /****************************************************************************
363 Make a connection, given the snum to connect to, and the vuser of the
364 connecting user if appropriate.
365 ****************************************************************************/
367 static connection_struct *make_connection_snum(int snum, user_struct *vuser,
372 struct passwd *pass = NULL;
374 connection_struct *conn;
382 SET_STAT_INVALID(st);
384 if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, dev))) {
390 DEBUG(0,("Couldn't find free connection.\n"));
391 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
395 if (lp_guest_only(snum)) {
396 const char *guestname = lp_guestaccount();
398 pass = getpwnam_alloc(guestname);
400 DEBUG(0,("make_connection_snum: Invalid guest "
401 "account %s??\n",guestname));
403 *status = NT_STATUS_NO_SUCH_USER;
406 fstrcpy(user,pass->pw_name);
407 conn->force_user = True;
408 conn->uid = pass->pw_uid;
409 conn->gid = pass->pw_gid;
410 string_set(&conn->user,pass->pw_name);
412 DEBUG(3,("Guest only user %s\n",user));
415 if (!lp_guest_ok(snum)) {
416 DEBUG(2, ("guest user (from session setup) "
417 "not permitted to access this share "
418 "(%s)\n", lp_servicename(snum)));
420 *status = NT_STATUS_ACCESS_DENIED;
424 if (!user_ok(vuser->user.unix_name, snum,
425 vuser->groups, vuser->n_groups)) {
426 DEBUG(2, ("user '%s' (from session setup) not "
427 "permitted to access this share "
428 "(%s)\n", vuser->user.unix_name,
429 lp_servicename(snum)));
431 *status = NT_STATUS_ACCESS_DENIED;
435 conn->vuid = vuser->vuid;
436 conn->uid = vuser->uid;
437 conn->gid = vuser->gid;
438 string_set(&conn->user,vuser->user.unix_name);
439 fstrcpy(user,vuser->user.unix_name);
440 guest = vuser->guest;
441 } else if (lp_security() == SEC_SHARE) {
442 /* add it as a possible user name if we
443 are in share mode security */
444 add_session_user(lp_servicename(snum));
445 /* shall we let them in? */
446 if (!authorise_login(snum,user,password,&guest)) {
447 DEBUG( 2, ( "Invalid username/password for [%s]\n",
448 lp_servicename(snum)) );
450 *status = NT_STATUS_WRONG_PASSWORD;
453 pass = Get_Pwnam(user);
454 conn->force_user = True;
455 conn->uid = pass->pw_uid;
456 conn->gid = pass->pw_gid;
457 string_set(&conn->user, pass->pw_name);
458 fstrcpy(user, pass->pw_name);
461 DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
463 *status = NT_STATUS_ACCESS_DENIED;
467 add_session_user(user);
469 safe_strcpy(conn->client_address, client_addr(),
470 sizeof(conn->client_address)-1);
471 conn->num_files_open = 0;
472 conn->lastused = time(NULL);
473 conn->service = snum;
475 conn->printer = (strncmp(dev,"LPT",3) == 0);
476 conn->ipc = ( (strncmp(dev,"IPC",3) == 0) ||
477 ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) );
480 /* Case options for the share. */
481 if (lp_casesensitive(snum) == Auto) {
482 /* We will be setting this per packet. Set to be case
483 * insensitive for now. */
484 conn->case_sensitive = False;
486 conn->case_sensitive = (BOOL)lp_casesensitive(snum);
489 conn->case_preserve = lp_preservecase(snum);
490 conn->short_case_preserve = lp_shortpreservecase(snum);
492 conn->veto_list = NULL;
493 conn->hide_list = NULL;
494 conn->veto_oplock_list = NULL;
495 conn->aio_write_behind_list = NULL;
496 string_set(&conn->dirpath,"");
497 string_set(&conn->user,user);
498 conn->nt_user_token = NULL;
500 conn->read_only = lp_readonly(conn->service);
501 conn->admin_user = False;
504 * If force user is true, then store the
505 * given userid and also the groups
506 * of the user we're forcing.
509 if (*lp_force_user(snum)) {
510 struct passwd *pass2;
512 pstrcpy(fuser,lp_force_user(snum));
514 /* Allow %S to be used by force user. */
515 pstring_sub(fuser,"%S",lp_servicename(snum));
517 pass2 = (struct passwd *)Get_Pwnam(fuser);
519 conn->uid = pass2->pw_uid;
520 conn->gid = pass2->pw_gid;
521 string_set(&conn->user,pass2->pw_name);
522 fstrcpy(user,pass2->pw_name);
523 conn->force_user = True;
524 DEBUG(3,("Forced user %s\n",user));
526 DEBUG(1,("Couldn't find user %s\n",fuser));
528 *status = NT_STATUS_NO_SUCH_USER;
535 * If force group is true, then override
536 * any groupid stored for the connecting user.
539 if (*lp_force_group(snum)) {
543 BOOL user_must_be_member = False;
545 pstrcpy(tmp_gname,lp_force_group(snum));
547 if (tmp_gname[0] == '+') {
548 user_must_be_member = True;
549 /* even now, tmp_gname is null terminated */
550 pstrcpy(gname,&tmp_gname[1]);
552 pstrcpy(gname,tmp_gname);
554 /* default service may be a group name */
555 pstring_sub(gname,"%S",lp_servicename(snum));
556 gid = nametogid(gname);
558 if (gid == (gid_t)-1) {
559 DEBUG(1,("Couldn't find group %s\n",gname));
561 *status = NT_STATUS_NO_SUCH_GROUP;
566 * If the user has been forced and the forced group starts
567 * with a '+', then we only set the group to be the forced
568 * group if the forced user is a member of that group.
569 * Otherwise, the meaning of the '+' would be ignored.
571 if (conn->force_user && user_must_be_member) {
572 if (user_in_group_list( user, gname, NULL, 0)) {
574 DEBUG(3,("Forced group %s for member %s\n",
579 DEBUG(3,("Forced group %s\n",gname));
581 conn->force_group = True;
583 #endif /* HAVE_GETGRNAM */
587 pstrcpy(s,lp_pathname(snum));
588 standard_sub_conn(conn,s,sizeof(s));
589 set_conn_connectpath(conn,s);
590 DEBUG(3,("Connect path is '%s' for service [%s]\n",s,
591 lp_servicename(snum)));
594 if (conn->force_user || conn->force_group) {
597 /* groups stuff added by ih */
601 /* Find all the groups this uid is in and
602 store them. Used by change_to_user() */
603 initialise_groups(conn->user, conn->uid, conn->gid);
604 get_current_groups(conn->gid, &ngroups, &conn->groups);
605 conn->ngroups = ngroups;
607 conn->nt_user_token =
608 create_nt_token(conn->uid, conn->gid,
609 conn->ngroups, conn->groups,
614 * New code to check if there's a share security descripter
615 * added from NT server manager. This is done after the
616 * smb.conf checks are done as we need a uid and token. JRA.
621 BOOL can_write = share_access_check(conn, snum, vuser,
625 if (!share_access_check(conn, snum, vuser,
627 /* No access, read or write. */
628 DEBUG(0,("make_connection: connection to %s "
629 "denied due to security "
631 lp_servicename(snum)));
633 *status = NT_STATUS_ACCESS_DENIED;
636 conn->read_only = True;
640 /* Initialise VFS function pointers */
642 if (!smbd_vfs_init(conn)) {
643 DEBUG(0, ("vfs_init failed for service %s\n",
644 lp_servicename(snum)));
646 *status = NT_STATUS_BAD_NETWORK_NAME;
651 * If widelinks are disallowed we need to canonicalise the connect
652 * path here to ensure we don't have any symlinks in the
653 * connectpath. We will be checking all paths on this connection are
654 * below this directory. We must do this after the VFS init as we
655 * depend on the realpath() pointer in the vfs table. JRA.
657 if (!lp_widelinks(snum)) {
659 pstrcpy(s,conn->connectpath);
660 canonicalize_path(conn, s);
661 set_conn_connectpath(conn,s);
664 /* ROOT Activities: */
665 /* check number of connections */
666 if (!claim_connection(conn,
667 lp_servicename(snum),
668 lp_max_connections(snum),
670 DEBUG(1,("too many connections - rejected\n"));
672 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
676 /* Preexecs are done here as they might make the dir we are to ChDir
678 /* execute any "root preexec = " line */
679 if (*lp_rootpreexec(snum)) {
681 pstrcpy(cmd,lp_rootpreexec(snum));
682 standard_sub_conn(conn,cmd,sizeof(cmd));
683 DEBUG(5,("cmd=%s\n",cmd));
684 ret = smbrun(cmd,NULL);
685 if (ret != 0 && lp_rootpreexec_close(snum)) {
686 DEBUG(1,("root preexec gave %d - failing "
687 "connection\n", ret));
688 yield_connection(conn, lp_servicename(snum));
690 *status = NT_STATUS_ACCESS_DENIED;
695 /* USER Activites: */
696 if (!change_to_user(conn, conn->vuid)) {
697 /* No point continuing if they fail the basic checks */
698 DEBUG(0,("Can't become connected user!\n"));
699 yield_connection(conn, lp_servicename(snum));
701 *status = NT_STATUS_LOGON_FAILURE;
705 /* Remember that a different vuid can connect later without these
708 /* Preexecs are done here as they might make the dir we are to ChDir
711 /* execute any "preexec = " line */
712 if (*lp_preexec(snum)) {
714 pstrcpy(cmd,lp_preexec(snum));
715 standard_sub_conn(conn,cmd,sizeof(cmd));
716 ret = smbrun(cmd,NULL);
717 if (ret != 0 && lp_preexec_close(snum)) {
718 DEBUG(1,("preexec gave %d - failing connection\n",
720 change_to_root_user();
721 yield_connection(conn, lp_servicename(snum));
723 *status = NT_STATUS_ACCESS_DENIED;
728 #ifdef WITH_FAKE_KASERVER
729 if (lp_afs_share(snum)) {
734 /* Add veto/hide lists */
735 if (!IS_IPC(conn) && !IS_PRINT(conn)) {
736 set_namearray( &conn->veto_list, lp_veto_files(snum));
737 set_namearray( &conn->hide_list, lp_hide_files(snum));
738 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(snum));
741 /* Invoke VFS make connection hook - do this before the VFS_STAT call
742 to allow any filesystems needing user credentials to initialize
745 if (SMB_VFS_CONNECT(conn, lp_servicename(snum), user) < 0) {
746 DEBUG(0,("make_connection: VFS make connection failed!\n"));
747 change_to_root_user();
748 yield_connection(conn, lp_servicename(snum));
750 *status = NT_STATUS_UNSUCCESSFUL;
754 /* win2000 does not check the permissions on the directory
755 during the tree connect, instead relying on permission
756 check during individual operations. To match this behaviour
757 I have disabled this chdir check (tridge) */
758 /* the alternative is just to check the directory exists */
759 if ((ret = SMB_VFS_STAT(conn, conn->connectpath, &st)) != 0 ||
760 !S_ISDIR(st.st_mode)) {
761 if (ret == 0 && !S_ISDIR(st.st_mode)) {
762 DEBUG(0,("'%s' is not a directory, when connecting to "
763 "[%s]\n", conn->connectpath,
764 lp_servicename(snum)));
766 DEBUG(0,("'%s' does not exist or permission denied "
767 "when connecting to [%s] Error was %s\n",
768 conn->connectpath, lp_servicename(snum),
771 change_to_root_user();
772 /* Call VFS disconnect hook */
773 SMB_VFS_DISCONNECT(conn);
774 yield_connection(conn, lp_servicename(snum));
776 *status = NT_STATUS_BAD_NETWORK_NAME;
780 string_set(&conn->origpath,conn->connectpath);
782 #if SOFTLINK_OPTIMISATION
783 /* resolve any soft links early if possible */
784 if (vfs_ChDir(conn,conn->connectpath) == 0) {
786 pstrcpy(s,conn->connectpath);
788 set_conn_connectpath(conn,s);
789 vfs_ChDir(conn,conn->connectpath);
794 * Print out the 'connected as' stuff here as we need
795 * to know the effective uid and gid we will be using
796 * (at least initially).
799 if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
800 dbgtext( "%s (%s) ", get_remote_machine_name(),
801 conn->client_address );
802 dbgtext( "%s", srv_is_signing_active() ? "signed " : "");
803 dbgtext( "connect to service %s ", lp_servicename(snum) );
804 dbgtext( "initially as user %s ", user );
805 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
806 dbgtext( "(pid %d)\n", (int)sys_getpid() );
809 /* we've finished with the user stuff - go back to root */
810 change_to_root_user();
814 /***************************************************************************************
815 Simple wrapper function for make_connection() to include a call to
817 **************************************************************************************/
819 connection_struct *make_connection_with_chdir(const char *service_in,
821 const char *dev, uint16 vuid,
824 connection_struct *conn = NULL;
826 conn = make_connection(service_in, password, dev, vuid, status);
829 * make_connection() does not change the directory for us any more
830 * so we have to do it as a separate step --jerry
833 if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) {
834 DEBUG(0,("move_driver_to_download_area: Can't change "
835 "directory to %s for [print$] (%s)\n",
836 conn->connectpath,strerror(errno)));
837 yield_connection(conn, lp_servicename(SNUM(conn)));
839 *status = NT_STATUS_UNSUCCESSFUL;
846 /****************************************************************************
847 Make a connection to a service.
850 ****************************************************************************/
852 connection_struct *make_connection(const char *service_in, DATA_BLOB password,
853 const char *pdev, uint16 vuid,
857 user_struct *vuser = NULL;
864 /* This must ONLY BE CALLED AS ROOT. As it exits this function as
866 if (!non_root_mode() && (euid = geteuid()) != 0) {
867 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot "
868 "(%u)\n", (unsigned int)euid ));
869 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
872 if(lp_security() != SEC_SHARE) {
873 vuser = get_valid_user_struct(vuid);
875 DEBUG(1,("make_connection: refusing to connect with "
876 "no session setup\n"));
877 *status = NT_STATUS_ACCESS_DENIED;
882 /* Logic to try and connect to the correct [homes] share, preferably
883 without too many getpwnam() lookups. This is particulary nasty for
884 winbind usernames, where the share name isn't the same as unix
887 The snum of the homes share is stored on the vuser at session setup
891 if (strequal(service_in,HOMES_NAME)) {
892 if(lp_security() != SEC_SHARE) {
893 DATA_BLOB no_pw = data_blob(NULL, 0);
894 if (vuser->homes_snum == -1) {
895 DEBUG(2, ("[homes] share not available for "
896 "this user because it was not found "
897 "or created at session setup "
899 *status = NT_STATUS_BAD_NETWORK_NAME;
902 DEBUG(5, ("making a connection to [homes] service "
903 "created at session setup time\n"));
904 return make_connection_snum(vuser->homes_snum,
908 /* Security = share. Try with
909 * current_user_info.smb_name as the username. */
910 if (*current_user_info.smb_name) {
911 fstring unix_username;
912 fstrcpy(unix_username,
913 current_user_info.smb_name);
914 map_username(unix_username);
915 snum = find_service(unix_username);
918 DEBUG(5, ("making a connection to 'homes' "
919 "service %s based on "
920 "security=share\n", service_in));
921 return make_connection_snum(snum, NULL,
926 } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
927 && strequal(service_in,
928 lp_servicename(vuser->homes_snum))) {
929 DATA_BLOB no_pw = data_blob(NULL, 0);
930 DEBUG(5, ("making a connection to 'homes' service [%s] "
931 "created at session setup time\n", service_in));
932 return make_connection_snum(vuser->homes_snum,
937 fstrcpy(service, service_in);
941 snum = find_service(service);
944 if (strequal(service,"IPC$") ||
945 (lp_enable_asu_support() && strequal(service,"ADMIN$"))) {
946 DEBUG(3,("refusing IPC connection to %s\n", service));
947 *status = NT_STATUS_ACCESS_DENIED;
951 DEBUG(0,("%s (%s) couldn't find service %s\n",
952 get_remote_machine_name(), client_addr(), service));
953 *status = NT_STATUS_BAD_NETWORK_NAME;
957 /* Handle non-Dfs clients attempting connections to msdfs proxy */
958 if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0')) {
959 DEBUG(3, ("refusing connection to dfs proxy share '%s' "
960 "(pointing to %s)\n",
961 service, lp_msdfs_proxy(snum)));
962 *status = NT_STATUS_BAD_NETWORK_NAME;
966 DEBUG(5, ("making a connection to 'normal' service %s\n", service));
968 return make_connection_snum(snum, vuser,
973 /****************************************************************************
975 ****************************************************************************/
977 void close_cnum(connection_struct *conn, uint16 vuid)
980 pipe_close_conn(conn);
982 file_close_conn(conn);
983 dptr_closecnum(conn);
986 change_to_root_user();
988 DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
989 get_remote_machine_name(),
990 conn->client_address,
991 lp_servicename(SNUM(conn))));
993 /* Call VFS disconnect hook */
994 SMB_VFS_DISCONNECT(conn);
996 yield_connection(conn, lp_servicename(SNUM(conn)));
998 /* make sure we leave the directory available for unmount */
999 vfs_ChDir(conn, "/");
1001 /* execute any "postexec = " line */
1002 if (*lp_postexec(SNUM(conn)) &&
1003 change_to_user(conn, vuid)) {
1005 pstrcpy(cmd,lp_postexec(SNUM(conn)));
1006 standard_sub_conn(conn,cmd,sizeof(cmd));
1008 change_to_root_user();
1011 change_to_root_user();
1012 /* execute any "root postexec = " line */
1013 if (*lp_rootpostexec(SNUM(conn))) {
1015 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
1016 standard_sub_conn(conn,cmd,sizeof(cmd));