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