r6497: Ensure yield_connection() is called on all appropriate error conditions.
[jerry/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 char magic_char;
24 extern struct timeval smb_last_time;
25 extern userdom_struct current_user_info;
26
27
28 /****************************************************************************
29  Load parameters specific to a connection/service.
30 ****************************************************************************/
31
32 BOOL set_current_service(connection_struct *conn, uint16 flags, BOOL do_chdir)
33 {
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         SMB_STRUCT_STAT st;
276         fstring user;
277         fstring dev;
278
279         *user = 0;
280         fstrcpy(dev, pdev);
281         ZERO_STRUCT(st);
282
283         if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, dev))) {
284                 return NULL;
285         }       
286
287         conn = conn_new();
288         if (!conn) {
289                 DEBUG(0,("Couldn't find free connection.\n"));
290                 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
291                 return NULL;
292         }
293
294         if (lp_guest_only(snum)) {
295                 const char *guestname = lp_guestaccount();
296                 guest = True;
297                 pass = getpwnam_alloc(guestname);
298                 if (!pass) {
299                         DEBUG(0,("make_connection_snum: Invalid guest account %s??\n",guestname));
300                         conn_free(conn);
301                         *status = NT_STATUS_NO_SUCH_USER;
302                         return NULL;
303                 }
304                 fstrcpy(user,pass->pw_name);
305                 conn->force_user = True;
306                 conn->uid = pass->pw_uid;
307                 conn->gid = pass->pw_gid;
308                 string_set(&conn->user,pass->pw_name);
309                 passwd_free(&pass);
310                 DEBUG(3,("Guest only user %s\n",user));
311         } else if (vuser) {
312                 if (vuser->guest) {
313                         if (!lp_guest_ok(snum)) {
314                                 DEBUG(2, ("guest user (from session setup) not permitted to access this share (%s)\n", lp_servicename(snum)));
315                                       conn_free(conn);
316                                       *status = NT_STATUS_ACCESS_DENIED;
317                                       return NULL;
318                         }
319                 } else {
320                         if (!user_ok(vuser->user.unix_name, snum, vuser->groups, vuser->n_groups)) {
321                                 DEBUG(2, ("user '%s' (from session setup) not permitted to access this share (%s)\n", vuser->user.unix_name, lp_servicename(snum)));
322                                 conn_free(conn);
323                                 *status = NT_STATUS_ACCESS_DENIED;
324                                 return NULL;
325                         }
326                 }
327                 conn->vuid = vuser->vuid;
328                 conn->uid = vuser->uid;
329                 conn->gid = vuser->gid;
330                 string_set(&conn->user,vuser->user.unix_name);
331                 fstrcpy(user,vuser->user.unix_name);
332                 guest = vuser->guest; 
333         } else if (lp_security() == SEC_SHARE) {
334                 /* add it as a possible user name if we 
335                    are in share mode security */
336                 add_session_user(lp_servicename(snum));
337                 /* shall we let them in? */
338                 if (!authorise_login(snum,user,password,&guest)) {
339                         DEBUG( 2, ( "Invalid username/password for [%s]\n", 
340                                     lp_servicename(snum)) );
341                         conn_free(conn);
342                         *status = NT_STATUS_WRONG_PASSWORD;
343                         return NULL;
344                 }
345                 pass = Get_Pwnam(user);
346                 conn->force_user = True;
347                 conn->uid = pass->pw_uid;
348                 conn->gid = pass->pw_gid;
349                 string_set(&conn->user, pass->pw_name);
350                 fstrcpy(user, pass->pw_name);
351
352         } else {
353                 DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
354                 conn_free(conn);
355                 *status = NT_STATUS_ACCESS_DENIED;
356                 return NULL;
357         }
358
359         add_session_user(user);
360
361         safe_strcpy(conn->client_address, client_addr(), 
362                     sizeof(conn->client_address)-1);
363         conn->num_files_open = 0;
364         conn->lastused = time(NULL);
365         conn->service = snum;
366         conn->used = True;
367         conn->printer = (strncmp(dev,"LPT",3) == 0);
368         conn->ipc = ((strncmp(dev,"IPC",3) == 0) || strequal(dev,"ADMIN$"));
369         conn->dirptr = NULL;
370
371         /* Case options for the share. */
372         if (lp_casesensitive(snum) == Auto) {
373                 /* We will be setting this per packet. Set to be case insensitive for now. */
374                 conn->case_sensitive = False;
375         } else {
376                 conn->case_sensitive = (BOOL)lp_casesensitive(snum);
377         }
378
379         conn->case_preserve = lp_preservecase(snum);
380         conn->short_case_preserve = lp_shortpreservecase(snum);
381
382         conn->veto_list = NULL;
383         conn->hide_list = NULL;
384         conn->veto_oplock_list = NULL;
385         string_set(&conn->dirpath,"");
386         string_set(&conn->user,user);
387         conn->nt_user_token = NULL;
388
389         conn->read_only = lp_readonly(conn->service);
390         conn->admin_user = False;
391
392         /*
393          * If force user is true, then store the
394          * given userid and also the groups
395          * of the user we're forcing.
396          */
397         
398         if (*lp_force_user(snum)) {
399                 struct passwd *pass2;
400                 pstring fuser;
401                 pstrcpy(fuser,lp_force_user(snum));
402
403                 /* Allow %S to be used by force user. */
404                 pstring_sub(fuser,"%S",lp_servicename(snum));
405
406                 pass2 = (struct passwd *)Get_Pwnam(fuser);
407                 if (pass2) {
408                         conn->uid = pass2->pw_uid;
409                         conn->gid = pass2->pw_gid;
410                         string_set(&conn->user,pass2->pw_name);
411                         fstrcpy(user,pass2->pw_name);
412                         conn->force_user = True;
413                         DEBUG(3,("Forced user %s\n",user));       
414                 } else {
415                         DEBUG(1,("Couldn't find user %s\n",fuser));
416                         conn_free(conn);
417                         *status = NT_STATUS_NO_SUCH_USER;
418                         return NULL;
419                 }
420         }
421
422 #ifdef HAVE_GETGRNAM 
423         /*
424          * If force group is true, then override
425          * any groupid stored for the connecting user.
426          */
427         
428         if (*lp_force_group(snum)) {
429                 gid_t gid;
430                 pstring gname;
431                 pstring tmp_gname;
432                 BOOL user_must_be_member = False;
433                 
434                 pstrcpy(tmp_gname,lp_force_group(snum));
435                 
436                 if (tmp_gname[0] == '+') {
437                         user_must_be_member = True;
438                         /* even now, tmp_gname is null terminated */
439                         pstrcpy(gname,&tmp_gname[1]);
440                 } else {
441                         pstrcpy(gname,tmp_gname);
442                 }
443                 /* default service may be a group name          */
444                 pstring_sub(gname,"%S",lp_servicename(snum));
445                 gid = nametogid(gname);
446                 
447                 if (gid != (gid_t)-1) {
448
449                         /*
450                          * If the user has been forced and the forced group starts
451                          * with a '+', then we only set the group to be the forced
452                          * group if the forced user is a member of that group.
453                          * Otherwise, the meaning of the '+' would be ignored.
454                          */
455                         if (conn->force_user && user_must_be_member) {
456                                 if (user_in_group_list( user, gname, NULL, 0)) {
457                                                 conn->gid = gid;
458                                                 DEBUG(3,("Forced group %s for member %s\n",gname,user));
459                                 }
460                         } else {
461                                 conn->gid = gid;
462                                 DEBUG(3,("Forced group %s\n",gname));
463                         }
464                         conn->force_group = True;
465                 } else {
466                         DEBUG(1,("Couldn't find group %s\n",gname));
467                         conn_free(conn);
468                         *status = NT_STATUS_NO_SUCH_GROUP;
469                         return NULL;
470                 }
471         }
472 #endif /* HAVE_GETGRNAM */
473
474         {
475                 pstring s;
476                 pstrcpy(s,lp_pathname(snum));
477                 standard_sub_conn(conn,s,sizeof(s));
478                 string_set(&conn->connectpath,s);
479                 DEBUG(3,("Connect path is '%s' for service [%s]\n",s, lp_servicename(snum)));
480         }
481
482         if (conn->force_user || conn->force_group) {
483
484                 /* groups stuff added by ih */
485                 conn->ngroups = 0;
486                 conn->groups = NULL;
487                 
488                 /* Find all the groups this uid is in and
489                    store them. Used by change_to_user() */
490                 initialise_groups(conn->user, conn->uid, conn->gid); 
491                 get_current_groups(conn->gid, &conn->ngroups,&conn->groups);
492                 
493                 conn->nt_user_token = create_nt_token(conn->uid, conn->gid, 
494                                                       conn->ngroups, conn->groups,
495                                                       guest);
496         }
497
498         /*
499          * New code to check if there's a share security descripter
500          * added from NT server manager. This is done after the
501          * smb.conf checks are done as we need a uid and token. JRA.
502          *
503          */
504
505         {
506                 BOOL can_write = share_access_check(conn, snum, vuser, FILE_WRITE_DATA);
507
508                 if (!can_write) {
509                         if (!share_access_check(conn, snum, vuser, FILE_READ_DATA)) {
510                                 /* No access, read or write. */
511                                 DEBUG(0,( "make_connection: connection to %s denied due to security descriptor.\n",
512                                           lp_servicename(snum)));
513                                 conn_free(conn);
514                                 *status = NT_STATUS_ACCESS_DENIED;
515                                 return NULL;
516                         } else {
517                                 conn->read_only = True;
518                         }
519                 }
520         }
521         /* Initialise VFS function pointers */
522
523         if (!smbd_vfs_init(conn)) {
524                 DEBUG(0, ("vfs_init failed for service %s\n", lp_servicename(snum)));
525                 conn_free(conn);
526                 *status = NT_STATUS_BAD_NETWORK_NAME;
527                 return NULL;
528         }
529
530         /*
531          * If widelinks are disallowed we need to canonicalise the
532          * connect path here to ensure we don't have any symlinks in
533          * the connectpath. We will be checking all paths on this
534          * connection are below this directory. We must do this after
535          * the VFS init as we depend on the realpath() pointer in the vfs table. JRA.
536          */
537         if (!lp_widelinks(snum)) {
538                 pstring s;
539                 pstrcpy(s,conn->connectpath);
540                 canonicalize_path(conn, s);
541                 string_set(&conn->connectpath,s);
542         }
543
544 /* ROOT Activities: */  
545         /* check number of connections */
546         if (!claim_connection(conn,
547                               lp_servicename(snum),
548                               lp_max_connections(snum),
549                               False,0)) {
550                 DEBUG(1,("too many connections - rejected\n"));
551                 conn_free(conn);
552                 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
553                 return NULL;
554         }  
555
556         /* Preexecs are done here as they might make the dir we are to ChDir to below */
557         /* execute any "root preexec = " line */
558         if (*lp_rootpreexec(snum)) {
559                 int ret;
560                 pstring cmd;
561                 pstrcpy(cmd,lp_rootpreexec(snum));
562                 standard_sub_conn(conn,cmd,sizeof(cmd));
563                 DEBUG(5,("cmd=%s\n",cmd));
564                 ret = smbrun(cmd,NULL);
565                 if (ret != 0 && lp_rootpreexec_close(snum)) {
566                         DEBUG(1,("root preexec gave %d - failing connection\n", ret));
567                         yield_connection(conn, lp_servicename(snum));
568                         conn_free(conn);
569                         *status = NT_STATUS_ACCESS_DENIED;
570                         return NULL;
571                 }
572         }
573
574 /* USER Activites: */
575         if (!change_to_user(conn, conn->vuid)) {
576                 /* No point continuing if they fail the basic checks */
577                 DEBUG(0,("Can't become connected user!\n"));
578                 yield_connection(conn, lp_servicename(snum));
579                 conn_free(conn);
580                 *status = NT_STATUS_LOGON_FAILURE;
581                 return NULL;
582         }
583
584         /* Remember that a different vuid can connect later without these checks... */
585         
586         /* Preexecs are done here as they might make the dir we are to ChDir to below */
587         /* execute any "preexec = " line */
588         if (*lp_preexec(snum)) {
589                 int ret;
590                 pstring cmd;
591                 pstrcpy(cmd,lp_preexec(snum));
592                 standard_sub_conn(conn,cmd,sizeof(cmd));
593                 ret = smbrun(cmd,NULL);
594                 if (ret != 0 && lp_preexec_close(snum)) {
595                         DEBUG(1,("preexec gave %d - failing connection\n", ret));
596                         change_to_root_user();
597                         yield_connection(conn, lp_servicename(snum));
598                         conn_free(conn);
599                         *status = NT_STATUS_ACCESS_DENIED;
600                         return NULL;
601                 }
602         }
603
604 #ifdef WITH_FAKE_KASERVER
605         if (lp_afs_share(snum)) {
606                 afs_login(conn);
607         }
608 #endif
609         
610         /* win2000 does not check the permissions on the directory
611            during the tree connect, instead relying on permission
612            check during individual operations. To match this behaviour
613            I have disabled this chdir check (tridge) */
614         /* the alternative is just to check the directory exists */
615         if (SMB_VFS_STAT(conn, conn->connectpath, &st) != 0 || !S_ISDIR(st.st_mode)) {
616                 DEBUG(0,("'%s' does not exist or is not a directory, when connecting to [%s]\n", conn->connectpath, lp_servicename(snum)));
617                 change_to_root_user();
618                 yield_connection(conn, lp_servicename(snum));
619                 conn_free(conn);
620                 *status = NT_STATUS_BAD_NETWORK_NAME;
621                 return NULL;
622         }
623         
624         string_set(&conn->origpath,conn->connectpath);
625         
626 #if SOFTLINK_OPTIMISATION
627         /* resolve any soft links early if possible */
628         if (vfs_ChDir(conn,conn->connectpath) == 0) {
629                 pstring s;
630                 pstrcpy(s,conn->connectpath);
631                 vfs_GetWd(conn,s);
632                 string_set(&conn->connectpath,s);
633                 vfs_ChDir(conn,conn->connectpath);
634         }
635 #endif
636         
637         /*
638          * Print out the 'connected as' stuff here as we need
639          * to know the effective uid and gid we will be using
640          * (at least initially).
641          */
642
643         if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
644                 dbgtext( "%s (%s) ", get_remote_machine_name(), conn->client_address );
645                 dbgtext( "%s", srv_is_signing_active() ? "signed " : "");
646                 dbgtext( "connect to service %s ", lp_servicename(snum) );
647                 dbgtext( "initially as user %s ", user );
648                 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
649                 dbgtext( "(pid %d)\n", (int)sys_getpid() );
650         }
651         
652         /* Add veto/hide lists */
653         if (!IS_IPC(conn) && !IS_PRINT(conn)) {
654                 set_namearray( &conn->veto_list, lp_veto_files(snum));
655                 set_namearray( &conn->hide_list, lp_hide_files(snum));
656                 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(snum));
657         }
658         
659         /* Invoke VFS make connection hook */
660
661         if (SMB_VFS_CONNECT(conn, lp_servicename(snum), user) < 0) {
662                 DEBUG(0,("make_connection: VFS make connection failed!\n"));
663                 change_to_root_user();
664                 yield_connection(conn, lp_servicename(snum));
665                 conn_free(conn);
666                 *status = NT_STATUS_UNSUCCESSFUL;
667                 return NULL;
668         }
669
670         /* we've finished with the user stuff - go back to root */
671         change_to_root_user();
672             
673         return(conn);
674 }
675
676 /***************************************************************************************
677  Simple wrapper function for make_connection() to include a call to 
678  vfs_chdir()
679  **************************************************************************************/
680  
681 connection_struct *make_connection_with_chdir(const char *service_in, DATA_BLOB password, 
682                                    const char *dev, uint16 vuid, NTSTATUS *status)
683 {
684         connection_struct *conn = NULL;
685         
686         conn = make_connection(service_in, password, dev, vuid, status);
687         
688         /*
689          * make_connection() does not change the directory for us any more
690          * so we have to do it as a separate step  --jerry
691          */
692          
693         if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) {
694                 DEBUG(0,("move_driver_to_download_area: Can't change directory to %s for [print$] (%s)\n",
695                          conn->connectpath,strerror(errno)));
696                 yield_connection(conn, lp_servicename(SNUM(conn)));
697                 conn_free(conn);
698                 *status = NT_STATUS_UNSUCCESSFUL;
699                 return NULL;
700         }
701         
702         return conn;
703 }
704
705 /****************************************************************************
706  Make a connection to a service.
707  *
708  * @param service 
709 ****************************************************************************/
710
711 connection_struct *make_connection(const char *service_in, DATA_BLOB password, 
712                                    const char *pdev, uint16 vuid, NTSTATUS *status)
713 {
714         uid_t euid;
715         user_struct *vuser = NULL;
716         fstring service;
717         fstring dev;
718         int snum = -1;
719
720         fstrcpy(dev, pdev);
721
722         /* This must ONLY BE CALLED AS ROOT. As it exits this function as root. */
723         if (!non_root_mode() && (euid = geteuid()) != 0) {
724                 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot (%u)\n", (unsigned int)euid ));
725                 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
726         }
727
728         if(lp_security() != SEC_SHARE) {
729                 vuser = get_valid_user_struct(vuid);
730                 if (!vuser) {
731                         DEBUG(1,("make_connection: refusing to connect with no session setup\n"));
732                         *status = NT_STATUS_ACCESS_DENIED;
733                         return NULL;
734                 }
735         }
736
737         /* Logic to try and connect to the correct [homes] share, preferably without too many
738            getpwnam() lookups.  This is particulary nasty for winbind usernames, where the
739            share name isn't the same as unix username.
740
741            The snum of the homes share is stored on the vuser at session setup time.
742         */
743
744         if (strequal(service_in,HOMES_NAME)) {
745                 if(lp_security() != SEC_SHARE) {
746                         DATA_BLOB no_pw = data_blob(NULL, 0);
747                         if (vuser->homes_snum == -1) {
748                                 DEBUG(2, ("[homes] share not available for this user because it was not found or created at session setup time\n"));
749                                 *status = NT_STATUS_BAD_NETWORK_NAME;
750                                 return NULL;
751                         }
752                         DEBUG(5, ("making a connection to [homes] service created at session setup time\n"));
753                         return make_connection_snum(vuser->homes_snum,
754                                                     vuser, no_pw, 
755                                                     dev, status);
756                 } else {
757                         /* Security = share. Try with current_user_info.smb_name
758                          * as the username.  */
759                         if (*current_user_info.smb_name) {
760                                 fstring unix_username;
761                                 fstrcpy(unix_username,
762                                         current_user_info.smb_name);
763                                 map_username(unix_username);
764                                 snum = find_service(unix_username);
765                         } 
766                         if (snum != -1) {
767                                 DEBUG(5, ("making a connection to 'homes' service %s based on security=share\n", service_in));
768                                 return make_connection_snum(snum, NULL,
769                                                             password,
770                                                             dev, status);
771                         }
772                 }
773         } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
774                    && strequal(service_in, lp_servicename(vuser->homes_snum))) {
775                 DATA_BLOB no_pw = data_blob(NULL, 0);
776                 DEBUG(5, ("making a connection to 'homes' service [%s] created at session setup time\n", service_in));
777                 return make_connection_snum(vuser->homes_snum,
778                                             vuser, no_pw, 
779                                             dev, status);
780         }
781         
782         fstrcpy(service, service_in);
783
784         strlower_m(service);
785
786         snum = find_service(service);
787
788         if (snum < 0) {
789                 if (strequal(service,"IPC$") || strequal(service,"ADMIN$")) {
790                         DEBUG(3,("refusing IPC connection to %s\n", service));
791                         *status = NT_STATUS_ACCESS_DENIED;
792                         return NULL;
793                 }
794
795                 DEBUG(0,("%s (%s) couldn't find service %s\n",
796                          get_remote_machine_name(), client_addr(), service));
797                 *status = NT_STATUS_BAD_NETWORK_NAME;
798                 return NULL;
799         }
800
801         /* Handle non-Dfs clients attempting connections to msdfs proxy */
802         if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0'))  {
803                 DEBUG(3, ("refusing connection to dfs proxy share '%s' (pointing to %s)\n", 
804                         service, lp_msdfs_proxy(snum)));
805                 *status = NT_STATUS_BAD_NETWORK_NAME;
806                 return NULL;
807         }
808
809         DEBUG(5, ("making a connection to 'normal' service %s\n", service));
810
811         return make_connection_snum(snum, vuser,
812                                     password,
813                                     dev, status);
814 }
815
816 /****************************************************************************
817  Close a cnum.
818 ****************************************************************************/
819
820 void close_cnum(connection_struct *conn, uint16 vuid)
821 {
822         if (IS_IPC(conn)) {
823                 pipe_close_conn(conn);
824         } else {
825                 file_close_conn(conn);
826                 dptr_closecnum(conn);
827         }
828
829         change_to_root_user();
830
831         DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
832                                  get_remote_machine_name(),conn->client_address,
833                                  lp_servicename(SNUM(conn))));
834
835         /* Call VFS disconnect hook */    
836         SMB_VFS_DISCONNECT(conn);
837
838         yield_connection(conn, lp_servicename(SNUM(conn)));
839
840         /* make sure we leave the directory available for unmount */
841         vfs_ChDir(conn, "/");
842
843         /* execute any "postexec = " line */
844         if (*lp_postexec(SNUM(conn)) && 
845             change_to_user(conn, vuid))  {
846                 pstring cmd;
847                 pstrcpy(cmd,lp_postexec(SNUM(conn)));
848                 standard_sub_conn(conn,cmd,sizeof(cmd));
849                 smbrun(cmd,NULL);
850                 change_to_root_user();
851         }
852
853         change_to_root_user();
854         /* execute any "root postexec = " line */
855         if (*lp_rootpostexec(SNUM(conn)))  {
856                 pstring cmd;
857                 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
858                 standard_sub_conn(conn,cmd,sizeof(cmd));
859                 smbrun(cmd,NULL);
860         }
861
862         conn_free(conn);
863 }