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

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

Update 3.3. to 3.3.8 (security update)

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