r16945: Sync trunk -> 3.0 for 3.0.24 code. Still need
[vlendec/samba-autobuild/.git] / source3 / smbd / service.c
1 /* 
2    Unix SMB/CIFS implementation.
3    service (connection) opening and closing
4    Copyright (C) Andrew Tridgell 1992-1998
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22
23 extern userdom_struct current_user_info;
24
25 /****************************************************************************
26  Ensure when setting connectpath it is a canonicalized (no ./ // or ../)
27  absolute path stating in / and not ending in /.
28  Observent people will notice a similarity between this and check_path_syntax :-).
29 ****************************************************************************/
30
31 void set_conn_connectpath(connection_struct *conn, const pstring connectpath)
32 {
33         pstring destname;
34         char *d = destname;
35         const char *s = connectpath;
36         BOOL start_of_name_component = True;
37
38         *d++ = '/'; /* Always start with root. */
39
40         while (*s) {
41                 if (*s == '/') {
42                         /* Eat multiple '/' */
43                         while (*s == '/') {
44                                 s++;
45                         }
46                         if ((d > destname + 1) && (*s != '\0')) {
47                                 *d++ = '/';
48                         }
49                         start_of_name_component = True;
50                         continue;
51                 }
52
53                 if (start_of_name_component) {
54                         if ((s[0] == '.') && (s[1] == '.') && (s[2] == '/' || s[2] == '\0')) {
55                                 /* Uh oh - "/../" or "/..\0" ! */
56
57                                 /* Go past the ../ or .. */
58                                 if (s[2] == '/') {
59                                         s += 3;
60                                 } else {
61                                         s += 2; /* Go past the .. */
62                                 }
63
64                                 /* If  we just added a '/' - delete it */
65                                 if ((d > destname) && (*(d-1) == '/')) {
66                                         *(d-1) = '\0';
67                                         d--;
68                                 }
69
70                                 /* Are we at the start ? Can't go back further if so. */
71                                 if (d <= destname) {
72                                         *d++ = '/'; /* Can't delete root */
73                                         continue;
74                                 }
75                                 /* Go back one level... */
76                                 /* Decrement d first as d points to the *next* char to write into. */
77                                 for (d--; d > destname; d--) {
78                                         if (*d == '/') {
79                                                 break;
80                                         }
81                                 }
82                                 /* We're still at the start of a name component, just the previous one. */
83                                 continue;
84                         } else if ((s[0] == '.') && ((s[1] == '\0') || s[1] == '/')) {
85                                 /* Component of pathname can't be "." only - skip the '.' . */
86                                 if (s[1] == '/') {
87                                         s += 2;
88                                 } else {
89                                         s++;
90                                 }
91                                 continue;
92                         }
93                 }
94
95                 if (!(*s & 0x80)) {
96                         *d++ = *s++;
97                 } else {
98                         switch(next_mb_char_size(s)) {
99                                 case 4:
100                                         *d++ = *s++;
101                                 case 3:
102                                         *d++ = *s++;
103                                 case 2:
104                                         *d++ = *s++;
105                                 case 1:
106                                         *d++ = *s++;
107                                         break;
108                                 default:
109                                         break;
110                         }
111                 }
112                 start_of_name_component = False;
113         }
114         *d = '\0';
115
116         /* And must not end in '/' */
117         if (d > destname + 1 && (*(d-1) == '/')) {
118                 *(d-1) = '\0';
119         }
120
121         DEBUG(10,("set_conn_connectpath: service %s, connectpath = %s\n",
122                 lp_servicename(SNUM(conn)), destname ));
123
124         string_set(&conn->connectpath, destname);
125 }
126
127 /****************************************************************************
128  Load parameters specific to a connection/service.
129 ****************************************************************************/
130
131 BOOL set_current_service(connection_struct *conn, uint16 flags, BOOL do_chdir)
132 {
133         static connection_struct *last_conn;
134         static uint16 last_flags;
135         int snum;
136
137         if (!conn)  {
138                 last_conn = NULL;
139                 return(False);
140         }
141
142         conn->lastused_count++;
143
144         snum = SNUM(conn);
145   
146         if (do_chdir &&
147             vfs_ChDir(conn,conn->connectpath) != 0 &&
148             vfs_ChDir(conn,conn->origpath) != 0) {
149                 DEBUG(0,("chdir (%s) failed\n",
150                          conn->connectpath));
151                 return(False);
152         }
153
154         if ((conn == last_conn) && (last_flags == flags)) {
155                 return(True);
156         }
157
158         last_conn = conn;
159         last_flags = flags;
160         
161         /* Obey the client case sensitivity requests - only for clients that support it. */
162         switch (lp_casesensitive(snum)) {
163                 case Auto:
164                         {
165                                 /* We need this uglyness due to DOS/Win9x clients that lie about case insensitivity. */
166                                 enum remote_arch_types ra_type = get_remote_arch();
167                                 if ((ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
168                                         /* Client can't support per-packet case sensitive pathnames. */
169                                         conn->case_sensitive = False;
170                                 } else {
171                                         conn->case_sensitive = !(flags & FLAG_CASELESS_PATHNAMES);
172                                 }
173                         }
174                         break;
175                 case True:
176                         conn->case_sensitive = True;
177                         break;
178                 default:
179                         conn->case_sensitive = False;
180                         break;
181         }
182         return(True);
183 }
184
185 /****************************************************************************
186  Add a home service. Returns the new service number or -1 if fail.
187 ****************************************************************************/
188
189 int add_home_service(const char *service, const char *username, const char *homedir)
190 {
191         int iHomeService;
192
193         if (!service || !homedir)
194                 return -1;
195
196         if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0)
197                 return -1;
198
199         /*
200          * If this is a winbindd provided username, remove
201          * the domain component before adding the service.
202          * Log a warning if the "path=" parameter does not
203          * include any macros.
204          */
205
206         {
207                 const char *p = strchr(service,*lp_winbind_separator());
208
209                 /* We only want the 'user' part of the string */
210                 if (p) {
211                         service = p + 1;
212                 }
213         }
214
215         if (!lp_add_home(service, iHomeService, username, homedir)) {
216                 return -1;
217         }
218         
219         return lp_servicenumber(service);
220
221 }
222
223
224 /**
225  * Find a service entry.
226  *
227  * @param service is modified (to canonical form??)
228  **/
229
230 int find_service(fstring service)
231 {
232         int iService;
233
234         all_string_sub(service,"\\","/",0);
235
236         iService = lp_servicenumber(service);
237
238         /* now handle the special case of a home directory */
239         if (iService < 0) {
240                 char *phome_dir = get_user_home_dir(service);
241
242                 if(!phome_dir) {
243                         /*
244                          * Try mapping the servicename, it may
245                          * be a Windows to unix mapped user name.
246                          */
247                         if(map_username(service))
248                                 phome_dir = get_user_home_dir(service);
249                 }
250
251                 DEBUG(3,("checking for home directory %s gave %s\n",service,
252                         phome_dir?phome_dir:"(NULL)"));
253
254                 iService = add_home_service(service,service /* 'username' */, phome_dir);
255         }
256
257         /* If we still don't have a service, attempt to add it as a printer. */
258         if (iService < 0) {
259                 int iPrinterService;
260
261                 if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) >= 0) {
262                         DEBUG(3,("checking whether %s is a valid printer name...\n", service));
263                         if (pcap_printername_ok(service)) {
264                                 DEBUG(3,("%s is a valid printer name\n", service));
265                                 DEBUG(3,("adding %s as a printer service\n", service));
266                                 lp_add_printer(service, iPrinterService);
267                                 iService = lp_servicenumber(service);
268                                 if (iService < 0) {
269                                         DEBUG(0,("failed to add %s as a printer service!\n", service));
270                                 }
271                         } else {
272                                 DEBUG(3,("%s is not a valid printer name\n", service));
273                         }
274                 }
275         }
276
277         /* Check for default vfs service?  Unsure whether to implement this */
278         if (iService < 0) {
279         }
280
281         /* just possibly it's a default service? */
282         if (iService < 0) {
283                 char *pdefservice = lp_defaultservice();
284                 if (pdefservice && *pdefservice && !strequal(pdefservice,service) && !strstr_m(service,"..")) {
285                         /*
286                          * We need to do a local copy here as lp_defaultservice() 
287                          * returns one of the rotating lp_string buffers that
288                          * could get overwritten by the recursive find_service() call
289                          * below. Fix from Josef Hinteregger <joehtg@joehtg.co.at>.
290                          */
291                         pstring defservice;
292                         pstrcpy(defservice, pdefservice);
293                         iService = find_service(defservice);
294                         if (iService >= 0) {
295                                 all_string_sub(service, "_","/",0);
296                                 iService = lp_add_service(service, iService);
297                         }
298                 }
299         }
300
301         /* Is it a usershare service ? */
302         if (iService < 0 && *lp_usershare_path()) {
303                 /* Ensure the name is canonicalized. */
304                 strlower_m(service);
305                 iService = load_usershare_service(service);
306         }
307
308         if (iService >= 0) {
309                 if (!VALID_SNUM(iService)) {
310                         DEBUG(0,("Invalid snum %d for %s\n",iService, service));
311                         iService = -1;
312                 }
313         }
314
315         if (iService < 0)
316                 DEBUG(3,("find_service() failed to find service %s\n", service));
317
318         return (iService);
319 }
320
321
322 /****************************************************************************
323  do some basic sainity checks on the share.  
324  This function modifies dev, ecode.
325 ****************************************************************************/
326
327 static NTSTATUS share_sanity_checks(int snum, fstring dev) 
328 {
329         
330         if (!lp_snum_ok(snum) || 
331             !check_access(smbd_server_fd(), 
332                           lp_hostsallow(snum), lp_hostsdeny(snum))) {    
333                 return NT_STATUS_ACCESS_DENIED;
334         }
335
336         if (dev[0] == '?' || !dev[0]) {
337                 if (lp_print_ok(snum)) {
338                         fstrcpy(dev,"LPT1:");
339                 } else if (strequal(lp_fstype(snum), "IPC")) {
340                         fstrcpy(dev, "IPC");
341                 } else {
342                         fstrcpy(dev,"A:");
343                 }
344         }
345
346         strupper_m(dev);
347
348         if (lp_print_ok(snum)) {
349                 if (!strequal(dev, "LPT1:")) {
350                         return NT_STATUS_BAD_DEVICE_TYPE;
351                 }
352         } else if (strequal(lp_fstype(snum), "IPC")) {
353                 if (!strequal(dev, "IPC")) {
354                         return NT_STATUS_BAD_DEVICE_TYPE;
355                 }
356         } else if (!strequal(dev, "A:")) {
357                 return NT_STATUS_BAD_DEVICE_TYPE;
358         }
359
360         /* Behave as a printer if we are supposed to */
361         if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) {
362                 fstrcpy(dev, "LPT1:");
363         }
364
365         return NT_STATUS_OK;
366 }
367
368 static NTSTATUS find_forced_user(int snum, BOOL vuser_is_guest,
369                                  uid_t *uid, gid_t *gid, fstring username,
370                                  struct nt_user_token **token)
371 {
372         TALLOC_CTX *mem_ctx;
373         char *fuser, *found_username;
374         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                 BOOL can_write = share_access_check(conn, snum, vuser,
771                                                     FILE_WRITE_DATA);
772
773                 if (!can_write) {
774                         if (!share_access_check(conn, snum, vuser,
775                                                 FILE_READ_DATA)) {
776                                 /* No access, read or write. */
777                                 DEBUG(0,("make_connection: connection to %s "
778                                          "denied due to security "
779                                          "descriptor.\n",
780                                           lp_servicename(snum)));
781                                 conn_free(conn);
782                                 *status = NT_STATUS_ACCESS_DENIED;
783                                 return NULL;
784                         } else {
785                                 conn->read_only = True;
786                         }
787                 }
788         }
789         /* Initialise VFS function pointers */
790
791         if (!smbd_vfs_init(conn)) {
792                 DEBUG(0, ("vfs_init failed for service %s\n",
793                           lp_servicename(snum)));
794                 conn_free(conn);
795                 *status = NT_STATUS_BAD_NETWORK_NAME;
796                 return NULL;
797         }
798
799         /*
800          * If widelinks are disallowed we need to canonicalise the connect
801          * path here to ensure we don't have any symlinks in the
802          * connectpath. We will be checking all paths on this connection are
803          * below this directory. We must do this after the VFS init as we
804          * depend on the realpath() pointer in the vfs table. JRA.
805          */
806         if (!lp_widelinks(snum)) {
807                 pstring s;
808                 pstrcpy(s,conn->connectpath);
809                 canonicalize_path(conn, s);
810                 set_conn_connectpath(conn,s);
811         }
812
813 /* ROOT Activities: */  
814         /* check number of connections */
815         if (!claim_connection(conn,
816                               lp_servicename(snum),
817                               lp_max_connections(snum),
818                               False,0)) {
819                 DEBUG(1,("too many connections - rejected\n"));
820                 conn_free(conn);
821                 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
822                 return NULL;
823         }  
824
825         /* Preexecs are done here as they might make the dir we are to ChDir
826          * to below */
827         /* execute any "root preexec = " line */
828         if (*lp_rootpreexec(snum)) {
829                 pstring cmd;
830                 pstrcpy(cmd,lp_rootpreexec(snum));
831                 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
832                                       conn->connectpath, conn->gid,
833                                       get_current_username(),
834                                       current_user_info.domain,
835                                       cmd, sizeof(cmd));
836                 DEBUG(5,("cmd=%s\n",cmd));
837                 ret = smbrun(cmd,NULL);
838                 if (ret != 0 && lp_rootpreexec_close(snum)) {
839                         DEBUG(1,("root preexec gave %d - failing "
840                                  "connection\n", ret));
841                         yield_connection(conn, lp_servicename(snum));
842                         conn_free(conn);
843                         *status = NT_STATUS_ACCESS_DENIED;
844                         return NULL;
845                 }
846         }
847
848 /* USER Activites: */
849         if (!change_to_user(conn, conn->vuid)) {
850                 /* No point continuing if they fail the basic checks */
851                 DEBUG(0,("Can't become connected user!\n"));
852                 yield_connection(conn, lp_servicename(snum));
853                 conn_free(conn);
854                 *status = NT_STATUS_LOGON_FAILURE;
855                 return NULL;
856         }
857
858         /* Remember that a different vuid can connect later without these
859          * checks... */
860         
861         /* Preexecs are done here as they might make the dir we are to ChDir
862          * to below */
863
864         /* execute any "preexec = " line */
865         if (*lp_preexec(snum)) {
866                 pstring cmd;
867                 pstrcpy(cmd,lp_preexec(snum));
868                 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
869                                       conn->connectpath, conn->gid,
870                                       get_current_username(),
871                                       current_user_info.domain,
872                                       cmd, sizeof(cmd));
873                 ret = smbrun(cmd,NULL);
874                 if (ret != 0 && lp_preexec_close(snum)) {
875                         DEBUG(1,("preexec gave %d - failing connection\n",
876                                  ret));
877                         change_to_root_user();
878                         yield_connection(conn, lp_servicename(snum));
879                         conn_free(conn);
880                         *status = NT_STATUS_ACCESS_DENIED;
881                         return NULL;
882                 }
883         }
884
885 #ifdef WITH_FAKE_KASERVER
886         if (lp_afs_share(snum)) {
887                 afs_login(conn);
888         }
889 #endif
890         
891         /* Add veto/hide lists */
892         if (!IS_IPC(conn) && !IS_PRINT(conn)) {
893                 set_namearray( &conn->veto_list, lp_veto_files(snum));
894                 set_namearray( &conn->hide_list, lp_hide_files(snum));
895                 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(snum));
896         }
897         
898         /* Invoke VFS make connection hook - do this before the VFS_STAT call
899            to allow any filesystems needing user credentials to initialize
900            themselves. */
901
902         if (SMB_VFS_CONNECT(conn, lp_servicename(snum), user) < 0) {
903                 DEBUG(0,("make_connection: VFS make connection failed!\n"));
904                 change_to_root_user();
905                 yield_connection(conn, lp_servicename(snum));
906                 conn_free(conn);
907                 *status = NT_STATUS_UNSUCCESSFUL;
908                 return NULL;
909         }
910
911         /* win2000 does not check the permissions on the directory
912            during the tree connect, instead relying on permission
913            check during individual operations. To match this behaviour
914            I have disabled this chdir check (tridge) */
915         /* the alternative is just to check the directory exists */
916         if ((ret = SMB_VFS_STAT(conn, conn->connectpath, &st)) != 0 ||
917             !S_ISDIR(st.st_mode)) {
918                 if (ret == 0 && !S_ISDIR(st.st_mode)) {
919                         DEBUG(0,("'%s' is not a directory, when connecting to "
920                                  "[%s]\n", conn->connectpath,
921                                  lp_servicename(snum)));
922                 } else {
923                         DEBUG(0,("'%s' does not exist or permission denied "
924                                  "when connecting to [%s] Error was %s\n",
925                                  conn->connectpath, lp_servicename(snum),
926                                  strerror(errno) ));
927                 }
928                 change_to_root_user();
929                 /* Call VFS disconnect hook */    
930                 SMB_VFS_DISCONNECT(conn);
931                 yield_connection(conn, lp_servicename(snum));
932                 conn_free(conn);
933                 *status = NT_STATUS_BAD_NETWORK_NAME;
934                 return NULL;
935         }
936         
937         string_set(&conn->origpath,conn->connectpath);
938         
939 #if SOFTLINK_OPTIMISATION
940         /* resolve any soft links early if possible */
941         if (vfs_ChDir(conn,conn->connectpath) == 0) {
942                 pstring s;
943                 pstrcpy(s,conn->connectpath);
944                 vfs_GetWd(conn,s);
945                 set_conn_connectpath(conn,s);
946                 vfs_ChDir(conn,conn->connectpath);
947         }
948 #endif
949         
950         /*
951          * Print out the 'connected as' stuff here as we need
952          * to know the effective uid and gid we will be using
953          * (at least initially).
954          */
955
956         if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
957                 dbgtext( "%s (%s) ", get_remote_machine_name(),
958                          conn->client_address );
959                 dbgtext( "%s", srv_is_signing_active() ? "signed " : "");
960                 dbgtext( "connect to service %s ", lp_servicename(snum) );
961                 dbgtext( "initially as user %s ", user );
962                 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
963                 dbgtext( "(pid %d)\n", (int)sys_getpid() );
964         }
965         
966         /* Setup the minimum value for a change notify wait time (seconds). */
967         set_change_notify_timeout(lp_change_notify_timeout(snum));
968
969         /* we've finished with the user stuff - go back to root */
970         change_to_root_user();
971         return(conn);
972 }
973
974 /***************************************************************************************
975  Simple wrapper function for make_connection() to include a call to 
976  vfs_chdir()
977  **************************************************************************************/
978  
979 connection_struct *make_connection_with_chdir(const char *service_in,
980                                               DATA_BLOB password, 
981                                               const char *dev, uint16 vuid,
982                                               NTSTATUS *status)
983 {
984         connection_struct *conn = NULL;
985         
986         conn = make_connection(service_in, password, dev, vuid, status);
987         
988         /*
989          * make_connection() does not change the directory for us any more
990          * so we have to do it as a separate step  --jerry
991          */
992          
993         if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) {
994                 DEBUG(0,("move_driver_to_download_area: Can't change "
995                          "directory to %s for [print$] (%s)\n",
996                          conn->connectpath,strerror(errno)));
997                 yield_connection(conn, lp_servicename(SNUM(conn)));
998                 conn_free(conn);
999                 *status = NT_STATUS_UNSUCCESSFUL;
1000                 return NULL;
1001         }
1002         
1003         return conn;
1004 }
1005
1006 /****************************************************************************
1007  Make a connection to a service.
1008  *
1009  * @param service 
1010 ****************************************************************************/
1011
1012 connection_struct *make_connection(const char *service_in, DATA_BLOB password, 
1013                                    const char *pdev, uint16 vuid,
1014                                    NTSTATUS *status)
1015 {
1016         uid_t euid;
1017         user_struct *vuser = NULL;
1018         fstring service;
1019         fstring dev;
1020         int snum = -1;
1021
1022         fstrcpy(dev, pdev);
1023
1024         /* This must ONLY BE CALLED AS ROOT. As it exits this function as
1025          * root. */
1026         if (!non_root_mode() && (euid = geteuid()) != 0) {
1027                 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot "
1028                          "(%u)\n", (unsigned int)euid ));
1029                 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
1030         }
1031
1032         if(lp_security() != SEC_SHARE) {
1033                 vuser = get_valid_user_struct(vuid);
1034                 if (!vuser) {
1035                         DEBUG(1,("make_connection: refusing to connect with "
1036                                  "no session setup\n"));
1037                         *status = NT_STATUS_ACCESS_DENIED;
1038                         return NULL;
1039                 }
1040         }
1041
1042         /* Logic to try and connect to the correct [homes] share, preferably
1043            without too many getpwnam() lookups.  This is particulary nasty for
1044            winbind usernames, where the share name isn't the same as unix
1045            username.
1046
1047            The snum of the homes share is stored on the vuser at session setup
1048            time.
1049         */
1050
1051         if (strequal(service_in,HOMES_NAME)) {
1052                 if(lp_security() != SEC_SHARE) {
1053                         DATA_BLOB no_pw = data_blob(NULL, 0);
1054                         if (vuser->homes_snum == -1) {
1055                                 DEBUG(2, ("[homes] share not available for "
1056                                           "this user because it was not found "
1057                                           "or created at session setup "
1058                                           "time\n"));
1059                                 *status = NT_STATUS_BAD_NETWORK_NAME;
1060                                 return NULL;
1061                         }
1062                         DEBUG(5, ("making a connection to [homes] service "
1063                                   "created at session setup time\n"));
1064                         return make_connection_snum(vuser->homes_snum,
1065                                                     vuser, no_pw, 
1066                                                     dev, status);
1067                 } else {
1068                         /* Security = share. Try with
1069                          * current_user_info.smb_name as the username.  */
1070                         if (*current_user_info.smb_name) {
1071                                 fstring unix_username;
1072                                 fstrcpy(unix_username,
1073                                         current_user_info.smb_name);
1074                                 map_username(unix_username);
1075                                 snum = find_service(unix_username);
1076                         } 
1077                         if (snum != -1) {
1078                                 DEBUG(5, ("making a connection to 'homes' "
1079                                           "service %s based on "
1080                                           "security=share\n", service_in));
1081                                 return make_connection_snum(snum, NULL,
1082                                                             password,
1083                                                             dev, status);
1084                         }
1085                 }
1086         } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
1087                    && strequal(service_in,
1088                                lp_servicename(vuser->homes_snum))) {
1089                 DATA_BLOB no_pw = data_blob(NULL, 0);
1090                 DEBUG(5, ("making a connection to 'homes' service [%s] "
1091                           "created at session setup time\n", service_in));
1092                 return make_connection_snum(vuser->homes_snum,
1093                                             vuser, no_pw, 
1094                                             dev, status);
1095         }
1096         
1097         fstrcpy(service, service_in);
1098
1099         strlower_m(service);
1100
1101         snum = find_service(service);
1102
1103         if (snum < 0) {
1104                 if (strequal(service,"IPC$") ||
1105                     (lp_enable_asu_support() && strequal(service,"ADMIN$"))) {
1106                         DEBUG(3,("refusing IPC connection to %s\n", service));
1107                         *status = NT_STATUS_ACCESS_DENIED;
1108                         return NULL;
1109                 }
1110
1111                 DEBUG(0,("%s (%s) couldn't find service %s\n",
1112                          get_remote_machine_name(), client_addr(), service));
1113                 *status = NT_STATUS_BAD_NETWORK_NAME;
1114                 return NULL;
1115         }
1116
1117         /* Handle non-Dfs clients attempting connections to msdfs proxy */
1118         if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0'))  {
1119                 DEBUG(3, ("refusing connection to dfs proxy share '%s' "
1120                           "(pointing to %s)\n", 
1121                         service, lp_msdfs_proxy(snum)));
1122                 *status = NT_STATUS_BAD_NETWORK_NAME;
1123                 return NULL;
1124         }
1125
1126         DEBUG(5, ("making a connection to 'normal' service %s\n", service));
1127
1128         return make_connection_snum(snum, vuser,
1129                                     password,
1130                                     dev, status);
1131 }
1132
1133 /****************************************************************************
1134  Close a cnum.
1135 ****************************************************************************/
1136
1137 void close_cnum(connection_struct *conn, uint16 vuid)
1138 {
1139         if (IS_IPC(conn)) {
1140                 pipe_close_conn(conn);
1141         } else {
1142                 file_close_conn(conn);
1143                 dptr_closecnum(conn);
1144         }
1145
1146         change_to_root_user();
1147
1148         DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
1149                                  get_remote_machine_name(),
1150                                  conn->client_address,
1151                                  lp_servicename(SNUM(conn))));
1152
1153         /* Call VFS disconnect hook */    
1154         SMB_VFS_DISCONNECT(conn);
1155
1156         yield_connection(conn, lp_servicename(SNUM(conn)));
1157
1158         /* make sure we leave the directory available for unmount */
1159         vfs_ChDir(conn, "/");
1160
1161         /* execute any "postexec = " line */
1162         if (*lp_postexec(SNUM(conn)) && 
1163             change_to_user(conn, vuid))  {
1164                 pstring cmd;
1165                 pstrcpy(cmd,lp_postexec(SNUM(conn)));
1166                 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
1167                                       conn->connectpath, conn->gid,
1168                                       get_current_username(),
1169                                       current_user_info.domain,
1170                                       cmd, sizeof(cmd));
1171                 smbrun(cmd,NULL);
1172                 change_to_root_user();
1173         }
1174
1175         change_to_root_user();
1176         /* execute any "root postexec = " line */
1177         if (*lp_rootpostexec(SNUM(conn)))  {
1178                 pstring cmd;
1179                 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
1180                 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
1181                                       conn->connectpath, conn->gid,
1182                                       get_current_username(),
1183                                       current_user_info.domain,
1184                                       cmd, sizeof(cmd));
1185                 smbrun(cmd,NULL);
1186         }
1187
1188         conn_free(conn);
1189 }