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

Last change on this file since 736 was 736, checked in by Silvan Scherrer, 13 years ago

Samba Server 3.5: update branche to 3.5.16

File size: 36.5 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 /* We don't want to replace the original sanitized_username
755 as it is the original user given in the connect attempt.
756 This is used in '%U' substitutions. */
757 TALLOC_FREE(forced_serverinfo->sanitized_username);
758 forced_serverinfo->sanitized_username =
759 talloc_move(forced_serverinfo,
760 &conn->server_info->sanitized_username);
761
762 TALLOC_FREE(conn->server_info);
763 conn->server_info = forced_serverinfo;
764
765 conn->force_user = True;
766 DEBUG(3,("Forced user %s\n", fuser));
767 }
768
769 /*
770 * If force group is true, then override
771 * any groupid stored for the connecting user.
772 */
773
774 if (*lp_force_group(snum)) {
775
776 status = find_forced_group(
777 conn->force_user, snum, conn->server_info->unix_name,
778 &conn->server_info->ptok->user_sids[1],
779 &conn->server_info->utok.gid);
780
781 if (!NT_STATUS_IS_OK(status)) {
782 conn_free(conn);
783 *pstatus = status;
784 return NULL;
785 }
786
787 /*
788 * We need to cache this gid, to use within
789 * change_to_user() separately from the conn->server_info
790 * struct. We only use conn->server_info directly if
791 * "force_user" was set.
792 */
793 conn->force_group_gid = conn->server_info->utok.gid;
794 }
795
796 conn->vuid = (vuser != NULL) ? vuser->vuid : UID_FIELD_INVALID;
797
798 {
799 char *s = talloc_sub_advanced(talloc_tos(),
800 lp_servicename(SNUM(conn)),
801 conn->server_info->unix_name,
802 conn->connectpath,
803 conn->server_info->utok.gid,
804 conn->server_info->sanitized_username,
805 pdb_get_domain(conn->server_info->sam_account),
806 lp_pathname(snum));
807 if (!s) {
808 conn_free(conn);
809 *pstatus = NT_STATUS_NO_MEMORY;
810 return NULL;
811 }
812
813 if (!set_conn_connectpath(conn,s)) {
814 TALLOC_FREE(s);
815 conn_free(conn);
816 *pstatus = NT_STATUS_NO_MEMORY;
817 return NULL;
818 }
819 DEBUG(3,("Connect path is '%s' for service [%s]\n",s,
820 lp_servicename(snum)));
821 TALLOC_FREE(s);
822 }
823
824 /*
825 * New code to check if there's a share security descripter
826 * added from NT server manager. This is done after the
827 * smb.conf checks are done as we need a uid and token. JRA.
828 *
829 */
830
831 {
832 bool can_write = False;
833
834 can_write = share_access_check(conn->server_info->ptok,
835 lp_servicename(snum),
836 FILE_WRITE_DATA);
837
838 if (!can_write) {
839 if (!share_access_check(conn->server_info->ptok,
840 lp_servicename(snum),
841 FILE_READ_DATA)) {
842 /* No access, read or write. */
843 DEBUG(0,("make_connection: connection to %s "
844 "denied due to security "
845 "descriptor.\n",
846 lp_servicename(snum)));
847 conn_free(conn);
848 *pstatus = NT_STATUS_ACCESS_DENIED;
849 return NULL;
850 } else {
851 conn->read_only = True;
852 }
853 }
854 }
855 /* Initialise VFS function pointers */
856
857 if (!smbd_vfs_init(conn)) {
858 DEBUG(0, ("vfs_init failed for service %s\n",
859 lp_servicename(snum)));
860 conn_free(conn);
861 *pstatus = NT_STATUS_BAD_NETWORK_NAME;
862 return NULL;
863 }
864
865 if ((!conn->printer) && (!conn->ipc)) {
866 conn->notify_ctx = notify_init(conn, server_id_self(),
867 smbd_messaging_context(),
868 smbd_event_context(),
869 conn);
870 }
871
872/* ROOT Activities: */
873 /* explicitly check widelinks here so that we can correctly warn
874 * in the logs. */
875 widelinks_warning(snum);
876
877 /*
878 * Enforce the max connections parameter.
879 */
880
881 if ((lp_max_connections(snum) > 0)
882 && (count_current_connections(lp_servicename(SNUM(conn)), True) >=
883 lp_max_connections(snum))) {
884
885 DEBUG(1, ("Max connections (%d) exceeded for %s\n",
886 lp_max_connections(snum), lp_servicename(snum)));
887 conn_free(conn);
888 *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
889 return NULL;
890 }
891
892 /*
893 * Get us an entry in the connections db
894 */
895 if (!claim_connection(conn, lp_servicename(snum), 0)) {
896 DEBUG(1, ("Could not store connections entry\n"));
897 conn_free(conn);
898 *pstatus = NT_STATUS_INTERNAL_DB_ERROR;
899 return NULL;
900 }
901
902 /* Invoke VFS make connection hook - must be the first
903 VFS operation we do. */
904
905 if (SMB_VFS_CONNECT(conn, lp_servicename(snum),
906 conn->server_info->unix_name) < 0) {
907 DEBUG(0,("make_connection: VFS make connection failed!\n"));
908 yield_connection(conn, lp_servicename(snum));
909 conn_free(conn);
910 *pstatus = NT_STATUS_UNSUCCESSFUL;
911 return NULL;
912 }
913
914 /*
915 * Fix compatibility issue pointed out by Volker.
916 * We pass the conn->connectpath to the preexec
917 * scripts as a parameter, so attempt to canonicalize
918 * it here before calling the preexec scripts.
919 * We ignore errors here, as it is possible that
920 * the conn->connectpath doesn't exist yet and
921 * the preexec scripts will create them.
922 */
923
924 (void)canonicalize_connect_path(conn);
925
926 /* Preexecs are done here as they might make the dir we are to ChDir
927 * to below */
928 /* execute any "root preexec = " line */
929 if (*lp_rootpreexec(snum)) {
930 char *cmd = talloc_sub_advanced(talloc_tos(),
931 lp_servicename(SNUM(conn)),
932 conn->server_info->unix_name,
933 conn->connectpath,
934 conn->server_info->utok.gid,
935 conn->server_info->sanitized_username,
936 pdb_get_domain(conn->server_info->sam_account),
937 lp_rootpreexec(snum));
938 DEBUG(5,("cmd=%s\n",cmd));
939 ret = smbrun(cmd,NULL);
940 TALLOC_FREE(cmd);
941 if (ret != 0 && lp_rootpreexec_close(snum)) {
942 DEBUG(1,("root preexec gave %d - failing "
943 "connection\n", ret));
944 SMB_VFS_DISCONNECT(conn);
945 yield_connection(conn, lp_servicename(snum));
946 conn_free(conn);
947 *pstatus = NT_STATUS_ACCESS_DENIED;
948 return NULL;
949 }
950 }
951
952/* USER Activites: */
953 if (!change_to_user(conn, conn->vuid)) {
954 /* No point continuing if they fail the basic checks */
955 DEBUG(0,("Can't become connected user!\n"));
956 SMB_VFS_DISCONNECT(conn);
957 yield_connection(conn, lp_servicename(snum));
958 conn_free(conn);
959 *pstatus = NT_STATUS_LOGON_FAILURE;
960 return NULL;
961 }
962
963 /* Remember that a different vuid can connect later without these
964 * checks... */
965
966 /* Preexecs are done here as they might make the dir we are to ChDir
967 * to below */
968
969 /* execute any "preexec = " line */
970 if (*lp_preexec(snum)) {
971 char *cmd = talloc_sub_advanced(talloc_tos(),
972 lp_servicename(SNUM(conn)),
973 conn->server_info->unix_name,
974 conn->connectpath,
975 conn->server_info->utok.gid,
976 conn->server_info->sanitized_username,
977 pdb_get_domain(conn->server_info->sam_account),
978 lp_preexec(snum));
979 ret = smbrun(cmd,NULL);
980 TALLOC_FREE(cmd);
981 if (ret != 0 && lp_preexec_close(snum)) {
982 DEBUG(1,("preexec gave %d - failing connection\n",
983 ret));
984 *pstatus = NT_STATUS_ACCESS_DENIED;
985 goto err_root_exit;
986 }
987 }
988
989 /*
990 * If widelinks are disallowed we need to canonicalise the connect
991 * path here to ensure we don't have any symlinks in the
992 * connectpath. We will be checking all paths on this connection are
993 * below this directory. We must do this after the VFS init as we
994 * depend on the realpath() pointer in the vfs table. JRA.
995 */
996 if (!lp_widelinks(snum)) {
997 if (!canonicalize_connect_path(conn)) {
998 DEBUG(0, ("canonicalize_connect_path failed "
999 "for service %s, path %s\n",
1000 lp_servicename(snum),
1001 conn->connectpath));
1002 *pstatus = NT_STATUS_BAD_NETWORK_NAME;
1003 goto err_root_exit;
1004 }
1005 }
1006
1007#ifdef WITH_FAKE_KASERVER
1008 if (lp_afs_share(snum)) {
1009 afs_login(conn);
1010 }
1011#endif
1012
1013 /* Add veto/hide lists */
1014 if (!IS_IPC(conn) && !IS_PRINT(conn)) {
1015 set_namearray( &conn->veto_list, lp_veto_files(snum));
1016 set_namearray( &conn->hide_list, lp_hide_files(snum));
1017 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(snum));
1018 set_namearray( &conn->aio_write_behind_list,
1019 lp_aio_write_behind(snum));
1020 }
1021
1022 status = create_synthetic_smb_fname(talloc_tos(), conn->connectpath,
1023 NULL, NULL, &smb_fname_cpath);
1024 if (!NT_STATUS_IS_OK(status)) {
1025 *pstatus = status;
1026 goto err_root_exit;
1027 }
1028
1029 /* win2000 does not check the permissions on the directory
1030 during the tree connect, instead relying on permission
1031 check during individual operations. To match this behaviour
1032 I have disabled this chdir check (tridge) */
1033 /* the alternative is just to check the directory exists */
1034 if ((ret = SMB_VFS_STAT(conn, smb_fname_cpath)) != 0 ||
1035 !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
1036 if (ret == 0 && !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
1037 DEBUG(0,("'%s' is not a directory, when connecting to "
1038 "[%s]\n", conn->connectpath,
1039 lp_servicename(snum)));
1040 } else {
1041 DEBUG(0,("'%s' does not exist or permission denied "
1042 "when connecting to [%s] Error was %s\n",
1043 conn->connectpath, lp_servicename(snum),
1044 strerror(errno) ));
1045 }
1046 *pstatus = NT_STATUS_BAD_NETWORK_NAME;
1047 goto err_root_exit;
1048 }
1049 conn->base_share_dev = smb_fname_cpath->st.st_ex_dev;
1050
1051 string_set(&conn->origpath,conn->connectpath);
1052
1053#if SOFTLINK_OPTIMISATION
1054 /* resolve any soft links early if possible */
1055 if (vfs_ChDir(conn,conn->connectpath) == 0) {
1056 TALLOC_CTX *ctx = talloc_tos();
1057 char *s = vfs_GetWd(ctx,s);
1058 if (!s) {
1059 *status = map_nt_error_from_unix(errno);
1060 goto err_root_exit;
1061 }
1062 if (!set_conn_connectpath(conn,s)) {
1063 *status = NT_STATUS_NO_MEMORY;
1064 goto err_root_exit;
1065 }
1066 vfs_ChDir(conn,conn->connectpath);
1067 }
1068#endif
1069
1070 /* Figure out the characteristics of the underlying filesystem. This
1071 * assumes that all the filesystem mounted withing a share path have
1072 * the same characteristics, which is likely but not guaranteed.
1073 */
1074
1075 conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
1076
1077 /*
1078 * Print out the 'connected as' stuff here as we need
1079 * to know the effective uid and gid we will be using
1080 * (at least initially).
1081 */
1082
1083 if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
1084 dbgtext( "%s (%s) ", get_remote_machine_name(),
1085 conn->client_address );
1086 dbgtext( "%s", srv_is_signing_active(smbd_server_conn) ? "signed " : "");
1087 dbgtext( "connect to service %s ", lp_servicename(snum) );
1088 dbgtext( "initially as user %s ",
1089 conn->server_info->unix_name );
1090 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
1091 dbgtext( "(pid %d)\n", (int)sys_getpid() );
1092 }
1093
1094 /* we've finished with the user stuff - go back to root */
1095 change_to_root_user();
1096 return(conn);
1097
1098 err_root_exit:
1099 TALLOC_FREE(smb_fname_cpath);
1100 change_to_root_user();
1101 /* Call VFS disconnect hook */
1102 SMB_VFS_DISCONNECT(conn);
1103 yield_connection(conn, lp_servicename(snum));
1104 conn_free(conn);
1105 return NULL;
1106}
1107
1108/****************************************************************************
1109 Make a connection to a service.
1110 *
1111 * @param service
1112****************************************************************************/
1113
1114connection_struct *make_connection(struct smbd_server_connection *sconn,
1115 const char *service_in, DATA_BLOB password,
1116 const char *pdev, uint16 vuid,
1117 NTSTATUS *status)
1118{
1119 uid_t euid;
1120 user_struct *vuser = NULL;
1121 fstring service;
1122 fstring dev;
1123 int snum = -1;
1124 char addr[INET6_ADDRSTRLEN];
1125
1126 fstrcpy(dev, pdev);
1127
1128 /* This must ONLY BE CALLED AS ROOT. As it exits this function as
1129 * root. */
1130 if (!non_root_mode() && (euid = geteuid()) != 0) {
1131 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot "
1132 "(%u)\n", (unsigned int)euid ));
1133 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
1134 }
1135
1136 if (conn_num_open(sconn) > 2047) {
1137 *status = NT_STATUS_INSUFF_SERVER_RESOURCES;
1138 return NULL;
1139 }
1140
1141 if(lp_security() != SEC_SHARE) {
1142 vuser = get_valid_user_struct(sconn, vuid);
1143 if (!vuser) {
1144 DEBUG(1,("make_connection: refusing to connect with "
1145 "no session setup\n"));
1146 *status = NT_STATUS_ACCESS_DENIED;
1147 return NULL;
1148 }
1149 }
1150
1151 /* Logic to try and connect to the correct [homes] share, preferably
1152 without too many getpwnam() lookups. This is particulary nasty for
1153 winbind usernames, where the share name isn't the same as unix
1154 username.
1155
1156 The snum of the homes share is stored on the vuser at session setup
1157 time.
1158 */
1159
1160 if (strequal(service_in,HOMES_NAME)) {
1161 if(lp_security() != SEC_SHARE) {
1162 DATA_BLOB no_pw = data_blob_null;
1163 if (vuser->homes_snum == -1) {
1164 DEBUG(2, ("[homes] share not available for "
1165 "this user because it was not found "
1166 "or created at session setup "
1167 "time\n"));
1168 *status = NT_STATUS_BAD_NETWORK_NAME;
1169 return NULL;
1170 }
1171 DEBUG(5, ("making a connection to [homes] service "
1172 "created at session setup time\n"));
1173 return make_connection_snum(sconn,
1174 vuser->homes_snum,
1175 vuser, no_pw,
1176 dev, status);
1177 } else {
1178 /* Security = share. Try with
1179 * current_user_info.smb_name as the username. */
1180 if (*current_user_info.smb_name) {
1181 fstring unix_username;
1182 fstrcpy(unix_username,
1183 current_user_info.smb_name);
1184 map_username(sconn, unix_username);
1185 snum = find_service(unix_username);
1186 }
1187 if (snum != -1) {
1188 DEBUG(5, ("making a connection to 'homes' "
1189 "service %s based on "
1190 "security=share\n", service_in));
1191 return make_connection_snum(sconn,
1192 snum, NULL,
1193 password,
1194 dev, status);
1195 }
1196 }
1197 } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
1198 && strequal(service_in,
1199 lp_servicename(vuser->homes_snum))) {
1200 DATA_BLOB no_pw = data_blob_null;
1201 DEBUG(5, ("making a connection to 'homes' service [%s] "
1202 "created at session setup time\n", service_in));
1203 return make_connection_snum(sconn,
1204 vuser->homes_snum,
1205 vuser, no_pw,
1206 dev, status);
1207 }
1208
1209 fstrcpy(service, service_in);
1210
1211 strlower_m(service);
1212
1213 snum = find_service(service);
1214
1215 if (snum < 0) {
1216 if (strequal(service,"IPC$") ||
1217 (lp_enable_asu_support() && strequal(service,"ADMIN$"))) {
1218 DEBUG(3,("refusing IPC connection to %s\n", service));
1219 *status = NT_STATUS_ACCESS_DENIED;
1220 return NULL;
1221 }
1222
1223 DEBUG(3,("%s (%s) couldn't find service %s\n",
1224 get_remote_machine_name(),
1225 client_addr(get_client_fd(),addr,sizeof(addr)),
1226 service));
1227 *status = NT_STATUS_BAD_NETWORK_NAME;
1228 return NULL;
1229 }
1230
1231 /* Handle non-Dfs clients attempting connections to msdfs proxy */
1232 if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0')) {
1233 DEBUG(3, ("refusing connection to dfs proxy share '%s' "
1234 "(pointing to %s)\n",
1235 service, lp_msdfs_proxy(snum)));
1236 *status = NT_STATUS_BAD_NETWORK_NAME;
1237 return NULL;
1238 }
1239
1240 DEBUG(5, ("making a connection to 'normal' service %s\n", service));
1241
1242 return make_connection_snum(sconn, snum, vuser,
1243 password,
1244 dev, status);
1245}
1246
1247/****************************************************************************
1248 Close a cnum.
1249****************************************************************************/
1250
1251void close_cnum(connection_struct *conn, uint16 vuid)
1252{
1253 file_close_conn(conn);
1254
1255 if (!IS_IPC(conn)) {
1256 dptr_closecnum(conn);
1257 }
1258
1259 change_to_root_user();
1260
1261 DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
1262 get_remote_machine_name(),
1263 conn->client_address,
1264 lp_servicename(SNUM(conn))));
1265
1266 /* Call VFS disconnect hook */
1267 SMB_VFS_DISCONNECT(conn);
1268
1269 yield_connection(conn, lp_servicename(SNUM(conn)));
1270
1271 /* make sure we leave the directory available for unmount */
1272 vfs_ChDir(conn, "/");
1273
1274 /* execute any "postexec = " line */
1275 if (*lp_postexec(SNUM(conn)) &&
1276 change_to_user(conn, vuid)) {
1277 char *cmd = talloc_sub_advanced(talloc_tos(),
1278 lp_servicename(SNUM(conn)),
1279 conn->server_info->unix_name,
1280 conn->connectpath,
1281 conn->server_info->utok.gid,
1282 conn->server_info->sanitized_username,
1283 pdb_get_domain(conn->server_info->sam_account),
1284 lp_postexec(SNUM(conn)));
1285 smbrun(cmd,NULL);
1286 TALLOC_FREE(cmd);
1287 change_to_root_user();
1288 }
1289
1290 change_to_root_user();
1291 /* execute any "root postexec = " line */
1292 if (*lp_rootpostexec(SNUM(conn))) {
1293 char *cmd = talloc_sub_advanced(talloc_tos(),
1294 lp_servicename(SNUM(conn)),
1295 conn->server_info->unix_name,
1296 conn->connectpath,
1297 conn->server_info->utok.gid,
1298 conn->server_info->sanitized_username,
1299 pdb_get_domain(conn->server_info->sam_account),
1300 lp_rootpostexec(SNUM(conn)));
1301 smbrun(cmd,NULL);
1302 TALLOC_FREE(cmd);
1303 }
1304
1305 conn_free(conn);
1306}
Note: See TracBrowser for help on using the repository browser.