Now make_connection_snum() is a static function that takes a
[metze/samba/wip.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 static NTSTATUS make_connection_snum(struct smbd_server_connection *sconn,
531                                         connection_struct *conn,
532                                         int snum, user_struct *vuser,
533                                         DATA_BLOB password,
534                                         const char *pdev)
535 {
536         struct smb_filename *smb_fname_cpath = NULL;
537         fstring dev;
538         int ret;
539         bool on_err_call_dis_hook = false;
540         bool claimed_connection = false;
541         uid_t effuid;
542         gid_t effgid;
543         NTSTATUS status;
544
545         fstrcpy(dev, pdev);
546
547         status = share_sanity_checks(sconn->remote_address,
548                                        sconn->remote_hostname,
549                                        snum,
550                                        dev);
551         if (NT_STATUS_IS_ERR(status)) {
552                 goto err_root_exit;
553         }
554
555         conn->params->service = snum;
556
557         status = create_connection_session_info(sconn,
558                 conn, snum, vuser ? vuser->session_info : NULL, password,
559                 &conn->session_info);
560
561         if (!NT_STATUS_IS_OK(status)) {
562                 DEBUG(1, ("create_connection_session_info failed: %s\n",
563                           nt_errstr(status)));
564                 goto err_root_exit;
565         }
566
567         if ((lp_guest_only(snum)) || (lp_security() == SEC_SHARE)) {
568                 conn->force_user = true;
569         }
570
571         add_session_user(sconn, conn->session_info->unix_info->unix_name);
572
573         conn->num_files_open = 0;
574         conn->lastused = conn->lastused_count = time(NULL);
575         conn->used = True;
576         conn->printer = (strncmp(dev,"LPT",3) == 0);
577         conn->ipc = ( (strncmp(dev,"IPC",3) == 0) ||
578                       ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) );
579
580         /* Case options for the share. */
581         if (lp_casesensitive(snum) == Auto) {
582                 /* We will be setting this per packet. Set to be case
583                  * insensitive for now. */
584                 conn->case_sensitive = False;
585         } else {
586                 conn->case_sensitive = (bool)lp_casesensitive(snum);
587         }
588
589         conn->case_preserve = lp_preservecase(snum);
590         conn->short_case_preserve = lp_shortpreservecase(snum);
591
592         conn->encrypt_level = lp_smb_encrypt(snum);
593
594         conn->veto_list = NULL;
595         conn->hide_list = NULL;
596         conn->veto_oplock_list = NULL;
597         conn->aio_write_behind_list = NULL;
598
599         conn->read_only = lp_readonly(SNUM(conn));
600
601         status = set_conn_force_user_group(conn, snum);
602         if (!NT_STATUS_IS_OK(status)) {
603                 goto err_root_exit;
604         }
605
606         conn->vuid = (vuser != NULL) ? vuser->vuid : UID_FIELD_INVALID;
607
608         {
609                 char *s = talloc_sub_advanced(talloc_tos(),
610                                         lp_servicename(SNUM(conn)),
611                                         conn->session_info->unix_info->unix_name,
612                                         conn->connectpath,
613                                         conn->session_info->unix_token->gid,
614                                         conn->session_info->unix_info->sanitized_username,
615                                         conn->session_info->info->domain_name,
616                                         lp_pathname(snum));
617                 if (!s) {
618                         status = NT_STATUS_NO_MEMORY;
619                         goto err_root_exit;
620                 }
621
622                 if (!set_conn_connectpath(conn,s)) {
623                         TALLOC_FREE(s);
624                         status = NT_STATUS_NO_MEMORY;
625                         goto err_root_exit;
626                 }
627                 DEBUG(3,("Connect path is '%s' for service [%s]\n",s,
628                          lp_servicename(snum)));
629                 TALLOC_FREE(s);
630         }
631
632         /*
633          * New code to check if there's a share security descripter
634          * added from NT server manager. This is done after the
635          * smb.conf checks are done as we need a uid and token. JRA.
636          *
637          */
638
639         share_access_check(conn->session_info->security_token,
640                            lp_servicename(snum), MAXIMUM_ALLOWED_ACCESS,
641                            &conn->share_access);
642
643         if ((conn->share_access & FILE_WRITE_DATA) == 0) {
644                 if ((conn->share_access & FILE_READ_DATA) == 0) {
645                         /* No access, read or write. */
646                         DEBUG(0,("make_connection: connection to %s "
647                                  "denied due to security "
648                                  "descriptor.\n",
649                                  lp_servicename(snum)));
650                         status = NT_STATUS_ACCESS_DENIED;
651                         goto err_root_exit;
652                 } else {
653                         conn->read_only = True;
654                 }
655         }
656         /* Initialise VFS function pointers */
657
658         if (!smbd_vfs_init(conn)) {
659                 DEBUG(0, ("vfs_init failed for service %s\n",
660                           lp_servicename(snum)));
661                 status = NT_STATUS_BAD_NETWORK_NAME;
662                 goto err_root_exit;
663         }
664
665 /* ROOT Activities: */
666         /* explicitly check widelinks here so that we can correctly warn
667          * in the logs. */
668         widelinks_warning(snum);
669
670         /*
671          * Enforce the max connections parameter.
672          */
673
674         if ((lp_max_connections(snum) > 0)
675             && (count_current_connections(lp_servicename(SNUM(conn)), True) >=
676                 lp_max_connections(snum))) {
677
678                 DEBUG(1, ("Max connections (%d) exceeded for %s\n",
679                           lp_max_connections(snum), lp_servicename(snum)));
680                 status = NT_STATUS_INSUFFICIENT_RESOURCES;
681                 goto err_root_exit;
682         }
683
684         /*
685          * Get us an entry in the connections db
686          */
687         if (!claim_connection(conn, lp_servicename(snum))) {
688                 DEBUG(1, ("Could not store connections entry\n"));
689                 status = NT_STATUS_INTERNAL_DB_ERROR;
690                 goto err_root_exit;
691         }
692         claimed_connection = true;
693
694         /* Invoke VFS make connection hook - this must be the first
695            filesystem operation that we do. */
696
697         if (SMB_VFS_CONNECT(conn, lp_servicename(snum),
698                             conn->session_info->unix_info->unix_name) < 0) {
699                 DEBUG(0,("make_connection: VFS make connection failed!\n"));
700                 status = NT_STATUS_UNSUCCESSFUL;
701                 goto err_root_exit;
702         }
703
704         /* Any error exit after here needs to call the disconnect hook. */
705         on_err_call_dis_hook = true;
706
707         if ((!conn->printer) && (!conn->ipc)) {
708                 conn->notify_ctx = notify_init(conn,
709                                                messaging_server_id(sconn->msg_ctx),
710                                                sconn->msg_ctx,
711                                                sconn->ev_ctx,
712                                                conn);
713         }
714
715         /*
716          * Fix compatibility issue pointed out by Volker.
717          * We pass the conn->connectpath to the preexec
718          * scripts as a parameter, so attempt to canonicalize
719          * it here before calling the preexec scripts.
720          * We ignore errors here, as it is possible that
721          * the conn->connectpath doesn't exist yet and
722          * the preexec scripts will create them.
723          */
724
725         (void)canonicalize_connect_path(conn);
726
727         /* Preexecs are done here as they might make the dir we are to ChDir
728          * to below */
729         /* execute any "root preexec = " line */
730         if (*lp_rootpreexec(snum)) {
731                 char *cmd = talloc_sub_advanced(talloc_tos(),
732                                         lp_servicename(SNUM(conn)),
733                                         conn->session_info->unix_info->unix_name,
734                                         conn->connectpath,
735                                         conn->session_info->unix_token->gid,
736                                         conn->session_info->unix_info->sanitized_username,
737                                         conn->session_info->info->domain_name,
738                                         lp_rootpreexec(snum));
739                 DEBUG(5,("cmd=%s\n",cmd));
740                 ret = smbrun(cmd,NULL);
741                 TALLOC_FREE(cmd);
742                 if (ret != 0 && lp_rootpreexec_close(snum)) {
743                         DEBUG(1,("root preexec gave %d - failing "
744                                  "connection\n", ret));
745                         status = NT_STATUS_ACCESS_DENIED;
746                         goto err_root_exit;
747                 }
748         }
749
750 /* USER Activites: */
751         if (!change_to_user(conn, conn->vuid)) {
752                 /* No point continuing if they fail the basic checks */
753                 DEBUG(0,("Can't become connected user!\n"));
754                 status = NT_STATUS_LOGON_FAILURE;
755                 goto err_root_exit;
756         }
757
758         effuid = geteuid();
759         effgid = getegid();
760
761         /* Remember that a different vuid can connect later without these
762          * checks... */
763
764         /* Preexecs are done here as they might make the dir we are to ChDir
765          * to below */
766
767         /* execute any "preexec = " line */
768         if (*lp_preexec(snum)) {
769                 char *cmd = talloc_sub_advanced(talloc_tos(),
770                                         lp_servicename(SNUM(conn)),
771                                         conn->session_info->unix_info->unix_name,
772                                         conn->connectpath,
773                                         conn->session_info->unix_token->gid,
774                                         conn->session_info->unix_info->sanitized_username,
775                                         conn->session_info->info->domain_name,
776                                         lp_preexec(snum));
777                 ret = smbrun(cmd,NULL);
778                 TALLOC_FREE(cmd);
779                 if (ret != 0 && lp_preexec_close(snum)) {
780                         DEBUG(1,("preexec gave %d - failing connection\n",
781                                  ret));
782                         status = NT_STATUS_ACCESS_DENIED;
783                         goto err_root_exit;
784                 }
785         }
786
787 #ifdef WITH_FAKE_KASERVER
788         if (lp_afs_share(snum)) {
789                 afs_login(conn);
790         }
791 #endif
792
793         /*
794          * we've finished with the user stuff - go back to root
795          * so the SMB_VFS_STAT call will only fail on path errors,
796          * not permission problems.
797          */
798         change_to_root_user();
799 /* ROOT Activites: */
800
801         /*
802          * If widelinks are disallowed we need to canonicalise the connect
803          * path here to ensure we don't have any symlinks in the
804          * connectpath. We will be checking all paths on this connection are
805          * below this directory. We must do this after the VFS init as we
806          * depend on the realpath() pointer in the vfs table. JRA.
807          */
808         if (!lp_widelinks(snum)) {
809                 if (!canonicalize_connect_path(conn)) {
810                         DEBUG(0, ("canonicalize_connect_path failed "
811                         "for service %s, path %s\n",
812                                 lp_servicename(snum),
813                                 conn->connectpath));
814                         status = NT_STATUS_BAD_NETWORK_NAME;
815                         goto err_root_exit;
816                 }
817         }
818
819         /* Add veto/hide lists */
820         if (!IS_IPC(conn) && !IS_PRINT(conn)) {
821                 set_namearray( &conn->veto_list, lp_veto_files(snum));
822                 set_namearray( &conn->hide_list, lp_hide_files(snum));
823                 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(snum));
824                 set_namearray( &conn->aio_write_behind_list,
825                                 lp_aio_write_behind(snum));
826         }
827         status = create_synthetic_smb_fname(talloc_tos(), conn->connectpath,
828                                             NULL, NULL, &smb_fname_cpath);
829         if (!NT_STATUS_IS_OK(status)) {
830                 goto err_root_exit;
831         }
832
833         /* win2000 does not check the permissions on the directory
834            during the tree connect, instead relying on permission
835            check during individual operations. To match this behaviour
836            I have disabled this chdir check (tridge) */
837         /* the alternative is just to check the directory exists */
838
839         if ((ret = SMB_VFS_STAT(conn, smb_fname_cpath)) != 0 ||
840             !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
841                 if (ret == 0 && !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
842                         DEBUG(0,("'%s' is not a directory, when connecting to "
843                                  "[%s]\n", conn->connectpath,
844                                  lp_servicename(snum)));
845                 } else {
846                         DEBUG(0,("'%s' does not exist or permission denied "
847                                  "when connecting to [%s] Error was %s\n",
848                                  conn->connectpath, lp_servicename(snum),
849                                  strerror(errno) ));
850                 }
851                 status = NT_STATUS_BAD_NETWORK_NAME;
852                 goto err_root_exit;
853         }
854         conn->base_share_dev = smb_fname_cpath->st.st_ex_dev;
855
856         string_set(&conn->origpath,conn->connectpath);
857
858         /* Figure out the characteristics of the underlying filesystem. This
859          * assumes that all the filesystem mounted withing a share path have
860          * the same characteristics, which is likely but not guaranteed.
861          */
862
863         conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
864
865         /*
866          * Print out the 'connected as' stuff here as we need
867          * to know the effective uid and gid we will be using
868          * (at least initially).
869          */
870
871         if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
872                 dbgtext( "%s (%s) ", get_remote_machine_name(),
873                          tsocket_address_string(conn->sconn->remote_address,
874                                                 talloc_tos()) );
875                 dbgtext( "%s", srv_is_signing_active(sconn) ? "signed " : "");
876                 dbgtext( "connect to service %s ", lp_servicename(snum) );
877                 dbgtext( "initially as user %s ",
878                          conn->session_info->unix_info->unix_name );
879                 dbgtext( "(uid=%d, gid=%d) ", (int)effuid, (int)effgid );
880                 dbgtext( "(pid %d)\n", (int)sys_getpid() );
881         }
882
883         return status;
884
885   err_root_exit:
886
887         TALLOC_FREE(smb_fname_cpath);
888         /* We must exit this function as root. */
889         if (geteuid() != 0) {
890                 change_to_root_user();
891         }
892         if (on_err_call_dis_hook) {
893                 /* Call VFS disconnect hook */
894                 SMB_VFS_DISCONNECT(conn);
895         }
896         if (claimed_connection) {
897                 yield_connection(conn, lp_servicename(snum));
898         }
899         return status;
900 }
901
902 /****************************************************************************
903  Make a connection to a service from SMB1. Internal interface.
904 ****************************************************************************/
905
906 static connection_struct *make_connection_smb1(struct smbd_server_connection *sconn,
907                                         int snum, user_struct *vuser,
908                                         DATA_BLOB password,
909                                         const char *pdev,
910                                         NTSTATUS *pstatus)
911 {
912         connection_struct *conn = conn_new(sconn);
913         if (!conn) {
914                 DEBUG(0,("make_connection_smb1: Couldn't find free connection.\n"));
915                 *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
916                 return NULL;
917         }
918         *pstatus = make_connection_snum(sconn,
919                                         conn,
920                                         snum,
921                                         vuser,
922                                         password,
923                                         pdev);
924         if (!NT_STATUS_IS_OK(*pstatus)) {
925                 conn_free(conn);
926                 return NULL;
927         }
928         return conn;
929 }
930
931 /****************************************************************************
932  Make a connection to a service from SMB2. External SMB2 interface.
933  We must set cnum before claiming connection.
934 ****************************************************************************/
935
936 connection_struct *make_connection_smb2(struct smbd_server_connection *sconn,
937                                         struct smbd_smb2_tcon *tcon,
938                                         user_struct *vuser,
939                                         DATA_BLOB password,
940                                         const char *pdev,
941                                         NTSTATUS *pstatus)
942 {
943         connection_struct *conn = conn_new(sconn);
944         if (!conn) {
945                 DEBUG(0,("make_connection_smb2: Couldn't find free connection.\n"));
946                 *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
947                 return NULL;
948         }
949         conn->cnum = tcon->tid;
950         *pstatus = make_connection_snum(sconn,
951                                         conn,
952                                         tcon->snum,
953                                         vuser,
954                                         password,
955                                         pdev);
956         if (!NT_STATUS_IS_OK(*pstatus)) {
957                 conn_free(conn);
958                 return NULL;
959         }
960         return conn;
961 }
962
963 /****************************************************************************
964  Make a connection to a service. External SMB1 interface.
965  *
966  * @param service 
967 ****************************************************************************/
968
969 connection_struct *make_connection(struct smbd_server_connection *sconn,
970                                    const char *service_in, DATA_BLOB password,
971                                    const char *pdev, uint16 vuid,
972                                    NTSTATUS *status)
973 {
974         uid_t euid;
975         user_struct *vuser = NULL;
976         char *service = NULL;
977         fstring dev;
978         int snum = -1;
979
980         fstrcpy(dev, pdev);
981
982         /* This must ONLY BE CALLED AS ROOT. As it exits this function as
983          * root. */
984         if (!non_root_mode() && (euid = geteuid()) != 0) {
985                 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot "
986                          "(%u)\n", (unsigned int)euid ));
987                 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
988         }
989
990         if (conn_num_open(sconn) > 2047) {
991                 *status = NT_STATUS_INSUFF_SERVER_RESOURCES;
992                 return NULL;
993         }
994
995         if(lp_security() != SEC_SHARE) {
996                 vuser = get_valid_user_struct(sconn, vuid);
997                 if (!vuser) {
998                         DEBUG(1,("make_connection: refusing to connect with "
999                                  "no session setup\n"));
1000                         *status = NT_STATUS_ACCESS_DENIED;
1001                         return NULL;
1002                 }
1003         }
1004
1005         /* Logic to try and connect to the correct [homes] share, preferably
1006            without too many getpwnam() lookups.  This is particulary nasty for
1007            winbind usernames, where the share name isn't the same as unix
1008            username.
1009
1010            The snum of the homes share is stored on the vuser at session setup
1011            time.
1012         */
1013
1014         if (strequal(service_in,HOMES_NAME)) {
1015                 if(lp_security() != SEC_SHARE) {
1016                         DATA_BLOB no_pw = data_blob_null;
1017                         if (vuser->homes_snum == -1) {
1018                                 DEBUG(2, ("[homes] share not available for "
1019                                           "this user because it was not found "
1020                                           "or created at session setup "
1021                                           "time\n"));
1022                                 *status = NT_STATUS_BAD_NETWORK_NAME;
1023                                 return NULL;
1024                         }
1025                         DEBUG(5, ("making a connection to [homes] service "
1026                                   "created at session setup time\n"));
1027                         return make_connection_smb1(sconn,
1028                                                     vuser->homes_snum,
1029                                                     vuser, no_pw, 
1030                                                     dev, status);
1031                 } else {
1032                         /* Security = share. Try with
1033                          * current_user_info.smb_name as the username.  */
1034                         if (*current_user_info.smb_name) {
1035                                 char *unix_username = NULL;
1036                                 (void)map_username(talloc_tos(),
1037                                                 current_user_info.smb_name,
1038                                                 &unix_username);
1039                                 snum = find_service(talloc_tos(),
1040                                                 unix_username,
1041                                                 &unix_username);
1042                                 if (!unix_username) {
1043                                         *status = NT_STATUS_NO_MEMORY;
1044                                 }
1045                                 return NULL;
1046                         }
1047                         if (snum != -1) {
1048                                 DEBUG(5, ("making a connection to 'homes' "
1049                                           "service %s based on "
1050                                           "security=share\n", service_in));
1051                                 return make_connection_smb1(sconn,
1052                                                             snum, NULL,
1053                                                             password,
1054                                                             dev, status);
1055                         }
1056                 }
1057         } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
1058                    && strequal(service_in,
1059                                lp_servicename(vuser->homes_snum))) {
1060                 DATA_BLOB no_pw = data_blob_null;
1061                 DEBUG(5, ("making a connection to 'homes' service [%s] "
1062                           "created at session setup time\n", service_in));
1063                 return make_connection_smb1(sconn,
1064                                             vuser->homes_snum,
1065                                             vuser, no_pw, 
1066                                             dev, status);
1067         }
1068
1069         service = talloc_strdup(talloc_tos(), service_in);
1070         if (!service) {
1071                 *status = NT_STATUS_NO_MEMORY;
1072                 return NULL;
1073         }
1074
1075         strlower_m(service);
1076
1077         snum = find_service(talloc_tos(), service, &service);
1078         if (!service) {
1079                 *status = NT_STATUS_NO_MEMORY;
1080                 return NULL;
1081         }
1082
1083         if (snum < 0) {
1084                 if (strequal(service,"IPC$") ||
1085                     (lp_enable_asu_support() && strequal(service,"ADMIN$"))) {
1086                         DEBUG(3,("refusing IPC connection to %s\n", service));
1087                         *status = NT_STATUS_ACCESS_DENIED;
1088                         return NULL;
1089                 }
1090
1091                 DEBUG(3,("%s (%s) couldn't find service %s\n",
1092                         get_remote_machine_name(),
1093                         tsocket_address_string(
1094                                 sconn->remote_address, talloc_tos()),
1095                         service));
1096                 *status = NT_STATUS_BAD_NETWORK_NAME;
1097                 return NULL;
1098         }
1099
1100         /* Handle non-Dfs clients attempting connections to msdfs proxy */
1101         if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0'))  {
1102                 DEBUG(3, ("refusing connection to dfs proxy share '%s' "
1103                           "(pointing to %s)\n", 
1104                         service, lp_msdfs_proxy(snum)));
1105                 *status = NT_STATUS_BAD_NETWORK_NAME;
1106                 return NULL;
1107         }
1108
1109         DEBUG(5, ("making a connection to 'normal' service %s\n", service));
1110
1111         return make_connection_smb1(sconn, snum, vuser,
1112                                     password,
1113                                     dev, status);
1114 }
1115
1116 /****************************************************************************
1117  Close a cnum.
1118 ****************************************************************************/
1119
1120 void close_cnum(connection_struct *conn, uint16 vuid)
1121 {
1122         file_close_conn(conn);
1123
1124         if (!IS_IPC(conn)) {
1125                 dptr_closecnum(conn);
1126         }
1127
1128         change_to_root_user();
1129
1130         DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
1131                                  get_remote_machine_name(),
1132                                  tsocket_address_string(conn->sconn->remote_address,
1133                                                         talloc_tos()),
1134                                  lp_servicename(SNUM(conn))));
1135
1136         /* Call VFS disconnect hook */    
1137         SMB_VFS_DISCONNECT(conn);
1138
1139         yield_connection(conn, lp_servicename(SNUM(conn)));
1140
1141         /* make sure we leave the directory available for unmount */
1142         vfs_ChDir(conn, "/");
1143
1144         /* execute any "postexec = " line */
1145         if (*lp_postexec(SNUM(conn)) && 
1146             change_to_user(conn, vuid))  {
1147                 char *cmd = talloc_sub_advanced(talloc_tos(),
1148                                         lp_servicename(SNUM(conn)),
1149                                         conn->session_info->unix_info->unix_name,
1150                                         conn->connectpath,
1151                                         conn->session_info->unix_token->gid,
1152                                         conn->session_info->unix_info->sanitized_username,
1153                                         conn->session_info->info->domain_name,
1154                                         lp_postexec(SNUM(conn)));
1155                 smbrun(cmd,NULL);
1156                 TALLOC_FREE(cmd);
1157                 change_to_root_user();
1158         }
1159
1160         change_to_root_user();
1161         /* execute any "root postexec = " line */
1162         if (*lp_rootpostexec(SNUM(conn)))  {
1163                 char *cmd = talloc_sub_advanced(talloc_tos(),
1164                                         lp_servicename(SNUM(conn)),
1165                                         conn->session_info->unix_info->unix_name,
1166                                         conn->connectpath,
1167                                         conn->session_info->unix_token->gid,
1168                                         conn->session_info->unix_info->sanitized_username,
1169                                         conn->session_info->info->domain_name,
1170                                         lp_rootpostexec(SNUM(conn)));
1171                 smbrun(cmd,NULL);
1172                 TALLOC_FREE(cmd);
1173         }
1174
1175         conn_free(conn);
1176 }