source: trunk/server/source3/smbd/service.c@ 874

Last change on this file since 874 was 862, checked in by Silvan Scherrer, 11 years ago

Samba Server: update trunk to 3.6.23

File size: 38.6 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 "../lib/tsocket/tsocket.h"
23#include "smbd/smbd.h"
24#include "smbd/globals.h"
25#include "../librpc/gen_ndr/netlogon.h"
26#include "../libcli/security/security.h"
27#include "printing/pcap.h"
28#include "passdb/lookup_sid.h"
29#include "auth.h"
30
31extern userdom_struct current_user_info;
32
33static bool canonicalize_connect_path(connection_struct *conn)
34{
35 bool ret;
36 char *resolved_name = SMB_VFS_REALPATH(conn,conn->connectpath);
37 if (!resolved_name) {
38 return false;
39 }
40 ret = set_conn_connectpath(conn,resolved_name);
41 SAFE_FREE(resolved_name);
42 return ret;
43}
44
45/****************************************************************************
46 Ensure when setting connectpath it is a canonicalized (no ./ // or ../)
47 absolute path stating in / and not ending in /.
48 Observent people will notice a similarity between this and check_path_syntax :-).
49****************************************************************************/
50
51bool set_conn_connectpath(connection_struct *conn, const char *connectpath)
52{
53 char *destname;
54 char *d;
55 const char *s = connectpath;
56 bool start_of_name_component = true;
57
58 if (connectpath == NULL || connectpath[0] == '\0') {
59 return false;
60 }
61
62 /* Allocate for strlen + '\0' + possible leading '/' */
63 destname = (char *)SMB_MALLOC(strlen(connectpath) + 2);
64 if (!destname) {
65 return false;
66 }
67 d = destname;
68
69#ifndef __OS2__
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#else
162 /* Assume OS/2 users are smart enough to put a correct path in smb.conf, and simply copy the string */
163 safe_strcpy(destname, connectpath, strlen(connectpath));
164#endif
165
166 DEBUG(10,("set_conn_connectpath: service %s, connectpath = %s\n",
167 lp_servicename(SNUM(conn)), destname ));
168
169 string_set(&conn->connectpath, destname);
170 SAFE_FREE(destname);
171 return true;
172}
173
174/****************************************************************************
175 Load parameters specific to a connection/service.
176****************************************************************************/
177
178bool set_current_service(connection_struct *conn, uint16 flags, bool do_chdir)
179{
180 int snum;
181
182 if (!conn) {
183 last_conn = NULL;
184 return(False);
185 }
186
187 conn->lastused_count++;
188
189 snum = SNUM(conn);
190
191 if (do_chdir &&
192 vfs_ChDir(conn,conn->connectpath) != 0 &&
193 vfs_ChDir(conn,conn->origpath) != 0) {
194 DEBUG(((errno!=EACCES)?0:3),("chdir (%s) failed, reason: %s\n",
195 conn->connectpath, strerror(errno)));
196 return(False);
197 }
198
199 if ((conn == last_conn) && (last_flags == flags)) {
200 return(True);
201 }
202
203 last_conn = conn;
204 last_flags = flags;
205
206 /* Obey the client case sensitivity requests - only for clients that support it. */
207 switch (lp_casesensitive(snum)) {
208 case Auto:
209 {
210 /* We need this uglyness due to DOS/Win9x clients that lie about case insensitivity. */
211 enum remote_arch_types ra_type = get_remote_arch();
212 if ((ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
213 /* Client can't support per-packet case sensitive pathnames. */
214 conn->case_sensitive = False;
215 } else {
216 conn->case_sensitive = !(flags & FLAG_CASELESS_PATHNAMES);
217 }
218 }
219 break;
220 case True:
221 conn->case_sensitive = True;
222 break;
223 default:
224 conn->case_sensitive = False;
225 break;
226 }
227 return(True);
228}
229
230static int load_registry_service(const char *servicename)
231{
232 if (!lp_registry_shares()) {
233 return -1;
234 }
235
236 if ((servicename == NULL) || (*servicename == '\0')) {
237 return -1;
238 }
239
240 if (strequal(servicename, GLOBAL_NAME)) {
241 return -2;
242 }
243
244 if (!process_registry_service(servicename)) {
245 return -1;
246 }
247
248 return lp_servicenumber(servicename);
249}
250
251void load_registry_shares(void)
252{
253 DEBUG(8, ("load_registry_shares()\n"));
254 if (!lp_registry_shares()) {
255 return;
256 }
257
258 process_registry_shares();
259
260 return;
261}
262
263/****************************************************************************
264 Add a home service. Returns the new service number or -1 if fail.
265****************************************************************************/
266
267int add_home_service(const char *service, const char *username, const char *homedir)
268{
269 int iHomeService;
270
271 if (!service || !homedir || homedir[0] == '\0')
272 return -1;
273
274 if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0) {
275 if ((iHomeService = load_registry_service(HOMES_NAME)) < 0) {
276 return -1;
277 }
278 }
279
280 /*
281 * If this is a winbindd provided username, remove
282 * the domain component before adding the service.
283 * Log a warning if the "path=" parameter does not
284 * include any macros.
285 */
286
287 {
288 const char *p = strchr(service,*lp_winbind_separator());
289
290 /* We only want the 'user' part of the string */
291 if (p) {
292 service = p + 1;
293 }
294 }
295
296 if (!lp_add_home(service, iHomeService, username, homedir)) {
297 return -1;
298 }
299
300 return lp_servicenumber(service);
301
302}
303
304/**
305 * Find a service entry.
306 *
307 * @param service is modified (to canonical form??)
308 **/
309
310int find_service(TALLOC_CTX *ctx, const char *service_in, char **p_service_out)
311{
312 int iService;
313
314 if (!service_in) {
315 return -1;
316 }
317
318 /* First make a copy. */
319 *p_service_out = talloc_strdup(ctx, service_in);
320 if (!*p_service_out) {
321 return -1;
322 }
323
324 all_string_sub(*p_service_out,"\\","/",0);
325
326 iService = lp_servicenumber(*p_service_out);
327
328 /* now handle the special case of a home directory */
329 if (iService < 0) {
330 char *phome_dir = get_user_home_dir(ctx, *p_service_out);
331
332 if(!phome_dir) {
333 /*
334 * Try mapping the servicename, it may
335 * be a Windows to unix mapped user name.
336 */
337 if(map_username(ctx, *p_service_out, p_service_out)) {
338 if (*p_service_out == NULL) {
339 /* Out of memory. */
340 return -1;
341 }
342 phome_dir = get_user_home_dir(
343 ctx, *p_service_out);
344 }
345 }
346
347 DEBUG(3,("checking for home directory %s gave %s\n",*p_service_out,
348 phome_dir?phome_dir:"(NULL)"));
349
350 iService = add_home_service(*p_service_out,*p_service_out /* 'username' */, phome_dir);
351 }
352
353 /* If we still don't have a service, attempt to add it as a printer. */
354 if (iService < 0) {
355 int iPrinterService;
356
357 if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) < 0) {
358 iPrinterService = load_registry_service(PRINTERS_NAME);
359 }
360 if (iPrinterService >= 0) {
361 DEBUG(3,("checking whether %s is a valid printer name...\n",
362 *p_service_out));
363 if (pcap_printername_ok(*p_service_out)) {
364 DEBUG(3,("%s is a valid printer name\n",
365 *p_service_out));
366 DEBUG(3,("adding %s as a printer service\n",
367 *p_service_out));
368 lp_add_printer(*p_service_out, iPrinterService);
369 iService = lp_servicenumber(*p_service_out);
370 if (iService < 0) {
371 DEBUG(0,("failed to add %s as a printer service!\n",
372 *p_service_out));
373 }
374 } else {
375 DEBUG(3,("%s is not a valid printer name\n",
376 *p_service_out));
377 }
378 }
379 }
380
381 /* Check for default vfs service? Unsure whether to implement this */
382 if (iService < 0) {
383 }
384
385 if (iService < 0) {
386 iService = load_registry_service(*p_service_out);
387 }
388
389 /* Is it a usershare service ? */
390 if (iService < 0 && *lp_usershare_path()) {
391 /* Ensure the name is canonicalized. */
392 strlower_m(*p_service_out);
393 iService = load_usershare_service(*p_service_out);
394 }
395
396 /* just possibly it's a default service? */
397 if (iService < 0) {
398 char *pdefservice = lp_defaultservice();
399 if (pdefservice &&
400 *pdefservice &&
401 !strequal(pdefservice, *p_service_out)
402 && !strstr_m(*p_service_out,"..")) {
403 /*
404 * We need to do a local copy here as lp_defaultservice()
405 * returns one of the rotating lp_string buffers that
406 * could get overwritten by the recursive find_service() call
407 * below. Fix from Josef Hinteregger <joehtg@joehtg.co.at>.
408 */
409 char *defservice = talloc_strdup(ctx, pdefservice);
410
411 if (!defservice) {
412 goto fail;
413 }
414
415 /* Disallow anything except explicit share names. */
416 if (strequal(defservice,HOMES_NAME) ||
417 strequal(defservice, PRINTERS_NAME) ||
418 strequal(defservice, "IPC$")) {
419 TALLOC_FREE(defservice);
420 goto fail;
421 }
422
423 iService = find_service(ctx, defservice, p_service_out);
424 if (!*p_service_out) {
425 TALLOC_FREE(defservice);
426 iService = -1;
427 goto fail;
428 }
429 if (iService >= 0) {
430 all_string_sub(*p_service_out, "_","/",0);
431 iService = lp_add_service(*p_service_out, iService);
432 }
433 TALLOC_FREE(defservice);
434 }
435 }
436
437 if (iService >= 0) {
438 if (!VALID_SNUM(iService)) {
439 DEBUG(0,("Invalid snum %d for %s\n",iService,
440 *p_service_out));
441 iService = -1;
442 }
443 }
444
445 fail:
446
447 if (iService < 0) {
448 DEBUG(3,("find_service() failed to find service %s\n",
449 *p_service_out));
450 }
451
452 return (iService);
453}
454
455
456/****************************************************************************
457 do some basic sainity checks on the share.
458 This function modifies dev, ecode.
459****************************************************************************/
460
461static NTSTATUS share_sanity_checks(struct client_address *client_id, int snum,
462 fstring dev)
463{
464 if (!lp_snum_ok(snum) ||
465 !allow_access(lp_hostsdeny(snum), lp_hostsallow(snum),
466 client_id->name, client_id->addr)) {
467 return NT_STATUS_ACCESS_DENIED;
468 }
469
470 if (dev[0] == '?' || !dev[0]) {
471 if (lp_print_ok(snum)) {
472 fstrcpy(dev,"LPT1:");
473 } else if (strequal(lp_fstype(snum), "IPC")) {
474 fstrcpy(dev, "IPC");
475 } else {
476 fstrcpy(dev,"A:");
477 }
478 }
479
480 strupper_m(dev);
481
482 if (lp_print_ok(snum)) {
483 if (!strequal(dev, "LPT1:")) {
484 return NT_STATUS_BAD_DEVICE_TYPE;
485 }
486 } else if (strequal(lp_fstype(snum), "IPC")) {
487 if (!strequal(dev, "IPC")) {
488 return NT_STATUS_BAD_DEVICE_TYPE;
489 }
490 } else if (!strequal(dev, "A:")) {
491 return NT_STATUS_BAD_DEVICE_TYPE;
492 }
493
494 /* Behave as a printer if we are supposed to */
495 if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) {
496 fstrcpy(dev, "LPT1:");
497 }
498
499 return NT_STATUS_OK;
500}
501
502/*
503 * Go through lookup_name etc to find the force'd group.
504 *
505 * Create a new token from src_token, replacing the primary group sid with the
506 * one found.
507 */
508
509static NTSTATUS find_forced_group(bool force_user,
510 int snum, const char *username,
511 struct dom_sid *pgroup_sid,
512 gid_t *pgid)
513{
514 NTSTATUS result = NT_STATUS_NO_SUCH_GROUP;
515 TALLOC_CTX *frame = talloc_stackframe();
516 struct dom_sid group_sid;
517 enum lsa_SidType type;
518 char *groupname;
519 bool user_must_be_member = False;
520 gid_t gid;
521
522 groupname = talloc_strdup(talloc_tos(), lp_force_group(snum));
523 if (groupname == NULL) {
524 DEBUG(1, ("talloc_strdup failed\n"));
525 result = NT_STATUS_NO_MEMORY;
526 goto done;
527 }
528
529 if (groupname[0] == '+') {
530 user_must_be_member = True;
531 groupname += 1;
532 }
533
534 groupname = talloc_string_sub(talloc_tos(), groupname,
535 "%S", lp_servicename(snum));
536 if (groupname == NULL) {
537 DEBUG(1, ("talloc_string_sub failed\n"));
538 result = NT_STATUS_NO_MEMORY;
539 goto done;
540 }
541
542 if (!lookup_name_smbconf(talloc_tos(), groupname,
543 LOOKUP_NAME_ALL|LOOKUP_NAME_GROUP,
544 NULL, NULL, &group_sid, &type)) {
545 DEBUG(10, ("lookup_name_smbconf(%s) failed\n",
546 groupname));
547 goto done;
548 }
549
550 if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
551 (type != SID_NAME_WKN_GRP)) {
552 DEBUG(10, ("%s is a %s, not a group\n", groupname,
553 sid_type_lookup(type)));
554 goto done;
555 }
556
557 if (!sid_to_gid(&group_sid, &gid)) {
558 DEBUG(10, ("sid_to_gid(%s) for %s failed\n",
559 sid_string_dbg(&group_sid), groupname));
560 goto done;
561 }
562
563 /*
564 * If the user has been forced and the forced group starts with a '+',
565 * then we only set the group to be the forced group if the forced
566 * user is a member of that group. Otherwise, the meaning of the '+'
567 * would be ignored.
568 */
569
570 if (force_user && user_must_be_member) {
571 if (user_in_group_sid(username, &group_sid)) {
572 sid_copy(pgroup_sid, &group_sid);
573 *pgid = gid;
574 DEBUG(3,("Forced group %s for member %s\n",
575 groupname, username));
576 } else {
577 DEBUG(0,("find_forced_group: forced user %s is not a member "
578 "of forced group %s. Disallowing access.\n",
579 username, groupname ));
580 result = NT_STATUS_MEMBER_NOT_IN_GROUP;
581 goto done;
582 }
583 } else {
584 sid_copy(pgroup_sid, &group_sid);
585 *pgid = gid;
586 DEBUG(3,("Forced group %s\n", groupname));
587 }
588
589 result = NT_STATUS_OK;
590 done:
591 TALLOC_FREE(frame);
592 return result;
593}
594
595/****************************************************************************
596 Create an auth_serversupplied_info structure for a connection_struct
597****************************************************************************/
598
599static NTSTATUS create_connection_session_info(struct smbd_server_connection *sconn,
600 TALLOC_CTX *mem_ctx, int snum,
601 struct auth_serversupplied_info *vuid_serverinfo,
602 DATA_BLOB password,
603 struct auth_serversupplied_info **presult)
604{
605 if (lp_guest_only(snum)) {
606 return make_server_info_guest(mem_ctx, presult);
607 }
608
609 if (vuid_serverinfo != NULL) {
610
611 struct auth_serversupplied_info *result;
612
613 /*
614 * This is the normal security != share case where we have a
615 * valid vuid from the session setup. */
616
617 if (vuid_serverinfo->guest) {
618 if (!lp_guest_ok(snum)) {
619 DEBUG(2, ("guest user (from session setup) "
620 "not permitted to access this share "
621 "(%s)\n", lp_servicename(snum)));
622 return NT_STATUS_ACCESS_DENIED;
623 }
624 } else {
625 if (!user_ok_token(vuid_serverinfo->unix_name,
626 vuid_serverinfo->info3->base.domain.string,
627 vuid_serverinfo->security_token, snum)) {
628 DEBUG(2, ("user '%s' (from session setup) not "
629 "permitted to access this share "
630 "(%s)\n",
631 vuid_serverinfo->unix_name,
632 lp_servicename(snum)));
633 return NT_STATUS_ACCESS_DENIED;
634 }
635 }
636
637 result = copy_serverinfo(mem_ctx, vuid_serverinfo);
638 if (result == NULL) {
639 return NT_STATUS_NO_MEMORY;
640 }
641
642 *presult = result;
643 return NT_STATUS_OK;
644 }
645
646 if (lp_security() == SEC_SHARE) {
647
648 fstring user;
649 bool guest;
650
651 /* add the sharename as a possible user name if we
652 are in share mode security */
653
654 add_session_user(sconn, lp_servicename(snum));
655
656 /* shall we let them in? */
657
658 if (!authorise_login(sconn, snum,user,password,&guest)) {
659 DEBUG( 2, ( "Invalid username/password for [%s]\n",
660 lp_servicename(snum)) );
661 return NT_STATUS_WRONG_PASSWORD;
662 }
663
664 return make_serverinfo_from_username(mem_ctx, user, guest, guest,
665 presult);
666 }
667
668 DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
669 return NT_STATUS_ACCESS_DENIED;
670}
671
672/****************************************************************************
673 set relavent user and group settings corresponding to force user/group
674 configuration for the given snum.
675****************************************************************************/
676
677NTSTATUS set_conn_force_user_group(connection_struct *conn, int snum)
678{
679 NTSTATUS status;
680
681 if (*lp_force_user(snum)) {
682
683 /*
684 * Replace conn->session_info with a completely faked up one
685 * from the username we are forced into :-)
686 */
687
688 char *fuser;
689 struct auth_serversupplied_info *forced_serverinfo;
690
691 fuser = talloc_string_sub(conn, lp_force_user(snum), "%S",
692 lp_const_servicename(snum));
693 if (fuser == NULL) {
694 return NT_STATUS_NO_MEMORY;
695 }
696
697 status = make_serverinfo_from_username(
698 conn, fuser, false, conn->session_info->guest,
699 &forced_serverinfo);
700 if (!NT_STATUS_IS_OK(status)) {
701 return status;
702 }
703
704 /* We don't want to replace the original sanitized_username
705 as it is the original user given in the connect attempt.
706 This is used in '%U' substitutions. */
707 TALLOC_FREE(forced_serverinfo->sanitized_username);
708 forced_serverinfo->sanitized_username =
709 talloc_move(forced_serverinfo,
710 &conn->session_info->sanitized_username);
711
712 TALLOC_FREE(conn->session_info);
713 conn->session_info = forced_serverinfo;
714
715 conn->force_user = true;
716 DEBUG(3,("Forced user %s\n", fuser));
717 }
718
719 /*
720 * If force group is true, then override
721 * any groupid stored for the connecting user.
722 */
723
724 if (*lp_force_group(snum)) {
725
726 status = find_forced_group(
727 conn->force_user, snum, conn->session_info->unix_name,
728 &conn->session_info->security_token->sids[1],
729 &conn->session_info->utok.gid);
730
731 if (!NT_STATUS_IS_OK(status)) {
732 return status;
733 }
734
735 /*
736 * We need to cache this gid, to use within
737 * change_to_user() separately from the conn->session_info
738 * struct. We only use conn->session_info directly if
739 * "force_user" was set.
740 */
741 conn->force_group_gid = conn->session_info->utok.gid;
742 }
743
744 return NT_STATUS_OK;
745}
746
747/****************************************************************************
748 Setup the share access mask for a connection.
749****************************************************************************/
750
751static void create_share_access_mask(connection_struct *conn, int snum)
752{
753 const struct security_token *token = conn->session_info->security_token;
754
755 share_access_check(token,
756 lp_servicename(snum),
757 MAXIMUM_ALLOWED_ACCESS,
758 &conn->share_access);
759
760 if (security_token_has_privilege(token, SEC_PRIV_SECURITY)) {
761 conn->share_access |= SEC_FLAG_SYSTEM_SECURITY;
762 }
763 if (security_token_has_privilege(token, SEC_PRIV_RESTORE)) {
764 conn->share_access |= (SEC_RIGHTS_PRIV_RESTORE);
765 }
766 if (security_token_has_privilege(token, SEC_PRIV_BACKUP)) {
767 conn->share_access |= (SEC_RIGHTS_PRIV_BACKUP);
768 }
769 if (security_token_has_privilege(token, SEC_PRIV_TAKE_OWNERSHIP)) {
770 conn->share_access |= (SEC_STD_WRITE_OWNER);
771 }
772}
773
774/****************************************************************************
775 Make a connection, given the snum to connect to, and the vuser of the
776 connecting user if appropriate.
777****************************************************************************/
778
779static connection_struct *make_connection_snum(struct smbd_server_connection *sconn,
780 connection_struct *conn,
781 int snum, user_struct *vuser,
782 DATA_BLOB password,
783 const char *pdev,
784 NTSTATUS *pstatus)
785{
786 struct smb_filename *smb_fname_cpath = NULL;
787 fstring dev;
788 int ret;
789 bool on_err_call_dis_hook = false;
790 bool claimed_connection = false;
791 uid_t effuid;
792 gid_t effgid;
793 NTSTATUS status;
794
795 fstrcpy(dev, pdev);
796
797 *pstatus = share_sanity_checks(&sconn->client_id, snum, dev);
798 if (NT_STATUS_IS_ERR(*pstatus)) {
799 goto err_root_exit;
800 }
801
802 conn->params->service = snum;
803
804 status = create_connection_session_info(sconn,
805 conn, snum, vuser ? vuser->session_info : NULL, password,
806 &conn->session_info);
807
808 if (!NT_STATUS_IS_OK(status)) {
809 DEBUG(1, ("create_connection_session_info failed: %s\n",
810 nt_errstr(status)));
811 *pstatus = status;
812 goto err_root_exit;
813 }
814
815 if ((lp_guest_only(snum)) || (lp_security() == SEC_SHARE)) {
816 conn->force_user = true;
817 }
818
819 add_session_user(sconn, conn->session_info->unix_name);
820
821 conn->num_files_open = 0;
822 conn->lastused = conn->lastused_count = time(NULL);
823 conn->used = True;
824 conn->printer = (strncmp(dev,"LPT",3) == 0);
825 conn->ipc = ( (strncmp(dev,"IPC",3) == 0) ||
826 ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) );
827
828 /* Case options for the share. */
829 if (lp_casesensitive(snum) == Auto) {
830 /* We will be setting this per packet. Set to be case
831 * insensitive for now. */
832 conn->case_sensitive = False;
833 } else {
834 conn->case_sensitive = (bool)lp_casesensitive(snum);
835 }
836
837 conn->case_preserve = lp_preservecase(snum);
838 conn->short_case_preserve = lp_shortpreservecase(snum);
839
840 conn->encrypt_level = lp_smb_encrypt(snum);
841
842 conn->veto_list = NULL;
843 conn->hide_list = NULL;
844 conn->veto_oplock_list = NULL;
845 conn->aio_write_behind_list = NULL;
846
847 conn->read_only = lp_readonly(SNUM(conn));
848
849 status = set_conn_force_user_group(conn, snum);
850 if (!NT_STATUS_IS_OK(status)) {
851 *pstatus = status;
852 return NULL;
853 }
854
855 conn->vuid = (vuser != NULL) ? vuser->vuid : UID_FIELD_INVALID;
856
857 {
858 char *s = talloc_sub_advanced(talloc_tos(),
859 lp_servicename(SNUM(conn)),
860 conn->session_info->unix_name,
861 conn->connectpath,
862 conn->session_info->utok.gid,
863 conn->session_info->sanitized_username,
864 conn->session_info->info3->base.domain.string,
865 lp_pathname(snum));
866 if (!s) {
867 *pstatus = NT_STATUS_NO_MEMORY;
868 goto err_root_exit;
869 }
870
871 if (!set_conn_connectpath(conn,s)) {
872 TALLOC_FREE(s);
873 *pstatus = NT_STATUS_NO_MEMORY;
874 goto err_root_exit;
875 }
876 DEBUG(3,("Connect path is '%s' for service [%s]\n",s,
877 lp_servicename(snum)));
878 TALLOC_FREE(s);
879 }
880
881 /*
882 * New code to check if there's a share security descripter
883 * added from NT server manager. This is done after the
884 * smb.conf checks are done as we need a uid and token. JRA.
885 *
886 */
887
888 create_share_access_mask(conn, snum);
889
890 if ((conn->share_access & FILE_WRITE_DATA) == 0) {
891 if ((conn->share_access & FILE_READ_DATA) == 0) {
892 /* No access, read or write. */
893 DEBUG(0,("make_connection: connection to %s "
894 "denied due to security "
895 "descriptor.\n",
896 lp_servicename(snum)));
897 *pstatus = NT_STATUS_ACCESS_DENIED;
898 goto err_root_exit;
899 } else {
900 conn->read_only = True;
901 }
902 }
903 /* Initialise VFS function pointers */
904
905 if (!smbd_vfs_init(conn)) {
906 DEBUG(0, ("vfs_init failed for service %s\n",
907 lp_servicename(snum)));
908 *pstatus = NT_STATUS_BAD_NETWORK_NAME;
909 goto err_root_exit;
910 }
911
912/* ROOT Activities: */
913 /* explicitly check widelinks here so that we can correctly warn
914 * in the logs. */
915 widelinks_warning(snum);
916
917 /*
918 * Enforce the max connections parameter.
919 */
920
921 if ((lp_max_connections(snum) > 0)
922 && (count_current_connections(lp_servicename(SNUM(conn)), True) >=
923 lp_max_connections(snum))) {
924
925 DEBUG(1, ("Max connections (%d) exceeded for %s\n",
926 lp_max_connections(snum), lp_servicename(snum)));
927 *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
928 goto err_root_exit;
929 }
930
931 /*
932 * Get us an entry in the connections db
933 */
934 if (!claim_connection(conn, lp_servicename(snum))) {
935 DEBUG(1, ("Could not store connections entry\n"));
936 *pstatus = NT_STATUS_INTERNAL_DB_ERROR;
937 goto err_root_exit;
938 }
939 claimed_connection = true;
940
941 /* Invoke VFS make connection hook - this must be the first
942 filesystem operation that we do. */
943
944 if (SMB_VFS_CONNECT(conn, lp_servicename(snum),
945 conn->session_info->unix_name) < 0) {
946 DEBUG(0,("make_connection: VFS make connection failed!\n"));
947 *pstatus = NT_STATUS_UNSUCCESSFUL;
948 goto err_root_exit;
949 }
950
951 /* Any error exit after here needs to call the disconnect hook. */
952 on_err_call_dis_hook = true;
953
954 if ((!conn->printer) && (!conn->ipc)) {
955 conn->notify_ctx = notify_init(conn,
956 sconn_server_id(sconn),
957 sconn->msg_ctx,
958 smbd_event_context(),
959 conn);
960 }
961
962 /*
963 * Fix compatibility issue pointed out by Volker.
964 * We pass the conn->connectpath to the preexec
965 * scripts as a parameter, so attempt to canonicalize
966 * it here before calling the preexec scripts.
967 * We ignore errors here, as it is possible that
968 * the conn->connectpath doesn't exist yet and
969 * the preexec scripts will create them.
970 */
971
972 (void)canonicalize_connect_path(conn);
973
974 /* Preexecs are done here as they might make the dir we are to ChDir
975 * to below */
976 /* execute any "root preexec = " line */
977 if (*lp_rootpreexec(snum)) {
978 char *cmd = talloc_sub_advanced(talloc_tos(),
979 lp_servicename(SNUM(conn)),
980 conn->session_info->unix_name,
981 conn->connectpath,
982 conn->session_info->utok.gid,
983 conn->session_info->sanitized_username,
984 conn->session_info->info3->base.domain.string,
985 lp_rootpreexec(snum));
986 DEBUG(5,("cmd=%s\n",cmd));
987 ret = smbrun(cmd,NULL);
988 TALLOC_FREE(cmd);
989 if (ret != 0 && lp_rootpreexec_close(snum)) {
990 DEBUG(1,("root preexec gave %d - failing "
991 "connection\n", ret));
992 *pstatus = NT_STATUS_ACCESS_DENIED;
993 goto err_root_exit;
994 }
995 }
996
997/* USER Activites: */
998 if (!change_to_user(conn, conn->vuid)) {
999 /* No point continuing if they fail the basic checks */
1000 DEBUG(0,("Can't become connected user!\n"));
1001 *pstatus = NT_STATUS_LOGON_FAILURE;
1002 goto err_root_exit;
1003 }
1004
1005 effuid = geteuid();
1006 effgid = getegid();
1007
1008 /* Remember that a different vuid can connect later without these
1009 * checks... */
1010
1011 /* Preexecs are done here as they might make the dir we are to ChDir
1012 * to below */
1013
1014 /* execute any "preexec = " line */
1015 if (*lp_preexec(snum)) {
1016 char *cmd = talloc_sub_advanced(talloc_tos(),
1017 lp_servicename(SNUM(conn)),
1018 conn->session_info->unix_name,
1019 conn->connectpath,
1020 conn->session_info->utok.gid,
1021 conn->session_info->sanitized_username,
1022 conn->session_info->info3->base.domain.string,
1023 lp_preexec(snum));
1024 ret = smbrun(cmd,NULL);
1025 TALLOC_FREE(cmd);
1026 if (ret != 0 && lp_preexec_close(snum)) {
1027 DEBUG(1,("preexec gave %d - failing connection\n",
1028 ret));
1029 *pstatus = NT_STATUS_ACCESS_DENIED;
1030 goto err_root_exit;
1031 }
1032 }
1033
1034#ifdef WITH_FAKE_KASERVER
1035 if (lp_afs_share(snum)) {
1036 afs_login(conn);
1037 }
1038#endif
1039
1040 /*
1041 * we've finished with the user stuff - go back to root
1042 * so the SMB_VFS_STAT call will only fail on path errors,
1043 * not permission problems.
1044 */
1045 change_to_root_user();
1046/* ROOT Activites: */
1047
1048 /*
1049 * If widelinks are disallowed we need to canonicalise the connect
1050 * path here to ensure we don't have any symlinks in the
1051 * connectpath. We will be checking all paths on this connection are
1052 * below this directory. We must do this after the VFS init as we
1053 * depend on the realpath() pointer in the vfs table. JRA.
1054 */
1055 if (!lp_widelinks(snum)) {
1056 if (!canonicalize_connect_path(conn)) {
1057 DEBUG(0, ("canonicalize_connect_path failed "
1058 "for service %s, path %s\n",
1059 lp_servicename(snum),
1060 conn->connectpath));
1061 *pstatus = NT_STATUS_BAD_NETWORK_NAME;
1062 goto err_root_exit;
1063 }
1064 }
1065
1066 /* Add veto/hide lists */
1067 if (!IS_IPC(conn) && !IS_PRINT(conn)) {
1068 set_namearray( &conn->veto_list, lp_veto_files(snum));
1069 set_namearray( &conn->hide_list, lp_hide_files(snum));
1070 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(snum));
1071 set_namearray( &conn->aio_write_behind_list,
1072 lp_aio_write_behind(snum));
1073 }
1074 status = create_synthetic_smb_fname(talloc_tos(), conn->connectpath,
1075 NULL, NULL, &smb_fname_cpath);
1076 if (!NT_STATUS_IS_OK(status)) {
1077 *pstatus = status;
1078 goto err_root_exit;
1079 }
1080
1081 /* win2000 does not check the permissions on the directory
1082 during the tree connect, instead relying on permission
1083 check during individual operations. To match this behaviour
1084 I have disabled this chdir check (tridge) */
1085 /* the alternative is just to check the directory exists */
1086
1087 if ((ret = SMB_VFS_STAT(conn, smb_fname_cpath)) != 0 ||
1088 !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
1089 if (ret == 0 && !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
1090 DEBUG(0,("'%s' is not a directory, when connecting to "
1091 "[%s]\n", conn->connectpath,
1092 lp_servicename(snum)));
1093 } else {
1094 DEBUG(0,("'%s' does not exist or permission denied "
1095 "when connecting to [%s] Error was %s\n",
1096 conn->connectpath, lp_servicename(snum),
1097 strerror(errno) ));
1098 }
1099 *pstatus = NT_STATUS_BAD_NETWORK_NAME;
1100 goto err_root_exit;
1101 }
1102 conn->base_share_dev = smb_fname_cpath->st.st_ex_dev;
1103
1104 string_set(&conn->origpath,conn->connectpath);
1105
1106 /* Figure out the characteristics of the underlying filesystem. This
1107 * assumes that all the filesystem mounted withing a share path have
1108 * the same characteristics, which is likely but not guaranteed.
1109 */
1110
1111 conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
1112
1113 /*
1114 * Print out the 'connected as' stuff here as we need
1115 * to know the effective uid and gid we will be using
1116 * (at least initially).
1117 */
1118
1119 if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
1120 dbgtext( "%s (%s) ", get_remote_machine_name(),
1121 conn->sconn->client_id.addr );
1122 dbgtext( "%s", srv_is_signing_active(sconn) ? "signed " : "");
1123 dbgtext( "connect to service %s ", lp_servicename(snum) );
1124 dbgtext( "initially as user %s ",
1125 conn->session_info->unix_name );
1126 dbgtext( "(uid=%d, gid=%d) ", (int)effuid, (int)effgid );
1127 dbgtext( "(pid %d)\n", (int)sys_getpid() );
1128 }
1129
1130 return(conn);
1131
1132 err_root_exit:
1133 TALLOC_FREE(smb_fname_cpath);
1134 /* We must exit this function as root. */
1135 if (geteuid() != 0) {
1136 change_to_root_user();
1137 }
1138 if (on_err_call_dis_hook) {
1139 /* Call VFS disconnect hook */
1140 SMB_VFS_DISCONNECT(conn);
1141 }
1142 if (claimed_connection) {
1143 yield_connection(conn, lp_servicename(snum));
1144 }
1145 return NULL;
1146}
1147
1148/****************************************************************************
1149 Make a connection to a service from SMB1. Internal interface.
1150****************************************************************************/
1151
1152static connection_struct *make_connection_smb1(struct smbd_server_connection *sconn,
1153 int snum, user_struct *vuser,
1154 DATA_BLOB password,
1155 const char *pdev,
1156 NTSTATUS *pstatus)
1157{
1158 connection_struct *ret_conn = NULL;
1159 connection_struct *conn = conn_new(sconn);
1160 if (!conn) {
1161 DEBUG(0,("make_connection_smb1: Couldn't find free connection.\n"));
1162 *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
1163 return NULL;
1164 }
1165 ret_conn = make_connection_snum(sconn,
1166 conn,
1167 snum,
1168 vuser,
1169 password,
1170 pdev,
1171 pstatus);
1172 if (ret_conn != conn) {
1173 conn_free(conn);
1174 return NULL;
1175 }
1176 return conn;
1177}
1178
1179/****************************************************************************
1180 Make a connection to a service from SMB2. External SMB2 interface.
1181 We must set cnum before claiming connection.
1182****************************************************************************/
1183
1184connection_struct *make_connection_smb2(struct smbd_server_connection *sconn,
1185 struct smbd_smb2_tcon *tcon,
1186 user_struct *vuser,
1187 DATA_BLOB password,
1188 const char *pdev,
1189 NTSTATUS *pstatus)
1190{
1191 connection_struct *ret_conn = NULL;
1192 connection_struct *conn = conn_new(sconn);
1193 if (!conn) {
1194 DEBUG(0,("make_connection_smb2: Couldn't find free connection.\n"));
1195 *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
1196 return NULL;
1197 }
1198 conn->cnum = tcon->tid;
1199 ret_conn = make_connection_snum(sconn,
1200 conn,
1201 tcon->snum,
1202 vuser,
1203 password,
1204 pdev,
1205 pstatus);
1206 if (ret_conn != conn) {
1207 conn_free(conn);
1208 return NULL;
1209 }
1210 return conn;
1211}
1212
1213/****************************************************************************
1214 Make a connection to a service. External SMB1 interface.
1215 *
1216 * @param service
1217****************************************************************************/
1218
1219connection_struct *make_connection(struct smbd_server_connection *sconn,
1220 const char *service_in, DATA_BLOB password,
1221 const char *pdev, uint16 vuid,
1222 NTSTATUS *status)
1223{
1224 uid_t euid;
1225 user_struct *vuser = NULL;
1226 char *service = NULL;
1227 fstring dev;
1228 int snum = -1;
1229
1230 fstrcpy(dev, pdev);
1231
1232 /* This must ONLY BE CALLED AS ROOT. As it exits this function as
1233 * root. */
1234 if (!non_root_mode() && (euid = geteuid()) != 0) {
1235 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot "
1236 "(%u)\n", (unsigned int)euid ));
1237 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
1238 }
1239
1240 if (conn_num_open(sconn) > 2047) {
1241 *status = NT_STATUS_INSUFF_SERVER_RESOURCES;
1242 return NULL;
1243 }
1244
1245 if(lp_security() != SEC_SHARE) {
1246 vuser = get_valid_user_struct(sconn, vuid);
1247 if (!vuser) {
1248 DEBUG(1,("make_connection: refusing to connect with "
1249 "no session setup\n"));
1250 *status = NT_STATUS_ACCESS_DENIED;
1251 return NULL;
1252 }
1253 }
1254
1255 /* Logic to try and connect to the correct [homes] share, preferably
1256 without too many getpwnam() lookups. This is particulary nasty for
1257 winbind usernames, where the share name isn't the same as unix
1258 username.
1259
1260 The snum of the homes share is stored on the vuser at session setup
1261 time.
1262 */
1263
1264 if (strequal(service_in,HOMES_NAME)) {
1265 if(lp_security() != SEC_SHARE) {
1266 DATA_BLOB no_pw = data_blob_null;
1267 if (vuser->homes_snum == -1) {
1268 DEBUG(2, ("[homes] share not available for "
1269 "this user because it was not found "
1270 "or created at session setup "
1271 "time\n"));
1272 *status = NT_STATUS_BAD_NETWORK_NAME;
1273 return NULL;
1274 }
1275 DEBUG(5, ("making a connection to [homes] service "
1276 "created at session setup time\n"));
1277 return make_connection_smb1(sconn,
1278 vuser->homes_snum,
1279 vuser, no_pw,
1280 dev, status);
1281 } else {
1282 /* Security = share. Try with
1283 * current_user_info.smb_name as the username. */
1284 if (*current_user_info.smb_name) {
1285 char *unix_username = NULL;
1286 (void)map_username(talloc_tos(),
1287 current_user_info.smb_name,
1288 &unix_username);
1289 snum = find_service(talloc_tos(),
1290 unix_username,
1291 &unix_username);
1292 if (!unix_username) {
1293 *status = NT_STATUS_NO_MEMORY;
1294 }
1295 return NULL;
1296 }
1297 if (snum != -1) {
1298 DEBUG(5, ("making a connection to 'homes' "
1299 "service %s based on "
1300 "security=share\n", service_in));
1301 return make_connection_smb1(sconn,
1302 snum, NULL,
1303 password,
1304 dev, status);
1305 }
1306 }
1307 } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
1308 && strequal(service_in,
1309 lp_servicename(vuser->homes_snum))) {
1310 DATA_BLOB no_pw = data_blob_null;
1311 DEBUG(5, ("making a connection to 'homes' service [%s] "
1312 "created at session setup time\n", service_in));
1313 return make_connection_smb1(sconn,
1314 vuser->homes_snum,
1315 vuser, no_pw,
1316 dev, status);
1317 }
1318
1319 service = talloc_strdup(talloc_tos(), service_in);
1320 if (!service) {
1321 *status = NT_STATUS_NO_MEMORY;
1322 return NULL;
1323 }
1324
1325 strlower_m(service);
1326
1327 snum = find_service(talloc_tos(), service, &service);
1328 if (!service) {
1329 *status = NT_STATUS_NO_MEMORY;
1330 return NULL;
1331 }
1332
1333 if (snum < 0) {
1334 if (strequal(service,"IPC$") ||
1335 (lp_enable_asu_support() && strequal(service,"ADMIN$"))) {
1336 DEBUG(3,("refusing IPC connection to %s\n", service));
1337 *status = NT_STATUS_ACCESS_DENIED;
1338 return NULL;
1339 }
1340
1341 DEBUG(3,("%s (%s) couldn't find service %s\n",
1342 get_remote_machine_name(),
1343 tsocket_address_string(
1344 sconn->remote_address, talloc_tos()),
1345 service));
1346 *status = NT_STATUS_BAD_NETWORK_NAME;
1347 return NULL;
1348 }
1349
1350 /* Handle non-Dfs clients attempting connections to msdfs proxy */
1351 if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0')) {
1352 DEBUG(3, ("refusing connection to dfs proxy share '%s' "
1353 "(pointing to %s)\n",
1354 service, lp_msdfs_proxy(snum)));
1355 *status = NT_STATUS_BAD_NETWORK_NAME;
1356 return NULL;
1357 }
1358
1359 DEBUG(5, ("making a connection to 'normal' service %s\n", service));
1360
1361 return make_connection_smb1(sconn, snum, vuser,
1362 password,
1363 dev, status);
1364}
1365
1366/****************************************************************************
1367 Close a cnum.
1368****************************************************************************/
1369
1370void close_cnum(connection_struct *conn, uint16 vuid)
1371{
1372 file_close_conn(conn);
1373
1374 if (!IS_IPC(conn)) {
1375 dptr_closecnum(conn);
1376 }
1377
1378 change_to_root_user();
1379
1380 DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
1381 get_remote_machine_name(),
1382 conn->sconn->client_id.addr,
1383 lp_servicename(SNUM(conn))));
1384
1385 /* Call VFS disconnect hook */
1386 SMB_VFS_DISCONNECT(conn);
1387
1388 yield_connection(conn, lp_servicename(SNUM(conn)));
1389
1390 /* make sure we leave the directory available for unmount */
1391 vfs_ChDir(conn, "/");
1392
1393 /* execute any "postexec = " line */
1394 if (*lp_postexec(SNUM(conn)) &&
1395 change_to_user(conn, vuid)) {
1396 char *cmd = talloc_sub_advanced(talloc_tos(),
1397 lp_servicename(SNUM(conn)),
1398 conn->session_info->unix_name,
1399 conn->connectpath,
1400 conn->session_info->utok.gid,
1401 conn->session_info->sanitized_username,
1402 conn->session_info->info3->base.domain.string,
1403 lp_postexec(SNUM(conn)));
1404 smbrun(cmd,NULL);
1405 TALLOC_FREE(cmd);
1406 change_to_root_user();
1407 }
1408
1409 change_to_root_user();
1410 /* execute any "root postexec = " line */
1411 if (*lp_rootpostexec(SNUM(conn))) {
1412 char *cmd = talloc_sub_advanced(talloc_tos(),
1413 lp_servicename(SNUM(conn)),
1414 conn->session_info->unix_name,
1415 conn->connectpath,
1416 conn->session_info->utok.gid,
1417 conn->session_info->sanitized_username,
1418 conn->session_info->info3->base.domain.string,
1419 lp_rootpostexec(SNUM(conn)));
1420 smbrun(cmd,NULL);
1421 TALLOC_FREE(cmd);
1422 }
1423
1424 conn_free(conn);
1425}
Note: See TracBrowser for help on using the repository browser.