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