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

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

Samba Server 3.5: merged changes from 3.3

File size: 36.1 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
1042 string_set(&conn->origpath,conn->connectpath);
1043
1044#if SOFTLINK_OPTIMISATION
1045 /* resolve any soft links early if possible */
1046 if (vfs_ChDir(conn,conn->connectpath) == 0) {
1047 TALLOC_CTX *ctx = talloc_tos();
1048 char *s = vfs_GetWd(ctx,s);
1049 if (!s) {
1050 *status = map_nt_error_from_unix(errno);
1051 goto err_root_exit;
1052 }
1053 if (!set_conn_connectpath(conn,s)) {
1054 *status = NT_STATUS_NO_MEMORY;
1055 goto err_root_exit;
1056 }
1057 vfs_ChDir(conn,conn->connectpath);
1058 }
1059#endif
1060
1061 /* Figure out the characteristics of the underlying filesystem. This
1062 * assumes that all the filesystem mounted withing a share path have
1063 * the same characteristics, which is likely but not guaranteed.
1064 */
1065
1066 conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
1067
1068 /*
1069 * Print out the 'connected as' stuff here as we need
1070 * to know the effective uid and gid we will be using
1071 * (at least initially).
1072 */
1073
1074 if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
1075 dbgtext( "%s (%s) ", get_remote_machine_name(),
1076 conn->client_address );
1077 dbgtext( "%s", srv_is_signing_active(smbd_server_conn) ? "signed " : "");
1078 dbgtext( "connect to service %s ", lp_servicename(snum) );
1079 dbgtext( "initially as user %s ",
1080 conn->server_info->unix_name );
1081 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
1082 dbgtext( "(pid %d)\n", (int)sys_getpid() );
1083 }
1084
1085 /* we've finished with the user stuff - go back to root */
1086 change_to_root_user();
1087 return(conn);
1088
1089 err_root_exit:
1090 TALLOC_FREE(smb_fname_cpath);
1091 change_to_root_user();
1092 /* Call VFS disconnect hook */
1093 SMB_VFS_DISCONNECT(conn);
1094 yield_connection(conn, lp_servicename(snum));
1095 conn_free(conn);
1096 return NULL;
1097}
1098
1099/****************************************************************************
1100 Make a connection to a service.
1101 *
1102 * @param service
1103****************************************************************************/
1104
1105connection_struct *make_connection(struct smbd_server_connection *sconn,
1106 const char *service_in, DATA_BLOB password,
1107 const char *pdev, uint16 vuid,
1108 NTSTATUS *status)
1109{
1110 uid_t euid;
1111 user_struct *vuser = NULL;
1112 fstring service;
1113 fstring dev;
1114 int snum = -1;
1115 char addr[INET6_ADDRSTRLEN];
1116
1117 fstrcpy(dev, pdev);
1118
1119 /* This must ONLY BE CALLED AS ROOT. As it exits this function as
1120 * root. */
1121 if (!non_root_mode() && (euid = geteuid()) != 0) {
1122 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot "
1123 "(%u)\n", (unsigned int)euid ));
1124 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
1125 }
1126
1127 if (conn_num_open(sconn) > 2047) {
1128 *status = NT_STATUS_INSUFF_SERVER_RESOURCES;
1129 return NULL;
1130 }
1131
1132 if(lp_security() != SEC_SHARE) {
1133 vuser = get_valid_user_struct(sconn, vuid);
1134 if (!vuser) {
1135 DEBUG(1,("make_connection: refusing to connect with "
1136 "no session setup\n"));
1137 *status = NT_STATUS_ACCESS_DENIED;
1138 return NULL;
1139 }
1140 }
1141
1142 /* Logic to try and connect to the correct [homes] share, preferably
1143 without too many getpwnam() lookups. This is particulary nasty for
1144 winbind usernames, where the share name isn't the same as unix
1145 username.
1146
1147 The snum of the homes share is stored on the vuser at session setup
1148 time.
1149 */
1150
1151 if (strequal(service_in,HOMES_NAME)) {
1152 if(lp_security() != SEC_SHARE) {
1153 DATA_BLOB no_pw = data_blob_null;
1154 if (vuser->homes_snum == -1) {
1155 DEBUG(2, ("[homes] share not available for "
1156 "this user because it was not found "
1157 "or created at session setup "
1158 "time\n"));
1159 *status = NT_STATUS_BAD_NETWORK_NAME;
1160 return NULL;
1161 }
1162 DEBUG(5, ("making a connection to [homes] service "
1163 "created at session setup time\n"));
1164 return make_connection_snum(sconn,
1165 vuser->homes_snum,
1166 vuser, no_pw,
1167 dev, status);
1168 } else {
1169 /* Security = share. Try with
1170 * current_user_info.smb_name as the username. */
1171 if (*current_user_info.smb_name) {
1172 fstring unix_username;
1173 fstrcpy(unix_username,
1174 current_user_info.smb_name);
1175 map_username(sconn, unix_username);
1176 snum = find_service(unix_username);
1177 }
1178 if (snum != -1) {
1179 DEBUG(5, ("making a connection to 'homes' "
1180 "service %s based on "
1181 "security=share\n", service_in));
1182 return make_connection_snum(sconn,
1183 snum, NULL,
1184 password,
1185 dev, status);
1186 }
1187 }
1188 } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
1189 && strequal(service_in,
1190 lp_servicename(vuser->homes_snum))) {
1191 DATA_BLOB no_pw = data_blob_null;
1192 DEBUG(5, ("making a connection to 'homes' service [%s] "
1193 "created at session setup time\n", service_in));
1194 return make_connection_snum(sconn,
1195 vuser->homes_snum,
1196 vuser, no_pw,
1197 dev, status);
1198 }
1199
1200 fstrcpy(service, service_in);
1201
1202 strlower_m(service);
1203
1204 snum = find_service(service);
1205
1206 if (snum < 0) {
1207 if (strequal(service,"IPC$") ||
1208 (lp_enable_asu_support() && strequal(service,"ADMIN$"))) {
1209 DEBUG(3,("refusing IPC connection to %s\n", service));
1210 *status = NT_STATUS_ACCESS_DENIED;
1211 return NULL;
1212 }
1213
1214 DEBUG(3,("%s (%s) couldn't find service %s\n",
1215 get_remote_machine_name(),
1216 client_addr(get_client_fd(),addr,sizeof(addr)),
1217 service));
1218 *status = NT_STATUS_BAD_NETWORK_NAME;
1219 return NULL;
1220 }
1221
1222 /* Handle non-Dfs clients attempting connections to msdfs proxy */
1223 if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0')) {
1224 DEBUG(3, ("refusing connection to dfs proxy share '%s' "
1225 "(pointing to %s)\n",
1226 service, lp_msdfs_proxy(snum)));
1227 *status = NT_STATUS_BAD_NETWORK_NAME;
1228 return NULL;
1229 }
1230
1231 DEBUG(5, ("making a connection to 'normal' service %s\n", service));
1232
1233 return make_connection_snum(sconn, snum, vuser,
1234 password,
1235 dev, status);
1236}
1237
1238/****************************************************************************
1239 Close a cnum.
1240****************************************************************************/
1241
1242void close_cnum(connection_struct *conn, uint16 vuid)
1243{
1244 file_close_conn(conn);
1245
1246 if (!IS_IPC(conn)) {
1247 dptr_closecnum(conn);
1248 }
1249
1250 change_to_root_user();
1251
1252 DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
1253 get_remote_machine_name(),
1254 conn->client_address,
1255 lp_servicename(SNUM(conn))));
1256
1257 /* Call VFS disconnect hook */
1258 SMB_VFS_DISCONNECT(conn);
1259
1260 yield_connection(conn, lp_servicename(SNUM(conn)));
1261
1262 /* make sure we leave the directory available for unmount */
1263 vfs_ChDir(conn, "/");
1264
1265 /* execute any "postexec = " line */
1266 if (*lp_postexec(SNUM(conn)) &&
1267 change_to_user(conn, vuid)) {
1268 char *cmd = talloc_sub_advanced(talloc_tos(),
1269 lp_servicename(SNUM(conn)),
1270 conn->server_info->unix_name,
1271 conn->connectpath,
1272 conn->server_info->utok.gid,
1273 conn->server_info->sanitized_username,
1274 pdb_get_domain(conn->server_info->sam_account),
1275 lp_postexec(SNUM(conn)));
1276 smbrun(cmd,NULL);
1277 TALLOC_FREE(cmd);
1278 change_to_root_user();
1279 }
1280
1281 change_to_root_user();
1282 /* execute any "root postexec = " line */
1283 if (*lp_rootpostexec(SNUM(conn))) {
1284 char *cmd = talloc_sub_advanced(talloc_tos(),
1285 lp_servicename(SNUM(conn)),
1286 conn->server_info->unix_name,
1287 conn->connectpath,
1288 conn->server_info->utok.gid,
1289 conn->server_info->sanitized_username,
1290 pdb_get_domain(conn->server_info->sam_account),
1291 lp_rootpostexec(SNUM(conn)));
1292 smbrun(cmd,NULL);
1293 TALLOC_FREE(cmd);
1294 }
1295
1296 conn_free(conn);
1297}
Note: See TracBrowser for help on using the repository browser.