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