This is a farily large patch (3300 lines) and reworks most of the AuthRewrite
[tprouty/samba.git] / source / smbd / service.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    service (connection) opening and closing
5    Copyright (C) Andrew Tridgell 1992-1998
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 extern struct timeval smb_last_time;
25 extern int case_default;
26 extern BOOL case_preserve;
27 extern BOOL short_case_preserve;
28 extern BOOL case_mangle;
29 extern BOOL case_sensitive;
30 extern BOOL use_mangled_map;
31 extern fstring remote_machine;
32 extern userdom_struct current_user_info;
33 extern fstring remote_machine;
34
35
36 /****************************************************************************
37  Load parameters specific to a connection/service.
38 ****************************************************************************/
39
40 BOOL set_current_service(connection_struct *conn,BOOL do_chdir)
41 {
42         extern char magic_char;
43         static connection_struct *last_conn;
44         int snum;
45
46         if (!conn)  {
47                 last_conn = NULL;
48                 return(False);
49         }
50
51         conn->lastused = smb_last_time.tv_sec;
52
53         snum = SNUM(conn);
54   
55         if (do_chdir &&
56             vfs_ChDir(conn,conn->connectpath) != 0 &&
57             vfs_ChDir(conn,conn->origpath) != 0) {
58                 DEBUG(0,("chdir (%s) failed\n",
59                          conn->connectpath));
60                 return(False);
61         }
62
63         if (conn == last_conn)
64                 return(True);
65
66         last_conn = conn;
67
68         case_default = lp_defaultcase(snum);
69         case_preserve = lp_preservecase(snum);
70         short_case_preserve = lp_shortpreservecase(snum);
71         case_mangle = lp_casemangle(snum);
72         case_sensitive = lp_casesensitive(snum);
73         magic_char = lp_magicchar(snum);
74         use_mangled_map = (*lp_mangled_map(snum) ? True:False);
75         return(True);
76 }
77
78 /****************************************************************************
79  Add a home service. Returns the new service number or -1 if fail.
80 ****************************************************************************/
81
82 int add_home_service(const char *service, const char *homedir)
83 {
84         int iHomeService;
85         int iService;
86         fstring new_service;
87         char *usr_p = NULL;
88
89         if (!service || !homedir)
90                 return -1;
91
92         if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0)
93                 return -1;
94
95         /*
96          * If this is a winbindd provided username, remove
97          * the domain component before adding the service.
98          * Log a warning if the "path=" parameter does not
99          * include any macros.
100          */
101
102         fstrcpy(new_service, service);
103
104         if ((usr_p = strchr_m(service,*lp_winbind_separator())) != NULL)
105                 fstrcpy(new_service, usr_p+1);
106
107         lp_add_home(new_service,iHomeService,homedir);
108         iService = lp_servicenumber(new_service);
109
110         return iService;
111 }
112
113 /****************************************************************************
114  Find a service entry. service is always in dos codepage.
115 ****************************************************************************/
116
117 int find_service(char *service)
118 {
119    int iService;
120
121    all_string_sub(service,"\\","/",0);
122
123    iService = lp_servicenumber(service);
124
125    /* now handle the special case of a home directory */
126    if (iService < 0)
127    {
128       char *phome_dir = get_user_home_dir(service);
129
130       if(!phome_dir)
131       {
132         /*
133          * Try mapping the servicename, it may
134          * be a Windows to unix mapped user name.
135          */
136         if(map_username(service))
137           phome_dir = get_user_home_dir(service);
138       }
139
140       DEBUG(3,("checking for home directory %s gave %s\n",service,
141             phome_dir?phome_dir:"(NULL)"));
142
143       iService = add_home_service(service,phome_dir);
144    }
145
146    /* If we still don't have a service, attempt to add it as a printer. */
147    if (iService < 0)
148    {
149       int iPrinterService;
150
151       if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) >= 0)
152       {
153          char *pszTemp;
154
155          DEBUG(3,("checking whether %s is a valid printer name...\n", service));
156          pszTemp = PRINTCAP;
157          if ((pszTemp != NULL) && pcap_printername_ok(service, pszTemp))
158          {
159             DEBUG(3,("%s is a valid printer name\n", service));
160             DEBUG(3,("adding %s as a printer service\n", service));
161             lp_add_printer(service,iPrinterService);
162             iService = lp_servicenumber(service);
163             if (iService < 0)
164                DEBUG(0,("failed to add %s as a printer service!\n", service));
165          }
166          else
167             DEBUG(3,("%s is not a valid printer name\n", service));
168       }
169    }
170
171    /* Check for default vfs service?  Unsure whether to implement this */
172    if (iService < 0)
173    {
174    }
175
176    /* just possibly it's a default service? */
177    if (iService < 0) 
178    {
179      char *pdefservice = lp_defaultservice();
180      if (pdefservice && *pdefservice && 
181          !strequal(pdefservice,service) &&
182          !strstr(service,".."))
183      {
184        /*
185         * We need to do a local copy here as lp_defaultservice() 
186         * returns one of the rotating lp_string buffers that
187         * could get overwritten by the recursive find_service() call
188         * below. Fix from Josef Hinteregger <joehtg@joehtg.co.at>.
189         */
190        pstring defservice;
191        pstrcpy(defservice, pdefservice);
192        iService = find_service(defservice);
193        if (iService >= 0)
194        {
195          all_string_sub(service,"_","/",0);
196          iService = lp_add_service(service,iService);
197        }
198      }
199    }
200
201    if (iService >= 0)
202      if (!VALID_SNUM(iService))
203      {
204        DEBUG(0,("Invalid snum %d for %s\n",iService,service));
205        iService = -1;
206      }
207
208    if (iService < 0)
209      DEBUG(3,("find_service() failed to find service %s\n", service));
210
211    return (iService);
212 }
213
214
215 /****************************************************************************
216  do some basic sainity checks on the share.  
217  This function modifies dev, ecode.
218 ****************************************************************************/
219 static NTSTATUS share_sanity_checks(int snum, char* service, char *dev) 
220 {
221         
222         if (!lp_snum_ok(snum) || 
223             !check_access(smbd_server_fd(), 
224                           lp_hostsallow(snum), lp_hostsdeny(snum))) {    
225                 return NT_STATUS_ACCESS_DENIED;
226         }
227
228         /* you can only connect to the IPC$ service as an ipc device */
229         if (strequal(service,"IPC$") || strequal(service,"ADMIN$"))
230                 pstrcpy(dev,"IPC");
231         
232         if (*dev == '?' || !*dev) {
233                 if (lp_print_ok(snum)) {
234                         pstrcpy(dev,"LPT1:");
235                 } else {
236                         pstrcpy(dev,"A:");
237                 }
238         }
239
240         /* if the request is as a printer and you can't print then refuse */
241         strupper(dev);
242         if (!lp_print_ok(snum) && (strncmp(dev,"LPT",3) == 0)) {
243                 DEBUG(1,("Attempt to connect to non-printer as a printer\n"));
244                 return NT_STATUS_BAD_DEVICE_TYPE;
245         }
246
247         /* Behave as a printer if we are supposed to */
248         if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) {
249                 pstrcpy(dev, "LPT1:");
250         }
251
252         return NT_STATUS_OK;
253 }
254
255
256 /****************************************************************************
257  readonly share?
258 ****************************************************************************/
259 static void set_read_only(connection_struct *conn) 
260 {
261         char **list;
262         char *service = lp_servicename(conn->service);
263         conn->read_only = lp_readonly(conn->service);
264
265         if (!service) return;
266
267         lp_list_copy(&list, lp_readlist(conn->service));
268         if (list) {
269                 if (!lp_list_substitute(list, "%S", service)) {
270                         DEBUG(0, ("ERROR: read list substitution failed\n"));
271                 }
272                 if (user_in_list(conn->user, list))
273                         conn->read_only = True;
274                 lp_list_free(&list);
275         }
276         
277         lp_list_copy(&list, lp_writelist(conn->service));
278         if (list) {
279                 if (!lp_list_substitute(list, "%S", service)) {
280                         DEBUG(0, ("ERROR: write list substitution failed\n"));
281                 }
282                 if (user_in_list(conn->user, list))
283                         conn->read_only = False;
284                 lp_list_free(&list);
285         }
286 }
287
288
289 /****************************************************************************
290   admin user check
291 ****************************************************************************/
292 static void set_admin_user(connection_struct *conn) 
293 {
294         /* admin user check */
295         
296         /* JRA - original code denied admin user if the share was
297            marked read_only. Changed as I don't think this is needed,
298            but old code left in case there is a problem here.
299         */
300         if (user_in_list(conn->user,lp_admin_users(conn->service)) 
301 #if 0
302             && !conn->read_only
303 #endif
304             ) {
305                 conn->admin_user = True;
306                 DEBUG(0,("%s logged in as admin user (root privileges)\n",conn->user));
307         } else {
308                 conn->admin_user = False;
309         }
310
311 #if 0 /* This done later, for now */    
312         /* admin users always run as uid=0 */
313         if (conn->admin_user) {
314                 conn->uid = 0;
315         }
316 #endif
317 }
318
319 /****************************************************************************
320  Make a connection to a service.
321 ****************************************************************************/
322
323 connection_struct *make_connection(char *service, DATA_BLOB password, 
324                                    char *dev,uint16 vuid, NTSTATUS *status)
325 {
326         int snum;
327         struct passwd *pass = NULL;
328         BOOL guest = False;
329         BOOL force = False;
330         connection_struct *conn;
331         uid_t euid;
332
333         fstring user;
334         ZERO_STRUCT(user);
335
336         /* This must ONLY BE CALLED AS ROOT. As it exits this function as root. */
337         if (!non_root_mode() && (euid = geteuid()) != 0) {
338                 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot (%u)\n", (unsigned int)euid ));
339                 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
340         }
341
342         strlower(service);
343
344         snum = find_service(service);
345
346         if (snum < 0) {
347                 if (strequal(service,"IPC$") || strequal(service,"ADMIN$")) {
348                         DEBUG(3,("refusing IPC connection\n"));
349                         *status = NT_STATUS_ACCESS_DENIED;
350                         return NULL;
351                 }
352
353                 DEBUG(0,("%s (%s) couldn't find service %s\n",
354                          remote_machine, client_addr(), service));
355                 *status = NT_STATUS_BAD_NETWORK_PATH;
356                 return NULL;
357         }
358
359         if (strequal(service,HOMES_NAME)) {
360                 if(lp_security() != SEC_SHARE) {
361                         if (validated_username(vuid)) {
362                                 fstring unix_username;
363                                 fstrcpy(unix_username,validated_username(vuid));
364                                 return(make_connection(unix_username,password,dev,vuid,status));
365                         }
366                 } else {
367                         /* Security = share. Try with current_user_info.smb_name
368                          * as the username.  */
369                         if(*current_user_info.smb_name) {
370                                 fstring unix_username;
371                                 fstrcpy(unix_username,current_user_info.smb_name);
372                                 map_username(unix_username);
373                                 return(make_connection(unix_username,password,dev,vuid,status));
374                         }
375                 }
376         }
377
378         if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, service, dev))) {
379                 return NULL;
380         }       
381
382         /* add it as a possible user name if we 
383            are in share mode security */
384         if (lp_security() == SEC_SHARE) {
385                 add_session_user(service);
386         }
387
388
389         /* shall we let them in? */
390         if (!authorise_login(snum,user,password,&guest,&force,vuid)) {
391                 DEBUG( 2, ( "Invalid username/password for %s [%s]\n", service, user ) );
392                 *status = NT_STATUS_WRONG_PASSWORD;
393                 return NULL;
394         }
395
396         add_session_user(user);
397   
398         conn = conn_new();
399         if (!conn) {
400                 DEBUG(0,("Couldn't find free connection.\n"));
401                 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
402                 return NULL;
403         }
404
405         /* find out some info about the user */
406         pass = smb_getpwnam(user,True);
407
408         if (pass == NULL) {
409                 DEBUG(0,( "Couldn't find account %s\n",user));
410                 *status = NT_STATUS_NO_SUCH_USER;
411                 conn_free(conn);
412                 return NULL;
413         }
414
415         conn->force_user = force;
416         conn->vuid = vuid;
417         conn->uid = pass->pw_uid;
418         conn->gid = pass->pw_gid;
419         safe_strcpy(conn->client_address, client_addr(), 
420                     sizeof(conn->client_address)-1);
421         conn->num_files_open = 0;
422         conn->lastused = time(NULL);
423         conn->service = snum;
424         conn->used = True;
425         conn->printer = (strncmp(dev,"LPT",3) == 0);
426         conn->ipc = ((strncmp(dev,"IPC",3) == 0) || strequal(dev,"ADMIN$"));
427         conn->dirptr = NULL;
428         conn->veto_list = NULL;
429         conn->hide_list = NULL;
430         conn->veto_oplock_list = NULL;
431         string_set(&conn->dirpath,"");
432         string_set(&conn->user,user);
433         conn->nt_user_token = NULL;
434         
435         set_read_only(conn);
436         
437         set_admin_user(conn);
438
439         /*
440          * If force user is true, then store the
441          * given userid and also the primary groupid
442          * of the user we're forcing.
443          */
444         
445         if (*lp_force_user(snum)) {
446                 struct passwd *pass2;
447                 pstring fuser;
448                 pstrcpy(fuser,lp_force_user(snum));
449
450                 /* Allow %S to be used by force user. */
451                 pstring_sub(fuser,"%S",service);
452
453                 pass2 = (struct passwd *)Get_Pwnam_Modify(fuser);
454                 if (pass2) {
455                         conn->uid = pass2->pw_uid;
456                         conn->gid = pass2->pw_gid;
457                         string_set(&conn->user,fuser);
458                         fstrcpy(user,fuser);
459                         conn->force_user = True;
460                         DEBUG(3,("Forced user %s\n",fuser));      
461                 } else {
462                         DEBUG(1,("Couldn't find user %s\n",fuser));
463                 }
464         }
465
466         /* admin users always run as uid=0 */
467         if (conn->admin_user) {
468                 conn->uid = 0;
469         }
470
471 #ifdef HAVE_GETGRNAM 
472         /*
473          * If force group is true, then override
474          * any groupid stored for the connecting user.
475          */
476         
477         if (*lp_force_group(snum)) {
478                 gid_t gid;
479                 pstring gname;
480                 pstring tmp_gname;
481                 BOOL user_must_be_member = False;
482                 
483                 StrnCpy(tmp_gname,lp_force_group(snum),sizeof(pstring)-1);
484
485                 if (tmp_gname[0] == '+') {
486                         user_must_be_member = True;
487                         StrnCpy(gname,&tmp_gname[1],sizeof(pstring)-2);
488                 } else {
489                         StrnCpy(gname,tmp_gname,sizeof(pstring)-1);
490                 }
491                 /* default service may be a group name          */
492                 pstring_sub(gname,"%S",service);
493                 gid = nametogid(gname);
494                 
495                 if (gid != (gid_t)-1) {
496                         /*
497                          * If the user has been forced and the forced group starts
498                          * with a '+', then we only set the group to be the forced
499                          * group if the forced user is a member of that group.
500                          * Otherwise, the meaning of the '+' would be ignored.
501                          */
502                         if (conn->force_user && user_must_be_member) {
503                                 if (user_in_group_list( user, gname )) {
504                                                 conn->gid = gid;
505                                                 DEBUG(3,("Forced group %s for member %s\n",gname,user));
506                                 }
507                         } else {
508                                 conn->gid = gid;
509                                 DEBUG(3,("Forced group %s\n",gname));
510                         }
511                 } else {
512                         DEBUG(1,("Couldn't find group %s\n",gname));
513                 }
514         }
515 #endif /* HAVE_GETGRNAM */
516
517         {
518                 pstring s;
519                 pstrcpy(s,lp_pathname(snum));
520                 standard_sub_conn(conn,s);
521                 string_set(&conn->connectpath,s);
522                 DEBUG(3,("Connect path is %s\n",s));
523         }
524
525         /* groups stuff added by ih */
526         conn->ngroups = 0;
527         conn->groups = NULL;
528         
529         /* Find all the groups this uid is in and
530            store them. Used by change_to_user() */
531         initialise_groups(conn->user, conn->uid, conn->gid); 
532         get_current_groups(&conn->ngroups,&conn->groups);
533                 
534         conn->nt_user_token = create_nt_token(conn->uid, conn->gid, 
535                                               conn->ngroups, conn->groups,
536                                               guest);
537
538         /*
539          * New code to check if there's a share security descripter
540          * added from NT server manager. This is done after the
541          * smb.conf checks are done as we need a uid and token. JRA.
542          */
543
544         {
545                 BOOL can_write = share_access_check(conn, snum, vuid, FILE_WRITE_DATA);
546
547                 if (!can_write) {
548                         if (!share_access_check(conn, snum, vuid, FILE_READ_DATA)) {
549                                 /* No access, read or write. */
550                                 *status = NT_STATUS_ACCESS_DENIED;
551                                 DEBUG(0,( "make_connection: connection to %s denied due to security descriptor.\n",
552                                         service ));
553                                 conn_free(conn);
554                                 return NULL;
555                         } else {
556                                 conn->read_only = True;
557                         }
558                 }
559         }
560         /* Initialise VFS function pointers */
561
562         if (!smbd_vfs_init(conn)) {
563                 DEBUG(0, ("vfs_init failed for service %s\n", lp_servicename(SNUM(conn))));
564                 conn_free(conn);
565                 return NULL;
566         }
567
568 /* ROOT Activities: */  
569         /* check number of connections */
570         if (!claim_connection(conn,
571                               lp_servicename(SNUM(conn)),
572                               lp_max_connections(SNUM(conn)),
573                               False)) {
574                 DEBUG(1,("too many connections - rejected\n"));
575                 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
576                 conn_free(conn);
577                 return NULL;
578         }  
579
580         /* Preexecs are done here as they might make the dir we are to ChDir to below */
581         /* execute any "root preexec = " line */
582         if (*lp_rootpreexec(SNUM(conn))) {
583                 int ret;
584                 pstring cmd;
585                 pstrcpy(cmd,lp_rootpreexec(SNUM(conn)));
586                 standard_sub_conn(conn,cmd);
587                 DEBUG(5,("cmd=%s\n",cmd));
588                 ret = smbrun(cmd,NULL);
589                 if (ret != 0 && lp_rootpreexec_close(SNUM(conn))) {
590                         DEBUG(1,("root preexec gave %d - failing connection\n", ret));
591                         yield_connection(conn,
592                                          lp_servicename(SNUM(conn)),
593                                          lp_max_connections(SNUM(conn)));
594                         conn_free(conn);
595                         *status = NT_STATUS_UNSUCCESSFUL;
596                         return NULL;
597                 }
598         }
599
600 /* USER Activites: */
601         if (!change_to_user(conn, conn->vuid)) {
602                 /* No point continuing if they fail the basic checks */
603                 DEBUG(0,("Can't become connected user!\n"));
604                 conn_free(conn);
605                 *status = NT_STATUS_LOGON_FAILURE;
606                 return NULL;
607         }
608
609         /* Remember that a different vuid can connect later without these checks... */
610
611         /* Preexecs are done here as they might make the dir we are to ChDir to below */
612         /* execute any "preexec = " line */
613         if (*lp_preexec(SNUM(conn))) {
614                 int ret;
615                 pstring cmd;
616                 pstrcpy(cmd,lp_preexec(SNUM(conn)));
617                 standard_sub_conn(conn,cmd);
618                 ret = smbrun(cmd,NULL);
619                 if (ret != 0 && lp_preexec_close(SNUM(conn))) {
620                         DEBUG(1,("preexec gave %d - failing connection\n", ret));
621                         change_to_root_user();
622                         yield_connection(conn, lp_servicename(SNUM(conn)), lp_max_connections(SNUM(conn)));
623                         conn_free(conn);
624                         *status = NT_STATUS_UNSUCCESSFUL;
625                         return NULL;
626                 }
627         }
628
629         if (vfs_ChDir(conn,conn->connectpath) != 0) {
630                 DEBUG(0,("%s (%s) Can't change directory to %s (%s)\n",
631                          remote_machine, conn->client_address,
632                          conn->connectpath,strerror(errno)));
633                 change_to_root_user();
634                 yield_connection(conn,
635                                  lp_servicename(SNUM(conn)),
636                                  lp_max_connections(SNUM(conn)));
637                 conn_free(conn);
638                 *status = NT_STATUS_BAD_NETWORK_NAME;
639                 return NULL;
640         }
641         
642         string_set(&conn->origpath,conn->connectpath);
643         
644 #if SOFTLINK_OPTIMISATION
645         /* resolve any soft links early */
646         {
647                 pstring s;
648                 pstrcpy(s,conn->connectpath);
649                 vfs_GetWd(conn,s);
650                 string_set(&conn->connectpath,s);
651                 vfs_ChDir(conn,conn->connectpath);
652         }
653 #endif
654         
655         /*
656          * Print out the 'connected as' stuff here as we need
657          * to know the effective uid and gid we will be using
658          * (at least initially).
659          */
660
661         if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
662                 dbgtext( "%s (%s) ", remote_machine, conn->client_address );
663                 dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)) );
664                 dbgtext( "initially as user %s ", user );
665                 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
666                 dbgtext( "(pid %d)\n", (int)sys_getpid() );
667         }
668         
669         /* Add veto/hide lists */
670         if (!IS_IPC(conn) && !IS_PRINT(conn)) {
671                 set_namearray( &conn->veto_list, lp_veto_files(SNUM(conn)));
672                 set_namearray( &conn->hide_list, lp_hide_files(SNUM(conn)));
673                 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(SNUM(conn)));
674         }
675         
676         /* Invoke VFS make connection hook */
677
678         if (conn->vfs_ops.connect) {
679                 if (conn->vfs_ops.connect(conn, service, user) < 0) {
680                         DEBUG(0,("make_connection: VFS make connection failed!\n"));
681                         *status = NT_STATUS_UNSUCCESSFUL;
682                         change_to_root_user();
683                         conn_free(conn);
684                         return NULL;
685                 }
686         }
687
688         /* we've finished with the user stuff - go back to root */
689         change_to_root_user();
690             
691         return(conn);
692 }
693
694
695 /****************************************************************************
696 close a cnum
697 ****************************************************************************/
698 void close_cnum(connection_struct *conn, uint16 vuid)
699 {
700         DirCacheFlush(SNUM(conn));
701
702         change_to_root_user();
703
704         DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
705                                  remote_machine,conn->client_address,
706                                  lp_servicename(SNUM(conn))));
707
708         if (conn->vfs_ops.disconnect != NULL) {
709
710             /* Call VFS disconnect hook */
711             
712             conn->vfs_ops.disconnect(conn);
713             
714         }
715
716         yield_connection(conn,
717                          lp_servicename(SNUM(conn)),
718                          lp_max_connections(SNUM(conn)));
719
720         file_close_conn(conn);
721         dptr_closecnum(conn);
722
723         /* execute any "postexec = " line */
724         if (*lp_postexec(SNUM(conn)) && 
725             change_to_user(conn, vuid))  {
726                 pstring cmd;
727                 pstrcpy(cmd,lp_postexec(SNUM(conn)));
728                 standard_sub_conn(conn,cmd);
729                 smbrun(cmd,NULL);
730                 change_to_root_user();
731         }
732
733         change_to_root_user();
734         /* execute any "root postexec = " line */
735         if (*lp_rootpostexec(SNUM(conn)))  {
736                 pstring cmd;
737                 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
738                 standard_sub_conn(conn,cmd);
739                 smbrun(cmd,NULL);
740         }
741         conn_free(conn);
742 }