r5608: BUG 2399 - removing dead code (not finished with bug yet).
[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 struct timeval smb_last_time;
24 extern userdom_struct current_user_info;
25
26
27 /****************************************************************************
28  Load parameters specific to a connection/service.
29 ****************************************************************************/
30
31 BOOL set_current_service(connection_struct *conn, uint16 flags, BOOL do_chdir)
32 {
33         extern char magic_char;
34         static connection_struct *last_conn;
35         static uint16 last_flags;
36         int snum;
37
38         if (!conn)  {
39                 last_conn = NULL;
40                 return(False);
41         }
42
43         conn->lastused = smb_last_time.tv_sec;
44
45         snum = SNUM(conn);
46   
47         if (do_chdir &&
48             vfs_ChDir(conn,conn->connectpath) != 0 &&
49             vfs_ChDir(conn,conn->origpath) != 0) {
50                 DEBUG(0,("chdir (%s) failed\n",
51                          conn->connectpath));
52                 return(False);
53         }
54
55         if ((conn == last_conn) && (last_flags == flags)) {
56                 return(True);
57         }
58
59         last_conn = conn;
60         last_flags = flags;
61         
62         /* Obey the client case sensitivity requests - only for clients that support it. */
63         switch (lp_casesensitive(snum)) {
64                 case Auto:
65                         {
66                                 /* We need this uglyness due to DOS/Win9x clients that lie about case insensitivity. */
67                                 enum remote_arch_types ra_type = get_remote_arch();
68                                 if ((ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
69                                         /* Client can't support per-packet case sensitive pathnames. */
70                                         conn->case_sensitive = False;
71                                 } else {
72                                         conn->case_sensitive = !(flags & FLAG_CASELESS_PATHNAMES);
73                                 }
74                         }
75                         break;
76                 case True:
77                         conn->case_sensitive = True;
78                         break;
79                 default:
80                         conn->case_sensitive = False;
81                         break;
82         }
83         magic_char = lp_magicchar(snum);
84         return(True);
85 }
86
87 /****************************************************************************
88  Add a home service. Returns the new service number or -1 if fail.
89 ****************************************************************************/
90
91 int add_home_service(const char *service, const char *username, const char *homedir)
92 {
93         int iHomeService;
94
95         if (!service || !homedir)
96                 return -1;
97
98         if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0)
99                 return -1;
100
101         /*
102          * If this is a winbindd provided username, remove
103          * the domain component before adding the service.
104          * Log a warning if the "path=" parameter does not
105          * include any macros.
106          */
107
108         {
109                 const char *p = strchr(service,*lp_winbind_separator());
110
111                 /* We only want the 'user' part of the string */
112                 if (p) {
113                         service = p + 1;
114                 }
115         }
116
117         if (!lp_add_home(service, iHomeService, username, homedir)) {
118                 return -1;
119         }
120         
121         return lp_servicenumber(service);
122
123 }
124
125
126 /**
127  * Find a service entry.
128  *
129  * @param service is modified (to canonical form??)
130  **/
131
132 int find_service(fstring service)
133 {
134         int iService;
135
136         all_string_sub(service,"\\","/",0);
137
138         iService = lp_servicenumber(service);
139
140         /* now handle the special case of a home directory */
141         if (iService < 0) {
142                 char *phome_dir = get_user_home_dir(service);
143
144                 if(!phome_dir) {
145                         /*
146                          * Try mapping the servicename, it may
147                          * be a Windows to unix mapped user name.
148                          */
149                         if(map_username(service))
150                                 phome_dir = get_user_home_dir(service);
151                 }
152
153                 DEBUG(3,("checking for home directory %s gave %s\n",service,
154                         phome_dir?phome_dir:"(NULL)"));
155
156                 iService = add_home_service(service,service /* 'username' */, phome_dir);
157         }
158
159         /* If we still don't have a service, attempt to add it as a printer. */
160         if (iService < 0) {
161                 int iPrinterService;
162
163                 if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) >= 0) {
164                         DEBUG(3,("checking whether %s is a valid printer name...\n", service));
165                         if (pcap_printername_ok(service)) {
166                                 DEBUG(3,("%s is a valid printer name\n", service));
167                                 DEBUG(3,("adding %s as a printer service\n", service));
168                                 lp_add_printer(service, iPrinterService);
169                                 iService = lp_servicenumber(service);
170                                 if (iService < 0) {
171                                         DEBUG(0,("failed to add %s as a printer service!\n", service));
172                                 }
173                         } else {
174                                 DEBUG(3,("%s is not a valid printer name\n", service));
175                         }
176                 }
177         }
178
179         /* Check for default vfs service?  Unsure whether to implement this */
180         if (iService < 0) {
181         }
182
183         /* just possibly it's a default service? */
184         if (iService < 0) {
185                 char *pdefservice = lp_defaultservice();
186                 if (pdefservice && *pdefservice && !strequal(pdefservice,service) && !strstr_m(service,"..")) {
187                         /*
188                          * We need to do a local copy here as lp_defaultservice() 
189                          * returns one of the rotating lp_string buffers that
190                          * could get overwritten by the recursive find_service() call
191                          * below. Fix from Josef Hinteregger <joehtg@joehtg.co.at>.
192                          */
193                         pstring defservice;
194                         pstrcpy(defservice, pdefservice);
195                         iService = find_service(defservice);
196                         if (iService >= 0) {
197                                 all_string_sub(service, "_","/",0);
198                                 iService = lp_add_service(service, iService);
199                         }
200                 }
201         }
202
203         if (iService >= 0) {
204                 if (!VALID_SNUM(iService)) {
205                         DEBUG(0,("Invalid snum %d for %s\n",iService, service));
206                         iService = -1;
207                 }
208         }
209
210         if (iService < 0)
211                 DEBUG(3,("find_service() failed to find service %s\n", service));
212
213         return (iService);
214 }
215
216
217 /****************************************************************************
218  do some basic sainity checks on the share.  
219  This function modifies dev, ecode.
220 ****************************************************************************/
221
222 static NTSTATUS share_sanity_checks(int snum, fstring dev) 
223 {
224         
225         if (!lp_snum_ok(snum) || 
226             !check_access(smbd_server_fd(), 
227                           lp_hostsallow(snum), lp_hostsdeny(snum))) {    
228                 return NT_STATUS_ACCESS_DENIED;
229         }
230
231         if (dev[0] == '?' || !dev[0]) {
232                 if (lp_print_ok(snum)) {
233                         fstrcpy(dev,"LPT1:");
234                 } else if (strequal(lp_fstype(snum), "IPC")) {
235                         fstrcpy(dev, "IPC");
236                 } else {
237                         fstrcpy(dev,"A:");
238                 }
239         }
240
241         strupper_m(dev);
242
243         if (lp_print_ok(snum)) {
244                 if (!strequal(dev, "LPT1:")) {
245                         return NT_STATUS_BAD_DEVICE_TYPE;
246                 }
247         } else if (strequal(lp_fstype(snum), "IPC")) {
248                 if (!strequal(dev, "IPC")) {
249                         return NT_STATUS_BAD_DEVICE_TYPE;
250                 }
251         } else if (!strequal(dev, "A:")) {
252                 return NT_STATUS_BAD_DEVICE_TYPE;
253         }
254
255         /* Behave as a printer if we are supposed to */
256         if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) {
257                 fstrcpy(dev, "LPT1:");
258         }
259
260         return NT_STATUS_OK;
261 }
262
263 /****************************************************************************
264   Make a connection, given the snum to connect to, and the vuser of the
265   connecting user if appropriate.
266 ****************************************************************************/
267
268 static connection_struct *make_connection_snum(int snum, user_struct *vuser,
269                                                DATA_BLOB password, 
270                                                const char *pdev, NTSTATUS *status)
271 {
272         struct passwd *pass = NULL;
273         BOOL guest = False;
274         connection_struct *conn;
275         struct stat st;
276         fstring user;
277         fstring dev;
278
279         *user = 0;
280         fstrcpy(dev, pdev);
281         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(conn))));
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(conn)),
548                               lp_max_connections(SNUM(conn)),
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(conn))) {
559                 int ret;
560                 pstring cmd;
561                 pstrcpy(cmd,lp_rootpreexec(SNUM(conn)));
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(conn))) {
566                         DEBUG(1,("root preexec gave %d - failing connection\n", ret));
567                         yield_connection(conn, lp_servicename(SNUM(conn)));
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                 conn_free(conn);
579                 *status = NT_STATUS_LOGON_FAILURE;
580                 return NULL;
581         }
582
583         /* Remember that a different vuid can connect later without these checks... */
584         
585         /* Preexecs are done here as they might make the dir we are to ChDir to below */
586         /* execute any "preexec = " line */
587         if (*lp_preexec(SNUM(conn))) {
588                 int ret;
589                 pstring cmd;
590                 pstrcpy(cmd,lp_preexec(SNUM(conn)));
591                 standard_sub_conn(conn,cmd,sizeof(cmd));
592                 ret = smbrun(cmd,NULL);
593                 if (ret != 0 && lp_preexec_close(SNUM(conn))) {
594                         DEBUG(1,("preexec gave %d - failing connection\n", ret));
595                         change_to_root_user();
596                         yield_connection(conn, lp_servicename(SNUM(conn)));
597                         conn_free(conn);
598                         *status = NT_STATUS_ACCESS_DENIED;
599                         return NULL;
600                 }
601         }
602
603 #ifdef WITH_FAKE_KASERVER
604         if (lp_afs_share(SNUM(conn))) {
605                 afs_login(conn);
606         }
607 #endif
608         
609         /* win2000 does not check the permissions on the directory
610            during the tree connect, instead relying on permission
611            check during individual operations. To match this behaviour
612            I have disabled this chdir check (tridge) */
613         /* the alternative is just to check the directory exists */
614         if (SMB_VFS_STAT(conn, conn->connectpath, &st) != 0 || !S_ISDIR(st.st_mode)) {
615                 DEBUG(0,("'%s' does not exist or is not a directory, when connecting to [%s]\n", conn->connectpath, lp_servicename(SNUM(conn))));
616                 change_to_root_user();
617                 yield_connection(conn, lp_servicename(SNUM(conn)));
618                 conn_free(conn);
619                 *status = NT_STATUS_BAD_NETWORK_NAME;
620                 return NULL;
621         }
622         
623         string_set(&conn->origpath,conn->connectpath);
624         
625 #if SOFTLINK_OPTIMISATION
626         /* resolve any soft links early if possible */
627         if (vfs_ChDir(conn,conn->connectpath) == 0) {
628                 pstring s;
629                 pstrcpy(s,conn->connectpath);
630                 vfs_GetWd(conn,s);
631                 string_set(&conn->connectpath,s);
632                 vfs_ChDir(conn,conn->connectpath);
633         }
634 #endif
635         
636         /*
637          * Print out the 'connected as' stuff here as we need
638          * to know the effective uid and gid we will be using
639          * (at least initially).
640          */
641
642         if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
643                 dbgtext( "%s (%s) ", get_remote_machine_name(), conn->client_address );
644                 dbgtext( "%s", srv_is_signing_active() ? "signed " : "");
645                 dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)) );
646                 dbgtext( "initially as user %s ", user );
647                 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
648                 dbgtext( "(pid %d)\n", (int)sys_getpid() );
649         }
650         
651         /* Add veto/hide lists */
652         if (!IS_IPC(conn) && !IS_PRINT(conn)) {
653                 set_namearray( &conn->veto_list, lp_veto_files(SNUM(conn)));
654                 set_namearray( &conn->hide_list, lp_hide_files(SNUM(conn)));
655                 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(SNUM(conn)));
656         }
657         
658         /* Invoke VFS make connection hook */
659
660         if (SMB_VFS_CONNECT(conn, lp_servicename(snum), user) < 0) {
661                 DEBUG(0,("make_connection: VFS make connection failed!\n"));
662                 change_to_root_user();
663                 conn_free(conn);
664                 *status = NT_STATUS_UNSUCCESSFUL;
665                 return NULL;
666         }
667
668         /* we've finished with the user stuff - go back to root */
669         change_to_root_user();
670             
671         return(conn);
672 }
673
674 /***************************************************************************************
675  Simple wrapper function for make_connection() to include a call to 
676  vfs_chdir()
677  **************************************************************************************/
678  
679 connection_struct *make_connection_with_chdir(const char *service_in, DATA_BLOB password, 
680                                    const char *dev, uint16 vuid, NTSTATUS *status)
681 {
682         connection_struct *conn = NULL;
683         
684         conn = make_connection(service_in, password, dev, vuid, status);
685         
686         /*
687          * make_connection() does not change the directory for us any more
688          * so we have to do it as a separate step  --jerry
689          */
690          
691         if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) {
692                 DEBUG(0,("move_driver_to_download_area: Can't change directory to %s for [print$] (%s)\n",
693                          conn->connectpath,strerror(errno)));
694                 yield_connection(conn, lp_servicename(SNUM(conn)));
695                 conn_free(conn);
696                 *status = NT_STATUS_UNSUCCESSFUL;
697                 return NULL;
698         }
699         
700         return conn;
701 }
702
703 /****************************************************************************
704  Make a connection to a service.
705  *
706  * @param service 
707 ****************************************************************************/
708
709 connection_struct *make_connection(const char *service_in, DATA_BLOB password, 
710                                    const char *pdev, uint16 vuid, NTSTATUS *status)
711 {
712         uid_t euid;
713         user_struct *vuser = NULL;
714         fstring service;
715         fstring dev;
716         int snum = -1;
717
718         fstrcpy(dev, pdev);
719
720         /* This must ONLY BE CALLED AS ROOT. As it exits this function as root. */
721         if (!non_root_mode() && (euid = geteuid()) != 0) {
722                 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot (%u)\n", (unsigned int)euid ));
723                 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
724         }
725
726         if(lp_security() != SEC_SHARE) {
727                 vuser = get_valid_user_struct(vuid);
728                 if (!vuser) {
729                         DEBUG(1,("make_connection: refusing to connect with no session setup\n"));
730                         *status = NT_STATUS_ACCESS_DENIED;
731                         return NULL;
732                 }
733         }
734
735         /* Logic to try and connect to the correct [homes] share, preferably without too many
736            getpwnam() lookups.  This is particulary nasty for winbind usernames, where the
737            share name isn't the same as unix username.
738
739            The snum of the homes share is stored on the vuser at session setup time.
740         */
741
742         if (strequal(service_in,HOMES_NAME)) {
743                 if(lp_security() != SEC_SHARE) {
744                         DATA_BLOB no_pw = data_blob(NULL, 0);
745                         if (vuser->homes_snum == -1) {
746                                 DEBUG(2, ("[homes] share not available for this user because it was not found or created at session setup time\n"));
747                                 *status = NT_STATUS_BAD_NETWORK_NAME;
748                                 return NULL;
749                         }
750                         DEBUG(5, ("making a connection to [homes] service created at session setup time\n"));
751                         return make_connection_snum(vuser->homes_snum,
752                                                     vuser, no_pw, 
753                                                     dev, status);
754                 } else {
755                         /* Security = share. Try with current_user_info.smb_name
756                          * as the username.  */
757                         if (*current_user_info.smb_name) {
758                                 fstring unix_username;
759                                 fstrcpy(unix_username,
760                                         current_user_info.smb_name);
761                                 map_username(unix_username);
762                                 snum = find_service(unix_username);
763                         } 
764                         if (snum != -1) {
765                                 DEBUG(5, ("making a connection to 'homes' service %s based on security=share\n", service_in));
766                                 return make_connection_snum(snum, NULL,
767                                                             password,
768                                                             dev, status);
769                         }
770                 }
771         } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
772                    && strequal(service_in, lp_servicename(vuser->homes_snum))) {
773                 DATA_BLOB no_pw = data_blob(NULL, 0);
774                 DEBUG(5, ("making a connection to 'homes' service [%s] created at session setup time\n", service_in));
775                 return make_connection_snum(vuser->homes_snum,
776                                             vuser, no_pw, 
777                                             dev, status);
778         }
779         
780         fstrcpy(service, service_in);
781
782         strlower_m(service);
783
784         snum = find_service(service);
785
786         if (snum < 0) {
787                 if (strequal(service,"IPC$") || strequal(service,"ADMIN$")) {
788                         DEBUG(3,("refusing IPC connection to %s\n", service));
789                         *status = NT_STATUS_ACCESS_DENIED;
790                         return NULL;
791                 }
792
793                 DEBUG(0,("%s (%s) couldn't find service %s\n",
794                          get_remote_machine_name(), client_addr(), service));
795                 *status = NT_STATUS_BAD_NETWORK_NAME;
796                 return NULL;
797         }
798
799         /* Handle non-Dfs clients attempting connections to msdfs proxy */
800         if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0'))  {
801                 DEBUG(3, ("refusing connection to dfs proxy share '%s' (pointing to %s)\n", 
802                         service, lp_msdfs_proxy(snum)));
803                 *status = NT_STATUS_BAD_NETWORK_NAME;
804                 return NULL;
805         }
806
807         DEBUG(5, ("making a connection to 'normal' service %s\n", service));
808
809         return make_connection_snum(snum, vuser,
810                                     password,
811                                     dev, status);
812 }
813
814 /****************************************************************************
815 close a cnum
816 ****************************************************************************/
817 void close_cnum(connection_struct *conn, uint16 vuid)
818 {
819         if (IS_IPC(conn)) {
820                 pipe_close_conn(conn);
821         } else {
822                 file_close_conn(conn);
823                 dptr_closecnum(conn);
824         }
825
826         change_to_root_user();
827
828         DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
829                                  get_remote_machine_name(),conn->client_address,
830                                  lp_servicename(SNUM(conn))));
831
832         /* Call VFS disconnect hook */    
833         SMB_VFS_DISCONNECT(conn);
834
835         yield_connection(conn, lp_servicename(SNUM(conn)));
836
837         /* make sure we leave the directory available for unmount */
838         vfs_ChDir(conn, "/");
839
840         /* execute any "postexec = " line */
841         if (*lp_postexec(SNUM(conn)) && 
842             change_to_user(conn, vuid))  {
843                 pstring cmd;
844                 pstrcpy(cmd,lp_postexec(SNUM(conn)));
845                 standard_sub_conn(conn,cmd,sizeof(cmd));
846                 smbrun(cmd,NULL);
847                 change_to_root_user();
848         }
849
850         change_to_root_user();
851         /* execute any "root postexec = " line */
852         if (*lp_rootpostexec(SNUM(conn)))  {
853                 pstring cmd;
854                 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
855                 standard_sub_conn(conn,cmd,sizeof(cmd));
856                 smbrun(cmd,NULL);
857         }
858
859         conn_free(conn);
860 }