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