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