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