c9f5330551485407f808c631038a0ca665c040cf
[abartlet/samba.git/.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(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,("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                 pstrcpy(tmp_gname,lp_force_group(snum));
490                 
491                 if (tmp_gname[0] == '+') {
492                         user_must_be_member = True;
493                         /* even now, tmp_gname is null terminated */
494                         pstrcpy(gname,&tmp_gname[1]);
495                 } else {
496                         pstrcpy(gname,tmp_gname);
497                 }
498                 /* default service may be a group name          */
499                 pstring_sub(gname,"%S",lp_servicename(snum));
500                 gid = nametogid(gname);
501                 
502                 if (gid != (gid_t)-1) {
503
504                         /*
505                          * If the user has been forced and the forced group starts
506                          * with a '+', then we only set the group to be the forced
507                          * group if the forced user is a member of that group.
508                          * Otherwise, the meaning of the '+' would be ignored.
509                          */
510                         if (conn->force_user && user_must_be_member) {
511                                 if (user_in_group_list( user, gname, NULL, 0)) {
512                                                 conn->gid = gid;
513                                                 DEBUG(3,("Forced group %s for member %s\n",gname,user));
514                                 }
515                         } else {
516                                 conn->gid = gid;
517                                 DEBUG(3,("Forced group %s\n",gname));
518                         }
519                         conn->force_group = True;
520                 } else {
521                         DEBUG(1,("Couldn't find group %s\n",gname));
522                         conn_free(conn);
523                         *status = NT_STATUS_NO_SUCH_GROUP;
524                         return NULL;
525                 }
526         }
527 #endif /* HAVE_GETGRNAM */
528
529         {
530                 pstring s;
531                 pstrcpy(s,lp_pathname(snum));
532                 standard_sub_conn(conn,s,sizeof(s));
533                 string_set(&conn->connectpath,s);
534                 DEBUG(3,("Connect path is '%s' for service [%s]\n",s, lp_servicename(snum)));
535         }
536
537         if (conn->force_user || conn->force_group) {
538
539                 /* groups stuff added by ih */
540                 conn->ngroups = 0;
541                 conn->groups = NULL;
542                 
543                 /* Find all the groups this uid is in and
544                    store them. Used by change_to_user() */
545                 initialise_groups(conn->user, conn->uid, conn->gid); 
546                 get_current_groups(conn->gid, &conn->ngroups,&conn->groups);
547                 
548                 conn->nt_user_token = create_nt_token(conn->uid, conn->gid, 
549                                                       conn->ngroups, conn->groups,
550                                                       guest);
551         }
552
553         /*
554          * New code to check if there's a share security descripter
555          * added from NT server manager. This is done after the
556          * smb.conf checks are done as we need a uid and token. JRA.
557          *
558          */
559
560         {
561                 BOOL can_write = share_access_check(conn, snum, vuser, FILE_WRITE_DATA);
562
563                 if (!can_write) {
564                         if (!share_access_check(conn, snum, vuser, FILE_READ_DATA)) {
565                                 /* No access, read or write. */
566                                 DEBUG(0,( "make_connection: connection to %s denied due to security descriptor.\n",
567                                           lp_servicename(snum)));
568                                 conn_free(conn);
569                                 *status = NT_STATUS_ACCESS_DENIED;
570                                 return NULL;
571                         } else {
572                                 conn->read_only = True;
573                         }
574                 }
575         }
576         /* Initialise VFS function pointers */
577
578         if (!smbd_vfs_init(conn)) {
579                 DEBUG(0, ("vfs_init failed for service %s\n", lp_servicename(SNUM(conn))));
580                 conn_free(conn);
581                 *status = NT_STATUS_BAD_NETWORK_NAME;
582                 return NULL;
583         }
584
585 /* ROOT Activities: */  
586         /* check number of connections */
587         if (!claim_connection(conn,
588                               lp_servicename(SNUM(conn)),
589                               lp_max_connections(SNUM(conn)),
590                               False,0)) {
591                 DEBUG(1,("too many connections - rejected\n"));
592                 conn_free(conn);
593                 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
594                 return NULL;
595         }  
596
597         /* Preexecs are done here as they might make the dir we are to ChDir to below */
598         /* execute any "root preexec = " line */
599         if (*lp_rootpreexec(SNUM(conn))) {
600                 int ret;
601                 pstring cmd;
602                 pstrcpy(cmd,lp_rootpreexec(SNUM(conn)));
603                 standard_sub_conn(conn,cmd,sizeof(cmd));
604                 DEBUG(5,("cmd=%s\n",cmd));
605                 ret = smbrun(cmd,NULL);
606                 if (ret != 0 && lp_rootpreexec_close(SNUM(conn))) {
607                         DEBUG(1,("root preexec gave %d - failing connection\n", ret));
608                         yield_connection(conn, lp_servicename(SNUM(conn)));
609                         conn_free(conn);
610                         *status = NT_STATUS_ACCESS_DENIED;
611                         return NULL;
612                 }
613         }
614
615 /* USER Activites: */
616         if (!change_to_user(conn, conn->vuid)) {
617                 /* No point continuing if they fail the basic checks */
618                 DEBUG(0,("Can't become connected user!\n"));
619                 conn_free(conn);
620                 *status = NT_STATUS_LOGON_FAILURE;
621                 return NULL;
622         }
623
624         /* Remember that a different vuid can connect later without these checks... */
625         
626         /* Preexecs are done here as they might make the dir we are to ChDir to below */
627         /* execute any "preexec = " line */
628         if (*lp_preexec(SNUM(conn))) {
629                 int ret;
630                 pstring cmd;
631                 pstrcpy(cmd,lp_preexec(SNUM(conn)));
632                 standard_sub_conn(conn,cmd,sizeof(cmd));
633                 ret = smbrun(cmd,NULL);
634                 if (ret != 0 && lp_preexec_close(SNUM(conn))) {
635                         DEBUG(1,("preexec gave %d - failing connection\n", ret));
636                         change_to_root_user();
637                         yield_connection(conn, lp_servicename(SNUM(conn)));
638                         conn_free(conn);
639                         *status = NT_STATUS_ACCESS_DENIED;
640                         return NULL;
641                 }
642         }
643         
644 #if CHECK_PATH_ON_TCONX
645         /* win2000 does not check the permissions on the directory
646            during the tree connect, instead relying on permission
647            check during individual operations. To match this behaviour
648            I have disabled this chdir check (tridge) */
649         if (vfs_ChDir(conn,conn->connectpath) != 0) {
650                 DEBUG(0,("%s (%s) Can't change directory to %s (%s)\n",
651                          get_remote_machine_name(), conn->client_address,
652                          conn->connectpath,strerror(errno)));
653                 change_to_root_user();
654                 yield_connection(conn, lp_servicename(SNUM(conn)));
655                 conn_free(conn);
656                 *status = NT_STATUS_BAD_NETWORK_NAME;
657                 return NULL;
658         }
659 #else
660         /* the alternative is just to check the directory exists */
661         if (stat(conn->connectpath, &st) != 0 || !S_ISDIR(st.st_mode)) {
662                 DEBUG(0,("'%s' is not a directory, when connecting to [%s]\n", conn->connectpath, lp_servicename(SNUM(conn))));
663                 change_to_root_user();
664                 yield_connection(conn, lp_servicename(SNUM(conn)));
665                 conn_free(conn);
666                 *status = NT_STATUS_BAD_NETWORK_NAME;
667                 return NULL;
668         }
669 #endif
670         
671         string_set(&conn->origpath,conn->connectpath);
672         
673 #if SOFTLINK_OPTIMISATION
674         /* resolve any soft links early if possible */
675         if (vfs_ChDir(conn,conn->connectpath) == 0) {
676                 pstring s;
677                 pstrcpy(s,conn->connectpath);
678                 vfs_GetWd(conn,s);
679                 string_set(&conn->connectpath,s);
680                 vfs_ChDir(conn,conn->connectpath);
681         }
682 #endif
683         
684         /*
685          * Print out the 'connected as' stuff here as we need
686          * to know the effective uid and gid we will be using
687          * (at least initially).
688          */
689
690         if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
691                 dbgtext( "%s (%s) ", get_remote_machine_name(), conn->client_address );
692                 dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)) );
693                 dbgtext( "initially as user %s ", user );
694                 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
695                 dbgtext( "(pid %d)\n", (int)sys_getpid() );
696         }
697         
698         /* Add veto/hide lists */
699         if (!IS_IPC(conn) && !IS_PRINT(conn)) {
700                 set_namearray( &conn->veto_list, lp_veto_files(SNUM(conn)));
701                 set_namearray( &conn->hide_list, lp_hide_files(SNUM(conn)));
702                 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(SNUM(conn)));
703         }
704         
705         /* Invoke VFS make connection hook */
706
707         if (conn->vfs_ops.connect) {
708                 if (conn->vfs_ops.connect(conn, lp_servicename(snum), user) < 0) {
709                         DEBUG(0,("make_connection: VFS make connection failed!\n"));
710                         change_to_root_user();
711                         conn_free(conn);
712                         *status = NT_STATUS_UNSUCCESSFUL;
713                         return NULL;
714                 }
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(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         if (conn->vfs_ops.disconnect != NULL) {
876
877             /* Call VFS disconnect hook */
878             
879             conn->vfs_ops.disconnect(conn);
880             
881         }
882
883         yield_connection(conn, lp_servicename(SNUM(conn)));
884
885         file_close_conn(conn);
886         dptr_closecnum(conn);
887
888         /* execute any "postexec = " line */
889         if (*lp_postexec(SNUM(conn)) && 
890             change_to_user(conn, vuid))  {
891                 pstring cmd;
892                 pstrcpy(cmd,lp_postexec(SNUM(conn)));
893                 standard_sub_conn(conn,cmd,sizeof(cmd));
894                 smbrun(cmd,NULL);
895                 change_to_root_user();
896         }
897
898         change_to_root_user();
899         /* execute any "root postexec = " line */
900         if (*lp_rootpostexec(SNUM(conn)))  {
901                 pstring cmd;
902                 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
903                 standard_sub_conn(conn,cmd,sizeof(cmd));
904                 smbrun(cmd,NULL);
905         }
906
907         /* make sure we leave the directory available for unmount */
908         vfs_ChDir(conn, "/");
909
910         conn_free(conn);
911 }