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