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