r4043: BUG 2091: don't remove statically defined printers in remove_stale_printers()
[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                         const char *pszTemp = lp_printcapname();
156
157                         DEBUG(3,("checking whether %s is a valid printer name...\n", service));
158                         if ((pszTemp != NULL) && pcap_printername_ok(service, pszTemp)) {
159                                 DEBUG(3,("%s is a valid printer name\n", service));
160                                 DEBUG(3,("adding %s as a printer service\n", service));
161                                 lp_add_printer(service, iPrinterService);
162                                 iService = lp_servicenumber(service);
163                                 if (iService < 0) {
164                                         DEBUG(0,("failed to add %s as a printer service!\n", service));
165                                 }
166                         } else {
167                                 DEBUG(3,("%s is not a valid printer name\n", service));
168                         }
169                 }
170         }
171
172         /* Check for default vfs service?  Unsure whether to implement this */
173         if (iService < 0) {
174         }
175
176         /* just possibly it's a default service? */
177         if (iService < 0) {
178                 char *pdefservice = lp_defaultservice();
179                 if (pdefservice && *pdefservice && !strequal(pdefservice,service) && !strstr_m(service,"..")) {
180                         /*
181                          * We need to do a local copy here as lp_defaultservice() 
182                          * returns one of the rotating lp_string buffers that
183                          * could get overwritten by the recursive find_service() call
184                          * below. Fix from Josef Hinteregger <joehtg@joehtg.co.at>.
185                          */
186                         pstring defservice;
187                         pstrcpy(defservice, pdefservice);
188                         iService = find_service(defservice);
189                         if (iService >= 0) {
190                                 all_string_sub(service, "_","/",0);
191                                 iService = lp_add_service(service, iService);
192                         }
193                 }
194         }
195
196         if (iService >= 0) {
197                 if (!VALID_SNUM(iService)) {
198                         DEBUG(0,("Invalid snum %d for %s\n",iService, service));
199                         iService = -1;
200                 }
201         }
202
203         if (iService < 0)
204                 DEBUG(3,("find_service() failed to find service %s\n", service));
205
206         return (iService);
207 }
208
209
210 /****************************************************************************
211  do some basic sainity checks on the share.  
212  This function modifies dev, ecode.
213 ****************************************************************************/
214
215 static NTSTATUS share_sanity_checks(int snum, fstring dev) 
216 {
217         
218         if (!lp_snum_ok(snum) || 
219             !check_access(smbd_server_fd(), 
220                           lp_hostsallow(snum), lp_hostsdeny(snum))) {    
221                 return NT_STATUS_ACCESS_DENIED;
222         }
223
224         if (dev[0] == '?' || !dev[0]) {
225                 if (lp_print_ok(snum)) {
226                         fstrcpy(dev,"LPT1:");
227                 } else if (strequal(lp_fstype(snum), "IPC")) {
228                         fstrcpy(dev, "IPC");
229                 } else {
230                         fstrcpy(dev,"A:");
231                 }
232         }
233
234         strupper_m(dev);
235
236         if (lp_print_ok(snum)) {
237                 if (!strequal(dev, "LPT1:")) {
238                         return NT_STATUS_BAD_DEVICE_TYPE;
239                 }
240         } else if (strequal(lp_fstype(snum), "IPC")) {
241                 if (!strequal(dev, "IPC")) {
242                         return NT_STATUS_BAD_DEVICE_TYPE;
243                 }
244         } else if (!strequal(dev, "A:")) {
245                 return NT_STATUS_BAD_DEVICE_TYPE;
246         }
247
248         /* Behave as a printer if we are supposed to */
249         if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) {
250                 fstrcpy(dev, "LPT1:");
251         }
252
253         return NT_STATUS_OK;
254 }
255
256 /****************************************************************************
257   Make a connection, given the snum to connect to, and the vuser of the
258   connecting user if appropriate.
259 ****************************************************************************/
260
261 static connection_struct *make_connection_snum(int snum, user_struct *vuser,
262                                                DATA_BLOB password, 
263                                                const char *pdev, NTSTATUS *status)
264 {
265         struct passwd *pass = NULL;
266         BOOL guest = False;
267         connection_struct *conn;
268         struct stat st;
269         fstring user;
270         fstring dev;
271
272         *user = 0;
273         fstrcpy(dev, pdev);
274
275         if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, dev))) {
276                 return NULL;
277         }       
278
279         conn = conn_new();
280         if (!conn) {
281                 DEBUG(0,("Couldn't find free connection.\n"));
282                 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
283                 return NULL;
284         }
285
286         if (lp_guest_only(snum)) {
287                 const char *guestname = lp_guestaccount();
288                 guest = True;
289                 pass = getpwnam_alloc(guestname);
290                 if (!pass) {
291                         DEBUG(0,("make_connection_snum: Invalid guest account %s??\n",guestname));
292                         conn_free(conn);
293                         *status = NT_STATUS_NO_SUCH_USER;
294                         return NULL;
295                 }
296                 fstrcpy(user,pass->pw_name);
297                 conn->force_user = True;
298                 conn->uid = pass->pw_uid;
299                 conn->gid = pass->pw_gid;
300                 string_set(&conn->user,pass->pw_name);
301                 passwd_free(&pass);
302                 DEBUG(3,("Guest only user %s\n",user));
303         } else if (vuser) {
304                 if (vuser->guest) {
305                         if (!lp_guest_ok(snum)) {
306                                 DEBUG(2, ("guest user (from session setup) not permitted to access this share (%s)\n", lp_servicename(snum)));
307                                       conn_free(conn);
308                                       *status = NT_STATUS_ACCESS_DENIED;
309                                       return NULL;
310                         }
311                 } else {
312                         if (!user_ok(vuser->user.unix_name, snum, vuser->groups, vuser->n_groups)) {
313                                 DEBUG(2, ("user '%s' (from session setup) not permitted to access this share (%s)\n", vuser->user.unix_name, lp_servicename(snum)));
314                                 conn_free(conn);
315                                 *status = NT_STATUS_ACCESS_DENIED;
316                                 return NULL;
317                         }
318                 }
319                 conn->vuid = vuser->vuid;
320                 conn->uid = vuser->uid;
321                 conn->gid = vuser->gid;
322                 string_set(&conn->user,vuser->user.unix_name);
323                 fstrcpy(user,vuser->user.unix_name);
324                 guest = vuser->guest; 
325         } else if (lp_security() == SEC_SHARE) {
326                 /* add it as a possible user name if we 
327                    are in share mode security */
328                 add_session_user(lp_servicename(snum));
329                 /* shall we let them in? */
330                 if (!authorise_login(snum,user,password,&guest)) {
331                         DEBUG( 2, ( "Invalid username/password for [%s]\n", 
332                                     lp_servicename(snum)) );
333                         conn_free(conn);
334                         *status = NT_STATUS_WRONG_PASSWORD;
335                         return NULL;
336                 }
337                 pass = Get_Pwnam(user);
338                 conn->force_user = True;
339                 conn->uid = pass->pw_uid;
340                 conn->gid = pass->pw_gid;
341                 string_set(&conn->user, pass->pw_name);
342                 fstrcpy(user, pass->pw_name);
343
344         } else {
345                 DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
346                 conn_free(conn);
347                 *status = NT_STATUS_ACCESS_DENIED;
348                 return NULL;
349         }
350
351         add_session_user(user);
352
353         safe_strcpy(conn->client_address, client_addr(), 
354                     sizeof(conn->client_address)-1);
355         conn->num_files_open = 0;
356         conn->lastused = time(NULL);
357         conn->service = snum;
358         conn->used = True;
359         conn->printer = (strncmp(dev,"LPT",3) == 0);
360         conn->ipc = ((strncmp(dev,"IPC",3) == 0) || strequal(dev,"ADMIN$"));
361         conn->dirptr = NULL;
362
363         /* Case options for the share. */
364         if (lp_casesensitive(snum) == Auto) {
365                 /* We will be setting this per packet. Set to be case insensitive for now. */
366                 conn->case_sensitive = False;
367         } else {
368                 conn->case_sensitive = (BOOL)lp_casesensitive(snum);
369         }
370
371         conn->case_preserve = lp_preservecase(snum);
372         conn->short_case_preserve = lp_shortpreservecase(snum);
373
374         conn->veto_list = NULL;
375         conn->hide_list = NULL;
376         conn->veto_oplock_list = NULL;
377         string_set(&conn->dirpath,"");
378         string_set(&conn->user,user);
379         conn->nt_user_token = NULL;
380
381         conn->read_only = lp_readonly(conn->service);
382         conn->admin_user = False;
383
384         /*
385          * If force user is true, then store the
386          * given userid and also the groups
387          * of the user we're forcing.
388          */
389         
390         if (*lp_force_user(snum)) {
391                 struct passwd *pass2;
392                 pstring fuser;
393                 pstrcpy(fuser,lp_force_user(snum));
394
395                 /* Allow %S to be used by force user. */
396                 pstring_sub(fuser,"%S",lp_servicename(snum));
397
398                 pass2 = (struct passwd *)Get_Pwnam(fuser);
399                 if (pass2) {
400                         conn->uid = pass2->pw_uid;
401                         conn->gid = pass2->pw_gid;
402                         string_set(&conn->user,pass2->pw_name);
403                         fstrcpy(user,pass2->pw_name);
404                         conn->force_user = True;
405                         DEBUG(3,("Forced user %s\n",user));       
406                 } else {
407                         DEBUG(1,("Couldn't find user %s\n",fuser));
408                         conn_free(conn);
409                         *status = NT_STATUS_NO_SUCH_USER;
410                         return NULL;
411                 }
412         }
413
414 #ifdef HAVE_GETGRNAM 
415         /*
416          * If force group is true, then override
417          * any groupid stored for the connecting user.
418          */
419         
420         if (*lp_force_group(snum)) {
421                 gid_t gid;
422                 pstring gname;
423                 pstring tmp_gname;
424                 BOOL user_must_be_member = False;
425                 
426                 pstrcpy(tmp_gname,lp_force_group(snum));
427                 
428                 if (tmp_gname[0] == '+') {
429                         user_must_be_member = True;
430                         /* even now, tmp_gname is null terminated */
431                         pstrcpy(gname,&tmp_gname[1]);
432                 } else {
433                         pstrcpy(gname,tmp_gname);
434                 }
435                 /* default service may be a group name          */
436                 pstring_sub(gname,"%S",lp_servicename(snum));
437                 gid = nametogid(gname);
438                 
439                 if (gid != (gid_t)-1) {
440
441                         /*
442                          * If the user has been forced and the forced group starts
443                          * with a '+', then we only set the group to be the forced
444                          * group if the forced user is a member of that group.
445                          * Otherwise, the meaning of the '+' would be ignored.
446                          */
447                         if (conn->force_user && user_must_be_member) {
448                                 if (user_in_group_list( user, gname, NULL, 0)) {
449                                                 conn->gid = gid;
450                                                 DEBUG(3,("Forced group %s for member %s\n",gname,user));
451                                 }
452                         } else {
453                                 conn->gid = gid;
454                                 DEBUG(3,("Forced group %s\n",gname));
455                         }
456                         conn->force_group = True;
457                 } else {
458                         DEBUG(1,("Couldn't find group %s\n",gname));
459                         conn_free(conn);
460                         *status = NT_STATUS_NO_SUCH_GROUP;
461                         return NULL;
462                 }
463         }
464 #endif /* HAVE_GETGRNAM */
465
466         {
467                 pstring s;
468                 pstrcpy(s,lp_pathname(snum));
469                 standard_sub_conn(conn,s,sizeof(s));
470                 string_set(&conn->connectpath,s);
471                 DEBUG(3,("Connect path is '%s' for service [%s]\n",s, lp_servicename(snum)));
472         }
473
474         if (conn->force_user || conn->force_group) {
475
476                 /* groups stuff added by ih */
477                 conn->ngroups = 0;
478                 conn->groups = NULL;
479                 
480                 /* Find all the groups this uid is in and
481                    store them. Used by change_to_user() */
482                 initialise_groups(conn->user, conn->uid, conn->gid); 
483                 get_current_groups(conn->gid, &conn->ngroups,&conn->groups);
484                 
485                 conn->nt_user_token = create_nt_token(conn->uid, conn->gid, 
486                                                       conn->ngroups, conn->groups,
487                                                       guest);
488         }
489
490         /*
491          * New code to check if there's a share security descripter
492          * added from NT server manager. This is done after the
493          * smb.conf checks are done as we need a uid and token. JRA.
494          *
495          */
496
497         {
498                 BOOL can_write = share_access_check(conn, snum, vuser, FILE_WRITE_DATA);
499
500                 if (!can_write) {
501                         if (!share_access_check(conn, snum, vuser, FILE_READ_DATA)) {
502                                 /* No access, read or write. */
503                                 DEBUG(0,( "make_connection: connection to %s denied due to security descriptor.\n",
504                                           lp_servicename(snum)));
505                                 conn_free(conn);
506                                 *status = NT_STATUS_ACCESS_DENIED;
507                                 return NULL;
508                         } else {
509                                 conn->read_only = True;
510                         }
511                 }
512         }
513         /* Initialise VFS function pointers */
514
515         if (!smbd_vfs_init(conn)) {
516                 DEBUG(0, ("vfs_init failed for service %s\n", lp_servicename(SNUM(conn))));
517                 conn_free(conn);
518                 *status = NT_STATUS_BAD_NETWORK_NAME;
519                 return NULL;
520         }
521
522         /*
523          * If widelinks are disallowed we need to canonicalise the
524          * connect path here to ensure we don't have any symlinks in
525          * the connectpath. We will be checking all paths on this
526          * connection are below this directory. We must do this after
527          * the VFS init as we depend on the realpath() pointer in the vfs table. JRA.
528          */
529         if (!lp_widelinks(snum)) {
530                 pstring s;
531                 pstrcpy(s,conn->connectpath);
532                 canonicalize_path(conn, s);
533                 string_set(&conn->connectpath,s);
534         }
535
536 /* ROOT Activities: */  
537         /* check number of connections */
538         if (!claim_connection(conn,
539                               lp_servicename(SNUM(conn)),
540                               lp_max_connections(SNUM(conn)),
541                               False,0)) {
542                 DEBUG(1,("too many connections - rejected\n"));
543                 conn_free(conn);
544                 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
545                 return NULL;
546         }  
547
548         /* Preexecs are done here as they might make the dir we are to ChDir to below */
549         /* execute any "root preexec = " line */
550         if (*lp_rootpreexec(SNUM(conn))) {
551                 int ret;
552                 pstring cmd;
553                 pstrcpy(cmd,lp_rootpreexec(SNUM(conn)));
554                 standard_sub_conn(conn,cmd,sizeof(cmd));
555                 DEBUG(5,("cmd=%s\n",cmd));
556                 ret = smbrun(cmd,NULL);
557                 if (ret != 0 && lp_rootpreexec_close(SNUM(conn))) {
558                         DEBUG(1,("root preexec gave %d - failing connection\n", ret));
559                         yield_connection(conn, lp_servicename(SNUM(conn)));
560                         conn_free(conn);
561                         *status = NT_STATUS_ACCESS_DENIED;
562                         return NULL;
563                 }
564         }
565
566 /* USER Activites: */
567         if (!change_to_user(conn, conn->vuid)) {
568                 /* No point continuing if they fail the basic checks */
569                 DEBUG(0,("Can't become connected user!\n"));
570                 conn_free(conn);
571                 *status = NT_STATUS_LOGON_FAILURE;
572                 return NULL;
573         }
574
575         /* Remember that a different vuid can connect later without these checks... */
576         
577         /* Preexecs are done here as they might make the dir we are to ChDir to below */
578         /* execute any "preexec = " line */
579         if (*lp_preexec(SNUM(conn))) {
580                 int ret;
581                 pstring cmd;
582                 pstrcpy(cmd,lp_preexec(SNUM(conn)));
583                 standard_sub_conn(conn,cmd,sizeof(cmd));
584                 ret = smbrun(cmd,NULL);
585                 if (ret != 0 && lp_preexec_close(SNUM(conn))) {
586                         DEBUG(1,("preexec gave %d - failing connection\n", ret));
587                         change_to_root_user();
588                         yield_connection(conn, lp_servicename(SNUM(conn)));
589                         conn_free(conn);
590                         *status = NT_STATUS_ACCESS_DENIED;
591                         return NULL;
592                 }
593         }
594
595 #ifdef WITH_FAKE_KASERVER
596         if (lp_afs_share(SNUM(conn))) {
597                 afs_login(conn);
598         }
599 #endif
600         
601 #if CHECK_PATH_ON_TCONX
602         /* win2000 does not check the permissions on the directory
603            during the tree connect, instead relying on permission
604            check during individual operations. To match this behaviour
605            I have disabled this chdir check (tridge) */
606         if (vfs_ChDir(conn,conn->connectpath) != 0) {
607                 DEBUG(0,("%s (%s) Can't change directory to %s (%s)\n",
608                          get_remote_machine_name(), conn->client_address,
609                          conn->connectpath,strerror(errno)));
610                 change_to_root_user();
611                 yield_connection(conn, lp_servicename(SNUM(conn)));
612                 conn_free(conn);
613                 *status = NT_STATUS_BAD_NETWORK_NAME;
614                 return NULL;
615         }
616 #else
617         /* the alternative is just to check the directory exists */
618         if (stat(conn->connectpath, &st) != 0 || !S_ISDIR(st.st_mode)) {
619                 DEBUG(0,("'%s' does not exist or is not a directory, when connecting to [%s]\n", conn->connectpath, lp_servicename(SNUM(conn))));
620                 change_to_root_user();
621                 yield_connection(conn, lp_servicename(SNUM(conn)));
622                 conn_free(conn);
623                 *status = NT_STATUS_BAD_NETWORK_NAME;
624                 return NULL;
625         }
626 #endif
627         
628         string_set(&conn->origpath,conn->connectpath);
629         
630 #if SOFTLINK_OPTIMISATION
631         /* resolve any soft links early if possible */
632         if (vfs_ChDir(conn,conn->connectpath) == 0) {
633                 pstring s;
634                 pstrcpy(s,conn->connectpath);
635                 vfs_GetWd(conn,s);
636                 string_set(&conn->connectpath,s);
637                 vfs_ChDir(conn,conn->connectpath);
638         }
639 #endif
640         
641         /*
642          * Print out the 'connected as' stuff here as we need
643          * to know the effective uid and gid we will be using
644          * (at least initially).
645          */
646
647         if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
648                 dbgtext( "%s (%s) ", get_remote_machine_name(), conn->client_address );
649                 dbgtext( "%s", srv_is_signing_active() ? "signed " : "");
650                 dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)) );
651                 dbgtext( "initially as user %s ", user );
652                 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
653                 dbgtext( "(pid %d)\n", (int)sys_getpid() );
654         }
655         
656         /* Add veto/hide lists */
657         if (!IS_IPC(conn) && !IS_PRINT(conn)) {
658                 set_namearray( &conn->veto_list, lp_veto_files(SNUM(conn)));
659                 set_namearray( &conn->hide_list, lp_hide_files(SNUM(conn)));
660                 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(SNUM(conn)));
661         }
662         
663         /* Invoke VFS make connection hook */
664
665         if (SMB_VFS_CONNECT(conn, lp_servicename(snum), user) < 0) {
666                 DEBUG(0,("make_connection: VFS make connection failed!\n"));
667                 change_to_root_user();
668                 conn_free(conn);
669                 *status = NT_STATUS_UNSUCCESSFUL;
670                 return NULL;
671         }
672
673         /* we've finished with the user stuff - go back to root */
674         change_to_root_user();
675             
676         return(conn);
677 }
678
679 /***************************************************************************************
680  Simple wrapper function for make_connection() to include a call to 
681  vfs_chdir()
682  **************************************************************************************/
683  
684 connection_struct *make_connection_with_chdir(const char *service_in, DATA_BLOB password, 
685                                    const char *dev, uint16 vuid, NTSTATUS *status)
686 {
687         connection_struct *conn = NULL;
688         
689         conn = make_connection(service_in, password, dev, vuid, status);
690         
691         /*
692          * make_connection() does not change the directory for us any more
693          * so we have to do it as a separate step  --jerry
694          */
695          
696         if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) {
697                 DEBUG(0,("move_driver_to_download_area: Can't change directory to %s for [print$] (%s)\n",
698                          conn->connectpath,strerror(errno)));
699                 yield_connection(conn, lp_servicename(SNUM(conn)));
700                 conn_free(conn);
701                 *status = NT_STATUS_UNSUCCESSFUL;
702                 return NULL;
703         }
704         
705         return conn;
706 }
707
708 /****************************************************************************
709  Make a connection to a service.
710  *
711  * @param service 
712 ****************************************************************************/
713
714 connection_struct *make_connection(const char *service_in, DATA_BLOB password, 
715                                    const char *pdev, uint16 vuid, NTSTATUS *status)
716 {
717         uid_t euid;
718         user_struct *vuser = NULL;
719         fstring service;
720         fstring dev;
721         int snum = -1;
722
723         fstrcpy(dev, pdev);
724
725         /* This must ONLY BE CALLED AS ROOT. As it exits this function as root. */
726         if (!non_root_mode() && (euid = geteuid()) != 0) {
727                 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot (%u)\n", (unsigned int)euid ));
728                 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
729         }
730
731         if(lp_security() != SEC_SHARE) {
732                 vuser = get_valid_user_struct(vuid);
733                 if (!vuser) {
734                         DEBUG(1,("make_connection: refusing to connect with no session setup\n"));
735                         *status = NT_STATUS_ACCESS_DENIED;
736                         return NULL;
737                 }
738         }
739
740         /* Logic to try and connect to the correct [homes] share, preferably without too many
741            getpwnam() lookups.  This is particulary nasty for winbind usernames, where the
742            share name isn't the same as unix username.
743
744            The snum of the homes share is stored on the vuser at session setup time.
745         */
746
747         if (strequal(service_in,HOMES_NAME)) {
748                 if(lp_security() != SEC_SHARE) {
749                         DATA_BLOB no_pw = data_blob(NULL, 0);
750                         if (vuser->homes_snum == -1) {
751                                 DEBUG(2, ("[homes] share not available for this user because it was not found or created at session setup time\n"));
752                                 *status = NT_STATUS_BAD_NETWORK_NAME;
753                                 return NULL;
754                         }
755                         DEBUG(5, ("making a connection to [homes] service created at session setup time\n"));
756                         return make_connection_snum(vuser->homes_snum,
757                                                     vuser, no_pw, 
758                                                     dev, status);
759                 } else {
760                         /* Security = share. Try with current_user_info.smb_name
761                          * as the username.  */
762                         if (*current_user_info.smb_name) {
763                                 fstring unix_username;
764                                 fstrcpy(unix_username,
765                                         current_user_info.smb_name);
766                                 map_username(unix_username);
767                                 snum = find_service(unix_username);
768                         } 
769                         if (snum != -1) {
770                                 DEBUG(5, ("making a connection to 'homes' service %s based on security=share\n", service_in));
771                                 return make_connection_snum(snum, NULL,
772                                                             password,
773                                                             dev, status);
774                         }
775                 }
776         } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
777                    && strequal(service_in, lp_servicename(vuser->homes_snum))) {
778                 DATA_BLOB no_pw = data_blob(NULL, 0);
779                 DEBUG(5, ("making a connection to 'homes' service [%s] created at session setup time\n", service_in));
780                 return make_connection_snum(vuser->homes_snum,
781                                             vuser, no_pw, 
782                                             dev, status);
783         }
784         
785         fstrcpy(service, service_in);
786
787         strlower_m(service);
788
789         snum = find_service(service);
790
791         if (snum < 0) {
792                 if (strequal(service,"IPC$") || strequal(service,"ADMIN$")) {
793                         DEBUG(3,("refusing IPC connection to %s\n", service));
794                         *status = NT_STATUS_ACCESS_DENIED;
795                         return NULL;
796                 }
797
798                 DEBUG(0,("%s (%s) couldn't find service %s\n",
799                          get_remote_machine_name(), client_addr(), service));
800                 *status = NT_STATUS_BAD_NETWORK_NAME;
801                 return NULL;
802         }
803
804         /* Handle non-Dfs clients attempting connections to msdfs proxy */
805         if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0'))  {
806                 DEBUG(3, ("refusing connection to dfs proxy share '%s' (pointing to %s)\n", 
807                         service, lp_msdfs_proxy(snum)));
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
880                 /* Never remove PRINTERS_NAME */
881
882                 if ( snum == printersServiceNum)
883                         continue;
884                 pname = lp_printername( snum);
885
886                 /* Is snum an autoloaded print service and still 
887                    in the printing subsystem? */
888
889                 if ( lp_snum_ok(snum) 
890                         && lp_print_ok(snum) 
891                         && lp_autoloaded(snum)
892                         && !pcap_printername_ok( pname, NULL)) 
893                 {
894                         DEBUG( 3, ( "Removing printer: %s\n", pname));
895                         lp_killservice( snum);
896                 }
897         }
898 }