source: branches/samba-3.3.x/source/smbd/service.c@ 222

Last change on this file since 222 was 222, checked in by Herwig Bauernfeind, 16 years ago

Update Samba 3.3 branch to 3.3.2

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