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