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