r7963: Add aio support to 3.0.
[obnox/samba-ctdb.git] / source / smbd / service.c
1 /* 
2    Unix SMB/CIFS implementation.
3    service (connection) opening and closing
4    Copyright (C) Andrew Tridgell 1992-1998
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22
23 extern struct timeval smb_last_time;
24 extern userdom_struct current_user_info;
25
26 /****************************************************************************
27  Load parameters specific to a connection/service.
28 ****************************************************************************/
29
30 BOOL set_current_service(connection_struct *conn, uint16 flags, BOOL do_chdir)
31 {
32         static connection_struct *last_conn;
33         static uint16 last_flags;
34         int snum;
35
36         if (!conn)  {
37                 last_conn = NULL;
38                 return(False);
39         }
40
41         conn->lastused = smb_last_time.tv_sec;
42
43         snum = SNUM(conn);
44   
45         if (do_chdir &&
46             vfs_ChDir(conn,conn->connectpath) != 0 &&
47             vfs_ChDir(conn,conn->origpath) != 0) {
48                 DEBUG(0,("chdir (%s) failed\n",
49                          conn->connectpath));
50                 return(False);
51         }
52
53         if ((conn == last_conn) && (last_flags == flags)) {
54                 return(True);
55         }
56
57         last_conn = conn;
58         last_flags = flags;
59         
60         /* Obey the client case sensitivity requests - only for clients that support it. */
61         switch (lp_casesensitive(snum)) {
62                 case Auto:
63                         {
64                                 /* We need this uglyness due to DOS/Win9x clients that lie about case insensitivity. */
65                                 enum remote_arch_types ra_type = get_remote_arch();
66                                 if ((ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
67                                         /* Client can't support per-packet case sensitive pathnames. */
68                                         conn->case_sensitive = False;
69                                 } else {
70                                         conn->case_sensitive = !(flags & FLAG_CASELESS_PATHNAMES);
71                                 }
72                         }
73                         break;
74                 case True:
75                         conn->case_sensitive = True;
76                         break;
77                 default:
78                         conn->case_sensitive = False;
79                         break;
80         }
81         return(True);
82 }
83
84 /****************************************************************************
85  Add a home service. Returns the new service number or -1 if fail.
86 ****************************************************************************/
87
88 int add_home_service(const char *service, const char *username, const char *homedir)
89 {
90         int iHomeService;
91
92         if (!service || !homedir)
93                 return -1;
94
95         if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0)
96                 return -1;
97
98         /*
99          * If this is a winbindd provided username, remove
100          * the domain component before adding the service.
101          * Log a warning if the "path=" parameter does not
102          * include any macros.
103          */
104
105         {
106                 const char *p = strchr(service,*lp_winbind_separator());
107
108                 /* We only want the 'user' part of the string */
109                 if (p) {
110                         service = p + 1;
111                 }
112         }
113
114         if (!lp_add_home(service, iHomeService, username, homedir)) {
115                 return -1;
116         }
117         
118         return lp_servicenumber(service);
119
120 }
121
122
123 /**
124  * Find a service entry.
125  *
126  * @param service is modified (to canonical form??)
127  **/
128
129 int find_service(fstring service)
130 {
131         int iService;
132
133         all_string_sub(service,"\\","/",0);
134
135         iService = lp_servicenumber(service);
136
137         /* now handle the special case of a home directory */
138         if (iService < 0) {
139                 char *phome_dir = get_user_home_dir(service);
140
141                 if(!phome_dir) {
142                         /*
143                          * Try mapping the servicename, it may
144                          * be a Windows to unix mapped user name.
145                          */
146                         if(map_username(service))
147                                 phome_dir = get_user_home_dir(service);
148                 }
149
150                 DEBUG(3,("checking for home directory %s gave %s\n",service,
151                         phome_dir?phome_dir:"(NULL)"));
152
153                 iService = add_home_service(service,service /* 'username' */, phome_dir);
154         }
155
156         /* If we still don't have a service, attempt to add it as a printer. */
157         if (iService < 0) {
158                 int iPrinterService;
159
160                 if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) >= 0) {
161                         DEBUG(3,("checking whether %s is a valid printer name...\n", service));
162                         if (pcap_printername_ok(service)) {
163                                 DEBUG(3,("%s is a valid printer name\n", service));
164                                 DEBUG(3,("adding %s as a printer service\n", service));
165                                 lp_add_printer(service, iPrinterService);
166                                 iService = lp_servicenumber(service);
167                                 if (iService < 0) {
168                                         DEBUG(0,("failed to add %s as a printer service!\n", service));
169                                 }
170                         } else {
171                                 DEBUG(3,("%s is not a valid printer name\n", service));
172                         }
173                 }
174         }
175
176         /* Check for default vfs service?  Unsure whether to implement this */
177         if (iService < 0) {
178         }
179
180         /* just possibly it's a default service? */
181         if (iService < 0) {
182                 char *pdefservice = lp_defaultservice();
183                 if (pdefservice && *pdefservice && !strequal(pdefservice,service) && !strstr_m(service,"..")) {
184                         /*
185                          * We need to do a local copy here as lp_defaultservice() 
186                          * returns one of the rotating lp_string buffers that
187                          * could get overwritten by the recursive find_service() call
188                          * below. Fix from Josef Hinteregger <joehtg@joehtg.co.at>.
189                          */
190                         pstring defservice;
191                         pstrcpy(defservice, pdefservice);
192                         iService = find_service(defservice);
193                         if (iService >= 0) {
194                                 all_string_sub(service, "_","/",0);
195                                 iService = lp_add_service(service, iService);
196                         }
197                 }
198         }
199
200         if (iService >= 0) {
201                 if (!VALID_SNUM(iService)) {
202                         DEBUG(0,("Invalid snum %d for %s\n",iService, service));
203                         iService = -1;
204                 }
205         }
206
207         if (iService < 0)
208                 DEBUG(3,("find_service() failed to find service %s\n", service));
209
210         return (iService);
211 }
212
213
214 /****************************************************************************
215  do some basic sainity checks on the share.  
216  This function modifies dev, ecode.
217 ****************************************************************************/
218
219 static NTSTATUS share_sanity_checks(int snum, fstring dev) 
220 {
221         
222         if (!lp_snum_ok(snum) || 
223             !check_access(smbd_server_fd(), 
224                           lp_hostsallow(snum), lp_hostsdeny(snum))) {    
225                 return NT_STATUS_ACCESS_DENIED;
226         }
227
228         if (dev[0] == '?' || !dev[0]) {
229                 if (lp_print_ok(snum)) {
230                         fstrcpy(dev,"LPT1:");
231                 } else if (strequal(lp_fstype(snum), "IPC")) {
232                         fstrcpy(dev, "IPC");
233                 } else {
234                         fstrcpy(dev,"A:");
235                 }
236         }
237
238         strupper_m(dev);
239
240         if (lp_print_ok(snum)) {
241                 if (!strequal(dev, "LPT1:")) {
242                         return NT_STATUS_BAD_DEVICE_TYPE;
243                 }
244         } else if (strequal(lp_fstype(snum), "IPC")) {
245                 if (!strequal(dev, "IPC")) {
246                         return NT_STATUS_BAD_DEVICE_TYPE;
247                 }
248         } else if (!strequal(dev, "A:")) {
249                 return NT_STATUS_BAD_DEVICE_TYPE;
250         }
251
252         /* Behave as a printer if we are supposed to */
253         if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) {
254                 fstrcpy(dev, "LPT1:");
255         }
256
257         return NT_STATUS_OK;
258 }
259
260 /****************************************************************************
261   Make a connection, given the snum to connect to, and the vuser of the
262   connecting user if appropriate.
263 ****************************************************************************/
264
265 static connection_struct *make_connection_snum(int snum, user_struct *vuser,
266                                                DATA_BLOB password, 
267                                                const char *pdev, NTSTATUS *status)
268 {
269         struct passwd *pass = NULL;
270         BOOL guest = False;
271         connection_struct *conn;
272         SMB_STRUCT_STAT st;
273         fstring user;
274         fstring dev;
275
276         *user = 0;
277         fstrcpy(dev, pdev);
278         SET_STAT_INVALID(st);
279
280         if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, dev))) {
281                 return NULL;
282         }       
283
284         conn = conn_new();
285         if (!conn) {
286                 DEBUG(0,("Couldn't find free connection.\n"));
287                 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
288                 return NULL;
289         }
290
291         if (lp_guest_only(snum)) {
292                 const char *guestname = lp_guestaccount();
293                 guest = True;
294                 pass = getpwnam_alloc(guestname);
295                 if (!pass) {
296                         DEBUG(0,("make_connection_snum: Invalid guest account %s??\n",guestname));
297                         conn_free(conn);
298                         *status = NT_STATUS_NO_SUCH_USER;
299                         return NULL;
300                 }
301                 fstrcpy(user,pass->pw_name);
302                 conn->force_user = True;
303                 conn->uid = pass->pw_uid;
304                 conn->gid = pass->pw_gid;
305                 string_set(&conn->user,pass->pw_name);
306                 passwd_free(&pass);
307                 DEBUG(3,("Guest only user %s\n",user));
308         } else if (vuser) {
309                 if (vuser->guest) {
310                         if (!lp_guest_ok(snum)) {
311                                 DEBUG(2, ("guest user (from session setup) not permitted to access this share (%s)\n", lp_servicename(snum)));
312                                       conn_free(conn);
313                                       *status = NT_STATUS_ACCESS_DENIED;
314                                       return NULL;
315                         }
316                 } else {
317                         if (!user_ok(vuser->user.unix_name, snum, vuser->groups, vuser->n_groups)) {
318                                 DEBUG(2, ("user '%s' (from session setup) not permitted to access this share (%s)\n", vuser->user.unix_name, lp_servicename(snum)));
319                                 conn_free(conn);
320                                 *status = NT_STATUS_ACCESS_DENIED;
321                                 return NULL;
322                         }
323                 }
324                 conn->vuid = vuser->vuid;
325                 conn->uid = vuser->uid;
326                 conn->gid = vuser->gid;
327                 string_set(&conn->user,vuser->user.unix_name);
328                 fstrcpy(user,vuser->user.unix_name);
329                 guest = vuser->guest; 
330         } else if (lp_security() == SEC_SHARE) {
331                 /* add it as a possible user name if we 
332                    are in share mode security */
333                 add_session_user(lp_servicename(snum));
334                 /* shall we let them in? */
335                 if (!authorise_login(snum,user,password,&guest)) {
336                         DEBUG( 2, ( "Invalid username/password for [%s]\n", 
337                                     lp_servicename(snum)) );
338                         conn_free(conn);
339                         *status = NT_STATUS_WRONG_PASSWORD;
340                         return NULL;
341                 }
342                 pass = Get_Pwnam(user);
343                 conn->force_user = True;
344                 conn->uid = pass->pw_uid;
345                 conn->gid = pass->pw_gid;
346                 string_set(&conn->user, pass->pw_name);
347                 fstrcpy(user, pass->pw_name);
348
349         } else {
350                 DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
351                 conn_free(conn);
352                 *status = NT_STATUS_ACCESS_DENIED;
353                 return NULL;
354         }
355
356         add_session_user(user);
357
358         safe_strcpy(conn->client_address, client_addr(), 
359                     sizeof(conn->client_address)-1);
360         conn->num_files_open = 0;
361         conn->lastused = time(NULL);
362         conn->service = snum;
363         conn->used = True;
364         conn->printer = (strncmp(dev,"LPT",3) == 0);
365         conn->ipc = ( (strncmp(dev,"IPC",3) == 0) || ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) );
366         conn->dirptr = NULL;
367
368         /* Case options for the share. */
369         if (lp_casesensitive(snum) == Auto) {
370                 /* We will be setting this per packet. Set to be case insensitive for now. */
371                 conn->case_sensitive = False;
372         } else {
373                 conn->case_sensitive = (BOOL)lp_casesensitive(snum);
374         }
375
376         conn->case_preserve = lp_preservecase(snum);
377         conn->short_case_preserve = lp_shortpreservecase(snum);
378
379         conn->veto_list = NULL;
380         conn->hide_list = NULL;
381         conn->veto_oplock_list = NULL;
382         conn->aio_write_behind_list = NULL;
383         string_set(&conn->dirpath,"");
384         string_set(&conn->user,user);
385         conn->nt_user_token = NULL;
386
387         conn->read_only = lp_readonly(conn->service);
388         conn->admin_user = False;
389
390         /*
391          * If force user is true, then store the
392          * given userid and also the groups
393          * of the user we're forcing.
394          */
395         
396         if (*lp_force_user(snum)) {
397                 struct passwd *pass2;
398                 pstring fuser;
399                 pstrcpy(fuser,lp_force_user(snum));
400
401                 /* Allow %S to be used by force user. */
402                 pstring_sub(fuser,"%S",lp_servicename(snum));
403
404                 pass2 = (struct passwd *)Get_Pwnam(fuser);
405                 if (pass2) {
406                         conn->uid = pass2->pw_uid;
407                         conn->gid = pass2->pw_gid;
408                         string_set(&conn->user,pass2->pw_name);
409                         fstrcpy(user,pass2->pw_name);
410                         conn->force_user = True;
411                         DEBUG(3,("Forced user %s\n",user));       
412                 } else {
413                         DEBUG(1,("Couldn't find user %s\n",fuser));
414                         conn_free(conn);
415                         *status = NT_STATUS_NO_SUCH_USER;
416                         return NULL;
417                 }
418         }
419
420 #ifdef HAVE_GETGRNAM 
421         /*
422          * If force group is true, then override
423          * any groupid stored for the connecting user.
424          */
425         
426         if (*lp_force_group(snum)) {
427                 gid_t gid;
428                 pstring gname;
429                 pstring tmp_gname;
430                 BOOL user_must_be_member = False;
431                 
432                 pstrcpy(tmp_gname,lp_force_group(snum));
433                 
434                 if (tmp_gname[0] == '+') {
435                         user_must_be_member = True;
436                         /* even now, tmp_gname is null terminated */
437                         pstrcpy(gname,&tmp_gname[1]);
438                 } else {
439                         pstrcpy(gname,tmp_gname);
440                 }
441                 /* default service may be a group name          */
442                 pstring_sub(gname,"%S",lp_servicename(snum));
443                 gid = nametogid(gname);
444                 
445                 if (gid != (gid_t)-1) {
446
447                         /*
448                          * If the user has been forced and the forced group starts
449                          * with a '+', then we only set the group to be the forced
450                          * group if the forced user is a member of that group.
451                          * Otherwise, the meaning of the '+' would be ignored.
452                          */
453                         if (conn->force_user && user_must_be_member) {
454                                 if (user_in_group_list( user, gname, NULL, 0)) {
455                                                 conn->gid = gid;
456                                                 DEBUG(3,("Forced group %s for member %s\n",gname,user));
457                                 }
458                         } else {
459                                 conn->gid = gid;
460                                 DEBUG(3,("Forced group %s\n",gname));
461                         }
462                         conn->force_group = True;
463                 } else {
464                         DEBUG(1,("Couldn't find group %s\n",gname));
465                         conn_free(conn);
466                         *status = NT_STATUS_NO_SUCH_GROUP;
467                         return NULL;
468                 }
469         }
470 #endif /* HAVE_GETGRNAM */
471
472         {
473                 pstring s;
474                 pstrcpy(s,lp_pathname(snum));
475                 standard_sub_conn(conn,s,sizeof(s));
476                 string_set(&conn->connectpath,s);
477                 DEBUG(3,("Connect path is '%s' for service [%s]\n",s, lp_servicename(snum)));
478         }
479
480         if (conn->force_user || conn->force_group) {
481
482                 /* groups stuff added by ih */
483                 conn->ngroups = 0;
484                 conn->groups = NULL;
485                 
486                 /* Find all the groups this uid is in and
487                    store them. Used by change_to_user() */
488                 initialise_groups(conn->user, conn->uid, conn->gid); 
489                 get_current_groups(conn->gid, &conn->ngroups,&conn->groups);
490                 
491                 conn->nt_user_token = create_nt_token(conn->uid, conn->gid, 
492                                                       conn->ngroups, conn->groups,
493                                                       guest);
494         }
495
496         /*
497          * New code to check if there's a share security descripter
498          * added from NT server manager. This is done after the
499          * smb.conf checks are done as we need a uid and token. JRA.
500          *
501          */
502
503         {
504                 BOOL can_write = share_access_check(conn, snum, vuser, FILE_WRITE_DATA);
505
506                 if (!can_write) {
507                         if (!share_access_check(conn, snum, vuser, FILE_READ_DATA)) {
508                                 /* No access, read or write. */
509                                 DEBUG(0,( "make_connection: connection to %s denied due to security descriptor.\n",
510                                           lp_servicename(snum)));
511                                 conn_free(conn);
512                                 *status = NT_STATUS_ACCESS_DENIED;
513                                 return NULL;
514                         } else {
515                                 conn->read_only = True;
516                         }
517                 }
518         }
519         /* Initialise VFS function pointers */
520
521         if (!smbd_vfs_init(conn)) {
522                 DEBUG(0, ("vfs_init failed for service %s\n", lp_servicename(snum)));
523                 conn_free(conn);
524                 *status = NT_STATUS_BAD_NETWORK_NAME;
525                 return NULL;
526         }
527
528         /*
529          * If widelinks are disallowed we need to canonicalise the
530          * connect path here to ensure we don't have any symlinks in
531          * the connectpath. We will be checking all paths on this
532          * connection are below this directory. We must do this after
533          * the VFS init as we depend on the realpath() pointer in the vfs table. JRA.
534          */
535         if (!lp_widelinks(snum)) {
536                 pstring s;
537                 pstrcpy(s,conn->connectpath);
538                 canonicalize_path(conn, s);
539                 string_set(&conn->connectpath,s);
540         }
541
542 /* ROOT Activities: */  
543         /* check number of connections */
544         if (!claim_connection(conn,
545                               lp_servicename(snum),
546                               lp_max_connections(snum),
547                               False,0)) {
548                 DEBUG(1,("too many connections - rejected\n"));
549                 conn_free(conn);
550                 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
551                 return NULL;
552         }  
553
554         /* Preexecs are done here as they might make the dir we are to ChDir to below */
555         /* execute any "root preexec = " line */
556         if (*lp_rootpreexec(snum)) {
557                 int ret;
558                 pstring cmd;
559                 pstrcpy(cmd,lp_rootpreexec(snum));
560                 standard_sub_conn(conn,cmd,sizeof(cmd));
561                 DEBUG(5,("cmd=%s\n",cmd));
562                 ret = smbrun(cmd,NULL);
563                 if (ret != 0 && lp_rootpreexec_close(snum)) {
564                         DEBUG(1,("root preexec gave %d - failing connection\n", ret));
565                         yield_connection(conn, lp_servicename(snum));
566                         conn_free(conn);
567                         *status = NT_STATUS_ACCESS_DENIED;
568                         return NULL;
569                 }
570         }
571
572 /* USER Activites: */
573         if (!change_to_user(conn, conn->vuid)) {
574                 /* No point continuing if they fail the basic checks */
575                 DEBUG(0,("Can't become connected user!\n"));
576                 yield_connection(conn, lp_servicename(snum));
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)) {
587                 int ret;
588                 pstring cmd;
589                 pstrcpy(cmd,lp_preexec(snum));
590                 standard_sub_conn(conn,cmd,sizeof(cmd));
591                 ret = smbrun(cmd,NULL);
592                 if (ret != 0 && lp_preexec_close(snum)) {
593                         DEBUG(1,("preexec gave %d - failing connection\n", ret));
594                         change_to_root_user();
595                         yield_connection(conn, lp_servicename(snum));
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)) {
604                 afs_login(conn);
605         }
606 #endif
607         
608         /* Add veto/hide lists */
609         if (!IS_IPC(conn) && !IS_PRINT(conn)) {
610                 set_namearray( &conn->veto_list, lp_veto_files(snum));
611                 set_namearray( &conn->hide_list, lp_hide_files(snum));
612                 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(snum));
613         }
614         
615         /* Invoke VFS make connection hook - do this before the VFS_STAT call to allow
616            any filesystems needing user credentials to initialize themselves. */
617
618         if (SMB_VFS_CONNECT(conn, lp_servicename(snum), user) < 0) {
619                 DEBUG(0,("make_connection: VFS make connection failed!\n"));
620                 change_to_root_user();
621                 yield_connection(conn, lp_servicename(snum));
622                 conn_free(conn);
623                 *status = NT_STATUS_UNSUCCESSFUL;
624                 return NULL;
625         }
626
627         /* win2000 does not check the permissions on the directory
628            during the tree connect, instead relying on permission
629            check during individual operations. To match this behaviour
630            I have disabled this chdir check (tridge) */
631         /* the alternative is just to check the directory exists */
632         if (SMB_VFS_STAT(conn, conn->connectpath, &st) != 0 || !S_ISDIR(st.st_mode)) {
633                 DEBUG(0,("'%s' does not exist or is not a directory, when connecting to [%s]\n", conn->connectpath, lp_servicename(snum)));
634                 change_to_root_user();
635                 /* Call VFS disconnect hook */    
636                 SMB_VFS_DISCONNECT(conn);
637                 yield_connection(conn, lp_servicename(snum));
638                 conn_free(conn);
639                 *status = NT_STATUS_BAD_NETWORK_NAME;
640                 return NULL;
641         }
642         
643         string_set(&conn->origpath,conn->connectpath);
644         
645 #if SOFTLINK_OPTIMISATION
646         /* resolve any soft links early if possible */
647         if (vfs_ChDir(conn,conn->connectpath) == 0) {
648                 pstring s;
649                 pstrcpy(s,conn->connectpath);
650                 vfs_GetWd(conn,s);
651                 string_set(&conn->connectpath,s);
652                 vfs_ChDir(conn,conn->connectpath);
653         }
654 #endif
655         
656         /*
657          * Print out the 'connected as' stuff here as we need
658          * to know the effective uid and gid we will be using
659          * (at least initially).
660          */
661
662         if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
663                 dbgtext( "%s (%s) ", get_remote_machine_name(), conn->client_address );
664                 dbgtext( "%s", srv_is_signing_active() ? "signed " : "");
665                 dbgtext( "connect to service %s ", lp_servicename(snum) );
666                 dbgtext( "initially as user %s ", user );
667                 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
668                 dbgtext( "(pid %d)\n", (int)sys_getpid() );
669         }
670         
671         /* we've finished with the user stuff - go back to root */
672         change_to_root_user();
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$") 
790                         || (lp_enable_asu_support() && strequal(service,"ADMIN$"))) 
791                 {
792                         DEBUG(3,("refusing IPC connection to %s\n", service));
793                         *status = NT_STATUS_ACCESS_DENIED;
794                         return NULL;
795                 }
796
797                 DEBUG(0,("%s (%s) couldn't find service %s\n",
798                          get_remote_machine_name(), client_addr(), service));
799                 *status = NT_STATUS_BAD_NETWORK_NAME;
800                 return NULL;
801         }
802
803         /* Handle non-Dfs clients attempting connections to msdfs proxy */
804         if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0'))  {
805                 DEBUG(3, ("refusing connection to dfs proxy share '%s' (pointing to %s)\n", 
806                         service, lp_msdfs_proxy(snum)));
807                 *status = NT_STATUS_BAD_NETWORK_NAME;
808                 return NULL;
809         }
810
811         DEBUG(5, ("making a connection to 'normal' service %s\n", service));
812
813         return make_connection_snum(snum, vuser,
814                                     password,
815                                     dev, status);
816 }
817
818 /****************************************************************************
819  Close a cnum.
820 ****************************************************************************/
821
822 void close_cnum(connection_struct *conn, uint16 vuid)
823 {
824         if (IS_IPC(conn)) {
825                 pipe_close_conn(conn);
826         } else {
827                 file_close_conn(conn);
828                 dptr_closecnum(conn);
829         }
830
831         change_to_root_user();
832
833         DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
834                                  get_remote_machine_name(),conn->client_address,
835                                  lp_servicename(SNUM(conn))));
836
837         /* Call VFS disconnect hook */    
838         SMB_VFS_DISCONNECT(conn);
839
840         yield_connection(conn, lp_servicename(SNUM(conn)));
841
842         /* make sure we leave the directory available for unmount */
843         vfs_ChDir(conn, "/");
844
845         /* execute any "postexec = " line */
846         if (*lp_postexec(SNUM(conn)) && 
847             change_to_user(conn, vuid))  {
848                 pstring cmd;
849                 pstrcpy(cmd,lp_postexec(SNUM(conn)));
850                 standard_sub_conn(conn,cmd,sizeof(cmd));
851                 smbrun(cmd,NULL);
852                 change_to_root_user();
853         }
854
855         change_to_root_user();
856         /* execute any "root postexec = " line */
857         if (*lp_rootpostexec(SNUM(conn)))  {
858                 pstring cmd;
859                 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
860                 standard_sub_conn(conn,cmd,sizeof(cmd));
861                 smbrun(cmd,NULL);
862         }
863
864         conn_free(conn);
865 }