source: vendor/current/source3/smbd/service.c

Last change on this file was 989, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.7

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