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