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