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