s3-auth use auth_user_info not netr_SamInfo3 in auth3_session_info
[amitay/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 "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 auth3_session_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 auth3_session_info *vuid_serverinfo,
382                                               DATA_BLOB password,
383                                               struct auth3_session_info **presult)
384 {
385         if (lp_guest_only(snum)) {
386                 return make_session_info_guest(mem_ctx, presult);
387         }
388
389         if (vuid_serverinfo != NULL) {
390
391                 struct auth3_session_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->unix_info->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_info->unix_name,
406                                            vuid_serverinfo->info->domain_name,
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_info->unix_name,
412                                           lp_servicename(snum)));
413                                 return NT_STATUS_ACCESS_DENIED;
414                         }
415                 }
416
417                 result = copy_session_info(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 auth3_session_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->unix_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_info->unix_name,
500                         &conn->session_info->security_token->sids[1],
501                         &conn->session_info->unix_token->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->unix_token->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_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_info->unix_name,
617                                         conn->connectpath,
618                                         conn->session_info->unix_token->gid,
619                                         conn->session_info->unix_info->sanitized_username,
620                                         conn->session_info->info->domain_name,
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         share_access_check(conn->session_info->security_token,
645                            lp_servicename(snum), MAXIMUM_ALLOWED_ACCESS,
646                            &conn->share_access);
647
648         if ((conn->share_access & FILE_WRITE_DATA) == 0) {
649                 if ((conn->share_access & FILE_READ_DATA) == 0) {
650                         /* No access, read or write. */
651                         DEBUG(0,("make_connection: connection to %s "
652                                  "denied due to security "
653                                  "descriptor.\n",
654                                  lp_servicename(snum)));
655                         *pstatus = NT_STATUS_ACCESS_DENIED;
656                         goto err_root_exit;
657                 } else {
658                         conn->read_only = True;
659                 }
660         }
661         /* Initialise VFS function pointers */
662
663         if (!smbd_vfs_init(conn)) {
664                 DEBUG(0, ("vfs_init failed for service %s\n",
665                           lp_servicename(snum)));
666                 *pstatus = NT_STATUS_BAD_NETWORK_NAME;
667                 goto err_root_exit;
668         }
669
670 /* ROOT Activities: */
671         /* explicitly check widelinks here so that we can correctly warn
672          * in the logs. */
673         widelinks_warning(snum);
674
675         /*
676          * Enforce the max connections parameter.
677          */
678
679         if ((lp_max_connections(snum) > 0)
680             && (count_current_connections(lp_servicename(SNUM(conn)), True) >=
681                 lp_max_connections(snum))) {
682
683                 DEBUG(1, ("Max connections (%d) exceeded for %s\n",
684                           lp_max_connections(snum), lp_servicename(snum)));
685                 *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
686                 goto err_root_exit;
687         }
688
689         /*
690          * Get us an entry in the connections db
691          */
692         if (!claim_connection(conn, lp_servicename(snum))) {
693                 DEBUG(1, ("Could not store connections entry\n"));
694                 *pstatus = NT_STATUS_INTERNAL_DB_ERROR;
695                 goto err_root_exit;
696         }
697         claimed_connection = true;
698
699         /* Invoke VFS make connection hook - this must be the first
700            filesystem operation that we do. */
701
702         if (SMB_VFS_CONNECT(conn, lp_servicename(snum),
703                             conn->session_info->unix_info->unix_name) < 0) {
704                 DEBUG(0,("make_connection: VFS make connection failed!\n"));
705                 *pstatus = NT_STATUS_UNSUCCESSFUL;
706                 goto err_root_exit;
707         }
708
709         /* Any error exit after here needs to call the disconnect hook. */
710         on_err_call_dis_hook = true;
711
712         if ((!conn->printer) && (!conn->ipc)) {
713                 conn->notify_ctx = notify_init(conn,
714                                                sconn_server_id(sconn),
715                                                sconn->msg_ctx,
716                                                server_event_context(),
717                                                conn);
718         }
719
720         /*
721          * Fix compatibility issue pointed out by Volker.
722          * We pass the conn->connectpath to the preexec
723          * scripts as a parameter, so attempt to canonicalize
724          * it here before calling the preexec scripts.
725          * We ignore errors here, as it is possible that
726          * the conn->connectpath doesn't exist yet and
727          * the preexec scripts will create them.
728          */
729
730         (void)canonicalize_connect_path(conn);
731
732         /* Preexecs are done here as they might make the dir we are to ChDir
733          * to below */
734         /* execute any "root preexec = " line */
735         if (*lp_rootpreexec(snum)) {
736                 char *cmd = talloc_sub_advanced(talloc_tos(),
737                                         lp_servicename(SNUM(conn)),
738                                         conn->session_info->unix_info->unix_name,
739                                         conn->connectpath,
740                                         conn->session_info->unix_token->gid,
741                                         conn->session_info->unix_info->sanitized_username,
742                                         conn->session_info->info->domain_name,
743                                         lp_rootpreexec(snum));
744                 DEBUG(5,("cmd=%s\n",cmd));
745                 ret = smbrun(cmd,NULL);
746                 TALLOC_FREE(cmd);
747                 if (ret != 0 && lp_rootpreexec_close(snum)) {
748                         DEBUG(1,("root preexec gave %d - failing "
749                                  "connection\n", ret));
750                         *pstatus = NT_STATUS_ACCESS_DENIED;
751                         goto err_root_exit;
752                 }
753         }
754
755 /* USER Activites: */
756         if (!change_to_user(conn, conn->vuid)) {
757                 /* No point continuing if they fail the basic checks */
758                 DEBUG(0,("Can't become connected user!\n"));
759                 *pstatus = NT_STATUS_LOGON_FAILURE;
760                 goto err_root_exit;
761         }
762
763         effuid = geteuid();
764         effgid = getegid();
765
766         /* Remember that a different vuid can connect later without these
767          * checks... */
768
769         /* Preexecs are done here as they might make the dir we are to ChDir
770          * to below */
771
772         /* execute any "preexec = " line */
773         if (*lp_preexec(snum)) {
774                 char *cmd = talloc_sub_advanced(talloc_tos(),
775                                         lp_servicename(SNUM(conn)),
776                                         conn->session_info->unix_info->unix_name,
777                                         conn->connectpath,
778                                         conn->session_info->unix_token->gid,
779                                         conn->session_info->unix_info->sanitized_username,
780                                         conn->session_info->info->domain_name,
781                                         lp_preexec(snum));
782                 ret = smbrun(cmd,NULL);
783                 TALLOC_FREE(cmd);
784                 if (ret != 0 && lp_preexec_close(snum)) {
785                         DEBUG(1,("preexec gave %d - failing connection\n",
786                                  ret));
787                         *pstatus = NT_STATUS_ACCESS_DENIED;
788                         goto err_root_exit;
789                 }
790         }
791
792 #ifdef WITH_FAKE_KASERVER
793         if (lp_afs_share(snum)) {
794                 afs_login(conn);
795         }
796 #endif
797
798         /*
799          * we've finished with the user stuff - go back to root
800          * so the SMB_VFS_STAT call will only fail on path errors,
801          * not permission problems.
802          */
803         change_to_root_user();
804 /* ROOT Activites: */
805
806         /*
807          * If widelinks are disallowed we need to canonicalise the connect
808          * path here to ensure we don't have any symlinks in the
809          * connectpath. We will be checking all paths on this connection are
810          * below this directory. We must do this after the VFS init as we
811          * depend on the realpath() pointer in the vfs table. JRA.
812          */
813         if (!lp_widelinks(snum)) {
814                 if (!canonicalize_connect_path(conn)) {
815                         DEBUG(0, ("canonicalize_connect_path failed "
816                         "for service %s, path %s\n",
817                                 lp_servicename(snum),
818                                 conn->connectpath));
819                         *pstatus = NT_STATUS_BAD_NETWORK_NAME;
820                         goto err_root_exit;
821                 }
822         }
823
824         /* Add veto/hide lists */
825         if (!IS_IPC(conn) && !IS_PRINT(conn)) {
826                 set_namearray( &conn->veto_list, lp_veto_files(snum));
827                 set_namearray( &conn->hide_list, lp_hide_files(snum));
828                 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(snum));
829                 set_namearray( &conn->aio_write_behind_list,
830                                 lp_aio_write_behind(snum));
831         }
832         status = create_synthetic_smb_fname(talloc_tos(), conn->connectpath,
833                                             NULL, NULL, &smb_fname_cpath);
834         if (!NT_STATUS_IS_OK(status)) {
835                 *pstatus = status;
836                 goto err_root_exit;
837         }
838
839         /* win2000 does not check the permissions on the directory
840            during the tree connect, instead relying on permission
841            check during individual operations. To match this behaviour
842            I have disabled this chdir check (tridge) */
843         /* the alternative is just to check the directory exists */
844
845         if ((ret = SMB_VFS_STAT(conn, smb_fname_cpath)) != 0 ||
846             !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
847                 if (ret == 0 && !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
848                         DEBUG(0,("'%s' is not a directory, when connecting to "
849                                  "[%s]\n", conn->connectpath,
850                                  lp_servicename(snum)));
851                 } else {
852                         DEBUG(0,("'%s' does not exist or permission denied "
853                                  "when connecting to [%s] Error was %s\n",
854                                  conn->connectpath, lp_servicename(snum),
855                                  strerror(errno) ));
856                 }
857                 *pstatus = NT_STATUS_BAD_NETWORK_NAME;
858                 goto err_root_exit;
859         }
860         conn->base_share_dev = smb_fname_cpath->st.st_ex_dev;
861
862         string_set(&conn->origpath,conn->connectpath);
863
864         /* Figure out the characteristics of the underlying filesystem. This
865          * assumes that all the filesystem mounted withing a share path have
866          * the same characteristics, which is likely but not guaranteed.
867          */
868
869         conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
870
871         /*
872          * Print out the 'connected as' stuff here as we need
873          * to know the effective uid and gid we will be using
874          * (at least initially).
875          */
876
877         if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
878                 dbgtext( "%s (%s) ", get_remote_machine_name(),
879                          tsocket_address_string(conn->sconn->remote_address,
880                                                 talloc_tos()) );
881                 dbgtext( "%s", srv_is_signing_active(sconn) ? "signed " : "");
882                 dbgtext( "connect to service %s ", lp_servicename(snum) );
883                 dbgtext( "initially as user %s ",
884                          conn->session_info->unix_info->unix_name );
885                 dbgtext( "(uid=%d, gid=%d) ", (int)effuid, (int)effgid );
886                 dbgtext( "(pid %d)\n", (int)sys_getpid() );
887         }
888
889         return(conn);
890
891   err_root_exit:
892         TALLOC_FREE(smb_fname_cpath);
893         /* We must exit this function as root. */
894         if (geteuid() != 0) {
895                 change_to_root_user();
896         }
897         if (on_err_call_dis_hook) {
898                 /* Call VFS disconnect hook */
899                 SMB_VFS_DISCONNECT(conn);
900         }
901         if (claimed_connection) {
902                 yield_connection(conn, lp_servicename(snum));
903         }
904         if (conn) {
905                 conn_free(conn);
906         }
907         return NULL;
908 }
909
910 /****************************************************************************
911  Make a connection to a service.
912  *
913  * @param service 
914 ****************************************************************************/
915
916 connection_struct *make_connection(struct smbd_server_connection *sconn,
917                                    const char *service_in, DATA_BLOB password,
918                                    const char *pdev, uint16 vuid,
919                                    NTSTATUS *status)
920 {
921         uid_t euid;
922         user_struct *vuser = NULL;
923         char *service = NULL;
924         fstring dev;
925         int snum = -1;
926
927         fstrcpy(dev, pdev);
928
929         /* This must ONLY BE CALLED AS ROOT. As it exits this function as
930          * root. */
931         if (!non_root_mode() && (euid = geteuid()) != 0) {
932                 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot "
933                          "(%u)\n", (unsigned int)euid ));
934                 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
935         }
936
937         if (conn_num_open(sconn) > 2047) {
938                 *status = NT_STATUS_INSUFF_SERVER_RESOURCES;
939                 return NULL;
940         }
941
942         if(lp_security() != SEC_SHARE) {
943                 vuser = get_valid_user_struct(sconn, vuid);
944                 if (!vuser) {
945                         DEBUG(1,("make_connection: refusing to connect with "
946                                  "no session setup\n"));
947                         *status = NT_STATUS_ACCESS_DENIED;
948                         return NULL;
949                 }
950         }
951
952         /* Logic to try and connect to the correct [homes] share, preferably
953            without too many getpwnam() lookups.  This is particulary nasty for
954            winbind usernames, where the share name isn't the same as unix
955            username.
956
957            The snum of the homes share is stored on the vuser at session setup
958            time.
959         */
960
961         if (strequal(service_in,HOMES_NAME)) {
962                 if(lp_security() != SEC_SHARE) {
963                         DATA_BLOB no_pw = data_blob_null;
964                         if (vuser->homes_snum == -1) {
965                                 DEBUG(2, ("[homes] share not available for "
966                                           "this user because it was not found "
967                                           "or created at session setup "
968                                           "time\n"));
969                                 *status = NT_STATUS_BAD_NETWORK_NAME;
970                                 return NULL;
971                         }
972                         DEBUG(5, ("making a connection to [homes] service "
973                                   "created at session setup time\n"));
974                         return make_connection_snum(sconn,
975                                                     vuser->homes_snum,
976                                                     vuser, no_pw, 
977                                                     dev, status);
978                 } else {
979                         /* Security = share. Try with
980                          * current_user_info.smb_name as the username.  */
981                         if (*current_user_info.smb_name) {
982                                 char *unix_username = NULL;
983                                 (void)map_username(talloc_tos(),
984                                                 current_user_info.smb_name,
985                                                 &unix_username);
986                                 snum = find_service(talloc_tos(),
987                                                 unix_username,
988                                                 &unix_username);
989                                 if (!unix_username) {
990                                         *status = NT_STATUS_NO_MEMORY;
991                                 }
992                                 return NULL;
993                         }
994                         if (snum != -1) {
995                                 DEBUG(5, ("making a connection to 'homes' "
996                                           "service %s based on "
997                                           "security=share\n", service_in));
998                                 return make_connection_snum(sconn,
999                                                             snum, NULL,
1000                                                             password,
1001                                                             dev, status);
1002                         }
1003                 }
1004         } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
1005                    && strequal(service_in,
1006                                lp_servicename(vuser->homes_snum))) {
1007                 DATA_BLOB no_pw = data_blob_null;
1008                 DEBUG(5, ("making a connection to 'homes' service [%s] "
1009                           "created at session setup time\n", service_in));
1010                 return make_connection_snum(sconn,
1011                                             vuser->homes_snum,
1012                                             vuser, no_pw, 
1013                                             dev, status);
1014         }
1015
1016         service = talloc_strdup(talloc_tos(), service_in);
1017         if (!service) {
1018                 *status = NT_STATUS_NO_MEMORY;
1019                 return NULL;
1020         }
1021
1022         strlower_m(service);
1023
1024         snum = find_service(talloc_tos(), service, &service);
1025         if (!service) {
1026                 *status = NT_STATUS_NO_MEMORY;
1027                 return NULL;
1028         }
1029
1030         if (snum < 0) {
1031                 if (strequal(service,"IPC$") ||
1032                     (lp_enable_asu_support() && strequal(service,"ADMIN$"))) {
1033                         DEBUG(3,("refusing IPC connection to %s\n", service));
1034                         *status = NT_STATUS_ACCESS_DENIED;
1035                         return NULL;
1036                 }
1037
1038                 DEBUG(3,("%s (%s) couldn't find service %s\n",
1039                         get_remote_machine_name(),
1040                         tsocket_address_string(
1041                                 sconn->remote_address, talloc_tos()),
1042                         service));
1043                 *status = NT_STATUS_BAD_NETWORK_NAME;
1044                 return NULL;
1045         }
1046
1047         /* Handle non-Dfs clients attempting connections to msdfs proxy */
1048         if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0'))  {
1049                 DEBUG(3, ("refusing connection to dfs proxy share '%s' "
1050                           "(pointing to %s)\n", 
1051                         service, lp_msdfs_proxy(snum)));
1052                 *status = NT_STATUS_BAD_NETWORK_NAME;
1053                 return NULL;
1054         }
1055
1056         DEBUG(5, ("making a connection to 'normal' service %s\n", service));
1057
1058         return make_connection_snum(sconn, snum, vuser,
1059                                     password,
1060                                     dev, status);
1061 }
1062
1063 /****************************************************************************
1064  Close a cnum.
1065 ****************************************************************************/
1066
1067 void close_cnum(connection_struct *conn, uint16 vuid)
1068 {
1069         file_close_conn(conn);
1070
1071         if (!IS_IPC(conn)) {
1072                 dptr_closecnum(conn);
1073         }
1074
1075         change_to_root_user();
1076
1077         DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
1078                                  get_remote_machine_name(),
1079                                  tsocket_address_string(conn->sconn->remote_address,
1080                                                         talloc_tos()),
1081                                  lp_servicename(SNUM(conn))));
1082
1083         /* Call VFS disconnect hook */    
1084         SMB_VFS_DISCONNECT(conn);
1085
1086         yield_connection(conn, lp_servicename(SNUM(conn)));
1087
1088         /* make sure we leave the directory available for unmount */
1089         vfs_ChDir(conn, "/");
1090
1091         /* execute any "postexec = " line */
1092         if (*lp_postexec(SNUM(conn)) && 
1093             change_to_user(conn, vuid))  {
1094                 char *cmd = talloc_sub_advanced(talloc_tos(),
1095                                         lp_servicename(SNUM(conn)),
1096                                         conn->session_info->unix_info->unix_name,
1097                                         conn->connectpath,
1098                                         conn->session_info->unix_token->gid,
1099                                         conn->session_info->unix_info->sanitized_username,
1100                                         conn->session_info->info->domain_name,
1101                                         lp_postexec(SNUM(conn)));
1102                 smbrun(cmd,NULL);
1103                 TALLOC_FREE(cmd);
1104                 change_to_root_user();
1105         }
1106
1107         change_to_root_user();
1108         /* execute any "root postexec = " line */
1109         if (*lp_rootpostexec(SNUM(conn)))  {
1110                 char *cmd = talloc_sub_advanced(talloc_tos(),
1111                                         lp_servicename(SNUM(conn)),
1112                                         conn->session_info->unix_info->unix_name,
1113                                         conn->connectpath,
1114                                         conn->session_info->unix_token->gid,
1115                                         conn->session_info->unix_info->sanitized_username,
1116                                         conn->session_info->info->domain_name,
1117                                         lp_rootpostexec(SNUM(conn)));
1118                 smbrun(cmd,NULL);
1119                 TALLOC_FREE(cmd);
1120         }
1121
1122         conn_free(conn);
1123 }