r12194: Ensure that when we set a connection path we've canonicalized
[samba.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  Ensure when setting connectpath it is a canonicalized (no ./ // or ../)
28  absolute path stating in / and not ending in /.
29  Observent people will notice a similarity between this and check_path_syntax :-).
30 ****************************************************************************/
31
32 void set_conn_connectpath(connection_struct *conn, const pstring connectpath)
33 {
34         pstring destname;
35         char *d = destname;
36         const char *s = connectpath;
37         BOOL start_of_name_component = True;
38
39         *d++ = '/'; /* Always start with root. */
40
41         while (*s) {
42                 if (*s == '/') {
43                         /* Eat multiple '/' */
44                         while (*s == '/') {
45                                 s++;
46                         }
47                         if ((d != destname) && (*s != '\0')) {
48                                 *d++ = '/';
49                         }
50                         start_of_name_component = True;
51                         continue;
52                 }
53
54                 if (start_of_name_component) {
55                         if ((s[0] == '.') && (s[1] == '.') && (s[2] == '/' || s[2] == '\0')) {
56                                 /* Uh oh - "/../" or "/..\0" ! */
57
58                                 /* Go past the ../ or .. */
59                                 if (s[2] == '/') {
60                                         s += 3;
61                                 } else {
62                                         s += 2; /* Go past the .. */
63                                 }
64
65                                 /* If  we just added a '/' - delete it */
66                                 if ((d > destname) && (*(d-1) == '/')) {
67                                         *(d-1) = '\0';
68                                         d--;
69                                 }
70
71                                 /* Are we at the start ? Can't go back further if so. */
72                                 if (d <= destname) {
73                                         *d++ = '/'; /* Can't delete root */
74                                         continue;
75                                 }
76                                 /* Go back one level... */
77                                 /* Decrement d first as d points to the *next* char to write into. */
78                                 for (d--; d > destname; d--) {
79                                         if (*d == '/') {
80                                                 break;
81                                         }
82                                 }
83                                 /* We're still at the start of a name component, just the previous one. */
84                                 continue;
85                         } else if ((s[0] == '.') && ((s[1] == '\0') || s[1] == '/')) {
86                                 /* Component of pathname can't be "." only - skip the '.' . */
87                                 if (s[1] == '/') {
88                                         s += 2;
89                                 } else {
90                                         s++;
91                                 }
92                                 continue;
93                         }
94                 }
95
96                 if (!(*s & 0x80)) {
97                         *d++ = *s++;
98                 } else {
99                         switch(next_mb_char_size(s)) {
100                                 case 4:
101                                         *d++ = *s++;
102                                 case 3:
103                                         *d++ = *s++;
104                                 case 2:
105                                         *d++ = *s++;
106                                 case 1:
107                                         *d++ = *s++;
108                                         break;
109                                 default:
110                                         break;
111                         }
112                 }
113                 start_of_name_component = False;
114         }
115         *d = '\0';
116
117         /* And must not end in '/' */
118         if (d > destname + 1 && (*(d-1) == '/')) {
119                 *(d-1) = '\0';
120         }
121
122         string_set(&conn->connectpath, destname);
123 }
124
125 /****************************************************************************
126  Load parameters specific to a connection/service.
127 ****************************************************************************/
128
129 BOOL set_current_service(connection_struct *conn, uint16 flags, BOOL do_chdir)
130 {
131         static connection_struct *last_conn;
132         static uint16 last_flags;
133         int snum;
134
135         if (!conn)  {
136                 last_conn = NULL;
137                 return(False);
138         }
139
140         conn->lastused = smb_last_time.tv_sec;
141
142         snum = SNUM(conn);
143   
144         if (do_chdir &&
145             vfs_ChDir(conn,conn->connectpath) != 0 &&
146             vfs_ChDir(conn,conn->origpath) != 0) {
147                 DEBUG(0,("chdir (%s) failed\n",
148                          conn->connectpath));
149                 return(False);
150         }
151
152         if ((conn == last_conn) && (last_flags == flags)) {
153                 return(True);
154         }
155
156         last_conn = conn;
157         last_flags = flags;
158         
159         /* Obey the client case sensitivity requests - only for clients that support it. */
160         switch (lp_casesensitive(snum)) {
161                 case Auto:
162                         {
163                                 /* We need this uglyness due to DOS/Win9x clients that lie about case insensitivity. */
164                                 enum remote_arch_types ra_type = get_remote_arch();
165                                 if ((ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
166                                         /* Client can't support per-packet case sensitive pathnames. */
167                                         conn->case_sensitive = False;
168                                 } else {
169                                         conn->case_sensitive = !(flags & FLAG_CASELESS_PATHNAMES);
170                                 }
171                         }
172                         break;
173                 case True:
174                         conn->case_sensitive = True;
175                         break;
176                 default:
177                         conn->case_sensitive = False;
178                         break;
179         }
180         return(True);
181 }
182
183 /****************************************************************************
184  Add a home service. Returns the new service number or -1 if fail.
185 ****************************************************************************/
186
187 int add_home_service(const char *service, const char *username, const char *homedir)
188 {
189         int iHomeService;
190
191         if (!service || !homedir)
192                 return -1;
193
194         if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0)
195                 return -1;
196
197         /*
198          * If this is a winbindd provided username, remove
199          * the domain component before adding the service.
200          * Log a warning if the "path=" parameter does not
201          * include any macros.
202          */
203
204         {
205                 const char *p = strchr(service,*lp_winbind_separator());
206
207                 /* We only want the 'user' part of the string */
208                 if (p) {
209                         service = p + 1;
210                 }
211         }
212
213         if (!lp_add_home(service, iHomeService, username, homedir)) {
214                 return -1;
215         }
216         
217         return lp_servicenumber(service);
218
219 }
220
221
222 /**
223  * Find a service entry.
224  *
225  * @param service is modified (to canonical form??)
226  **/
227
228 int find_service(fstring service)
229 {
230         int iService;
231
232         all_string_sub(service,"\\","/",0);
233
234         iService = lp_servicenumber(service);
235
236         /* now handle the special case of a home directory */
237         if (iService < 0) {
238                 char *phome_dir = get_user_home_dir(service);
239
240                 if(!phome_dir) {
241                         /*
242                          * Try mapping the servicename, it may
243                          * be a Windows to unix mapped user name.
244                          */
245                         if(map_username(service))
246                                 phome_dir = get_user_home_dir(service);
247                 }
248
249                 DEBUG(3,("checking for home directory %s gave %s\n",service,
250                         phome_dir?phome_dir:"(NULL)"));
251
252                 iService = add_home_service(service,service /* 'username' */, phome_dir);
253         }
254
255         /* If we still don't have a service, attempt to add it as a printer. */
256         if (iService < 0) {
257                 int iPrinterService;
258
259                 if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) >= 0) {
260                         DEBUG(3,("checking whether %s is a valid printer name...\n", service));
261                         if (pcap_printername_ok(service)) {
262                                 DEBUG(3,("%s is a valid printer name\n", service));
263                                 DEBUG(3,("adding %s as a printer service\n", service));
264                                 lp_add_printer(service, iPrinterService);
265                                 iService = lp_servicenumber(service);
266                                 if (iService < 0) {
267                                         DEBUG(0,("failed to add %s as a printer service!\n", service));
268                                 }
269                         } else {
270                                 DEBUG(3,("%s is not a valid printer name\n", service));
271                         }
272                 }
273         }
274
275         /* Check for default vfs service?  Unsure whether to implement this */
276         if (iService < 0) {
277         }
278
279         /* just possibly it's a default service? */
280         if (iService < 0) {
281                 char *pdefservice = lp_defaultservice();
282                 if (pdefservice && *pdefservice && !strequal(pdefservice,service) && !strstr_m(service,"..")) {
283                         /*
284                          * We need to do a local copy here as lp_defaultservice() 
285                          * returns one of the rotating lp_string buffers that
286                          * could get overwritten by the recursive find_service() call
287                          * below. Fix from Josef Hinteregger <joehtg@joehtg.co.at>.
288                          */
289                         pstring defservice;
290                         pstrcpy(defservice, pdefservice);
291                         iService = find_service(defservice);
292                         if (iService >= 0) {
293                                 all_string_sub(service, "_","/",0);
294                                 iService = lp_add_service(service, iService);
295                         }
296                 }
297         }
298
299         if (iService >= 0) {
300                 if (!VALID_SNUM(iService)) {
301                         DEBUG(0,("Invalid snum %d for %s\n",iService, service));
302                         iService = -1;
303                 }
304         }
305
306         if (iService < 0)
307                 DEBUG(3,("find_service() failed to find service %s\n", service));
308
309         return (iService);
310 }
311
312
313 /****************************************************************************
314  do some basic sainity checks on the share.  
315  This function modifies dev, ecode.
316 ****************************************************************************/
317
318 static NTSTATUS share_sanity_checks(int snum, fstring dev) 
319 {
320         
321         if (!lp_snum_ok(snum) || 
322             !check_access(smbd_server_fd(), 
323                           lp_hostsallow(snum), lp_hostsdeny(snum))) {    
324                 return NT_STATUS_ACCESS_DENIED;
325         }
326
327         if (dev[0] == '?' || !dev[0]) {
328                 if (lp_print_ok(snum)) {
329                         fstrcpy(dev,"LPT1:");
330                 } else if (strequal(lp_fstype(snum), "IPC")) {
331                         fstrcpy(dev, "IPC");
332                 } else {
333                         fstrcpy(dev,"A:");
334                 }
335         }
336
337         strupper_m(dev);
338
339         if (lp_print_ok(snum)) {
340                 if (!strequal(dev, "LPT1:")) {
341                         return NT_STATUS_BAD_DEVICE_TYPE;
342                 }
343         } else if (strequal(lp_fstype(snum), "IPC")) {
344                 if (!strequal(dev, "IPC")) {
345                         return NT_STATUS_BAD_DEVICE_TYPE;
346                 }
347         } else if (!strequal(dev, "A:")) {
348                 return NT_STATUS_BAD_DEVICE_TYPE;
349         }
350
351         /* Behave as a printer if we are supposed to */
352         if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) {
353                 fstrcpy(dev, "LPT1:");
354         }
355
356         return NT_STATUS_OK;
357 }
358
359 /****************************************************************************
360   Make a connection, given the snum to connect to, and the vuser of the
361   connecting user if appropriate.
362 ****************************************************************************/
363
364 static connection_struct *make_connection_snum(int snum, user_struct *vuser,
365                                                DATA_BLOB password, 
366                                                const char *pdev, NTSTATUS *status)
367 {
368         struct passwd *pass = NULL;
369         BOOL guest = False;
370         connection_struct *conn;
371         SMB_STRUCT_STAT st;
372         fstring user;
373         fstring dev;
374         int ret;
375
376         *user = 0;
377         fstrcpy(dev, pdev);
378         SET_STAT_INVALID(st);
379
380         if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, dev))) {
381                 return NULL;
382         }       
383
384         conn = conn_new();
385         if (!conn) {
386                 DEBUG(0,("Couldn't find free connection.\n"));
387                 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
388                 return NULL;
389         }
390
391         if (lp_guest_only(snum)) {
392                 const char *guestname = lp_guestaccount();
393                 guest = True;
394                 pass = getpwnam_alloc(guestname);
395                 if (!pass) {
396                         DEBUG(0,("make_connection_snum: Invalid guest account %s??\n",guestname));
397                         conn_free(conn);
398                         *status = NT_STATUS_NO_SUCH_USER;
399                         return NULL;
400                 }
401                 fstrcpy(user,pass->pw_name);
402                 conn->force_user = True;
403                 conn->uid = pass->pw_uid;
404                 conn->gid = pass->pw_gid;
405                 string_set(&conn->user,pass->pw_name);
406                 passwd_free(&pass);
407                 DEBUG(3,("Guest only user %s\n",user));
408         } else if (vuser) {
409                 if (vuser->guest) {
410                         if (!lp_guest_ok(snum)) {
411                                 DEBUG(2, ("guest user (from session setup) not permitted to access this share (%s)\n", lp_servicename(snum)));
412                                       conn_free(conn);
413                                       *status = NT_STATUS_ACCESS_DENIED;
414                                       return NULL;
415                         }
416                 } else {
417                         if (!user_ok(vuser->user.unix_name, snum, vuser->groups, vuser->n_groups)) {
418                                 DEBUG(2, ("user '%s' (from session setup) not permitted to access this share (%s)\n", vuser->user.unix_name, lp_servicename(snum)));
419                                 conn_free(conn);
420                                 *status = NT_STATUS_ACCESS_DENIED;
421                                 return NULL;
422                         }
423                 }
424                 conn->vuid = vuser->vuid;
425                 conn->uid = vuser->uid;
426                 conn->gid = vuser->gid;
427                 string_set(&conn->user,vuser->user.unix_name);
428                 fstrcpy(user,vuser->user.unix_name);
429                 guest = vuser->guest; 
430         } else if (lp_security() == SEC_SHARE) {
431                 /* add it as a possible user name if we 
432                    are in share mode security */
433                 add_session_user(lp_servicename(snum));
434                 /* shall we let them in? */
435                 if (!authorise_login(snum,user,password,&guest)) {
436                         DEBUG( 2, ( "Invalid username/password for [%s]\n", 
437                                     lp_servicename(snum)) );
438                         conn_free(conn);
439                         *status = NT_STATUS_WRONG_PASSWORD;
440                         return NULL;
441                 }
442                 pass = Get_Pwnam(user);
443                 conn->force_user = True;
444                 conn->uid = pass->pw_uid;
445                 conn->gid = pass->pw_gid;
446                 string_set(&conn->user, pass->pw_name);
447                 fstrcpy(user, pass->pw_name);
448
449         } else {
450                 DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
451                 conn_free(conn);
452                 *status = NT_STATUS_ACCESS_DENIED;
453                 return NULL;
454         }
455
456         add_session_user(user);
457
458         safe_strcpy(conn->client_address, client_addr(), 
459                     sizeof(conn->client_address)-1);
460         conn->num_files_open = 0;
461         conn->lastused = time(NULL);
462         conn->service = snum;
463         conn->used = True;
464         conn->printer = (strncmp(dev,"LPT",3) == 0);
465         conn->ipc = ( (strncmp(dev,"IPC",3) == 0) || ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) );
466         conn->dirptr = NULL;
467
468         /* Case options for the share. */
469         if (lp_casesensitive(snum) == Auto) {
470                 /* We will be setting this per packet. Set to be case insensitive for now. */
471                 conn->case_sensitive = False;
472         } else {
473                 conn->case_sensitive = (BOOL)lp_casesensitive(snum);
474         }
475
476         conn->case_preserve = lp_preservecase(snum);
477         conn->short_case_preserve = lp_shortpreservecase(snum);
478
479         conn->veto_list = NULL;
480         conn->hide_list = NULL;
481         conn->veto_oplock_list = NULL;
482         conn->aio_write_behind_list = NULL;
483         string_set(&conn->dirpath,"");
484         string_set(&conn->user,user);
485         conn->nt_user_token = NULL;
486
487         conn->read_only = lp_readonly(conn->service);
488         conn->admin_user = False;
489
490         /*
491          * If force user is true, then store the
492          * given userid and also the groups
493          * of the user we're forcing.
494          */
495         
496         if (*lp_force_user(snum)) {
497                 struct passwd *pass2;
498                 pstring fuser;
499                 pstrcpy(fuser,lp_force_user(snum));
500
501                 /* Allow %S to be used by force user. */
502                 pstring_sub(fuser,"%S",lp_servicename(snum));
503
504                 pass2 = (struct passwd *)Get_Pwnam(fuser);
505                 if (pass2) {
506                         conn->uid = pass2->pw_uid;
507                         conn->gid = pass2->pw_gid;
508                         string_set(&conn->user,pass2->pw_name);
509                         fstrcpy(user,pass2->pw_name);
510                         conn->force_user = True;
511                         DEBUG(3,("Forced user %s\n",user));       
512                 } else {
513                         DEBUG(1,("Couldn't find user %s\n",fuser));
514                         conn_free(conn);
515                         *status = NT_STATUS_NO_SUCH_USER;
516                         return NULL;
517                 }
518         }
519
520 #ifdef HAVE_GETGRNAM 
521         /*
522          * If force group is true, then override
523          * any groupid stored for the connecting user.
524          */
525         
526         if (*lp_force_group(snum)) {
527                 gid_t gid;
528                 pstring gname;
529                 pstring tmp_gname;
530                 BOOL user_must_be_member = False;
531                 
532                 pstrcpy(tmp_gname,lp_force_group(snum));
533                 
534                 if (tmp_gname[0] == '+') {
535                         user_must_be_member = True;
536                         /* even now, tmp_gname is null terminated */
537                         pstrcpy(gname,&tmp_gname[1]);
538                 } else {
539                         pstrcpy(gname,tmp_gname);
540                 }
541                 /* default service may be a group name          */
542                 pstring_sub(gname,"%S",lp_servicename(snum));
543                 gid = nametogid(gname);
544                 
545                 if (gid != (gid_t)-1) {
546
547                         /*
548                          * If the user has been forced and the forced group starts
549                          * with a '+', then we only set the group to be the forced
550                          * group if the forced user is a member of that group.
551                          * Otherwise, the meaning of the '+' would be ignored.
552                          */
553                         if (conn->force_user && user_must_be_member) {
554                                 if (user_in_group_list( user, gname, NULL, 0)) {
555                                                 conn->gid = gid;
556                                                 DEBUG(3,("Forced group %s for member %s\n",gname,user));
557                                 }
558                         } else {
559                                 conn->gid = gid;
560                                 DEBUG(3,("Forced group %s\n",gname));
561                         }
562                         conn->force_group = True;
563                 } else {
564                         DEBUG(1,("Couldn't find group %s\n",gname));
565                         conn_free(conn);
566                         *status = NT_STATUS_NO_SUCH_GROUP;
567                         return NULL;
568                 }
569         }
570 #endif /* HAVE_GETGRNAM */
571
572         {
573                 pstring s;
574                 pstrcpy(s,lp_pathname(snum));
575                 standard_sub_conn(conn,s,sizeof(s));
576                 set_conn_connectpath(conn,s);
577                 DEBUG(3,("Connect path is '%s' for service [%s]\n",s, lp_servicename(snum)));
578         }
579
580         if (conn->force_user || conn->force_group) {
581
582                 /* groups stuff added by ih */
583                 conn->ngroups = 0;
584                 conn->groups = NULL;
585                 
586                 /* Find all the groups this uid is in and
587                    store them. Used by change_to_user() */
588                 initialise_groups(conn->user, conn->uid, conn->gid); 
589                 get_current_groups(conn->gid, &conn->ngroups,&conn->groups);
590                 
591                 conn->nt_user_token = create_nt_token(conn->uid, conn->gid, 
592                                                       conn->ngroups, conn->groups,
593                                                       guest);
594         }
595
596         /*
597          * New code to check if there's a share security descripter
598          * added from NT server manager. This is done after the
599          * smb.conf checks are done as we need a uid and token. JRA.
600          *
601          */
602
603         {
604                 BOOL can_write = share_access_check(conn, snum, vuser, FILE_WRITE_DATA);
605
606                 if (!can_write) {
607                         if (!share_access_check(conn, snum, vuser, FILE_READ_DATA)) {
608                                 /* No access, read or write. */
609                                 DEBUG(0,( "make_connection: connection to %s denied due to security descriptor.\n",
610                                           lp_servicename(snum)));
611                                 conn_free(conn);
612                                 *status = NT_STATUS_ACCESS_DENIED;
613                                 return NULL;
614                         } else {
615                                 conn->read_only = True;
616                         }
617                 }
618         }
619         /* Initialise VFS function pointers */
620
621         if (!smbd_vfs_init(conn)) {
622                 DEBUG(0, ("vfs_init failed for service %s\n", lp_servicename(snum)));
623                 conn_free(conn);
624                 *status = NT_STATUS_BAD_NETWORK_NAME;
625                 return NULL;
626         }
627
628         /*
629          * If widelinks are disallowed we need to canonicalise the
630          * connect path here to ensure we don't have any symlinks in
631          * the connectpath. We will be checking all paths on this
632          * connection are below this directory. We must do this after
633          * the VFS init as we depend on the realpath() pointer in the vfs table. JRA.
634          */
635         if (!lp_widelinks(snum)) {
636                 pstring s;
637                 pstrcpy(s,conn->connectpath);
638                 canonicalize_path(conn, s);
639                 set_conn_connectpath(conn,s);
640         }
641
642 /* ROOT Activities: */  
643         /* check number of connections */
644         if (!claim_connection(conn,
645                               lp_servicename(snum),
646                               lp_max_connections(snum),
647                               False,0)) {
648                 DEBUG(1,("too many connections - rejected\n"));
649                 conn_free(conn);
650                 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
651                 return NULL;
652         }  
653
654         /* Preexecs are done here as they might make the dir we are to ChDir to below */
655         /* execute any "root preexec = " line */
656         if (*lp_rootpreexec(snum)) {
657                 pstring cmd;
658                 pstrcpy(cmd,lp_rootpreexec(snum));
659                 standard_sub_conn(conn,cmd,sizeof(cmd));
660                 DEBUG(5,("cmd=%s\n",cmd));
661                 ret = smbrun(cmd,NULL);
662                 if (ret != 0 && lp_rootpreexec_close(snum)) {
663                         DEBUG(1,("root preexec gave %d - failing connection\n", ret));
664                         yield_connection(conn, lp_servicename(snum));
665                         conn_free(conn);
666                         *status = NT_STATUS_ACCESS_DENIED;
667                         return NULL;
668                 }
669         }
670
671 /* USER Activites: */
672         if (!change_to_user(conn, conn->vuid)) {
673                 /* No point continuing if they fail the basic checks */
674                 DEBUG(0,("Can't become connected user!\n"));
675                 yield_connection(conn, lp_servicename(snum));
676                 conn_free(conn);
677                 *status = NT_STATUS_LOGON_FAILURE;
678                 return NULL;
679         }
680
681         /* Remember that a different vuid can connect later without these checks... */
682         
683         /* Preexecs are done here as they might make the dir we are to ChDir to below */
684         /* execute any "preexec = " line */
685         if (*lp_preexec(snum)) {
686                 pstring cmd;
687                 pstrcpy(cmd,lp_preexec(snum));
688                 standard_sub_conn(conn,cmd,sizeof(cmd));
689                 ret = smbrun(cmd,NULL);
690                 if (ret != 0 && lp_preexec_close(snum)) {
691                         DEBUG(1,("preexec gave %d - failing connection\n", ret));
692                         change_to_root_user();
693                         yield_connection(conn, lp_servicename(snum));
694                         conn_free(conn);
695                         *status = NT_STATUS_ACCESS_DENIED;
696                         return NULL;
697                 }
698         }
699
700 #ifdef WITH_FAKE_KASERVER
701         if (lp_afs_share(snum)) {
702                 afs_login(conn);
703         }
704 #endif
705         
706         /* Add veto/hide lists */
707         if (!IS_IPC(conn) && !IS_PRINT(conn)) {
708                 set_namearray( &conn->veto_list, lp_veto_files(snum));
709                 set_namearray( &conn->hide_list, lp_hide_files(snum));
710                 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(snum));
711         }
712         
713         /* Invoke VFS make connection hook - do this before the VFS_STAT call to allow
714            any filesystems needing user credentials to initialize themselves. */
715
716         if (SMB_VFS_CONNECT(conn, lp_servicename(snum), user) < 0) {
717                 DEBUG(0,("make_connection: VFS make connection failed!\n"));
718                 change_to_root_user();
719                 yield_connection(conn, lp_servicename(snum));
720                 conn_free(conn);
721                 *status = NT_STATUS_UNSUCCESSFUL;
722                 return NULL;
723         }
724
725         /* win2000 does not check the permissions on the directory
726            during the tree connect, instead relying on permission
727            check during individual operations. To match this behaviour
728            I have disabled this chdir check (tridge) */
729         /* the alternative is just to check the directory exists */
730         if ((ret = SMB_VFS_STAT(conn, conn->connectpath, &st)) != 0 || !S_ISDIR(st.st_mode)) {
731                 if (ret == 0 && !S_ISDIR(st.st_mode)) {
732                         DEBUG(0,("'%s' is not a directory, when connecting to [%s]\n", conn->connectpath, lp_servicename(snum)));
733                 } else {
734                         DEBUG(0,("'%s' does not exist or permission denied when connecting to [%s] "
735                                 "Error was %s\n", conn->connectpath, lp_servicename(snum), strerror(errno) ));
736                 }
737                 change_to_root_user();
738                 /* Call VFS disconnect hook */    
739                 SMB_VFS_DISCONNECT(conn);
740                 yield_connection(conn, lp_servicename(snum));
741                 conn_free(conn);
742                 *status = NT_STATUS_BAD_NETWORK_NAME;
743                 return NULL;
744         }
745         
746         string_set(&conn->origpath,conn->connectpath);
747         
748 #if SOFTLINK_OPTIMISATION
749         /* resolve any soft links early if possible */
750         if (vfs_ChDir(conn,conn->connectpath) == 0) {
751                 pstring s;
752                 pstrcpy(s,conn->connectpath);
753                 vfs_GetWd(conn,s);
754                 set_conn_connectpath(conn,s);
755                 vfs_ChDir(conn,conn->connectpath);
756         }
757 #endif
758         
759         /*
760          * Print out the 'connected as' stuff here as we need
761          * to know the effective uid and gid we will be using
762          * (at least initially).
763          */
764
765         if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
766                 dbgtext( "%s (%s) ", get_remote_machine_name(), conn->client_address );
767                 dbgtext( "%s", srv_is_signing_active() ? "signed " : "");
768                 dbgtext( "connect to service %s ", lp_servicename(snum) );
769                 dbgtext( "initially as user %s ", user );
770                 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
771                 dbgtext( "(pid %d)\n", (int)sys_getpid() );
772         }
773         
774         /* we've finished with the user stuff - go back to root */
775         change_to_root_user();
776         return(conn);
777 }
778
779 /***************************************************************************************
780  Simple wrapper function for make_connection() to include a call to 
781  vfs_chdir()
782  **************************************************************************************/
783  
784 connection_struct *make_connection_with_chdir(const char *service_in, DATA_BLOB password, 
785                                    const char *dev, uint16 vuid, NTSTATUS *status)
786 {
787         connection_struct *conn = NULL;
788         
789         conn = make_connection(service_in, password, dev, vuid, status);
790         
791         /*
792          * make_connection() does not change the directory for us any more
793          * so we have to do it as a separate step  --jerry
794          */
795          
796         if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) {
797                 DEBUG(0,("move_driver_to_download_area: Can't change directory to %s for [print$] (%s)\n",
798                          conn->connectpath,strerror(errno)));
799                 yield_connection(conn, lp_servicename(SNUM(conn)));
800                 conn_free(conn);
801                 *status = NT_STATUS_UNSUCCESSFUL;
802                 return NULL;
803         }
804         
805         return conn;
806 }
807
808 /****************************************************************************
809  Make a connection to a service.
810  *
811  * @param service 
812 ****************************************************************************/
813
814 connection_struct *make_connection(const char *service_in, DATA_BLOB password, 
815                                    const char *pdev, uint16 vuid, NTSTATUS *status)
816 {
817         uid_t euid;
818         user_struct *vuser = NULL;
819         fstring service;
820         fstring dev;
821         int snum = -1;
822
823         fstrcpy(dev, pdev);
824
825         /* This must ONLY BE CALLED AS ROOT. As it exits this function as root. */
826         if (!non_root_mode() && (euid = geteuid()) != 0) {
827                 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot (%u)\n", (unsigned int)euid ));
828                 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
829         }
830
831         if(lp_security() != SEC_SHARE) {
832                 vuser = get_valid_user_struct(vuid);
833                 if (!vuser) {
834                         DEBUG(1,("make_connection: refusing to connect with no session setup\n"));
835                         *status = NT_STATUS_ACCESS_DENIED;
836                         return NULL;
837                 }
838         }
839
840         /* Logic to try and connect to the correct [homes] share, preferably without too many
841            getpwnam() lookups.  This is particulary nasty for winbind usernames, where the
842            share name isn't the same as unix username.
843
844            The snum of the homes share is stored on the vuser at session setup time.
845         */
846
847         if (strequal(service_in,HOMES_NAME)) {
848                 if(lp_security() != SEC_SHARE) {
849                         DATA_BLOB no_pw = data_blob(NULL, 0);
850                         if (vuser->homes_snum == -1) {
851                                 DEBUG(2, ("[homes] share not available for this user because it was not found or created at session setup time\n"));
852                                 *status = NT_STATUS_BAD_NETWORK_NAME;
853                                 return NULL;
854                         }
855                         DEBUG(5, ("making a connection to [homes] service created at session setup time\n"));
856                         return make_connection_snum(vuser->homes_snum,
857                                                     vuser, no_pw, 
858                                                     dev, status);
859                 } else {
860                         /* Security = share. Try with current_user_info.smb_name
861                          * as the username.  */
862                         if (*current_user_info.smb_name) {
863                                 fstring unix_username;
864                                 fstrcpy(unix_username,
865                                         current_user_info.smb_name);
866                                 map_username(unix_username);
867                                 snum = find_service(unix_username);
868                         } 
869                         if (snum != -1) {
870                                 DEBUG(5, ("making a connection to 'homes' service %s based on security=share\n", service_in));
871                                 return make_connection_snum(snum, NULL,
872                                                             password,
873                                                             dev, status);
874                         }
875                 }
876         } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
877                    && strequal(service_in, lp_servicename(vuser->homes_snum))) {
878                 DATA_BLOB no_pw = data_blob(NULL, 0);
879                 DEBUG(5, ("making a connection to 'homes' service [%s] created at session setup time\n", service_in));
880                 return make_connection_snum(vuser->homes_snum,
881                                             vuser, no_pw, 
882                                             dev, status);
883         }
884         
885         fstrcpy(service, service_in);
886
887         strlower_m(service);
888
889         snum = find_service(service);
890
891         if (snum < 0) {
892                 if (strequal(service,"IPC$") 
893                         || (lp_enable_asu_support() && strequal(service,"ADMIN$"))) 
894                 {
895                         DEBUG(3,("refusing IPC connection to %s\n", service));
896                         *status = NT_STATUS_ACCESS_DENIED;
897                         return NULL;
898                 }
899
900                 DEBUG(0,("%s (%s) couldn't find service %s\n",
901                          get_remote_machine_name(), client_addr(), service));
902                 *status = NT_STATUS_BAD_NETWORK_NAME;
903                 return NULL;
904         }
905
906         /* Handle non-Dfs clients attempting connections to msdfs proxy */
907         if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0'))  {
908                 DEBUG(3, ("refusing connection to dfs proxy share '%s' (pointing to %s)\n", 
909                         service, lp_msdfs_proxy(snum)));
910                 *status = NT_STATUS_BAD_NETWORK_NAME;
911                 return NULL;
912         }
913
914         DEBUG(5, ("making a connection to 'normal' service %s\n", service));
915
916         return make_connection_snum(snum, vuser,
917                                     password,
918                                     dev, status);
919 }
920
921 /****************************************************************************
922  Close a cnum.
923 ****************************************************************************/
924
925 void close_cnum(connection_struct *conn, uint16 vuid)
926 {
927         if (IS_IPC(conn)) {
928                 pipe_close_conn(conn);
929         } else {
930                 file_close_conn(conn);
931                 dptr_closecnum(conn);
932         }
933
934         change_to_root_user();
935
936         DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
937                                  get_remote_machine_name(),conn->client_address,
938                                  lp_servicename(SNUM(conn))));
939
940         /* Call VFS disconnect hook */    
941         SMB_VFS_DISCONNECT(conn);
942
943         yield_connection(conn, lp_servicename(SNUM(conn)));
944
945         /* make sure we leave the directory available for unmount */
946         vfs_ChDir(conn, "/");
947
948         /* execute any "postexec = " line */
949         if (*lp_postexec(SNUM(conn)) && 
950             change_to_user(conn, vuid))  {
951                 pstring cmd;
952                 pstrcpy(cmd,lp_postexec(SNUM(conn)));
953                 standard_sub_conn(conn,cmd,sizeof(cmd));
954                 smbrun(cmd,NULL);
955                 change_to_root_user();
956         }
957
958         change_to_root_user();
959         /* execute any "root postexec = " line */
960         if (*lp_rootpostexec(SNUM(conn)))  {
961                 pstring cmd;
962                 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
963                 standard_sub_conn(conn,cmd,sizeof(cmd));
964                 smbrun(cmd,NULL);
965         }
966
967         conn_free(conn);
968 }