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