Fix from Steve Langasek <vorlon@netexpress.net> for non-RPC printing.
[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,"LPT:");
233                 } else if (strequal(lp_fstype(snum), "IPC")) {
234                         fstrcpy(dev, "IPC");
235                 } else {
236                         fstrcpy(dev,"A:");
237                 }
238         }
239
240         strupper(dev);
241
242         if (lp_print_ok(snum)) {
243                 if (!strequal(dev, "LPT:")) {
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, "LPT:");
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,("authorise_login: 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                 string_set(&conn->user,pass->pw_name);
370                 passwd_free(&pass);
371                 DEBUG(3,("Guest only user %s\n",user));
372         } else if (vuser) {
373                 if (vuser->guest) {
374                         if (!lp_guest_ok(snum)) {
375                                 DEBUG(2, ("guest user (from session setup) not permitted to access this share (%s)\n", lp_servicename(snum)));
376                                       conn_free(conn);
377                                       *status = NT_STATUS_ACCESS_DENIED;
378                                       return NULL;
379                         }
380                 } else {
381                         if (!user_ok(vuser->user.unix_name, snum, vuser->groups, vuser->n_groups)) {
382                                 DEBUG(2, ("user '%s' (from session setup) not permitted to access this share (%s)\n", vuser->user.unix_name, lp_servicename(snum)));
383                                 conn_free(conn);
384                                 *status = NT_STATUS_ACCESS_DENIED;
385                                 return NULL;
386                         }
387                 }
388                 conn->vuid = vuser->vuid;
389                 conn->uid = vuser->uid;
390                 conn->gid = vuser->gid;
391                 string_set(&conn->user,vuser->user.unix_name);
392                 fstrcpy(user,vuser->user.unix_name);
393                 guest = vuser->guest; 
394         } else if (lp_security() == SEC_SHARE) {
395                 /* add it as a possible user name if we 
396                    are in share mode security */
397                 add_session_user(lp_servicename(snum));
398                 /* shall we let them in? */
399                 if (!authorise_login(snum,user,password,&guest)) {
400                         DEBUG( 2, ( "Invalid username/password for [%s]\n", 
401                                     lp_servicename(snum)) );
402                         conn_free(conn);
403                         *status = NT_STATUS_WRONG_PASSWORD;
404                         return NULL;
405                 }
406                 pass = Get_Pwnam(user);
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);
411                 fstrcpy(user, pass->pw_name);
412
413         } else {
414                 DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
415                 conn_free(conn);
416                 *status = NT_STATUS_ACCESS_DENIED;
417                 return NULL;
418         }
419
420         add_session_user(user);
421
422         safe_strcpy(conn->client_address, client_addr(), 
423                     sizeof(conn->client_address)-1);
424         conn->num_files_open = 0;
425         conn->lastused = time(NULL);
426         conn->service = snum;
427         conn->used = True;
428         conn->printer = (strncmp(dev,"LPT",3) == 0);
429         conn->ipc = ((strncmp(dev,"IPC",3) == 0) || strequal(dev,"ADMIN$"));
430         conn->dirptr = NULL;
431         conn->veto_list = NULL;
432         conn->hide_list = NULL;
433         conn->veto_oplock_list = NULL;
434         string_set(&conn->dirpath,"");
435         string_set(&conn->user,user);
436         conn->nt_user_token = NULL;
437         
438         set_read_only(conn, vuser ? vuser->groups : NULL, vuser ? vuser->n_groups : 0);
439         
440         set_admin_user(conn, vuser ? vuser->groups : NULL, vuser ? vuser->n_groups : 0);
441
442         /*
443          * If force user is true, then store the
444          * given userid and also the groups
445          * of the user we're forcing.
446          */
447         
448         if (*lp_force_user(snum)) {
449                 struct passwd *pass2;
450                 pstring fuser;
451                 pstrcpy(fuser,lp_force_user(snum));
452
453                 /* Allow %S to be used by force user. */
454                 pstring_sub(fuser,"%S",lp_servicename(snum));
455
456                 pass2 = (struct passwd *)Get_Pwnam(fuser);
457                 if (pass2) {
458                         conn->uid = pass2->pw_uid;
459                         conn->gid = pass2->pw_gid;
460                         string_set(&conn->user,pass2->pw_name);
461                         fstrcpy(user,pass2->pw_name);
462                         conn->force_user = True;
463                         DEBUG(3,("Forced user %s\n",user));       
464                 } else {
465                         DEBUG(1,("Couldn't find user %s\n",fuser));
466                         conn_free(conn);
467                         *status = NT_STATUS_NO_SUCH_USER;
468                         return NULL;
469                 }
470         }
471
472         /* admin users always run as uid=0 */
473         if (conn->admin_user) {
474                 conn->uid = 0;
475         }
476
477 #ifdef HAVE_GETGRNAM 
478         /*
479          * If force group is true, then override
480          * any groupid stored for the connecting user.
481          */
482         
483         if (*lp_force_group(snum)) {
484                 gid_t gid;
485                 pstring gname;
486                 pstring tmp_gname;
487                 BOOL user_must_be_member = False;
488                 
489                 StrnCpy(tmp_gname,lp_force_group(snum),sizeof(pstring)-1);
490                 
491                 if (tmp_gname[0] == '+') {
492                         user_must_be_member = True;
493                         StrnCpy(gname,&tmp_gname[1],sizeof(pstring)-2);
494                 } else {
495                         StrnCpy(gname,tmp_gname,sizeof(pstring)-1);
496                 }
497                 /* default service may be a group name          */
498                 pstring_sub(gname,"%S",lp_servicename(snum));
499                 gid = nametogid(gname);
500                 
501                 if (gid != (gid_t)-1) {
502
503                         /*
504                          * If the user has been forced and the forced group starts
505                          * with a '+', then we only set the group to be the forced
506                          * group if the forced user is a member of that group.
507                          * Otherwise, the meaning of the '+' would be ignored.
508                          */
509                         if (conn->force_user && user_must_be_member) {
510                                 if (user_in_group_list( user, gname, NULL, 0)) {
511                                                 conn->gid = gid;
512                                                 DEBUG(3,("Forced group %s for member %s\n",gname,user));
513                                 }
514                         } else {
515                                 conn->gid = gid;
516                                 DEBUG(3,("Forced group %s\n",gname));
517                         }
518                         conn->force_group = True;
519                 } else {
520                         DEBUG(1,("Couldn't find group %s\n",gname));
521                         conn_free(conn);
522                         *status = NT_STATUS_NO_SUCH_GROUP;
523                         return NULL;
524                 }
525         }
526 #endif /* HAVE_GETGRNAM */
527
528         {
529                 pstring s;
530                 pstrcpy(s,lp_pathname(snum));
531                 standard_sub_conn(conn,s,sizeof(s));
532                 string_set(&conn->connectpath,s);
533                 DEBUG(3,("Connect path is '%s' for service [%s]\n",s, lp_servicename(snum)));
534         }
535
536         if (conn->force_user || conn->force_group) {
537
538                 /* groups stuff added by ih */
539                 conn->ngroups = 0;
540                 conn->groups = NULL;
541                 
542                 /* Find all the groups this uid is in and
543                    store them. Used by change_to_user() */
544                 initialise_groups(conn->user, conn->uid, conn->gid); 
545                 get_current_groups(conn->gid, &conn->ngroups,&conn->groups);
546                 
547                 conn->nt_user_token = create_nt_token(conn->uid, conn->gid, 
548                                                       conn->ngroups, conn->groups,
549                                                       guest);
550         }
551
552         /*
553          * New code to check if there's a share security descripter
554          * added from NT server manager. This is done after the
555          * smb.conf checks are done as we need a uid and token. JRA.
556          *
557          */
558
559         {
560                 BOOL can_write = share_access_check(conn, snum, vuser, FILE_WRITE_DATA);
561
562                 if (!can_write) {
563                         if (!share_access_check(conn, snum, vuser, FILE_READ_DATA)) {
564                                 /* No access, read or write. */
565                                 DEBUG(0,( "make_connection: connection to %s denied due to security descriptor.\n",
566                                           lp_servicename(snum)));
567                                 conn_free(conn);
568                                 *status = NT_STATUS_ACCESS_DENIED;
569                                 return NULL;
570                         } else {
571                                 conn->read_only = True;
572                         }
573                 }
574         }
575         /* Initialise VFS function pointers */
576
577         if (!smbd_vfs_init(conn)) {
578                 DEBUG(0, ("vfs_init failed for service %s\n", lp_servicename(SNUM(conn))));
579                 conn_free(conn);
580                 *status = NT_STATUS_BAD_NETWORK_NAME;
581                 return NULL;
582         }
583
584 /* ROOT Activities: */  
585         /* check number of connections */
586         if (!claim_connection(conn,
587                               lp_servicename(SNUM(conn)),
588                               lp_max_connections(SNUM(conn)),
589                               False,0)) {
590                 DEBUG(1,("too many connections - rejected\n"));
591                 conn_free(conn);
592                 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
593                 return NULL;
594         }  
595
596         /* Preexecs are done here as they might make the dir we are to ChDir to below */
597         /* execute any "root preexec = " line */
598         if (*lp_rootpreexec(SNUM(conn))) {
599                 int ret;
600                 pstring cmd;
601                 pstrcpy(cmd,lp_rootpreexec(SNUM(conn)));
602                 standard_sub_conn(conn,cmd,sizeof(cmd));
603                 DEBUG(5,("cmd=%s\n",cmd));
604                 ret = smbrun(cmd,NULL);
605                 if (ret != 0 && lp_rootpreexec_close(SNUM(conn))) {
606                         DEBUG(1,("root preexec gave %d - failing connection\n", ret));
607                         yield_connection(conn, lp_servicename(SNUM(conn)));
608                         conn_free(conn);
609                         *status = NT_STATUS_ACCESS_DENIED;
610                         return NULL;
611                 }
612         }
613
614 /* USER Activites: */
615         if (!change_to_user(conn, conn->vuid)) {
616                 /* No point continuing if they fail the basic checks */
617                 DEBUG(0,("Can't become connected user!\n"));
618                 conn_free(conn);
619                 *status = NT_STATUS_LOGON_FAILURE;
620                 return NULL;
621         }
622
623         /* Remember that a different vuid can connect later without these checks... */
624         
625         /* Preexecs are done here as they might make the dir we are to ChDir to below */
626         /* execute any "preexec = " line */
627         if (*lp_preexec(SNUM(conn))) {
628                 int ret;
629                 pstring cmd;
630                 pstrcpy(cmd,lp_preexec(SNUM(conn)));
631                 standard_sub_conn(conn,cmd,sizeof(cmd));
632                 ret = smbrun(cmd,NULL);
633                 if (ret != 0 && lp_preexec_close(SNUM(conn))) {
634                         DEBUG(1,("preexec gave %d - failing connection\n", ret));
635                         change_to_root_user();
636                         yield_connection(conn, lp_servicename(SNUM(conn)));
637                         conn_free(conn);
638                         *status = NT_STATUS_ACCESS_DENIED;
639                         return NULL;
640                 }
641         }
642         
643 #if CHECK_PATH_ON_TCONX
644         /* win2000 does not check the permissions on the directory
645            during the tree connect, instead relying on permission
646            check during individual operations. To match this behaviour
647            I have disabled this chdir check (tridge) */
648         if (vfs_ChDir(conn,conn->connectpath) != 0) {
649                 DEBUG(0,("%s (%s) Can't change directory to %s (%s)\n",
650                          get_remote_machine_name(), conn->client_address,
651                          conn->connectpath,strerror(errno)));
652                 change_to_root_user();
653                 yield_connection(conn, lp_servicename(SNUM(conn)));
654                 conn_free(conn);
655                 *status = NT_STATUS_BAD_NETWORK_NAME;
656                 return NULL;
657         }
658 #else
659         /* the alternative is just to check the directory exists */
660         if (stat(conn->connectpath, &st) != 0 || !S_ISDIR(st.st_mode)) {
661                 DEBUG(0,("'%s' is not a directory, when connecting to [%s]\n", conn->connectpath, lp_servicename(SNUM(conn))));
662                 change_to_root_user();
663                 yield_connection(conn, lp_servicename(SNUM(conn)));
664                 conn_free(conn);
665                 *status = NT_STATUS_BAD_NETWORK_NAME;
666                 return NULL;
667         }
668 #endif
669         
670         string_set(&conn->origpath,conn->connectpath);
671         
672 #if SOFTLINK_OPTIMISATION
673         /* resolve any soft links early if possible */
674         if (vfs_ChDir(conn,conn->connectpath) == 0) {
675                 pstring s;
676                 pstrcpy(s,conn->connectpath);
677                 vfs_GetWd(conn,s);
678                 string_set(&conn->connectpath,s);
679                 vfs_ChDir(conn,conn->connectpath);
680         }
681 #endif
682         
683         /*
684          * Print out the 'connected as' stuff here as we need
685          * to know the effective uid and gid we will be using
686          * (at least initially).
687          */
688
689         if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
690                 dbgtext( "%s (%s) ", get_remote_machine_name(), conn->client_address );
691                 dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)) );
692                 dbgtext( "initially as user %s ", user );
693                 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
694                 dbgtext( "(pid %d)\n", (int)sys_getpid() );
695         }
696         
697         /* Add veto/hide lists */
698         if (!IS_IPC(conn) && !IS_PRINT(conn)) {
699                 set_namearray( &conn->veto_list, lp_veto_files(SNUM(conn)));
700                 set_namearray( &conn->hide_list, lp_hide_files(SNUM(conn)));
701                 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(SNUM(conn)));
702         }
703         
704         /* Invoke VFS make connection hook */
705
706         if (conn->vfs_ops.connect) {
707                 if (conn->vfs_ops.connect(conn, lp_servicename(snum), user) < 0) {
708                         DEBUG(0,("make_connection: VFS make connection failed!\n"));
709                         change_to_root_user();
710                         conn_free(conn);
711                         *status = NT_STATUS_UNSUCCESSFUL;
712                         return NULL;
713                 }
714         }
715
716         /* we've finished with the user stuff - go back to root */
717         change_to_root_user();
718             
719         return(conn);
720 }
721
722 /***************************************************************************************
723  Simple wrapper function for make_connection() to include a call to 
724  vfs_chdir()
725  **************************************************************************************/
726  
727 connection_struct *make_connection_with_chdir(const char *service_in, DATA_BLOB password, 
728                                    const char *dev, uint16 vuid, NTSTATUS *status)
729 {
730         connection_struct *conn = NULL;
731         
732         conn = make_connection(service_in, password, dev, vuid, status);
733         
734         /*
735          * make_connection() does not change the directory for us any more
736          * so we have to do it as a separate step  --jerry
737          */
738          
739         if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) {
740                 DEBUG(0,("move_driver_to_download_area: Can't change directory to %s for [print$] (%s)\n",
741                          conn->connectpath,strerror(errno)));
742                 yield_connection(conn, lp_servicename(SNUM(conn)));
743                 conn_free(conn);
744                 *status = NT_STATUS_UNSUCCESSFUL;
745                 return NULL;
746         }
747         
748         return conn;
749 }
750
751 /****************************************************************************
752  Make a connection to a service.
753  *
754  * @param service 
755 ****************************************************************************/
756
757 connection_struct *make_connection(const char *service_in, DATA_BLOB password, 
758                                    const char *pdev, uint16 vuid, NTSTATUS *status)
759 {
760         uid_t euid;
761         user_struct *vuser = NULL;
762         fstring service;
763         fstring dev;
764         int snum = -1;
765
766         fstrcpy(dev, pdev);
767
768         /* This must ONLY BE CALLED AS ROOT. As it exits this function as root. */
769         if (!non_root_mode() && (euid = geteuid()) != 0) {
770                 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot (%u)\n", (unsigned int)euid ));
771                 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
772         }
773
774         if(lp_security() != SEC_SHARE) {
775                 vuser = get_valid_user_struct(vuid);
776                 if (!vuser) {
777                         DEBUG(1,("make_connection: refusing to connect with no session setup\n"));
778                         *status = NT_STATUS_ACCESS_DENIED;
779                         return NULL;
780                 }
781         }
782
783         /* Logic to try and connect to the correct [homes] share, preferably without too many
784            getpwnam() lookups.  This is particulary nasty for winbind usernames, where the
785            share name isn't the same as unix username.
786
787            The snum of the homes share is stored on the vuser at session setup time.
788         */
789
790         if (strequal(service_in,HOMES_NAME)) {
791                 if(lp_security() != SEC_SHARE) {
792                         DATA_BLOB no_pw = data_blob(NULL, 0);
793                         if (vuser->homes_snum == -1) {
794                                 DEBUG(2, ("[homes] share not available for this user becouse it was not found or created at session setup time\n"));
795                                 *status = NT_STATUS_BAD_NETWORK_NAME;
796                                 return NULL;
797                         }
798                         DEBUG(5, ("making a connection to [homes] service created at session setup time\n"));
799                         return make_connection_snum(vuser->homes_snum,
800                                                     vuser, no_pw, 
801                                                     dev, status);
802                 } else {
803                         /* Security = share. Try with current_user_info.smb_name
804                          * as the username.  */
805                         if (*current_user_info.smb_name) {
806                                 fstring unix_username;
807                                 fstrcpy(unix_username,
808                                         current_user_info.smb_name);
809                                 map_username(unix_username);
810                                 snum = find_service(unix_username);
811                         } 
812                         if (snum != -1) {
813                                 DEBUG(5, ("making a connection to 'homes' service %s based on security=share\n", service_in));
814                                 return make_connection_snum(snum, NULL,
815                                                             password,
816                                                             dev, status);
817                         }
818                 }
819         } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
820                    && strequal(service_in, lp_servicename(vuser->homes_snum))) {
821                 DATA_BLOB no_pw = data_blob(NULL, 0);
822                 DEBUG(5, ("making a connection to 'homes' service [%s] created at session setup time\n", service_in));
823                 return make_connection_snum(vuser->homes_snum,
824                                             vuser, no_pw, 
825                                             dev, status);
826         }
827         
828         fstrcpy(service, service_in);
829
830         strlower(service);
831
832         snum = find_service(service);
833
834         if (snum < 0) {
835                 if (strequal(service,"IPC$") || strequal(service,"ADMIN$")) {
836                         DEBUG(3,("refusing IPC connection to %s\n", service));
837                         *status = NT_STATUS_ACCESS_DENIED;
838                         return NULL;
839                 }
840
841                 DEBUG(0,("%s (%s) couldn't find service %s\n",
842                          get_remote_machine_name(), client_addr(), service));
843                 *status = NT_STATUS_BAD_NETWORK_NAME;
844                 return NULL;
845         }
846
847         /* Handle non-Dfs clients attempting connections to msdfs proxy */
848         if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0'))  {
849                 DEBUG(3, ("refusing connection to dfs proxy '%s'\n", service));
850                 *status = NT_STATUS_BAD_NETWORK_NAME;
851                 return NULL;
852         }
853
854         DEBUG(5, ("making a connection to 'normal' service %s\n", service));
855
856         return make_connection_snum(snum, vuser,
857                                     password,
858                                     dev, status);
859 }
860
861 /****************************************************************************
862 close a cnum
863 ****************************************************************************/
864 void close_cnum(connection_struct *conn, uint16 vuid)
865 {
866         DirCacheFlush(SNUM(conn));
867
868         change_to_root_user();
869
870         DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
871                                  get_remote_machine_name(),conn->client_address,
872                                  lp_servicename(SNUM(conn))));
873
874         if (conn->vfs_ops.disconnect != NULL) {
875
876             /* Call VFS disconnect hook */
877             
878             conn->vfs_ops.disconnect(conn);
879             
880         }
881
882         yield_connection(conn, lp_servicename(SNUM(conn)));
883
884         file_close_conn(conn);
885         dptr_closecnum(conn);
886
887         /* execute any "postexec = " line */
888         if (*lp_postexec(SNUM(conn)) && 
889             change_to_user(conn, vuid))  {
890                 pstring cmd;
891                 pstrcpy(cmd,lp_postexec(SNUM(conn)));
892                 standard_sub_conn(conn,cmd,sizeof(cmd));
893                 smbrun(cmd,NULL);
894                 change_to_root_user();
895         }
896
897         change_to_root_user();
898         /* execute any "root postexec = " line */
899         if (*lp_rootpostexec(SNUM(conn)))  {
900                 pstring cmd;
901                 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
902                 standard_sub_conn(conn,cmd,sizeof(cmd));
903                 smbrun(cmd,NULL);
904         }
905
906         /* make sure we leave the directory available for unmount */
907         vfs_ChDir(conn, "/");
908
909         conn_free(conn);
910 }