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) && (*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 string_set(&conn->connectpath, destname);
125 /****************************************************************************
126 Load parameters specific to a connection/service.
127 ****************************************************************************/
129 BOOL set_current_service(connection_struct *conn, uint16 flags, BOOL do_chdir)
131 static connection_struct *last_conn;
132 static uint16 last_flags;
140 conn->lastused = smb_last_time.tv_sec;
145 vfs_ChDir(conn,conn->connectpath) != 0 &&
146 vfs_ChDir(conn,conn->origpath) != 0) {
147 DEBUG(0,("chdir (%s) failed\n",
152 if ((conn == last_conn) && (last_flags == flags)) {
159 /* Obey the client case sensitivity requests - only for clients that support it. */
160 switch (lp_casesensitive(snum)) {
163 /* We need this uglyness due to DOS/Win9x clients that lie about case insensitivity. */
164 enum remote_arch_types ra_type = get_remote_arch();
165 if ((ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
166 /* Client can't support per-packet case sensitive pathnames. */
167 conn->case_sensitive = False;
169 conn->case_sensitive = !(flags & FLAG_CASELESS_PATHNAMES);
174 conn->case_sensitive = True;
177 conn->case_sensitive = False;
183 /****************************************************************************
184 Add a home service. Returns the new service number or -1 if fail.
185 ****************************************************************************/
187 int add_home_service(const char *service, const char *username, const char *homedir)
191 if (!service || !homedir)
194 if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0)
198 * If this is a winbindd provided username, remove
199 * the domain component before adding the service.
200 * Log a warning if the "path=" parameter does not
201 * include any macros.
205 const char *p = strchr(service,*lp_winbind_separator());
207 /* We only want the 'user' part of the string */
213 if (!lp_add_home(service, iHomeService, username, homedir)) {
217 return lp_servicenumber(service);
223 * Find a service entry.
225 * @param service is modified (to canonical form??)
228 int find_service(fstring service)
232 all_string_sub(service,"\\","/",0);
234 iService = lp_servicenumber(service);
236 /* now handle the special case of a home directory */
238 char *phome_dir = get_user_home_dir(service);
242 * Try mapping the servicename, it may
243 * be a Windows to unix mapped user name.
245 if(map_username(service))
246 phome_dir = get_user_home_dir(service);
249 DEBUG(3,("checking for home directory %s gave %s\n",service,
250 phome_dir?phome_dir:"(NULL)"));
252 iService = add_home_service(service,service /* 'username' */, phome_dir);
255 /* If we still don't have a service, attempt to add it as a printer. */
259 if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) >= 0) {
260 DEBUG(3,("checking whether %s is a valid printer name...\n", service));
261 if (pcap_printername_ok(service)) {
262 DEBUG(3,("%s is a valid printer name\n", service));
263 DEBUG(3,("adding %s as a printer service\n", service));
264 lp_add_printer(service, iPrinterService);
265 iService = lp_servicenumber(service);
267 DEBUG(0,("failed to add %s as a printer service!\n", service));
270 DEBUG(3,("%s is not a valid printer name\n", service));
275 /* Check for default vfs service? Unsure whether to implement this */
279 /* just possibly it's a default service? */
281 char *pdefservice = lp_defaultservice();
282 if (pdefservice && *pdefservice && !strequal(pdefservice,service) && !strstr_m(service,"..")) {
284 * We need to do a local copy here as lp_defaultservice()
285 * returns one of the rotating lp_string buffers that
286 * could get overwritten by the recursive find_service() call
287 * below. Fix from Josef Hinteregger <joehtg@joehtg.co.at>.
290 pstrcpy(defservice, pdefservice);
291 iService = find_service(defservice);
293 all_string_sub(service, "_","/",0);
294 iService = lp_add_service(service, iService);
300 if (!VALID_SNUM(iService)) {
301 DEBUG(0,("Invalid snum %d for %s\n",iService, service));
307 DEBUG(3,("find_service() failed to find service %s\n", service));
313 /****************************************************************************
314 do some basic sainity checks on the share.
315 This function modifies dev, ecode.
316 ****************************************************************************/
318 static NTSTATUS share_sanity_checks(int snum, fstring dev)
321 if (!lp_snum_ok(snum) ||
322 !check_access(smbd_server_fd(),
323 lp_hostsallow(snum), lp_hostsdeny(snum))) {
324 return NT_STATUS_ACCESS_DENIED;
327 if (dev[0] == '?' || !dev[0]) {
328 if (lp_print_ok(snum)) {
329 fstrcpy(dev,"LPT1:");
330 } else if (strequal(lp_fstype(snum), "IPC")) {
339 if (lp_print_ok(snum)) {
340 if (!strequal(dev, "LPT1:")) {
341 return NT_STATUS_BAD_DEVICE_TYPE;
343 } else if (strequal(lp_fstype(snum), "IPC")) {
344 if (!strequal(dev, "IPC")) {
345 return NT_STATUS_BAD_DEVICE_TYPE;
347 } else if (!strequal(dev, "A:")) {
348 return NT_STATUS_BAD_DEVICE_TYPE;
351 /* Behave as a printer if we are supposed to */
352 if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) {
353 fstrcpy(dev, "LPT1:");
359 /****************************************************************************
360 Make a connection, given the snum to connect to, and the vuser of the
361 connecting user if appropriate.
362 ****************************************************************************/
364 static connection_struct *make_connection_snum(int snum, user_struct *vuser,
366 const char *pdev, NTSTATUS *status)
368 struct passwd *pass = NULL;
370 connection_struct *conn;
378 SET_STAT_INVALID(st);
380 if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, dev))) {
386 DEBUG(0,("Couldn't find free connection.\n"));
387 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
391 if (lp_guest_only(snum)) {
392 const char *guestname = lp_guestaccount();
394 pass = getpwnam_alloc(guestname);
396 DEBUG(0,("make_connection_snum: Invalid guest account %s??\n",guestname));
398 *status = NT_STATUS_NO_SUCH_USER;
401 fstrcpy(user,pass->pw_name);
402 conn->force_user = True;
403 conn->uid = pass->pw_uid;
404 conn->gid = pass->pw_gid;
405 string_set(&conn->user,pass->pw_name);
407 DEBUG(3,("Guest only user %s\n",user));
410 if (!lp_guest_ok(snum)) {
411 DEBUG(2, ("guest user (from session setup) not permitted to access this share (%s)\n", lp_servicename(snum)));
413 *status = NT_STATUS_ACCESS_DENIED;
417 if (!user_ok(vuser->user.unix_name, snum, vuser->groups, vuser->n_groups)) {
418 DEBUG(2, ("user '%s' (from session setup) not permitted to access this share (%s)\n", vuser->user.unix_name, lp_servicename(snum)));
420 *status = NT_STATUS_ACCESS_DENIED;
424 conn->vuid = vuser->vuid;
425 conn->uid = vuser->uid;
426 conn->gid = vuser->gid;
427 string_set(&conn->user,vuser->user.unix_name);
428 fstrcpy(user,vuser->user.unix_name);
429 guest = vuser->guest;
430 } else if (lp_security() == SEC_SHARE) {
431 /* add it as a possible user name if we
432 are in share mode security */
433 add_session_user(lp_servicename(snum));
434 /* shall we let them in? */
435 if (!authorise_login(snum,user,password,&guest)) {
436 DEBUG( 2, ( "Invalid username/password for [%s]\n",
437 lp_servicename(snum)) );
439 *status = NT_STATUS_WRONG_PASSWORD;
442 pass = Get_Pwnam(user);
443 conn->force_user = True;
444 conn->uid = pass->pw_uid;
445 conn->gid = pass->pw_gid;
446 string_set(&conn->user, pass->pw_name);
447 fstrcpy(user, pass->pw_name);
450 DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
452 *status = NT_STATUS_ACCESS_DENIED;
456 add_session_user(user);
458 safe_strcpy(conn->client_address, client_addr(),
459 sizeof(conn->client_address)-1);
460 conn->num_files_open = 0;
461 conn->lastused = time(NULL);
462 conn->service = snum;
464 conn->printer = (strncmp(dev,"LPT",3) == 0);
465 conn->ipc = ( (strncmp(dev,"IPC",3) == 0) || ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) );
468 /* Case options for the share. */
469 if (lp_casesensitive(snum) == Auto) {
470 /* We will be setting this per packet. Set to be case insensitive for now. */
471 conn->case_sensitive = False;
473 conn->case_sensitive = (BOOL)lp_casesensitive(snum);
476 conn->case_preserve = lp_preservecase(snum);
477 conn->short_case_preserve = lp_shortpreservecase(snum);
479 conn->veto_list = NULL;
480 conn->hide_list = NULL;
481 conn->veto_oplock_list = NULL;
482 conn->aio_write_behind_list = NULL;
483 string_set(&conn->dirpath,"");
484 string_set(&conn->user,user);
485 conn->nt_user_token = NULL;
487 conn->read_only = lp_readonly(conn->service);
488 conn->admin_user = False;
491 * If force user is true, then store the
492 * given userid and also the groups
493 * of the user we're forcing.
496 if (*lp_force_user(snum)) {
497 struct passwd *pass2;
499 pstrcpy(fuser,lp_force_user(snum));
501 /* Allow %S to be used by force user. */
502 pstring_sub(fuser,"%S",lp_servicename(snum));
504 pass2 = (struct passwd *)Get_Pwnam(fuser);
506 conn->uid = pass2->pw_uid;
507 conn->gid = pass2->pw_gid;
508 string_set(&conn->user,pass2->pw_name);
509 fstrcpy(user,pass2->pw_name);
510 conn->force_user = True;
511 DEBUG(3,("Forced user %s\n",user));
513 DEBUG(1,("Couldn't find user %s\n",fuser));
515 *status = NT_STATUS_NO_SUCH_USER;
522 * If force group is true, then override
523 * any groupid stored for the connecting user.
526 if (*lp_force_group(snum)) {
530 BOOL user_must_be_member = False;
532 pstrcpy(tmp_gname,lp_force_group(snum));
534 if (tmp_gname[0] == '+') {
535 user_must_be_member = True;
536 /* even now, tmp_gname is null terminated */
537 pstrcpy(gname,&tmp_gname[1]);
539 pstrcpy(gname,tmp_gname);
541 /* default service may be a group name */
542 pstring_sub(gname,"%S",lp_servicename(snum));
543 gid = nametogid(gname);
545 if (gid != (gid_t)-1) {
548 * If the user has been forced and the forced group starts
549 * with a '+', then we only set the group to be the forced
550 * group if the forced user is a member of that group.
551 * Otherwise, the meaning of the '+' would be ignored.
553 if (conn->force_user && user_must_be_member) {
554 if (user_in_group_list( user, gname, NULL, 0)) {
556 DEBUG(3,("Forced group %s for member %s\n",gname,user));
560 DEBUG(3,("Forced group %s\n",gname));
562 conn->force_group = True;
564 DEBUG(1,("Couldn't find group %s\n",gname));
566 *status = NT_STATUS_NO_SUCH_GROUP;
570 #endif /* HAVE_GETGRNAM */
574 pstrcpy(s,lp_pathname(snum));
575 standard_sub_conn(conn,s,sizeof(s));
576 set_conn_connectpath(conn,s);
577 DEBUG(3,("Connect path is '%s' for service [%s]\n",s, lp_servicename(snum)));
580 if (conn->force_user || conn->force_group) {
582 /* groups stuff added by ih */
586 /* Find all the groups this uid is in and
587 store them. Used by change_to_user() */
588 initialise_groups(conn->user, conn->uid, conn->gid);
589 get_current_groups(conn->gid, &conn->ngroups,&conn->groups);
591 conn->nt_user_token = create_nt_token(conn->uid, conn->gid,
592 conn->ngroups, conn->groups,
597 * New code to check if there's a share security descripter
598 * added from NT server manager. This is done after the
599 * smb.conf checks are done as we need a uid and token. JRA.
604 BOOL can_write = share_access_check(conn, snum, vuser, FILE_WRITE_DATA);
607 if (!share_access_check(conn, snum, vuser, FILE_READ_DATA)) {
608 /* No access, read or write. */
609 DEBUG(0,( "make_connection: connection to %s denied due to security descriptor.\n",
610 lp_servicename(snum)));
612 *status = NT_STATUS_ACCESS_DENIED;
615 conn->read_only = True;
619 /* Initialise VFS function pointers */
621 if (!smbd_vfs_init(conn)) {
622 DEBUG(0, ("vfs_init failed for service %s\n", lp_servicename(snum)));
624 *status = NT_STATUS_BAD_NETWORK_NAME;
629 * If widelinks are disallowed we need to canonicalise the
630 * connect path here to ensure we don't have any symlinks in
631 * the connectpath. We will be checking all paths on this
632 * connection are below this directory. We must do this after
633 * the VFS init as we depend on the realpath() pointer in the vfs table. JRA.
635 if (!lp_widelinks(snum)) {
637 pstrcpy(s,conn->connectpath);
638 canonicalize_path(conn, s);
639 set_conn_connectpath(conn,s);
642 /* ROOT Activities: */
643 /* check number of connections */
644 if (!claim_connection(conn,
645 lp_servicename(snum),
646 lp_max_connections(snum),
648 DEBUG(1,("too many connections - rejected\n"));
650 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
654 /* Preexecs are done here as they might make the dir we are to ChDir to below */
655 /* execute any "root preexec = " line */
656 if (*lp_rootpreexec(snum)) {
658 pstrcpy(cmd,lp_rootpreexec(snum));
659 standard_sub_conn(conn,cmd,sizeof(cmd));
660 DEBUG(5,("cmd=%s\n",cmd));
661 ret = smbrun(cmd,NULL);
662 if (ret != 0 && lp_rootpreexec_close(snum)) {
663 DEBUG(1,("root preexec gave %d - failing connection\n", ret));
664 yield_connection(conn, lp_servicename(snum));
666 *status = NT_STATUS_ACCESS_DENIED;
671 /* USER Activites: */
672 if (!change_to_user(conn, conn->vuid)) {
673 /* No point continuing if they fail the basic checks */
674 DEBUG(0,("Can't become connected user!\n"));
675 yield_connection(conn, lp_servicename(snum));
677 *status = NT_STATUS_LOGON_FAILURE;
681 /* Remember that a different vuid can connect later without these checks... */
683 /* Preexecs are done here as they might make the dir we are to ChDir to below */
684 /* execute any "preexec = " line */
685 if (*lp_preexec(snum)) {
687 pstrcpy(cmd,lp_preexec(snum));
688 standard_sub_conn(conn,cmd,sizeof(cmd));
689 ret = smbrun(cmd,NULL);
690 if (ret != 0 && lp_preexec_close(snum)) {
691 DEBUG(1,("preexec gave %d - failing connection\n", ret));
692 change_to_root_user();
693 yield_connection(conn, lp_servicename(snum));
695 *status = NT_STATUS_ACCESS_DENIED;
700 #ifdef WITH_FAKE_KASERVER
701 if (lp_afs_share(snum)) {
706 /* Add veto/hide lists */
707 if (!IS_IPC(conn) && !IS_PRINT(conn)) {
708 set_namearray( &conn->veto_list, lp_veto_files(snum));
709 set_namearray( &conn->hide_list, lp_hide_files(snum));
710 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(snum));
713 /* Invoke VFS make connection hook - do this before the VFS_STAT call to allow
714 any filesystems needing user credentials to initialize themselves. */
716 if (SMB_VFS_CONNECT(conn, lp_servicename(snum), user) < 0) {
717 DEBUG(0,("make_connection: VFS make connection failed!\n"));
718 change_to_root_user();
719 yield_connection(conn, lp_servicename(snum));
721 *status = NT_STATUS_UNSUCCESSFUL;
725 /* win2000 does not check the permissions on the directory
726 during the tree connect, instead relying on permission
727 check during individual operations. To match this behaviour
728 I have disabled this chdir check (tridge) */
729 /* the alternative is just to check the directory exists */
730 if ((ret = SMB_VFS_STAT(conn, conn->connectpath, &st)) != 0 || !S_ISDIR(st.st_mode)) {
731 if (ret == 0 && !S_ISDIR(st.st_mode)) {
732 DEBUG(0,("'%s' is not a directory, when connecting to [%s]\n", conn->connectpath, lp_servicename(snum)));
734 DEBUG(0,("'%s' does not exist or permission denied when connecting to [%s] "
735 "Error was %s\n", conn->connectpath, lp_servicename(snum), strerror(errno) ));
737 change_to_root_user();
738 /* Call VFS disconnect hook */
739 SMB_VFS_DISCONNECT(conn);
740 yield_connection(conn, lp_servicename(snum));
742 *status = NT_STATUS_BAD_NETWORK_NAME;
746 string_set(&conn->origpath,conn->connectpath);
748 #if SOFTLINK_OPTIMISATION
749 /* resolve any soft links early if possible */
750 if (vfs_ChDir(conn,conn->connectpath) == 0) {
752 pstrcpy(s,conn->connectpath);
754 set_conn_connectpath(conn,s);
755 vfs_ChDir(conn,conn->connectpath);
760 * Print out the 'connected as' stuff here as we need
761 * to know the effective uid and gid we will be using
762 * (at least initially).
765 if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
766 dbgtext( "%s (%s) ", get_remote_machine_name(), conn->client_address );
767 dbgtext( "%s", srv_is_signing_active() ? "signed " : "");
768 dbgtext( "connect to service %s ", lp_servicename(snum) );
769 dbgtext( "initially as user %s ", user );
770 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
771 dbgtext( "(pid %d)\n", (int)sys_getpid() );
774 /* we've finished with the user stuff - go back to root */
775 change_to_root_user();
779 /***************************************************************************************
780 Simple wrapper function for make_connection() to include a call to
782 **************************************************************************************/
784 connection_struct *make_connection_with_chdir(const char *service_in, DATA_BLOB password,
785 const char *dev, uint16 vuid, NTSTATUS *status)
787 connection_struct *conn = NULL;
789 conn = make_connection(service_in, password, dev, vuid, status);
792 * make_connection() does not change the directory for us any more
793 * so we have to do it as a separate step --jerry
796 if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) {
797 DEBUG(0,("move_driver_to_download_area: Can't change directory to %s for [print$] (%s)\n",
798 conn->connectpath,strerror(errno)));
799 yield_connection(conn, lp_servicename(SNUM(conn)));
801 *status = NT_STATUS_UNSUCCESSFUL;
808 /****************************************************************************
809 Make a connection to a service.
812 ****************************************************************************/
814 connection_struct *make_connection(const char *service_in, DATA_BLOB password,
815 const char *pdev, uint16 vuid, NTSTATUS *status)
818 user_struct *vuser = NULL;
825 /* This must ONLY BE CALLED AS ROOT. As it exits this function as root. */
826 if (!non_root_mode() && (euid = geteuid()) != 0) {
827 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot (%u)\n", (unsigned int)euid ));
828 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
831 if(lp_security() != SEC_SHARE) {
832 vuser = get_valid_user_struct(vuid);
834 DEBUG(1,("make_connection: refusing to connect with no session setup\n"));
835 *status = NT_STATUS_ACCESS_DENIED;
840 /* Logic to try and connect to the correct [homes] share, preferably without too many
841 getpwnam() lookups. This is particulary nasty for winbind usernames, where the
842 share name isn't the same as unix username.
844 The snum of the homes share is stored on the vuser at session setup time.
847 if (strequal(service_in,HOMES_NAME)) {
848 if(lp_security() != SEC_SHARE) {
849 DATA_BLOB no_pw = data_blob(NULL, 0);
850 if (vuser->homes_snum == -1) {
851 DEBUG(2, ("[homes] share not available for this user because it was not found or created at session setup time\n"));
852 *status = NT_STATUS_BAD_NETWORK_NAME;
855 DEBUG(5, ("making a connection to [homes] service created at session setup time\n"));
856 return make_connection_snum(vuser->homes_snum,
860 /* Security = share. Try with current_user_info.smb_name
861 * as the username. */
862 if (*current_user_info.smb_name) {
863 fstring unix_username;
864 fstrcpy(unix_username,
865 current_user_info.smb_name);
866 map_username(unix_username);
867 snum = find_service(unix_username);
870 DEBUG(5, ("making a connection to 'homes' service %s based on security=share\n", service_in));
871 return make_connection_snum(snum, NULL,
876 } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
877 && strequal(service_in, lp_servicename(vuser->homes_snum))) {
878 DATA_BLOB no_pw = data_blob(NULL, 0);
879 DEBUG(5, ("making a connection to 'homes' service [%s] created at session setup time\n", service_in));
880 return make_connection_snum(vuser->homes_snum,
885 fstrcpy(service, service_in);
889 snum = find_service(service);
892 if (strequal(service,"IPC$")
893 || (lp_enable_asu_support() && strequal(service,"ADMIN$")))
895 DEBUG(3,("refusing IPC connection to %s\n", service));
896 *status = NT_STATUS_ACCESS_DENIED;
900 DEBUG(0,("%s (%s) couldn't find service %s\n",
901 get_remote_machine_name(), client_addr(), service));
902 *status = NT_STATUS_BAD_NETWORK_NAME;
906 /* Handle non-Dfs clients attempting connections to msdfs proxy */
907 if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0')) {
908 DEBUG(3, ("refusing connection to dfs proxy share '%s' (pointing to %s)\n",
909 service, lp_msdfs_proxy(snum)));
910 *status = NT_STATUS_BAD_NETWORK_NAME;
914 DEBUG(5, ("making a connection to 'normal' service %s\n", service));
916 return make_connection_snum(snum, vuser,
921 /****************************************************************************
923 ****************************************************************************/
925 void close_cnum(connection_struct *conn, uint16 vuid)
928 pipe_close_conn(conn);
930 file_close_conn(conn);
931 dptr_closecnum(conn);
934 change_to_root_user();
936 DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
937 get_remote_machine_name(),conn->client_address,
938 lp_servicename(SNUM(conn))));
940 /* Call VFS disconnect hook */
941 SMB_VFS_DISCONNECT(conn);
943 yield_connection(conn, lp_servicename(SNUM(conn)));
945 /* make sure we leave the directory available for unmount */
946 vfs_ChDir(conn, "/");
948 /* execute any "postexec = " line */
949 if (*lp_postexec(SNUM(conn)) &&
950 change_to_user(conn, vuid)) {
952 pstrcpy(cmd,lp_postexec(SNUM(conn)));
953 standard_sub_conn(conn,cmd,sizeof(cmd));
955 change_to_root_user();
958 change_to_root_user();
959 /* execute any "root postexec = " line */
960 if (*lp_rootpostexec(SNUM(conn))) {
962 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
963 standard_sub_conn(conn,cmd,sizeof(cmd));