source: branches/samba-3.0/source/smbd/service.c@ 397

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

Update 3.0 to 3.0.37 (unsupported security update)

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