63991904ff63cbb1b0185cbbc3c589b22faeb0da
[ira/wip.git] / source3 / smbd / service.c
1 /* 
2    Unix SMB/CIFS implementation.
3    service (connection) opening and closing
4    Copyright (C) Andrew Tridgell 1992-1998
5    
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.
10    
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.
15    
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.
19 */
20
21 #include "includes.h"
22
23 extern struct timeval smb_last_time;
24 extern int case_default;
25 extern BOOL case_preserve;
26 extern BOOL short_case_preserve;
27 extern BOOL case_mangle;
28 extern BOOL case_sensitive;
29 extern BOOL use_mangled_map;
30 extern userdom_struct current_user_info;
31
32
33 /****************************************************************************
34  Load parameters specific to a connection/service.
35 ****************************************************************************/
36
37 BOOL set_current_service(connection_struct *conn,BOOL do_chdir)
38 {
39         extern char magic_char;
40         static connection_struct *last_conn;
41         int snum;
42
43         if (!conn)  {
44                 last_conn = NULL;
45                 return(False);
46         }
47
48         conn->lastused = smb_last_time.tv_sec;
49
50         snum = SNUM(conn);
51   
52         if (do_chdir &&
53             vfs_ChDir(conn,conn->connectpath) != 0 &&
54             vfs_ChDir(conn,conn->origpath) != 0) {
55                 DEBUG(0,("chdir (%s) failed\n",
56                          conn->connectpath));
57                 return(False);
58         }
59
60         if (conn == last_conn)
61                 return(True);
62
63         last_conn = conn;
64
65         case_default = lp_defaultcase(snum);
66         case_preserve = lp_preservecase(snum);
67         short_case_preserve = lp_shortpreservecase(snum);
68         case_mangle = lp_casemangle(snum);
69         case_sensitive = lp_casesensitive(snum);
70         magic_char = lp_magicchar(snum);
71         use_mangled_map = (*lp_mangled_map(snum) ? True:False);
72         return(True);
73 }
74
75 /****************************************************************************
76  Add a home service. Returns the new service number or -1 if fail.
77 ****************************************************************************/
78
79 int add_home_service(const char *service, const char *username, const char *homedir)
80 {
81         int iHomeService;
82
83         if (!service || !homedir)
84                 return -1;
85
86         if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0)
87                 return -1;
88
89         /*
90          * If this is a winbindd provided username, remove
91          * the domain component before adding the service.
92          * Log a warning if the "path=" parameter does not
93          * include any macros.
94          */
95
96         {
97                 const char *p = strchr(service,*lp_winbind_separator());
98
99                 /* We only want the 'user' part of the string */
100                 if (p) {
101                         service = p + 1;
102                 }
103         }
104
105         if (!lp_add_home(service, iHomeService, username, homedir)) {
106                 return -1;
107         }
108         
109         return lp_servicenumber(service);
110
111 }
112
113
114 /**
115  * Find a service entry. service is always in dos codepage.
116  *
117  * @param service is modified (to canonical form??)
118  **/
119 int find_service(fstring service)
120 {
121    int iService;
122
123    all_string_sub(service,"\\","/",0);
124
125    iService = lp_servicenumber(service);
126
127    /* now handle the special case of a home directory */
128    if (iService < 0)
129    {
130       char *phome_dir = get_user_home_dir(service);
131
132       if(!phome_dir)
133       {
134         /*
135          * Try mapping the servicename, it may
136          * be a Windows to unix mapped user name.
137          */
138         if(map_username(service))
139           phome_dir = get_user_home_dir(service);
140       }
141
142       DEBUG(3,("checking for home directory %s gave %s\n",service,
143             phome_dir?phome_dir:"(NULL)"));
144
145       iService = add_home_service(service,service /* 'username' */, phome_dir);
146    }
147
148    /* If we still don't have a service, attempt to add it as a printer. */
149    if (iService < 0)
150    {
151       int iPrinterService;
152
153       if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) >= 0)
154       {
155          char *pszTemp;
156
157          DEBUG(3,("checking whether %s is a valid printer name...\n", service));
158          pszTemp = lp_printcapname();
159          if ((pszTemp != NULL) && pcap_printername_ok(service, pszTemp))
160          {
161             DEBUG(3,("%s is a valid printer name\n", service));
162             DEBUG(3,("adding %s as a printer service\n", service));
163             lp_add_printer(service, iPrinterService);
164             iService = lp_servicenumber(service);
165             if (iService < 0)
166                DEBUG(0,("failed to add %s as a printer service!\n", service));
167          }
168          else
169             DEBUG(3,("%s is not a valid printer name\n", service));
170       }
171    }
172
173    /* Check for default vfs service?  Unsure whether to implement this */
174    if (iService < 0)
175    {
176    }
177
178    /* just possibly it's a default service? */
179    if (iService < 0) 
180    {
181      char *pdefservice = lp_defaultservice();
182      if (pdefservice && *pdefservice && 
183          !strequal(pdefservice,service) &&
184          !strstr(service,".."))
185      {
186        /*
187         * We need to do a local copy here as lp_defaultservice() 
188         * returns one of the rotating lp_string buffers that
189         * could get overwritten by the recursive find_service() call
190         * below. Fix from Josef Hinteregger <joehtg@joehtg.co.at>.
191         */
192        pstring defservice;
193        pstrcpy(defservice, pdefservice);
194        iService = find_service(defservice);
195        if (iService >= 0)
196        {
197          all_string_sub(service, "_","/",0);
198          iService = lp_add_service(service, iService);
199        }
200      }
201    }
202
203    if (iService >= 0)
204      if (!VALID_SNUM(iService))
205      {
206        DEBUG(0,("Invalid snum %d for %s\n",iService, service));
207        iService = -1;
208      }
209
210    if (iService < 0)
211      DEBUG(3,("find_service() failed to find service %s\n", service));
212
213    return (iService);
214 }
215
216
217 /****************************************************************************
218  do some basic sainity checks on the share.  
219  This function modifies dev, ecode.
220 ****************************************************************************/
221 static NTSTATUS share_sanity_checks(int snum, fstring dev) 
222 {
223         
224         if (!lp_snum_ok(snum) || 
225             !check_access(smbd_server_fd(), 
226                           lp_hostsallow(snum), lp_hostsdeny(snum))) {    
227                 return NT_STATUS_ACCESS_DENIED;
228         }
229
230         if (dev[0] == '?' || !dev[0]) {
231                 if (lp_print_ok(snum)) {
232                         fstrcpy(dev,"LPT1:");
233                 } else if (strequal(lp_fstype(snum), "IPC")) {
234                         fstrcpy(dev, "IPC");
235                 } else {
236                         fstrcpy(dev,"A:");
237                 }
238         }
239
240         strupper_m(dev);
241
242         if (lp_print_ok(snum)) {
243                 if (!strequal(dev, "LPT1:")) {
244                         return NT_STATUS_BAD_DEVICE_TYPE;
245                 }
246         } else if (strequal(lp_fstype(snum), "IPC")) {
247                 if (!strequal(dev, "IPC")) {
248                         return NT_STATUS_BAD_DEVICE_TYPE;
249                 }
250         } else if (!strequal(dev, "A:")) {
251                 return NT_STATUS_BAD_DEVICE_TYPE;
252         }
253
254         /* Behave as a printer if we are supposed to */
255         if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) {
256                 fstrcpy(dev, "LPT1:");
257         }
258
259         return NT_STATUS_OK;
260 }
261
262
263 /****************************************************************************
264  readonly share?
265 ****************************************************************************/
266 static void set_read_only(connection_struct *conn, gid_t *groups, size_t n_groups)
267 {
268         char **list;
269         char *service = lp_servicename(conn->service);
270         conn->read_only = lp_readonly(conn->service);
271
272         if (!service) return;
273
274         str_list_copy(&list, lp_readlist(conn->service));
275         if (list) {
276                 if (!str_list_substitute(list, "%S", service)) {
277                         DEBUG(0, ("ERROR: read list substitution failed\n"));
278                 }
279                 if (user_in_list(conn->user, (const char **)list, groups, n_groups))
280                         conn->read_only = True;
281                 str_list_free(&list);
282         }
283         
284         str_list_copy(&list, lp_writelist(conn->service));
285         if (list) {
286                 if (!str_list_substitute(list, "%S", service)) {
287                         DEBUG(0, ("ERROR: write list substitution failed\n"));
288                 }
289                 if (user_in_list(conn->user, (const char **)list, groups, n_groups))
290                         conn->read_only = False;
291                 str_list_free(&list);
292         }
293 }
294
295
296 /****************************************************************************
297   admin user check
298 ****************************************************************************/
299 static void set_admin_user(connection_struct *conn, gid_t *groups, size_t n_groups)
300 {
301         /* admin user check */
302         
303         /* JRA - original code denied admin user if the share was
304            marked read_only. Changed as I don't think this is needed,
305            but old code left in case there is a problem here.
306         */
307         if (user_in_list(conn->user,lp_admin_users(conn->service), groups, n_groups) 
308 #if 0
309             && !conn->read_only
310 #endif
311             ) {
312                 conn->admin_user = True;
313                 conn->force_user = True;  /* Admin users are effectivly 'forced' */
314                 DEBUG(0,("%s logged in as admin user (root privileges)\n",conn->user));
315         } else {
316                 conn->admin_user = False;
317         }
318
319 #if 0 /* This done later, for now */    
320         /* admin users always run as uid=0 */
321         if (conn->admin_user) {
322                 conn->uid = 0;
323         }
324 #endif
325 }
326
327 /****************************************************************************
328   Make a connection, given the snum to connect to, and the vuser of the
329   connecting user if appropriate.
330 ****************************************************************************/
331
332 static connection_struct *make_connection_snum(int snum, user_struct *vuser,
333                                                DATA_BLOB password, 
334                                                const char *pdev, NTSTATUS *status)
335 {
336         struct passwd *pass = NULL;
337         BOOL guest = False;
338         connection_struct *conn;
339         struct stat st;
340         fstring user;
341         fstring dev;
342
343         *user = 0;
344         fstrcpy(dev, pdev);
345
346         if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, dev))) {
347                 return NULL;
348         }       
349
350         conn = conn_new();
351         if (!conn) {
352                 DEBUG(0,("Couldn't find free connection.\n"));
353                 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
354                 return NULL;
355         }
356
357         if (lp_guest_only(snum)) {
358                 const char *guestname = lp_guestaccount();
359                 guest = True;
360                 pass = getpwnam_alloc(guestname);
361                 if (!pass) {
362                         DEBUG(0,("make_conncection_snum: Invalid guest account %s??\n",guestname));
363                         conn_free(conn);
364                         *status = NT_STATUS_NO_SUCH_USER;
365                         return NULL;
366                 }
367                 fstrcpy(user,pass->pw_name);
368                 conn->force_user = True;
369                 conn->uid = pass->pw_uid;
370                 conn->gid = pass->pw_gid;
371                 string_set(&conn->user,pass->pw_name);
372                 passwd_free(&pass);
373                 DEBUG(3,("Guest only user %s\n",user));
374         } else if (vuser) {
375                 if (vuser->guest) {
376                         if (!lp_guest_ok(snum)) {
377                                 DEBUG(2, ("guest user (from session setup) not permitted to access this share (%s)\n", lp_servicename(snum)));
378                                       conn_free(conn);
379                                       *status = NT_STATUS_ACCESS_DENIED;
380                                       return NULL;
381                         }
382                 } else {
383                         if (!user_ok(vuser->user.unix_name, snum, vuser->groups, vuser->n_groups)) {
384                                 DEBUG(2, ("user '%s' (from session setup) not permitted to access this share (%s)\n", vuser->user.unix_name, lp_servicename(snum)));
385                                 conn_free(conn);
386                                 *status = NT_STATUS_ACCESS_DENIED;
387                                 return NULL;
388                         }
389                 }
390                 conn->vuid = vuser->vuid;
391                 conn->uid = vuser->uid;
392                 conn->gid = vuser->gid;
393                 string_set(&conn->user,vuser->user.unix_name);
394                 fstrcpy(user,vuser->user.unix_name);
395                 guest = vuser->guest; 
396         } else if (lp_security() == SEC_SHARE) {
397                 /* add it as a possible user name if we 
398                    are in share mode security */
399                 add_session_user(lp_servicename(snum));
400                 /* shall we let them in? */
401                 if (!authorise_login(snum,user,password,&guest)) {
402                         DEBUG( 2, ( "Invalid username/password for [%s]\n", 
403                                     lp_servicename(snum)) );
404                         conn_free(conn);
405                         *status = NT_STATUS_WRONG_PASSWORD;
406                         return NULL;
407                 }
408                 pass = Get_Pwnam(user);
409                 conn->force_user = True;
410                 conn->uid = pass->pw_uid;
411                 conn->gid = pass->pw_gid;
412                 string_set(&conn->user, pass->pw_name);
413                 fstrcpy(user, pass->pw_name);
414
415         } else {
416                 DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
417                 conn_free(conn);
418                 *status = NT_STATUS_ACCESS_DENIED;
419                 return NULL;
420         }
421
422         add_session_user(user);
423
424         safe_strcpy(conn->client_address, client_addr(), 
425                     sizeof(conn->client_address)-1);
426         conn->num_files_open = 0;
427         conn->lastused = time(NULL);
428         conn->service = snum;
429         conn->used = True;
430         conn->printer = (strncmp(dev,"LPT",3) == 0);
431         conn->ipc = ((strncmp(dev,"IPC",3) == 0) || strequal(dev,"ADMIN$"));
432         conn->dirptr = NULL;
433         conn->veto_list = NULL;
434         conn->hide_list = NULL;
435         conn->veto_oplock_list = NULL;
436         string_set(&conn->dirpath,"");
437         string_set(&conn->user,user);
438         conn->nt_user_token = NULL;
439         
440         set_read_only(conn, vuser ? vuser->groups : NULL, vuser ? vuser->n_groups : 0);
441         
442         set_admin_user(conn, vuser ? vuser->groups : NULL, vuser ? vuser->n_groups : 0);
443
444         /*
445          * If force user is true, then store the
446          * given userid and also the groups
447          * of the user we're forcing.
448          */
449         
450         if (*lp_force_user(snum)) {
451                 struct passwd *pass2;
452                 pstring fuser;
453                 pstrcpy(fuser,lp_force_user(snum));
454
455                 /* Allow %S to be used by force user. */
456                 pstring_sub(fuser,"%S",lp_servicename(snum));
457
458                 pass2 = (struct passwd *)Get_Pwnam(fuser);
459                 if (pass2) {
460                         conn->uid = pass2->pw_uid;
461                         conn->gid = pass2->pw_gid;
462                         string_set(&conn->user,pass2->pw_name);
463                         fstrcpy(user,pass2->pw_name);
464                         conn->force_user = True;
465                         DEBUG(3,("Forced user %s\n",user));       
466                 } else {
467                         DEBUG(1,("Couldn't find user %s\n",fuser));
468                         conn_free(conn);
469                         *status = NT_STATUS_NO_SUCH_USER;
470                         return NULL;
471                 }
472         }
473
474         /* admin users always run as uid=0 */
475         if (conn->admin_user) {
476                 conn->uid = 0;
477         }
478
479 #ifdef HAVE_GETGRNAM 
480         /*
481          * If force group is true, then override
482          * any groupid stored for the connecting user.
483          */
484         
485         if (*lp_force_group(snum)) {
486                 gid_t gid;
487                 pstring gname;
488                 pstring tmp_gname;
489                 BOOL user_must_be_member = False;
490                 
491                 pstrcpy(tmp_gname,lp_force_group(snum));
492                 
493                 if (tmp_gname[0] == '+') {
494                         user_must_be_member = True;
495                         /* even now, tmp_gname is null terminated */
496                         pstrcpy(gname,&tmp_gname[1]);
497                 } else {
498                         pstrcpy(gname,tmp_gname);
499                 }
500                 /* default service may be a group name          */
501                 pstring_sub(gname,"%S",lp_servicename(snum));
502                 gid = nametogid(gname);
503                 
504                 if (gid != (gid_t)-1) {
505
506                         /*
507                          * If the user has been forced and the forced group starts
508                          * with a '+', then we only set the group to be the forced
509                          * group if the forced user is a member of that group.
510                          * Otherwise, the meaning of the '+' would be ignored.
511                          */
512                         if (conn->force_user && user_must_be_member) {
513                                 if (user_in_group_list( user, gname, NULL, 0)) {
514                                                 conn->gid = gid;
515                                                 DEBUG(3,("Forced group %s for member %s\n",gname,user));
516                                 }
517                         } else {
518                                 conn->gid = gid;
519                                 DEBUG(3,("Forced group %s\n",gname));
520                         }
521                         conn->force_group = True;
522                 } else {
523                         DEBUG(1,("Couldn't find group %s\n",gname));
524                         conn_free(conn);
525                         *status = NT_STATUS_NO_SUCH_GROUP;
526                         return NULL;
527                 }
528         }
529 #endif /* HAVE_GETGRNAM */
530
531         {
532                 pstring s;
533                 pstrcpy(s,lp_pathname(snum));
534                 standard_sub_conn(conn,s,sizeof(s));
535                 string_set(&conn->connectpath,s);
536                 DEBUG(3,("Connect path is '%s' for service [%s]\n",s, lp_servicename(snum)));
537         }
538
539         if (conn->force_user || conn->force_group) {
540
541                 /* groups stuff added by ih */
542                 conn->ngroups = 0;
543                 conn->groups = NULL;
544                 
545                 /* Find all the groups this uid is in and
546                    store them. Used by change_to_user() */
547                 initialise_groups(conn->user, conn->uid, conn->gid); 
548                 get_current_groups(conn->gid, &conn->ngroups,&conn->groups);
549                 
550                 conn->nt_user_token = create_nt_token(conn->uid, conn->gid, 
551                                                       conn->ngroups, conn->groups,
552                                                       guest);
553         }
554
555         /*
556          * New code to check if there's a share security descripter
557          * added from NT server manager. This is done after the
558          * smb.conf checks are done as we need a uid and token. JRA.
559          *
560          */
561
562         {
563                 BOOL can_write = share_access_check(conn, snum, vuser, FILE_WRITE_DATA);
564
565                 if (!can_write) {
566                         if (!share_access_check(conn, snum, vuser, FILE_READ_DATA)) {
567                                 /* No access, read or write. */
568                                 DEBUG(0,( "make_connection: connection to %s denied due to security descriptor.\n",
569                                           lp_servicename(snum)));
570                                 conn_free(conn);
571                                 *status = NT_STATUS_ACCESS_DENIED;
572                                 return NULL;
573                         } else {
574                                 conn->read_only = True;
575                         }
576                 }
577         }
578         /* Initialise VFS function pointers */
579
580         if (!smbd_vfs_init(conn)) {
581                 DEBUG(0, ("vfs_init failed for service %s\n", lp_servicename(SNUM(conn))));
582                 conn_free(conn);
583                 *status = NT_STATUS_BAD_NETWORK_NAME;
584                 return NULL;
585         }
586
587 /* ROOT Activities: */  
588         /* check number of connections */
589         if (!claim_connection(conn,
590                               lp_servicename(SNUM(conn)),
591                               lp_max_connections(SNUM(conn)),
592                               False,0)) {
593                 DEBUG(1,("too many connections - rejected\n"));
594                 conn_free(conn);
595                 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
596                 return NULL;
597         }  
598
599         /* Preexecs are done here as they might make the dir we are to ChDir to below */
600         /* execute any "root preexec = " line */
601         if (*lp_rootpreexec(SNUM(conn))) {
602                 int ret;
603                 pstring cmd;
604                 pstrcpy(cmd,lp_rootpreexec(SNUM(conn)));
605                 standard_sub_conn(conn,cmd,sizeof(cmd));
606                 DEBUG(5,("cmd=%s\n",cmd));
607                 ret = smbrun(cmd,NULL);
608                 if (ret != 0 && lp_rootpreexec_close(SNUM(conn))) {
609                         DEBUG(1,("root preexec gave %d - failing connection\n", ret));
610                         yield_connection(conn, lp_servicename(SNUM(conn)));
611                         conn_free(conn);
612                         *status = NT_STATUS_ACCESS_DENIED;
613                         return NULL;
614                 }
615         }
616
617 /* USER Activites: */
618         if (!change_to_user(conn, conn->vuid)) {
619                 /* No point continuing if they fail the basic checks */
620                 DEBUG(0,("Can't become connected user!\n"));
621                 conn_free(conn);
622                 *status = NT_STATUS_LOGON_FAILURE;
623                 return NULL;
624         }
625
626         /* Remember that a different vuid can connect later without these checks... */
627         
628         /* Preexecs are done here as they might make the dir we are to ChDir to below */
629         /* execute any "preexec = " line */
630         if (*lp_preexec(SNUM(conn))) {
631                 int ret;
632                 pstring cmd;
633                 pstrcpy(cmd,lp_preexec(SNUM(conn)));
634                 standard_sub_conn(conn,cmd,sizeof(cmd));
635                 ret = smbrun(cmd,NULL);
636                 if (ret != 0 && lp_preexec_close(SNUM(conn))) {
637                         DEBUG(1,("preexec gave %d - failing connection\n", ret));
638                         change_to_root_user();
639                         yield_connection(conn, lp_servicename(SNUM(conn)));
640                         conn_free(conn);
641                         *status = NT_STATUS_ACCESS_DENIED;
642                         return NULL;
643                 }
644         }
645         
646 #if CHECK_PATH_ON_TCONX
647         /* win2000 does not check the permissions on the directory
648            during the tree connect, instead relying on permission
649            check during individual operations. To match this behaviour
650            I have disabled this chdir check (tridge) */
651         if (vfs_ChDir(conn,conn->connectpath) != 0) {
652                 DEBUG(0,("%s (%s) Can't change directory to %s (%s)\n",
653                          get_remote_machine_name(), conn->client_address,
654                          conn->connectpath,strerror(errno)));
655                 change_to_root_user();
656                 yield_connection(conn, lp_servicename(SNUM(conn)));
657                 conn_free(conn);
658                 *status = NT_STATUS_BAD_NETWORK_NAME;
659                 return NULL;
660         }
661 #else
662         /* the alternative is just to check the directory exists */
663         if (stat(conn->connectpath, &st) != 0 || !S_ISDIR(st.st_mode)) {
664                 DEBUG(0,("'%s' is not a directory, when connecting to [%s]\n", conn->connectpath, lp_servicename(SNUM(conn))));
665                 change_to_root_user();
666                 yield_connection(conn, lp_servicename(SNUM(conn)));
667                 conn_free(conn);
668                 *status = NT_STATUS_BAD_NETWORK_NAME;
669                 return NULL;
670         }
671 #endif
672         
673         string_set(&conn->origpath,conn->connectpath);
674         
675 #if SOFTLINK_OPTIMISATION
676         /* resolve any soft links early if possible */
677         if (vfs_ChDir(conn,conn->connectpath) == 0) {
678                 pstring s;
679                 pstrcpy(s,conn->connectpath);
680                 vfs_GetWd(conn,s);
681                 string_set(&conn->connectpath,s);
682                 vfs_ChDir(conn,conn->connectpath);
683         }
684 #endif
685         
686         /*
687          * Print out the 'connected as' stuff here as we need
688          * to know the effective uid and gid we will be using
689          * (at least initially).
690          */
691
692         if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
693                 dbgtext( "%s (%s) ", get_remote_machine_name(), conn->client_address );
694                 dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)) );
695                 dbgtext( "initially as user %s ", user );
696                 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
697                 dbgtext( "(pid %d)\n", (int)sys_getpid() );
698         }
699         
700         /* Add veto/hide lists */
701         if (!IS_IPC(conn) && !IS_PRINT(conn)) {
702                 set_namearray( &conn->veto_list, lp_veto_files(SNUM(conn)));
703                 set_namearray( &conn->hide_list, lp_hide_files(SNUM(conn)));
704                 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(SNUM(conn)));
705         }
706         
707         /* Invoke VFS make connection hook */
708
709         if (SMB_VFS_CONNECT(conn, lp_servicename(snum), user) < 0) {
710                 DEBUG(0,("make_connection: VFS make connection failed!\n"));
711                 change_to_root_user();
712                 conn_free(conn);
713                 *status = NT_STATUS_UNSUCCESSFUL;
714                 return NULL;
715         }
716
717         /* we've finished with the user stuff - go back to root */
718         change_to_root_user();
719             
720         return(conn);
721 }
722
723 /***************************************************************************************
724  Simple wrapper function for make_connection() to include a call to 
725  vfs_chdir()
726  **************************************************************************************/
727  
728 connection_struct *make_connection_with_chdir(const char *service_in, DATA_BLOB password, 
729                                    const char *dev, uint16 vuid, NTSTATUS *status)
730 {
731         connection_struct *conn = NULL;
732         
733         conn = make_connection(service_in, password, dev, vuid, status);
734         
735         /*
736          * make_connection() does not change the directory for us any more
737          * so we have to do it as a separate step  --jerry
738          */
739          
740         if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) {
741                 DEBUG(0,("move_driver_to_download_area: Can't change directory to %s for [print$] (%s)\n",
742                          conn->connectpath,strerror(errno)));
743                 yield_connection(conn, lp_servicename(SNUM(conn)));
744                 conn_free(conn);
745                 *status = NT_STATUS_UNSUCCESSFUL;
746                 return NULL;
747         }
748         
749         return conn;
750 }
751
752 /****************************************************************************
753  Make a connection to a service.
754  *
755  * @param service 
756 ****************************************************************************/
757
758 connection_struct *make_connection(const char *service_in, DATA_BLOB password, 
759                                    const char *pdev, uint16 vuid, NTSTATUS *status)
760 {
761         uid_t euid;
762         user_struct *vuser = NULL;
763         fstring service;
764         fstring dev;
765         int snum = -1;
766
767         fstrcpy(dev, pdev);
768
769         /* This must ONLY BE CALLED AS ROOT. As it exits this function as root. */
770         if (!non_root_mode() && (euid = geteuid()) != 0) {
771                 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot (%u)\n", (unsigned int)euid ));
772                 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
773         }
774
775         if(lp_security() != SEC_SHARE) {
776                 vuser = get_valid_user_struct(vuid);
777                 if (!vuser) {
778                         DEBUG(1,("make_connection: refusing to connect with no session setup\n"));
779                         *status = NT_STATUS_ACCESS_DENIED;
780                         return NULL;
781                 }
782         }
783
784         /* Logic to try and connect to the correct [homes] share, preferably without too many
785            getpwnam() lookups.  This is particulary nasty for winbind usernames, where the
786            share name isn't the same as unix username.
787
788            The snum of the homes share is stored on the vuser at session setup time.
789         */
790
791         if (strequal(service_in,HOMES_NAME)) {
792                 if(lp_security() != SEC_SHARE) {
793                         DATA_BLOB no_pw = data_blob(NULL, 0);
794                         if (vuser->homes_snum == -1) {
795                                 DEBUG(2, ("[homes] share not available for this user because it was not found or created at session setup time\n"));
796                                 *status = NT_STATUS_BAD_NETWORK_NAME;
797                                 return NULL;
798                         }
799                         DEBUG(5, ("making a connection to [homes] service created at session setup time\n"));
800                         return make_connection_snum(vuser->homes_snum,
801                                                     vuser, no_pw, 
802                                                     dev, status);
803                 } else {
804                         /* Security = share. Try with current_user_info.smb_name
805                          * as the username.  */
806                         if (*current_user_info.smb_name) {
807                                 fstring unix_username;
808                                 fstrcpy(unix_username,
809                                         current_user_info.smb_name);
810                                 map_username(unix_username);
811                                 snum = find_service(unix_username);
812                         } 
813                         if (snum != -1) {
814                                 DEBUG(5, ("making a connection to 'homes' service %s based on security=share\n", service_in));
815                                 return make_connection_snum(snum, NULL,
816                                                             password,
817                                                             dev, status);
818                         }
819                 }
820         } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
821                    && strequal(service_in, lp_servicename(vuser->homes_snum))) {
822                 DATA_BLOB no_pw = data_blob(NULL, 0);
823                 DEBUG(5, ("making a connection to 'homes' service [%s] created at session setup time\n", service_in));
824                 return make_connection_snum(vuser->homes_snum,
825                                             vuser, no_pw, 
826                                             dev, status);
827         }
828         
829         fstrcpy(service, service_in);
830
831         strlower_m(service);
832
833         snum = find_service(service);
834
835         if (snum < 0) {
836                 if (strequal(service,"IPC$") || strequal(service,"ADMIN$")) {
837                         DEBUG(3,("refusing IPC connection to %s\n", service));
838                         *status = NT_STATUS_ACCESS_DENIED;
839                         return NULL;
840                 }
841
842                 DEBUG(0,("%s (%s) couldn't find service %s\n",
843                          get_remote_machine_name(), client_addr(), service));
844                 *status = NT_STATUS_BAD_NETWORK_NAME;
845                 return NULL;
846         }
847
848         /* Handle non-Dfs clients attempting connections to msdfs proxy */
849         if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0'))  {
850                 DEBUG(3, ("refusing connection to dfs proxy '%s'\n", service));
851                 *status = NT_STATUS_BAD_NETWORK_NAME;
852                 return NULL;
853         }
854
855         DEBUG(5, ("making a connection to 'normal' service %s\n", service));
856
857         return make_connection_snum(snum, vuser,
858                                     password,
859                                     dev, status);
860 }
861
862 /****************************************************************************
863 close a cnum
864 ****************************************************************************/
865 void close_cnum(connection_struct *conn, uint16 vuid)
866 {
867         DirCacheFlush(SNUM(conn));
868
869         change_to_root_user();
870
871         DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
872                                  get_remote_machine_name(),conn->client_address,
873                                  lp_servicename(SNUM(conn))));
874
875         /* Call VFS disconnect hook */    
876         SMB_VFS_DISCONNECT(conn);
877
878         yield_connection(conn, lp_servicename(SNUM(conn)));
879
880         file_close_conn(conn);
881         dptr_closecnum(conn);
882
883         /* execute any "postexec = " line */
884         if (*lp_postexec(SNUM(conn)) && 
885             change_to_user(conn, vuid))  {
886                 pstring cmd;
887                 pstrcpy(cmd,lp_postexec(SNUM(conn)));
888                 standard_sub_conn(conn,cmd,sizeof(cmd));
889                 smbrun(cmd,NULL);
890                 change_to_root_user();
891         }
892
893         change_to_root_user();
894         /* execute any "root postexec = " line */
895         if (*lp_rootpostexec(SNUM(conn)))  {
896                 pstring cmd;
897                 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
898                 standard_sub_conn(conn,cmd,sizeof(cmd));
899                 smbrun(cmd,NULL);
900         }
901
902         /* make sure we leave the directory available for unmount */
903         vfs_ChDir(conn, "/");
904
905         conn_free(conn);
906 }