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