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