s3:smbd: fix typo in comment for set_conn_force_user_group()
[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 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 *)talloc_size(conn, 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(talloc_tos(), SNUM(conn)), destname ));
164
165         talloc_free(conn->connectpath);
166         conn->connectpath = destname;
167         /* Ensure conn->cwd is initialized - start as conn->connectpath. */
168         TALLOC_FREE(conn->cwd);
169         conn->cwd = talloc_strdup(conn, conn->connectpath);
170         if (!conn->cwd) {
171                 return false;
172         }
173         return true;
174 }
175
176 /****************************************************************************
177  Load parameters specific to a connection/service.
178 ****************************************************************************/
179
180 bool set_current_service(connection_struct *conn, uint16 flags, bool do_chdir)
181 {
182         int snum;
183
184         if (!conn)  {
185                 last_conn = NULL;
186                 return(False);
187         }
188
189         conn->lastused_count++;
190
191         snum = SNUM(conn);
192
193         if (do_chdir &&
194             vfs_ChDir(conn,conn->connectpath) != 0 &&
195             vfs_ChDir(conn,conn->origpath) != 0) {
196                 DEBUG(((errno!=EACCES)?0:3),("chdir (%s) failed, reason: %s\n",
197                          conn->connectpath, strerror(errno)));
198                 return(False);
199         }
200
201         if ((conn == last_conn) && (last_flags == flags)) {
202                 return(True);
203         }
204
205         last_conn = conn;
206         last_flags = flags;
207
208         /* Obey the client case sensitivity requests - only for clients that support it. */
209         switch (lp_case_sensitive(snum)) {
210                 case Auto:
211                         {
212                                 /* We need this uglyness due to DOS/Win9x clients that lie about case insensitivity. */
213                                 enum remote_arch_types ra_type = get_remote_arch();
214                                 if ((ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
215                                         /* Client can't support per-packet case sensitive pathnames. */
216                                         conn->case_sensitive = False;
217                                 } else {
218                                         conn->case_sensitive = !(flags & FLAG_CASELESS_PATHNAMES);
219                                 }
220                         }
221                         break;
222                 case True:
223                         conn->case_sensitive = True;
224                         break;
225                 default:
226                         conn->case_sensitive = False;
227                         break;
228         }
229         return(True);
230 }
231
232 /****************************************************************************
233  do some basic sainity checks on the share.  
234  This function modifies dev, ecode.
235 ****************************************************************************/
236
237 static NTSTATUS share_sanity_checks(const struct tsocket_address *remote_address,
238                                     const char *rhost,
239                                     int snum,
240                                     fstring dev)
241 {
242         char *raddr;
243
244         raddr = tsocket_address_inet_addr_string(remote_address,
245                                                  talloc_tos());
246         if (raddr == NULL) {
247                 return NT_STATUS_NO_MEMORY;
248         }
249
250         if (!lp_snum_ok(snum) ||
251             !allow_access(lp_hosts_deny(snum), lp_hosts_allow(snum),
252                           rhost, raddr)) {
253                 return NT_STATUS_ACCESS_DENIED;
254         }
255
256         if (dev[0] == '?' || !dev[0]) {
257                 if (lp_printable(snum)) {
258                         fstrcpy(dev,"LPT1:");
259                 } else if (strequal(lp_fstype(snum), "IPC")) {
260                         fstrcpy(dev, "IPC");
261                 } else {
262                         fstrcpy(dev,"A:");
263                 }
264         }
265
266         if (!strupper_m(dev)) {
267                 DEBUG(2,("strupper_m %s failed\n", dev));
268                 return NT_STATUS_INVALID_PARAMETER;
269         }
270
271         if (lp_printable(snum)) {
272                 if (!strequal(dev, "LPT1:")) {
273                         return NT_STATUS_BAD_DEVICE_TYPE;
274                 }
275         } else if (strequal(lp_fstype(snum), "IPC")) {
276                 if (!strequal(dev, "IPC")) {
277                         return NT_STATUS_BAD_DEVICE_TYPE;
278                 }
279         } else if (!strequal(dev, "A:")) {
280                 return NT_STATUS_BAD_DEVICE_TYPE;
281         }
282
283         /* Behave as a printer if we are supposed to */
284         if (lp_printable(snum) && (strcmp(dev, "A:") == 0)) {
285                 fstrcpy(dev, "LPT1:");
286         }
287
288         return NT_STATUS_OK;
289 }
290
291 /*
292  * Go through lookup_name etc to find the force'd group.  
293  *
294  * Create a new token from src_token, replacing the primary group sid with the
295  * one found.
296  */
297
298 static NTSTATUS find_forced_group(bool force_user,
299                                   int snum, const char *username,
300                                   struct dom_sid *pgroup_sid,
301                                   gid_t *pgid)
302 {
303         NTSTATUS result = NT_STATUS_NO_SUCH_GROUP;
304         TALLOC_CTX *frame = talloc_stackframe();
305         struct dom_sid group_sid;
306         enum lsa_SidType type;
307         char *groupname;
308         bool user_must_be_member = False;
309         gid_t gid;
310
311         groupname = lp_force_group(talloc_tos(), snum);
312         if (groupname == NULL) {
313                 DEBUG(1, ("talloc_strdup failed\n"));
314                 result = NT_STATUS_NO_MEMORY;
315                 goto done;
316         }
317
318         if (groupname[0] == '+') {
319                 user_must_be_member = True;
320                 groupname += 1;
321         }
322
323         groupname = talloc_string_sub(talloc_tos(), groupname,
324                                       "%S", lp_servicename(talloc_tos(), snum));
325         if (groupname == NULL) {
326                 DEBUG(1, ("talloc_string_sub failed\n"));
327                 result = NT_STATUS_NO_MEMORY;
328                 goto done;
329         }
330
331         if (!lookup_name_smbconf(talloc_tos(), groupname,
332                          LOOKUP_NAME_ALL|LOOKUP_NAME_GROUP,
333                          NULL, NULL, &group_sid, &type)) {
334                 DEBUG(10, ("lookup_name_smbconf(%s) failed\n",
335                            groupname));
336                 goto done;
337         }
338
339         if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
340             (type != SID_NAME_WKN_GRP)) {
341                 DEBUG(10, ("%s is a %s, not a group\n", groupname,
342                            sid_type_lookup(type)));
343                 goto done;
344         }
345
346         if (!sid_to_gid(&group_sid, &gid)) {
347                 DEBUG(10, ("sid_to_gid(%s) for %s failed\n",
348                            sid_string_dbg(&group_sid), groupname));
349                 goto done;
350         }
351
352         /*
353          * If the user has been forced and the forced group starts with a '+',
354          * then we only set the group to be the forced group if the forced
355          * user is a member of that group.  Otherwise, the meaning of the '+'
356          * would be ignored.
357          */
358
359         if (force_user && user_must_be_member) {
360                 if (user_in_group_sid(username, &group_sid)) {
361                         sid_copy(pgroup_sid, &group_sid);
362                         *pgid = gid;
363                         DEBUG(3,("Forced group %s for member %s\n",
364                                  groupname, username));
365                 } else {
366                         DEBUG(0,("find_forced_group: forced user %s is not a member "
367                                 "of forced group %s. Disallowing access.\n",
368                                 username, groupname ));
369                         result = NT_STATUS_MEMBER_NOT_IN_GROUP;
370                         goto done;
371                 }
372         } else {
373                 sid_copy(pgroup_sid, &group_sid);
374                 *pgid = gid;
375                 DEBUG(3,("Forced group %s\n", groupname));
376         }
377
378         result = NT_STATUS_OK;
379  done:
380         TALLOC_FREE(frame);
381         return result;
382 }
383
384 /****************************************************************************
385   Create an auth_session_info structure for a connection_struct
386 ****************************************************************************/
387
388 static NTSTATUS create_connection_session_info(struct smbd_server_connection *sconn,
389                                               TALLOC_CTX *mem_ctx, int snum,
390                                               struct auth_session_info *session_info,
391                                               struct auth_session_info **presult)
392 {
393         struct auth_session_info *result;
394
395         if (lp_guest_only(snum)) {
396                 return make_session_info_guest(mem_ctx, presult);
397         }
398
399         /*
400          * This is the normal security != share case where we have a
401          * valid vuid from the session setup.                 */
402
403         if (security_session_user_level(session_info, NULL) < SECURITY_USER) {
404                 if (!lp_guest_ok(snum)) {
405                         DEBUG(2, ("guest user (from session setup) "
406                                   "not permitted to access this share "
407                                   "(%s)\n", lp_servicename(talloc_tos(), snum)));
408                         return NT_STATUS_ACCESS_DENIED;
409                 }
410         } else {
411                 if (!user_ok_token(session_info->unix_info->unix_name,
412                                    session_info->info->domain_name,
413                                    session_info->security_token, snum)) {
414                         DEBUG(2, ("user '%s' (from session setup) not "
415                                   "permitted to access this share "
416                                   "(%s)\n",
417                                   session_info->unix_info->unix_name,
418                                   lp_servicename(talloc_tos(), snum)));
419                         return NT_STATUS_ACCESS_DENIED;
420                 }
421         }
422
423         result = copy_session_info(mem_ctx, session_info);
424         if (result == NULL) {
425                 return NT_STATUS_NO_MEMORY;
426         }
427
428         *presult = result;
429         return NT_STATUS_OK;
430 }
431
432 /****************************************************************************
433   Set relevant user and group settings corresponding to force user/group
434   configuration for the given snum.
435 ****************************************************************************/
436
437 NTSTATUS set_conn_force_user_group(connection_struct *conn, int snum)
438 {
439         NTSTATUS status;
440
441         if (*lp_force_user(talloc_tos(), snum)) {
442
443                 /*
444                  * Replace conn->session_info with a completely faked up one
445                  * from the username we are forced into :-)
446                  */
447
448                 char *fuser;
449                 char *sanitized_username;
450                 struct auth_session_info *forced_serverinfo;
451                 bool guest;
452
453                 fuser = talloc_string_sub(conn, lp_force_user(talloc_tos(), snum), "%S",
454                                           lp_const_servicename(snum));
455                 if (fuser == NULL) {
456                         return NT_STATUS_NO_MEMORY;
457                 }
458
459                 guest = security_session_user_level(conn->session_info, NULL) < SECURITY_USER;
460
461                 status = make_session_info_from_username(
462                         conn, fuser,
463                         guest,
464                         &forced_serverinfo);
465                 if (!NT_STATUS_IS_OK(status)) {
466                         return status;
467                 }
468
469                 /* We don't want to replace the original sanitized_username
470                    as it is the original user given in the connect attempt.
471                    This is used in '%U' substitutions. */
472                 sanitized_username = discard_const_p(char,
473                         forced_serverinfo->unix_info->sanitized_username);
474                 TALLOC_FREE(sanitized_username);
475                 forced_serverinfo->unix_info->sanitized_username =
476                         talloc_move(forced_serverinfo->unix_info,
477                                 &conn->session_info->unix_info->sanitized_username);
478
479                 TALLOC_FREE(conn->session_info);
480                 conn->session_info = forced_serverinfo;
481
482                 conn->force_user = true;
483                 DEBUG(3,("Forced user %s\n", fuser));
484         }
485
486         /*
487          * If force group is true, then override
488          * any groupid stored for the connecting user.
489          */
490
491         if (*lp_force_group(talloc_tos(), snum)) {
492
493                 status = find_forced_group(
494                         conn->force_user, snum, conn->session_info->unix_info->unix_name,
495                         &conn->session_info->security_token->sids[1],
496                         &conn->session_info->unix_token->gid);
497
498                 if (!NT_STATUS_IS_OK(status)) {
499                         return status;
500                 }
501
502                 /*
503                  * We need to cache this gid, to use within
504                  * change_to_user() separately from the conn->session_info
505                  * struct. We only use conn->session_info directly if
506                  * "force_user" was set.
507                  */
508                 conn->force_group_gid = conn->session_info->unix_token->gid;
509         }
510
511         return NT_STATUS_OK;
512 }
513
514 /****************************************************************************
515   Make a connection, given the snum to connect to, and the vuser of the
516   connecting user if appropriate.
517 ****************************************************************************/
518
519 static NTSTATUS make_connection_snum(struct smbd_server_connection *sconn,
520                                         connection_struct *conn,
521                                         int snum, struct user_struct *vuser,
522                                         const char *pdev)
523 {
524         struct smb_filename *smb_fname_cpath = NULL;
525         fstring dev;
526         int ret;
527         bool on_err_call_dis_hook = false;
528         uid_t effuid;
529         gid_t effgid;
530         NTSTATUS status;
531
532         fstrcpy(dev, pdev);
533
534         status = share_sanity_checks(sconn->remote_address,
535                                        sconn->remote_hostname,
536                                        snum,
537                                        dev);
538         if (NT_STATUS_IS_ERR(status)) {
539                 goto err_root_exit;
540         }
541
542         conn->params->service = snum;
543
544         status = create_connection_session_info(sconn,
545                 conn, snum, vuser->session_info,
546                 &conn->session_info);
547
548         if (!NT_STATUS_IS_OK(status)) {
549                 DEBUG(1, ("create_connection_session_info failed: %s\n",
550                           nt_errstr(status)));
551                 goto err_root_exit;
552         }
553
554         if (lp_guest_only(snum)) {
555                 conn->force_user = true;
556         }
557
558         conn->num_files_open = 0;
559         conn->lastused = conn->lastused_count = time(NULL);
560         conn->printer = (strncmp(dev,"LPT",3) == 0);
561         conn->ipc = ( (strncmp(dev,"IPC",3) == 0) ||
562                       ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) );
563
564         /* Case options for the share. */
565         if (lp_case_sensitive(snum) == Auto) {
566                 /* We will be setting this per packet. Set to be case
567                  * insensitive for now. */
568                 conn->case_sensitive = False;
569         } else {
570                 conn->case_sensitive = (bool)lp_case_sensitive(snum);
571         }
572
573         conn->case_preserve = lp_preserve_case(snum);
574         conn->short_case_preserve = lp_short_preserve_case(snum);
575
576         conn->encrypt_level = lp_smb_encrypt(snum);
577
578         conn->veto_list = NULL;
579         conn->hide_list = NULL;
580         conn->veto_oplock_list = NULL;
581         conn->aio_write_behind_list = NULL;
582
583         conn->read_only = lp_read_only(SNUM(conn));
584
585         status = set_conn_force_user_group(conn, snum);
586         if (!NT_STATUS_IS_OK(status)) {
587                 goto err_root_exit;
588         }
589
590         conn->vuid = vuser->vuid;
591
592         {
593                 char *s = talloc_sub_advanced(talloc_tos(),
594                                         lp_servicename(talloc_tos(), SNUM(conn)),
595                                         conn->session_info->unix_info->unix_name,
596                                         conn->connectpath,
597                                         conn->session_info->unix_token->gid,
598                                         conn->session_info->unix_info->sanitized_username,
599                                         conn->session_info->info->domain_name,
600                                         lp_path(talloc_tos(), snum));
601                 if (!s) {
602                         status = NT_STATUS_NO_MEMORY;
603                         goto err_root_exit;
604                 }
605
606                 if (!set_conn_connectpath(conn,s)) {
607                         TALLOC_FREE(s);
608                         status = NT_STATUS_NO_MEMORY;
609                         goto err_root_exit;
610                 }
611                 DEBUG(3,("Connect path is '%s' for service [%s]\n",s,
612                          lp_servicename(talloc_tos(), snum)));
613                 TALLOC_FREE(s);
614         }
615
616         /*
617          * Set up the share security descriptor.
618          * NOTE - we use the *INCOMING USER* session_info
619          * here, as does (indirectly) change_to_user(),
620          * which can be called on any incoming packet.
621          * This way we set up the share access based
622          * on the authenticated user, not the forced
623          * user. See bug:
624          *
625          * https://bugzilla.samba.org/show_bug.cgi?id=9878
626          */
627
628         status = check_user_share_access(conn,
629                                         vuser->session_info,
630                                         &conn->share_access,
631                                         &conn->read_only);
632         if (!NT_STATUS_IS_OK(status)) {
633                 goto err_root_exit;
634         }
635
636         /* Initialise VFS function pointers */
637
638         if (!smbd_vfs_init(conn)) {
639                 DEBUG(0, ("vfs_init failed for service %s\n",
640                           lp_servicename(talloc_tos(), snum)));
641                 status = NT_STATUS_BAD_NETWORK_NAME;
642                 goto err_root_exit;
643         }
644
645 /* ROOT Activities: */
646         /* explicitly check widelinks here so that we can correctly warn
647          * in the logs. */
648         widelinks_warning(snum);
649
650         /*
651          * Enforce the max connections parameter.
652          */
653
654         if ((lp_max_connections(snum) > 0)
655             && (count_current_connections(lp_servicename(talloc_tos(), SNUM(conn)), True) >=
656                 lp_max_connections(snum))) {
657
658                 DEBUG(1, ("Max connections (%d) exceeded for %s\n",
659                           lp_max_connections(snum),
660                           lp_servicename(talloc_tos(), snum)));
661                 status = NT_STATUS_INSUFFICIENT_RESOURCES;
662                 goto err_root_exit;
663         }
664
665         /* Invoke VFS make connection hook - this must be the first
666            filesystem operation that we do. */
667
668         if (SMB_VFS_CONNECT(conn, lp_servicename(talloc_tos(), snum),
669                             conn->session_info->unix_info->unix_name) < 0) {
670                 DEBUG(0,("make_connection: VFS make connection failed!\n"));
671                 status = NT_STATUS_UNSUCCESSFUL;
672                 goto err_root_exit;
673         }
674
675         /* Any error exit after here needs to call the disconnect hook. */
676         on_err_call_dis_hook = true;
677
678         if ((!conn->printer) && (!conn->ipc) &&
679             lp_change_notify(conn->params)) {
680                 if (sconn->notify_ctx == NULL) {
681                         sconn->notify_ctx = notify_init(
682                                 sconn, sconn->msg_ctx, sconn->ev_ctx);
683                 }
684                 if (sconn->sys_notify_ctx == NULL) {
685                         sconn->sys_notify_ctx = sys_notify_context_create(
686                                 sconn, sconn->ev_ctx);
687                 }
688         }
689
690         if (lp_kernel_oplocks(snum)) {
691                 init_kernel_oplocks(conn->sconn);
692         }
693
694         /*
695          * Fix compatibility issue pointed out by Volker.
696          * We pass the conn->connectpath to the preexec
697          * scripts as a parameter, so attempt to canonicalize
698          * it here before calling the preexec scripts.
699          * We ignore errors here, as it is possible that
700          * the conn->connectpath doesn't exist yet and
701          * the preexec scripts will create them.
702          */
703
704         (void)canonicalize_connect_path(conn);
705
706         /* Preexecs are done here as they might make the dir we are to ChDir
707          * to below */
708         /* execute any "root preexec = " line */
709         if (*lp_root_preexec(talloc_tos(), snum)) {
710                 char *cmd = talloc_sub_advanced(talloc_tos(),
711                                         lp_servicename(talloc_tos(), SNUM(conn)),
712                                         conn->session_info->unix_info->unix_name,
713                                         conn->connectpath,
714                                         conn->session_info->unix_token->gid,
715                                         conn->session_info->unix_info->sanitized_username,
716                                         conn->session_info->info->domain_name,
717                                         lp_root_preexec(talloc_tos(), snum));
718                 DEBUG(5,("cmd=%s\n",cmd));
719                 ret = smbrun(cmd,NULL);
720                 TALLOC_FREE(cmd);
721                 if (ret != 0 && lp_root_preexec_close(snum)) {
722                         DEBUG(1,("root preexec gave %d - failing "
723                                  "connection\n", ret));
724                         status = NT_STATUS_ACCESS_DENIED;
725                         goto err_root_exit;
726                 }
727         }
728
729 /* USER Activites: */
730         if (!change_to_user(conn, conn->vuid)) {
731                 /* No point continuing if they fail the basic checks */
732                 DEBUG(0,("Can't become connected user!\n"));
733                 status = NT_STATUS_LOGON_FAILURE;
734                 goto err_root_exit;
735         }
736
737         effuid = geteuid();
738         effgid = getegid();
739
740         /* Remember that a different vuid can connect later without these
741          * checks... */
742
743         /* Preexecs are done here as they might make the dir we are to ChDir
744          * to below */
745
746         /* execute any "preexec = " line */
747         if (*lp_preexec(talloc_tos(), snum)) {
748                 char *cmd = talloc_sub_advanced(talloc_tos(),
749                                         lp_servicename(talloc_tos(), SNUM(conn)),
750                                         conn->session_info->unix_info->unix_name,
751                                         conn->connectpath,
752                                         conn->session_info->unix_token->gid,
753                                         conn->session_info->unix_info->sanitized_username,
754                                         conn->session_info->info->domain_name,
755                                         lp_preexec(talloc_tos(), snum));
756                 ret = smbrun(cmd,NULL);
757                 TALLOC_FREE(cmd);
758                 if (ret != 0 && lp_preexec_close(snum)) {
759                         DEBUG(1,("preexec gave %d - failing connection\n",
760                                  ret));
761                         status = NT_STATUS_ACCESS_DENIED;
762                         goto err_root_exit;
763                 }
764         }
765
766 #ifdef WITH_FAKE_KASERVER
767         if (lp_afs_share(snum)) {
768                 afs_login(conn);
769         }
770 #endif
771
772         /*
773          * we've finished with the user stuff - go back to root
774          * so the SMB_VFS_STAT call will only fail on path errors,
775          * not permission problems.
776          */
777         change_to_root_user();
778 /* ROOT Activites: */
779
780         /*
781          * If widelinks are disallowed we need to canonicalise the connect
782          * path here to ensure we don't have any symlinks in the
783          * connectpath. We will be checking all paths on this connection are
784          * below this directory. We must do this after the VFS init as we
785          * depend on the realpath() pointer in the vfs table. JRA.
786          */
787         if (!lp_widelinks(snum)) {
788                 if (!canonicalize_connect_path(conn)) {
789                         DEBUG(0, ("canonicalize_connect_path failed "
790                         "for service %s, path %s\n",
791                                 lp_servicename(talloc_tos(), snum),
792                                 conn->connectpath));
793                         status = NT_STATUS_BAD_NETWORK_NAME;
794                         goto err_root_exit;
795                 }
796         }
797
798         /* Add veto/hide lists */
799         if (!IS_IPC(conn) && !IS_PRINT(conn)) {
800                 set_namearray( &conn->veto_list,
801                                lp_veto_files(talloc_tos(), snum));
802                 set_namearray( &conn->hide_list,
803                                lp_hide_files(talloc_tos(), snum));
804                 set_namearray( &conn->veto_oplock_list,
805                                lp_veto_oplock_files(talloc_tos(), snum));
806                 set_namearray( &conn->aio_write_behind_list,
807                                 lp_aio_write_behind(talloc_tos(), snum));
808         }
809         smb_fname_cpath = synthetic_smb_fname(talloc_tos(), conn->connectpath,
810                                               NULL, NULL);
811         if (smb_fname_cpath == NULL) {
812                 status = NT_STATUS_NO_MEMORY;
813                 goto err_root_exit;
814         }
815
816         /* win2000 does not check the permissions on the directory
817            during the tree connect, instead relying on permission
818            check during individual operations. To match this behaviour
819            I have disabled this chdir check (tridge) */
820         /* the alternative is just to check the directory exists */
821
822         if ((ret = SMB_VFS_STAT(conn, smb_fname_cpath)) != 0 ||
823             !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
824                 if (ret == 0 && !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
825                         DEBUG(0,("'%s' is not a directory, when connecting to "
826                                  "[%s]\n", conn->connectpath,
827                                  lp_servicename(talloc_tos(), snum)));
828                 } else {
829                         DEBUG(0,("'%s' does not exist or permission denied "
830                                  "when connecting to [%s] Error was %s\n",
831                                  conn->connectpath,
832                                  lp_servicename(talloc_tos(), snum),
833                                  strerror(errno) ));
834                 }
835                 status = NT_STATUS_BAD_NETWORK_NAME;
836                 goto err_root_exit;
837         }
838         conn->base_share_dev = smb_fname_cpath->st.st_ex_dev;
839
840         talloc_free(conn->origpath);
841         conn->origpath = talloc_strdup(conn, conn->connectpath);
842
843         /* Figure out the characteristics of the underlying filesystem. This
844          * assumes that all the filesystem mounted withing a share path have
845          * the same characteristics, which is likely but not guaranteed.
846          */
847
848         conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
849
850         /*
851          * Print out the 'connected as' stuff here as we need
852          * to know the effective uid and gid we will be using
853          * (at least initially).
854          */
855
856         if( DEBUGLVL( IS_IPC(conn) ? 3 : 2 ) ) {
857                 dbgtext( "%s (%s) ", get_remote_machine_name(),
858                          tsocket_address_string(conn->sconn->remote_address,
859                                                 talloc_tos()) );
860                 dbgtext( "%s", srv_is_signing_active(sconn) ? "signed " : "");
861                 dbgtext( "connect to service %s ",
862                          lp_servicename(talloc_tos(), snum) );
863                 dbgtext( "initially as user %s ",
864                          conn->session_info->unix_info->unix_name );
865                 dbgtext( "(uid=%d, gid=%d) ", (int)effuid, (int)effgid );
866                 dbgtext( "(pid %d)\n", (int)getpid() );
867         }
868
869         return status;
870
871   err_root_exit:
872
873         TALLOC_FREE(smb_fname_cpath);
874         /* We must exit this function as root. */
875         if (geteuid() != 0) {
876                 change_to_root_user();
877         }
878         if (on_err_call_dis_hook) {
879                 /* Call VFS disconnect hook */
880                 SMB_VFS_DISCONNECT(conn);
881         }
882         return status;
883 }
884
885 /****************************************************************************
886  Make a connection to a service from SMB1. Internal interface.
887 ****************************************************************************/
888
889 static connection_struct *make_connection_smb1(struct smbd_server_connection *sconn,
890                                         NTTIME now,
891                                         int snum, struct user_struct *vuser,
892                                         const char *pdev,
893                                         NTSTATUS *pstatus)
894 {
895         struct smbXsrv_tcon *tcon;
896         NTSTATUS status;
897         struct connection_struct *conn;
898
899         status = smb1srv_tcon_create(sconn->conn, now, &tcon);
900         if (!NT_STATUS_IS_OK(status)) {
901                 DEBUG(0,("make_connection_smb1: Couldn't find free tcon %s.\n",
902                          nt_errstr(status)));
903                 *pstatus = status;
904                 return NULL;
905         }
906
907         conn = conn_new(sconn);
908         if (!conn) {
909                 TALLOC_FREE(tcon);
910
911                 DEBUG(0,("make_connection_smb1: Couldn't find free connection.\n"));
912                 *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
913                 return NULL;
914         }
915
916         conn->cnum = tcon->global->tcon_wire_id;
917         conn->tcon = tcon;
918
919         *pstatus = make_connection_snum(sconn,
920                                         conn,
921                                         snum,
922                                         vuser,
923                                         pdev);
924         if (!NT_STATUS_IS_OK(*pstatus)) {
925                 conn_free(conn);
926                 TALLOC_FREE(tcon);
927                 return NULL;
928         }
929
930         tcon->global->share_name = lp_servicename(tcon->global, SNUM(conn));
931         if (tcon->global->share_name == NULL) {
932                 conn_free(conn);
933                 TALLOC_FREE(tcon);
934                 *pstatus = NT_STATUS_NO_MEMORY;
935                 return NULL;
936         }
937         tcon->global->session_global_id =
938                 vuser->session->global->session_global_id;
939
940         tcon->compat = talloc_move(tcon, &conn);
941         tcon->status = NT_STATUS_OK;
942
943         *pstatus = smbXsrv_tcon_update(tcon);
944         if (!NT_STATUS_IS_OK(*pstatus)) {
945                 TALLOC_FREE(tcon);
946                 return NULL;
947         }
948
949         return tcon->compat;
950 }
951
952 /****************************************************************************
953  Make a connection to a service from SMB2. External SMB2 interface.
954  We must set cnum before claiming connection.
955 ****************************************************************************/
956
957 connection_struct *make_connection_smb2(struct smbd_server_connection *sconn,
958                                         struct smbXsrv_tcon *tcon,
959                                         int snum,
960                                         struct user_struct *vuser,
961                                         const char *pdev,
962                                         NTSTATUS *pstatus)
963 {
964         connection_struct *conn = conn_new(sconn);
965         if (!conn) {
966                 DEBUG(0,("make_connection_smb2: Couldn't find free connection.\n"));
967                 *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
968                 return NULL;
969         }
970
971         conn->cnum = tcon->global->tcon_wire_id;
972         conn->tcon = tcon;
973
974         *pstatus = make_connection_snum(sconn,
975                                         conn,
976                                         snum,
977                                         vuser,
978                                         pdev);
979         if (!NT_STATUS_IS_OK(*pstatus)) {
980                 conn_free(conn);
981                 return NULL;
982         }
983         return conn;
984 }
985
986 /****************************************************************************
987  Make a connection to a service. External SMB1 interface.
988  *
989  * @param service 
990 ****************************************************************************/
991
992 connection_struct *make_connection(struct smbd_server_connection *sconn,
993                                    NTTIME now,
994                                    const char *service_in,
995                                    const char *pdev, uint64_t vuid,
996                                    NTSTATUS *status)
997 {
998         uid_t euid;
999         struct user_struct *vuser = NULL;
1000         char *service = NULL;
1001         fstring dev;
1002         int snum = -1;
1003
1004         fstrcpy(dev, pdev);
1005
1006         /* This must ONLY BE CALLED AS ROOT. As it exits this function as
1007          * root. */
1008         if (!non_root_mode() && (euid = geteuid()) != 0) {
1009                 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot "
1010                          "(%u)\n", (unsigned int)euid ));
1011                 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
1012         }
1013
1014         if (conn_num_open(sconn) > 2047) {
1015                 *status = NT_STATUS_INSUFF_SERVER_RESOURCES;
1016                 return NULL;
1017         }
1018
1019         vuser = get_valid_user_struct(sconn, vuid);
1020         if (!vuser) {
1021                 DEBUG(1,("make_connection: refusing to connect with "
1022                          "no session setup\n"));
1023                 *status = NT_STATUS_ACCESS_DENIED;
1024                 return NULL;
1025         }
1026
1027         /* Logic to try and connect to the correct [homes] share, preferably
1028            without too many getpwnam() lookups.  This is particulary nasty for
1029            winbind usernames, where the share name isn't the same as unix
1030            username.
1031
1032            The snum of the homes share is stored on the vuser at session setup
1033            time.
1034         */
1035
1036         if (strequal(service_in,HOMES_NAME)) {
1037                 if (vuser->homes_snum == -1) {
1038                         DEBUG(2, ("[homes] share not available for "
1039                                   "this user because it was not found "
1040                                   "or created at session setup "
1041                                   "time\n"));
1042                         *status = NT_STATUS_BAD_NETWORK_NAME;
1043                         return NULL;
1044                 }
1045                 DEBUG(5, ("making a connection to [homes] service "
1046                           "created at session setup time\n"));
1047                 return make_connection_smb1(sconn, now,
1048                                             vuser->homes_snum,
1049                                             vuser,
1050                                             dev, status);
1051         } else if ((vuser->homes_snum != -1)
1052                    && strequal(service_in,
1053                                lp_servicename(talloc_tos(), vuser->homes_snum))) {
1054                 DEBUG(5, ("making a connection to 'homes' service [%s] "
1055                           "created at session setup time\n", service_in));
1056                 return make_connection_smb1(sconn, now,
1057                                             vuser->homes_snum,
1058                                             vuser,
1059                                             dev, status);
1060         }
1061
1062         service = talloc_strdup(talloc_tos(), service_in);
1063         if (!service) {
1064                 *status = NT_STATUS_NO_MEMORY;
1065                 return NULL;
1066         }
1067
1068         if (!strlower_m(service)) {
1069                 DEBUG(2, ("strlower_m %s failed\n", service));
1070                 *status = NT_STATUS_INVALID_PARAMETER;
1071                 return NULL;
1072         }
1073
1074         snum = find_service(talloc_tos(), service, &service);
1075         if (!service) {
1076                 *status = NT_STATUS_NO_MEMORY;
1077                 return NULL;
1078         }
1079
1080         if (snum < 0) {
1081                 if (strequal(service,"IPC$") ||
1082                     (lp_enable_asu_support() && strequal(service,"ADMIN$"))) {
1083                         DEBUG(3,("refusing IPC connection to %s\n", service));
1084                         *status = NT_STATUS_ACCESS_DENIED;
1085                         return NULL;
1086                 }
1087
1088                 DEBUG(3,("%s (%s) couldn't find service %s\n",
1089                         get_remote_machine_name(),
1090                         tsocket_address_string(
1091                                 sconn->remote_address, talloc_tos()),
1092                         service));
1093                 *status = NT_STATUS_BAD_NETWORK_NAME;
1094                 return NULL;
1095         }
1096
1097         /* Handle non-Dfs clients attempting connections to msdfs proxy */
1098         if (lp_host_msdfs() && (*lp_msdfs_proxy(talloc_tos(), snum) != '\0'))  {
1099                 DEBUG(3, ("refusing connection to dfs proxy share '%s' "
1100                           "(pointing to %s)\n", 
1101                         service, lp_msdfs_proxy(talloc_tos(), snum)));
1102                 *status = NT_STATUS_BAD_NETWORK_NAME;
1103                 return NULL;
1104         }
1105
1106         DEBUG(5, ("making a connection to 'normal' service %s\n", service));
1107
1108         return make_connection_smb1(sconn, now, snum, vuser,
1109                                     dev, status);
1110 }
1111
1112 /****************************************************************************
1113  Close a cnum.
1114 ****************************************************************************/
1115
1116 void close_cnum(connection_struct *conn, uint64_t vuid)
1117 {
1118         file_close_conn(conn);
1119
1120         if (!IS_IPC(conn)) {
1121                 dptr_closecnum(conn);
1122         }
1123
1124         change_to_root_user();
1125
1126         DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
1127                                  get_remote_machine_name(),
1128                                  tsocket_address_string(conn->sconn->remote_address,
1129                                                         talloc_tos()),
1130                                  lp_servicename(talloc_tos(), SNUM(conn))));
1131
1132         /* Call VFS disconnect hook */    
1133         SMB_VFS_DISCONNECT(conn);
1134
1135         /* make sure we leave the directory available for unmount */
1136         vfs_ChDir(conn, "/");
1137
1138         /* execute any "postexec = " line */
1139         if (*lp_postexec(talloc_tos(), SNUM(conn)) &&
1140             change_to_user(conn, vuid))  {
1141                 char *cmd = talloc_sub_advanced(talloc_tos(),
1142                                         lp_servicename(talloc_tos(), SNUM(conn)),
1143                                         conn->session_info->unix_info->unix_name,
1144                                         conn->connectpath,
1145                                         conn->session_info->unix_token->gid,
1146                                         conn->session_info->unix_info->sanitized_username,
1147                                         conn->session_info->info->domain_name,
1148                                         lp_postexec(talloc_tos(), SNUM(conn)));
1149                 smbrun(cmd,NULL);
1150                 TALLOC_FREE(cmd);
1151                 change_to_root_user();
1152         }
1153
1154         change_to_root_user();
1155         /* execute any "root postexec = " line */
1156         if (*lp_root_postexec(talloc_tos(), SNUM(conn)))  {
1157                 char *cmd = talloc_sub_advanced(talloc_tos(),
1158                                         lp_servicename(talloc_tos(), SNUM(conn)),
1159                                         conn->session_info->unix_info->unix_name,
1160                                         conn->connectpath,
1161                                         conn->session_info->unix_token->gid,
1162                                         conn->session_info->unix_info->sanitized_username,
1163                                         conn->session_info->info->domain_name,
1164                                         lp_root_postexec(talloc_tos(), SNUM(conn)));
1165                 smbrun(cmd,NULL);
1166                 TALLOC_FREE(cmd);
1167         }
1168
1169         conn_free(conn);
1170 }