source: branches/samba-3.5.x/source3/smbd/service.c@ 717

Last change on this file since 717 was 480, checked in by Silvan Scherrer, 15 years ago

Samba Server 3.5: trunk update to 3.5.4

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