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