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