r17096: Simplify share_access_check a bit: It takes the sharename instead of the...
[obnox/samba-ctdb.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 /****************************************************************************
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         struct nt_user_token *tmp_token;
375         NTSTATUS result;
376
377         if (!(mem_ctx = talloc_new(NULL))) {
378                 DEBUG(0, ("talloc_new failed\n"));
379                 return NT_STATUS_NO_MEMORY;
380         }
381
382         if (!(fuser = talloc_string_sub(mem_ctx, lp_force_user(snum), "%S",
383                                         lp_servicename(snum)))) {
384                 TALLOC_FREE(mem_ctx);
385                 return NT_STATUS_NO_MEMORY;
386                 
387         }
388
389         result = create_token_from_username(mem_ctx, fuser, vuser_is_guest,
390                                             uid, gid, &found_username,
391                                             &tmp_token);
392         if (!NT_STATUS_IS_OK(result)) {
393                 TALLOC_FREE(mem_ctx);
394                 return result;
395         }
396
397         if (!(*token = dup_nt_token(NULL, tmp_token))) {
398                 TALLOC_FREE(mem_ctx);
399                 return NT_STATUS_NO_MEMORY;
400         }
401
402         fstrcpy(username, found_username);
403
404         TALLOC_FREE(mem_ctx);
405         return NT_STATUS_OK;
406 }
407
408 /*
409  * Go through lookup_name etc to find the force'd group.  
410  *
411  * Create a new token from src_token, replacing the primary group sid with the
412  * one found.
413  */
414
415 static NTSTATUS find_forced_group(BOOL force_user,
416                                   int snum, const char *username,
417                                   DOM_SID *pgroup_sid,
418                                   gid_t *pgid)
419 {
420         NTSTATUS result = NT_STATUS_NO_SUCH_GROUP;
421         TALLOC_CTX *mem_ctx;
422         DOM_SID group_sid;
423         enum SID_NAME_USE type;
424         char *groupname;
425         BOOL user_must_be_member = False;
426         gid_t gid;
427
428         mem_ctx = talloc_new(NULL);
429         if (mem_ctx == NULL) {
430                 DEBUG(0, ("talloc_new failed\n"));
431                 return NT_STATUS_NO_MEMORY;
432         }
433
434         groupname = talloc_strdup(mem_ctx, lp_force_group(snum));
435         if (groupname == NULL) {
436                 DEBUG(1, ("talloc_strdup failed\n"));
437                 result = NT_STATUS_NO_MEMORY;
438                 goto done;
439         }
440
441         if (groupname[0] == '+') {
442                 user_must_be_member = True;
443                 groupname += 1;
444         }
445
446         groupname = talloc_string_sub(mem_ctx, groupname,
447                                       "%S", lp_servicename(snum));
448
449         if (!lookup_name(mem_ctx, groupname,
450                          LOOKUP_NAME_ALL|LOOKUP_NAME_GROUP,
451                          NULL, NULL, &group_sid, &type)) {
452                 DEBUG(10, ("lookup_name(%s) failed\n",
453                            groupname));
454                 goto done;
455         }
456
457         if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
458             (type != SID_NAME_WKN_GRP)) {
459                 DEBUG(10, ("%s is a %s, not a group\n", groupname,
460                            sid_type_lookup(type)));
461                 goto done;
462         }
463
464         if (!sid_to_gid(&group_sid, &gid)) {
465                 DEBUG(10, ("sid_to_gid(%s) for %s failed\n",
466                            sid_string_static(&group_sid), groupname));
467                 goto done;
468         }
469
470         /*
471          * If the user has been forced and the forced group starts with a '+',
472          * then we only set the group to be the forced group if the forced
473          * user is a member of that group.  Otherwise, the meaning of the '+'
474          * would be ignored.
475          */
476
477         if (force_user && user_must_be_member) {
478                 if (user_in_group_sid(username, &group_sid)) {
479                         sid_copy(pgroup_sid, &group_sid);
480                         *pgid = gid;
481                         DEBUG(3,("Forced group %s for member %s\n",
482                                  groupname, username));
483                 }
484         } else {
485                 sid_copy(pgroup_sid, &group_sid);
486                 *pgid = gid;
487                 DEBUG(3,("Forced group %s\n", groupname));
488         }
489
490         result = NT_STATUS_OK;
491  done:
492         TALLOC_FREE(mem_ctx);
493         return result;
494 }
495
496 /****************************************************************************
497   Make a connection, given the snum to connect to, and the vuser of the
498   connecting user if appropriate.
499 ****************************************************************************/
500
501 static connection_struct *make_connection_snum(int snum, user_struct *vuser,
502                                                DATA_BLOB password, 
503                                                const char *pdev,
504                                                NTSTATUS *status)
505 {
506         struct passwd *pass = NULL;
507         BOOL guest = False;
508         connection_struct *conn;
509         SMB_STRUCT_STAT st;
510         fstring user;
511         fstring dev;
512         int ret;
513
514         *user = 0;
515         fstrcpy(dev, pdev);
516         SET_STAT_INVALID(st);
517
518         if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, dev))) {
519                 return NULL;
520         }       
521
522         conn = conn_new();
523         if (!conn) {
524                 DEBUG(0,("Couldn't find free connection.\n"));
525                 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
526                 return NULL;
527         }
528
529         conn->nt_user_token = NULL;
530
531         if (lp_guest_only(snum)) {
532                 const char *guestname = lp_guestaccount();
533                 NTSTATUS status2;
534                 char *found_username;
535                 guest = True;
536                 pass = getpwnam_alloc(NULL, guestname);
537                 if (!pass) {
538                         DEBUG(0,("make_connection_snum: Invalid guest "
539                                  "account %s??\n",guestname));
540                         conn_free(conn);
541                         *status = NT_STATUS_NO_SUCH_USER;
542                         return NULL;
543                 }
544                 status2 = create_token_from_username(NULL, pass->pw_name, True,
545                                                      &conn->uid, &conn->gid,
546                                                      &found_username,
547                                                      &conn->nt_user_token);
548                 if (!NT_STATUS_IS_OK(status2)) {
549                         conn_free(conn);
550                         *status = status2;
551                         return NULL;
552                 }
553                 fstrcpy(user, found_username);
554                 string_set(&conn->user,user);
555                 conn->force_user = True;
556                 TALLOC_FREE(pass);
557                 DEBUG(3,("Guest only user %s\n",user));
558         } else if (vuser) {
559                 if (vuser->guest) {
560                         if (!lp_guest_ok(snum)) {
561                                 DEBUG(2, ("guest user (from session setup) "
562                                           "not permitted to access this share "
563                                           "(%s)\n", lp_servicename(snum)));
564                                       conn_free(conn);
565                                       *status = NT_STATUS_ACCESS_DENIED;
566                                       return NULL;
567                         }
568                 } else {
569                         if (!user_ok_token(vuser->user.unix_name,
570                                            vuser->nt_user_token, snum)) {
571                                 DEBUG(2, ("user '%s' (from session setup) not "
572                                           "permitted to access this share "
573                                           "(%s)\n", vuser->user.unix_name,
574                                           lp_servicename(snum)));
575                                 conn_free(conn);
576                                 *status = NT_STATUS_ACCESS_DENIED;
577                                 return NULL;
578                         }
579                 }
580                 conn->vuid = vuser->vuid;
581                 conn->uid = vuser->uid;
582                 conn->gid = vuser->gid;
583                 string_set(&conn->user,vuser->user.unix_name);
584                 fstrcpy(user,vuser->user.unix_name);
585                 guest = vuser->guest; 
586         } else if (lp_security() == SEC_SHARE) {
587                 NTSTATUS status2;
588                 char *found_username;
589                 /* add it as a possible user name if we 
590                    are in share mode security */
591                 add_session_user(lp_servicename(snum));
592                 /* shall we let them in? */
593                 if (!authorise_login(snum,user,password,&guest)) {
594                         DEBUG( 2, ( "Invalid username/password for [%s]\n", 
595                                     lp_servicename(snum)) );
596                         conn_free(conn);
597                         *status = NT_STATUS_WRONG_PASSWORD;
598                         return NULL;
599                 }
600                 pass = Get_Pwnam(user);
601                 status2 = create_token_from_username(NULL, pass->pw_name, True,
602                                                      &conn->uid, &conn->gid,
603                                                      &found_username,
604                                                      &conn->nt_user_token);
605                 if (!NT_STATUS_IS_OK(status2)) {
606                         conn_free(conn);
607                         *status = status2;
608                         return NULL;
609                 }
610                 fstrcpy(user, found_username);
611                 string_set(&conn->user,user);
612                 conn->force_user = True;
613         } else {
614                 DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
615                 conn_free(conn);
616                 *status = NT_STATUS_ACCESS_DENIED;
617                 return NULL;
618         }
619
620         add_session_user(user);
621
622         safe_strcpy(conn->client_address, client_addr(), 
623                     sizeof(conn->client_address)-1);
624         conn->num_files_open = 0;
625         conn->lastused = conn->lastused_count = time(NULL);
626         conn->params->service = snum;
627         conn->used = True;
628         conn->printer = (strncmp(dev,"LPT",3) == 0);
629         conn->ipc = ( (strncmp(dev,"IPC",3) == 0) ||
630                       ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) );
631         conn->dirptr = NULL;
632
633         /* Case options for the share. */
634         if (lp_casesensitive(snum) == Auto) {
635                 /* We will be setting this per packet. Set to be case
636                  * insensitive for now. */
637                 conn->case_sensitive = False;
638         } else {
639                 conn->case_sensitive = (BOOL)lp_casesensitive(snum);
640         }
641
642         conn->case_preserve = lp_preservecase(snum);
643         conn->short_case_preserve = lp_shortpreservecase(snum);
644
645         conn->veto_list = NULL;
646         conn->hide_list = NULL;
647         conn->veto_oplock_list = NULL;
648         conn->aio_write_behind_list = NULL;
649         string_set(&conn->dirpath,"");
650         string_set(&conn->user,user);
651
652         conn->read_only = lp_readonly(SNUM(conn));
653         conn->admin_user = False;
654
655         /*
656          * If force user is true, then store the given userid and the gid of
657          * the user we're forcing.
658          * For auxiliary groups see below.
659          */
660         
661         if (*lp_force_user(snum)) {
662                 NTSTATUS status2;
663
664                 status2 = find_forced_user(snum,
665                                            (vuser != NULL) && vuser->guest,
666                                            &conn->uid, &conn->gid, user,
667                                            &conn->nt_user_token);
668                 if (!NT_STATUS_IS_OK(status2)) {
669                         conn_free(conn);
670                         *status = status2;
671                         return NULL;
672                 }
673                 string_set(&conn->user,user);
674                 conn->force_user = True;
675                 DEBUG(3,("Forced user %s\n",user));       
676         }
677
678         /*
679          * If force group is true, then override
680          * any groupid stored for the connecting user.
681          */
682         
683         if (*lp_force_group(snum)) {
684                 NTSTATUS status2;
685                 DOM_SID group_sid;
686
687                 status2 = find_forced_group(conn->force_user,
688                                             snum, user,
689                                             &group_sid, &conn->gid);
690                 if (!NT_STATUS_IS_OK(status2)) {
691                         conn_free(conn);
692                         *status = status2;
693                         return NULL;
694                 }
695
696                 if ((conn->nt_user_token == NULL) && (vuser != NULL)) {
697
698                         /* Not force user and not security=share, but force
699                          * group. vuser has a token to copy */
700                         
701                         conn->nt_user_token = dup_nt_token(
702                                 NULL, vuser->nt_user_token);
703                         if (conn->nt_user_token == NULL) {
704                                 DEBUG(0, ("dup_nt_token failed\n"));
705                                 conn_free(conn);
706                                 *status = NT_STATUS_NO_MEMORY;
707                                 return NULL;
708                         }
709                 }
710
711                 /* If conn->nt_user_token is still NULL, we have
712                  * security=share. This means ignore the SID, as we had no
713                  * vuser to copy from */
714
715                 if (conn->nt_user_token != NULL) {
716                         /* Overwrite the primary group sid */
717                         sid_copy(&conn->nt_user_token->user_sids[1],
718                                  &group_sid);
719
720                 }
721                 conn->force_group = True;
722         }
723
724         if (conn->nt_user_token != NULL) {
725                 size_t i;
726
727                 /* We have a share-specific token from force [user|group].
728                  * This means we have to create the list of unix groups from
729                  * the list of sids. */
730
731                 conn->ngroups = 0;
732                 conn->groups = NULL;
733
734                 for (i=0; i<conn->nt_user_token->num_sids; i++) {
735                         gid_t gid;
736                         DOM_SID *sid = &conn->nt_user_token->user_sids[i];
737
738                         if (!sid_to_gid(sid, &gid)) {
739                                 DEBUG(10, ("Could not convert SID %s to gid, "
740                                            "ignoring it\n",
741                                            sid_string_static(sid)));
742                                 continue;
743                         }
744                         add_gid_to_array_unique(NULL, gid, &conn->groups,
745                                                 &conn->ngroups);
746                 }
747         }
748
749         {
750                 pstring s;
751                 pstrcpy(s,lp_pathname(snum));
752                 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
753                                       conn->connectpath, conn->gid,
754                                       get_current_username(),
755                                       current_user_info.domain,
756                                       s, sizeof(s));
757                 set_conn_connectpath(conn,s);
758                 DEBUG(3,("Connect path is '%s' for service [%s]\n",s,
759                          lp_servicename(snum)));
760         }
761
762         /*
763          * New code to check if there's a share security descripter
764          * added from NT server manager. This is done after the
765          * smb.conf checks are done as we need a uid and token. JRA.
766          *
767          */
768
769         {
770                 NT_USER_TOKEN *token = conn->nt_user_token ?
771                         conn->nt_user_token : vuser->nt_user_token;
772
773                 BOOL can_write = share_access_check(token,
774                                                     lp_servicename(snum),
775                                                     FILE_WRITE_DATA);
776
777                 if (!can_write) {
778                         if (!share_access_check(token,
779                                                 lp_servicename(snum),
780                                                 FILE_READ_DATA)) {
781                                 /* No access, read or write. */
782                                 DEBUG(0,("make_connection: connection to %s "
783                                          "denied due to security "
784                                          "descriptor.\n",
785                                           lp_servicename(snum)));
786                                 conn_free(conn);
787                                 *status = NT_STATUS_ACCESS_DENIED;
788                                 return NULL;
789                         } else {
790                                 conn->read_only = True;
791                         }
792                 }
793         }
794         /* Initialise VFS function pointers */
795
796         if (!smbd_vfs_init(conn)) {
797                 DEBUG(0, ("vfs_init failed for service %s\n",
798                           lp_servicename(snum)));
799                 conn_free(conn);
800                 *status = NT_STATUS_BAD_NETWORK_NAME;
801                 return NULL;
802         }
803
804         /*
805          * If widelinks are disallowed we need to canonicalise the connect
806          * path here to ensure we don't have any symlinks in the
807          * connectpath. We will be checking all paths on this connection are
808          * below this directory. We must do this after the VFS init as we
809          * depend on the realpath() pointer in the vfs table. JRA.
810          */
811         if (!lp_widelinks(snum)) {
812                 pstring s;
813                 pstrcpy(s,conn->connectpath);
814                 canonicalize_path(conn, s);
815                 set_conn_connectpath(conn,s);
816         }
817
818 /* ROOT Activities: */  
819         /* check number of connections */
820         if (!claim_connection(conn,
821                               lp_servicename(snum),
822                               lp_max_connections(snum),
823                               False,0)) {
824                 DEBUG(1,("too many connections - rejected\n"));
825                 conn_free(conn);
826                 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
827                 return NULL;
828         }  
829
830         /* Preexecs are done here as they might make the dir we are to ChDir
831          * to below */
832         /* execute any "root preexec = " line */
833         if (*lp_rootpreexec(snum)) {
834                 pstring cmd;
835                 pstrcpy(cmd,lp_rootpreexec(snum));
836                 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
837                                       conn->connectpath, conn->gid,
838                                       get_current_username(),
839                                       current_user_info.domain,
840                                       cmd, sizeof(cmd));
841                 DEBUG(5,("cmd=%s\n",cmd));
842                 ret = smbrun(cmd,NULL);
843                 if (ret != 0 && lp_rootpreexec_close(snum)) {
844                         DEBUG(1,("root preexec gave %d - failing "
845                                  "connection\n", ret));
846                         yield_connection(conn, lp_servicename(snum));
847                         conn_free(conn);
848                         *status = NT_STATUS_ACCESS_DENIED;
849                         return NULL;
850                 }
851         }
852
853 /* USER Activites: */
854         if (!change_to_user(conn, conn->vuid)) {
855                 /* No point continuing if they fail the basic checks */
856                 DEBUG(0,("Can't become connected user!\n"));
857                 yield_connection(conn, lp_servicename(snum));
858                 conn_free(conn);
859                 *status = NT_STATUS_LOGON_FAILURE;
860                 return NULL;
861         }
862
863         /* Remember that a different vuid can connect later without these
864          * checks... */
865         
866         /* Preexecs are done here as they might make the dir we are to ChDir
867          * to below */
868
869         /* execute any "preexec = " line */
870         if (*lp_preexec(snum)) {
871                 pstring cmd;
872                 pstrcpy(cmd,lp_preexec(snum));
873                 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
874                                       conn->connectpath, conn->gid,
875                                       get_current_username(),
876                                       current_user_info.domain,
877                                       cmd, sizeof(cmd));
878                 ret = smbrun(cmd,NULL);
879                 if (ret != 0 && lp_preexec_close(snum)) {
880                         DEBUG(1,("preexec gave %d - failing connection\n",
881                                  ret));
882                         change_to_root_user();
883                         yield_connection(conn, lp_servicename(snum));
884                         conn_free(conn);
885                         *status = NT_STATUS_ACCESS_DENIED;
886                         return NULL;
887                 }
888         }
889
890 #ifdef WITH_FAKE_KASERVER
891         if (lp_afs_share(snum)) {
892                 afs_login(conn);
893         }
894 #endif
895         
896         /* Add veto/hide lists */
897         if (!IS_IPC(conn) && !IS_PRINT(conn)) {
898                 set_namearray( &conn->veto_list, lp_veto_files(snum));
899                 set_namearray( &conn->hide_list, lp_hide_files(snum));
900                 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(snum));
901         }
902         
903         /* Invoke VFS make connection hook - do this before the VFS_STAT call
904            to allow any filesystems needing user credentials to initialize
905            themselves. */
906
907         if (SMB_VFS_CONNECT(conn, lp_servicename(snum), user) < 0) {
908                 DEBUG(0,("make_connection: VFS make connection failed!\n"));
909                 change_to_root_user();
910                 yield_connection(conn, lp_servicename(snum));
911                 conn_free(conn);
912                 *status = NT_STATUS_UNSUCCESSFUL;
913                 return NULL;
914         }
915
916         /* win2000 does not check the permissions on the directory
917            during the tree connect, instead relying on permission
918            check during individual operations. To match this behaviour
919            I have disabled this chdir check (tridge) */
920         /* the alternative is just to check the directory exists */
921         if ((ret = SMB_VFS_STAT(conn, conn->connectpath, &st)) != 0 ||
922             !S_ISDIR(st.st_mode)) {
923                 if (ret == 0 && !S_ISDIR(st.st_mode)) {
924                         DEBUG(0,("'%s' is not a directory, when connecting to "
925                                  "[%s]\n", conn->connectpath,
926                                  lp_servicename(snum)));
927                 } else {
928                         DEBUG(0,("'%s' does not exist or permission denied "
929                                  "when connecting to [%s] Error was %s\n",
930                                  conn->connectpath, lp_servicename(snum),
931                                  strerror(errno) ));
932                 }
933                 change_to_root_user();
934                 /* Call VFS disconnect hook */    
935                 SMB_VFS_DISCONNECT(conn);
936                 yield_connection(conn, lp_servicename(snum));
937                 conn_free(conn);
938                 *status = NT_STATUS_BAD_NETWORK_NAME;
939                 return NULL;
940         }
941         
942         string_set(&conn->origpath,conn->connectpath);
943         
944 #if SOFTLINK_OPTIMISATION
945         /* resolve any soft links early if possible */
946         if (vfs_ChDir(conn,conn->connectpath) == 0) {
947                 pstring s;
948                 pstrcpy(s,conn->connectpath);
949                 vfs_GetWd(conn,s);
950                 set_conn_connectpath(conn,s);
951                 vfs_ChDir(conn,conn->connectpath);
952         }
953 #endif
954         
955         /*
956          * Print out the 'connected as' stuff here as we need
957          * to know the effective uid and gid we will be using
958          * (at least initially).
959          */
960
961         if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
962                 dbgtext( "%s (%s) ", get_remote_machine_name(),
963                          conn->client_address );
964                 dbgtext( "%s", srv_is_signing_active() ? "signed " : "");
965                 dbgtext( "connect to service %s ", lp_servicename(snum) );
966                 dbgtext( "initially as user %s ", user );
967                 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
968                 dbgtext( "(pid %d)\n", (int)sys_getpid() );
969         }
970         
971         /* Setup the minimum value for a change notify wait time (seconds). */
972         set_change_notify_timeout(lp_change_notify_timeout(snum));
973
974         /* we've finished with the user stuff - go back to root */
975         change_to_root_user();
976         return(conn);
977 }
978
979 /***************************************************************************************
980  Simple wrapper function for make_connection() to include a call to 
981  vfs_chdir()
982  **************************************************************************************/
983  
984 connection_struct *make_connection_with_chdir(const char *service_in,
985                                               DATA_BLOB password, 
986                                               const char *dev, uint16 vuid,
987                                               NTSTATUS *status)
988 {
989         connection_struct *conn = NULL;
990         
991         conn = make_connection(service_in, password, dev, vuid, status);
992         
993         /*
994          * make_connection() does not change the directory for us any more
995          * so we have to do it as a separate step  --jerry
996          */
997          
998         if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) {
999                 DEBUG(0,("move_driver_to_download_area: Can't change "
1000                          "directory to %s for [print$] (%s)\n",
1001                          conn->connectpath,strerror(errno)));
1002                 yield_connection(conn, lp_servicename(SNUM(conn)));
1003                 conn_free(conn);
1004                 *status = NT_STATUS_UNSUCCESSFUL;
1005                 return NULL;
1006         }
1007         
1008         return conn;
1009 }
1010
1011 /****************************************************************************
1012  Make a connection to a service.
1013  *
1014  * @param service 
1015 ****************************************************************************/
1016
1017 connection_struct *make_connection(const char *service_in, DATA_BLOB password, 
1018                                    const char *pdev, uint16 vuid,
1019                                    NTSTATUS *status)
1020 {
1021         uid_t euid;
1022         user_struct *vuser = NULL;
1023         fstring service;
1024         fstring dev;
1025         int snum = -1;
1026
1027         fstrcpy(dev, pdev);
1028
1029         /* This must ONLY BE CALLED AS ROOT. As it exits this function as
1030          * root. */
1031         if (!non_root_mode() && (euid = geteuid()) != 0) {
1032                 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot "
1033                          "(%u)\n", (unsigned int)euid ));
1034                 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
1035         }
1036
1037         if(lp_security() != SEC_SHARE) {
1038                 vuser = get_valid_user_struct(vuid);
1039                 if (!vuser) {
1040                         DEBUG(1,("make_connection: refusing to connect with "
1041                                  "no session setup\n"));
1042                         *status = NT_STATUS_ACCESS_DENIED;
1043                         return NULL;
1044                 }
1045         }
1046
1047         /* Logic to try and connect to the correct [homes] share, preferably
1048            without too many getpwnam() lookups.  This is particulary nasty for
1049            winbind usernames, where the share name isn't the same as unix
1050            username.
1051
1052            The snum of the homes share is stored on the vuser at session setup
1053            time.
1054         */
1055
1056         if (strequal(service_in,HOMES_NAME)) {
1057                 if(lp_security() != SEC_SHARE) {
1058                         DATA_BLOB no_pw = data_blob(NULL, 0);
1059                         if (vuser->homes_snum == -1) {
1060                                 DEBUG(2, ("[homes] share not available for "
1061                                           "this user because it was not found "
1062                                           "or created at session setup "
1063                                           "time\n"));
1064                                 *status = NT_STATUS_BAD_NETWORK_NAME;
1065                                 return NULL;
1066                         }
1067                         DEBUG(5, ("making a connection to [homes] service "
1068                                   "created at session setup time\n"));
1069                         return make_connection_snum(vuser->homes_snum,
1070                                                     vuser, no_pw, 
1071                                                     dev, status);
1072                 } else {
1073                         /* Security = share. Try with
1074                          * current_user_info.smb_name as the username.  */
1075                         if (*current_user_info.smb_name) {
1076                                 fstring unix_username;
1077                                 fstrcpy(unix_username,
1078                                         current_user_info.smb_name);
1079                                 map_username(unix_username);
1080                                 snum = find_service(unix_username);
1081                         } 
1082                         if (snum != -1) {
1083                                 DEBUG(5, ("making a connection to 'homes' "
1084                                           "service %s based on "
1085                                           "security=share\n", service_in));
1086                                 return make_connection_snum(snum, NULL,
1087                                                             password,
1088                                                             dev, status);
1089                         }
1090                 }
1091         } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
1092                    && strequal(service_in,
1093                                lp_servicename(vuser->homes_snum))) {
1094                 DATA_BLOB no_pw = data_blob(NULL, 0);
1095                 DEBUG(5, ("making a connection to 'homes' service [%s] "
1096                           "created at session setup time\n", service_in));
1097                 return make_connection_snum(vuser->homes_snum,
1098                                             vuser, no_pw, 
1099                                             dev, status);
1100         }
1101         
1102         fstrcpy(service, service_in);
1103
1104         strlower_m(service);
1105
1106         snum = find_service(service);
1107
1108         if (snum < 0) {
1109                 if (strequal(service,"IPC$") ||
1110                     (lp_enable_asu_support() && strequal(service,"ADMIN$"))) {
1111                         DEBUG(3,("refusing IPC connection to %s\n", service));
1112                         *status = NT_STATUS_ACCESS_DENIED;
1113                         return NULL;
1114                 }
1115
1116                 DEBUG(0,("%s (%s) couldn't find service %s\n",
1117                          get_remote_machine_name(), client_addr(), service));
1118                 *status = NT_STATUS_BAD_NETWORK_NAME;
1119                 return NULL;
1120         }
1121
1122         /* Handle non-Dfs clients attempting connections to msdfs proxy */
1123         if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0'))  {
1124                 DEBUG(3, ("refusing connection to dfs proxy share '%s' "
1125                           "(pointing to %s)\n", 
1126                         service, lp_msdfs_proxy(snum)));
1127                 *status = NT_STATUS_BAD_NETWORK_NAME;
1128                 return NULL;
1129         }
1130
1131         DEBUG(5, ("making a connection to 'normal' service %s\n", service));
1132
1133         return make_connection_snum(snum, vuser,
1134                                     password,
1135                                     dev, status);
1136 }
1137
1138 /****************************************************************************
1139  Close a cnum.
1140 ****************************************************************************/
1141
1142 void close_cnum(connection_struct *conn, uint16 vuid)
1143 {
1144         if (IS_IPC(conn)) {
1145                 pipe_close_conn(conn);
1146         } else {
1147                 file_close_conn(conn);
1148                 dptr_closecnum(conn);
1149         }
1150
1151         change_to_root_user();
1152
1153         DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
1154                                  get_remote_machine_name(),
1155                                  conn->client_address,
1156                                  lp_servicename(SNUM(conn))));
1157
1158         /* Call VFS disconnect hook */    
1159         SMB_VFS_DISCONNECT(conn);
1160
1161         yield_connection(conn, lp_servicename(SNUM(conn)));
1162
1163         /* make sure we leave the directory available for unmount */
1164         vfs_ChDir(conn, "/");
1165
1166         /* execute any "postexec = " line */
1167         if (*lp_postexec(SNUM(conn)) && 
1168             change_to_user(conn, vuid))  {
1169                 pstring cmd;
1170                 pstrcpy(cmd,lp_postexec(SNUM(conn)));
1171                 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
1172                                       conn->connectpath, conn->gid,
1173                                       get_current_username(),
1174                                       current_user_info.domain,
1175                                       cmd, sizeof(cmd));
1176                 smbrun(cmd,NULL);
1177                 change_to_root_user();
1178         }
1179
1180         change_to_root_user();
1181         /* execute any "root postexec = " line */
1182         if (*lp_rootpostexec(SNUM(conn)))  {
1183                 pstring cmd;
1184                 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
1185                 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
1186                                       conn->connectpath, conn->gid,
1187                                       get_current_username(),
1188                                       current_user_info.domain,
1189                                       cmd, sizeof(cmd));
1190                 smbrun(cmd,NULL);
1191         }
1192
1193         conn_free(conn);
1194 }