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

Last change on this file since 314 was 108, checked in by Paul Smedley, 18 years ago

test fix for Ticket #9

File size: 34.8 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)
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 set_conn_connectpath(conn,s);
808 DEBUG(3,("Connect path is '%s' for service [%s]\n",s,
809 lp_servicename(snum)));
810 }
811
812 /*
813 * New code to check if there's a share security descripter
814 * added from NT server manager. This is done after the
815 * smb.conf checks are done as we need a uid and token. JRA.
816 *
817 */
818
819 {
820 BOOL can_write = False;
821 NT_USER_TOKEN *token = conn->nt_user_token ?
822 conn->nt_user_token :
823 (vuser ? vuser->nt_user_token : NULL);
824
825 /*
826 * I don't believe this can happen. But the
827 * logic above is convoluted enough to confuse
828 * automated checkers, so be sure. JRA.
829 */
830
831 if (token == NULL) {
832 DEBUG(0,("make_connection: connection to %s "
833 "denied due to missing "
834 "NT token.\n",
835 lp_servicename(snum)));
836 conn_free(conn);
837 *status = NT_STATUS_ACCESS_DENIED;
838 return NULL;
839 }
840
841 can_write = share_access_check(token,
842 lp_servicename(snum),
843 FILE_WRITE_DATA);
844
845 if (!can_write) {
846 if (!share_access_check(token,
847 lp_servicename(snum),
848 FILE_READ_DATA)) {
849 /* No access, read or write. */
850 DEBUG(0,("make_connection: connection to %s "
851 "denied due to security "
852 "descriptor.\n",
853 lp_servicename(snum)));
854 conn_free(conn);
855 *status = NT_STATUS_ACCESS_DENIED;
856 return NULL;
857 } else {
858 conn->read_only = True;
859 }
860 }
861 }
862 /* Initialise VFS function pointers */
863
864 if (!smbd_vfs_init(conn)) {
865 DEBUG(0, ("vfs_init failed for service %s\n",
866 lp_servicename(snum)));
867 conn_free(conn);
868 *status = NT_STATUS_BAD_NETWORK_NAME;
869 return NULL;
870 }
871
872 /*
873 * If widelinks are disallowed we need to canonicalise the connect
874 * path here to ensure we don't have any symlinks in the
875 * connectpath. We will be checking all paths on this connection are
876 * below this directory. We must do this after the VFS init as we
877 * depend on the realpath() pointer in the vfs table. JRA.
878 */
879 if (!lp_widelinks(snum)) {
880 pstring s;
881 pstrcpy(s,conn->connectpath);
882 canonicalize_path(conn, s);
883 set_conn_connectpath(conn,s);
884 }
885
886 if ((!conn->printer) && (!conn->ipc)) {
887 conn->notify_ctx = notify_init(conn->mem_ctx, server_id_self(),
888 smbd_messaging_context(),
889 smbd_event_context(),
890 conn);
891 }
892
893/* ROOT Activities: */
894 /* check number of connections */
895 if (!claim_connection(conn,
896 lp_servicename(snum),
897 lp_max_connections(snum),
898 False,0)) {
899 DEBUG(1,("too many connections - rejected\n"));
900 conn_free(conn);
901 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
902 return NULL;
903 }
904
905 /* Preexecs are done here as they might make the dir we are to ChDir
906 * to below */
907 /* execute any "root preexec = " line */
908 if (*lp_rootpreexec(snum)) {
909 pstring cmd;
910 pstrcpy(cmd,lp_rootpreexec(snum));
911 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
912 conn->connectpath, conn->gid,
913 get_current_username(),
914 current_user_info.domain,
915 cmd, sizeof(cmd));
916 DEBUG(5,("cmd=%s\n",cmd));
917 ret = smbrun(cmd,NULL);
918 if (ret != 0 && lp_rootpreexec_close(snum)) {
919 DEBUG(1,("root preexec gave %d - failing "
920 "connection\n", ret));
921 yield_connection(conn, lp_servicename(snum));
922 conn_free(conn);
923 *status = NT_STATUS_ACCESS_DENIED;
924 return NULL;
925 }
926 }
927
928/* USER Activites: */
929 if (!change_to_user(conn, conn->vuid)) {
930 /* No point continuing if they fail the basic checks */
931 DEBUG(0,("Can't become connected user!\n"));
932 yield_connection(conn, lp_servicename(snum));
933 conn_free(conn);
934 *status = NT_STATUS_LOGON_FAILURE;
935 return NULL;
936 }
937
938 /* Remember that a different vuid can connect later without these
939 * checks... */
940
941 /* Preexecs are done here as they might make the dir we are to ChDir
942 * to below */
943
944 /* execute any "preexec = " line */
945 if (*lp_preexec(snum)) {
946 pstring cmd;
947 pstrcpy(cmd,lp_preexec(snum));
948 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
949 conn->connectpath, conn->gid,
950 get_current_username(),
951 current_user_info.domain,
952 cmd, sizeof(cmd));
953 ret = smbrun(cmd,NULL);
954 if (ret != 0 && lp_preexec_close(snum)) {
955 DEBUG(1,("preexec gave %d - failing connection\n",
956 ret));
957 change_to_root_user();
958 yield_connection(conn, lp_servicename(snum));
959 conn_free(conn);
960 *status = NT_STATUS_ACCESS_DENIED;
961 return NULL;
962 }
963 }
964
965#ifdef WITH_FAKE_KASERVER
966 if (lp_afs_share(snum)) {
967 afs_login(conn);
968 }
969#endif
970
971 /* Add veto/hide lists */
972 if (!IS_IPC(conn) && !IS_PRINT(conn)) {
973 set_namearray( &conn->veto_list, lp_veto_files(snum));
974 set_namearray( &conn->hide_list, lp_hide_files(snum));
975 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(snum));
976 }
977
978 /* Invoke VFS make connection hook - do this before the VFS_STAT call
979 to allow any filesystems needing user credentials to initialize
980 themselves. */
981
982 if (SMB_VFS_CONNECT(conn, lp_servicename(snum), user) < 0) {
983 DEBUG(0,("make_connection: VFS make connection failed!\n"));
984 change_to_root_user();
985 yield_connection(conn, lp_servicename(snum));
986 conn_free(conn);
987 *status = NT_STATUS_UNSUCCESSFUL;
988 return NULL;
989 }
990
991 /* win2000 does not check the permissions on the directory
992 during the tree connect, instead relying on permission
993 check during individual operations. To match this behaviour
994 I have disabled this chdir check (tridge) */
995 /* the alternative is just to check the directory exists */
996 if ((ret = SMB_VFS_STAT(conn, conn->connectpath, &st)) != 0 ||
997 !S_ISDIR(st.st_mode)) {
998 if (ret == 0 && !S_ISDIR(st.st_mode)) {
999 DEBUG(0,("'%s' is not a directory, when connecting to "
1000 "[%s]\n", conn->connectpath,
1001 lp_servicename(snum)));
1002 } else {
1003 DEBUG(0,("'%s' does not exist or permission denied "
1004 "when connecting to [%s] Error was %s\n",
1005 conn->connectpath, lp_servicename(snum),
1006 strerror(errno) ));
1007 }
1008 change_to_root_user();
1009 /* Call VFS disconnect hook */
1010 SMB_VFS_DISCONNECT(conn);
1011 yield_connection(conn, lp_servicename(snum));
1012 conn_free(conn);
1013 *status = NT_STATUS_BAD_NETWORK_NAME;
1014 return NULL;
1015 }
1016
1017 string_set(&conn->origpath,conn->connectpath);
1018
1019#if SOFTLINK_OPTIMISATION
1020 /* resolve any soft links early if possible */
1021 if (vfs_ChDir(conn,conn->connectpath) == 0) {
1022 pstring s;
1023 pstrcpy(s,conn->connectpath);
1024 vfs_GetWd(conn,s);
1025 set_conn_connectpath(conn,s);
1026 vfs_ChDir(conn,conn->connectpath);
1027 }
1028#endif
1029
1030 /*
1031 * Print out the 'connected as' stuff here as we need
1032 * to know the effective uid and gid we will be using
1033 * (at least initially).
1034 */
1035
1036 if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
1037 dbgtext( "%s (%s) ", get_remote_machine_name(),
1038 conn->client_address );
1039 dbgtext( "%s", srv_is_signing_active() ? "signed " : "");
1040 dbgtext( "connect to service %s ", lp_servicename(snum) );
1041 dbgtext( "initially as user %s ", user );
1042 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
1043 dbgtext( "(pid %d)\n", (int)sys_getpid() );
1044 }
1045
1046 /* we've finished with the user stuff - go back to root */
1047 change_to_root_user();
1048 return(conn);
1049}
1050
1051/***************************************************************************************
1052 Simple wrapper function for make_connection() to include a call to
1053 vfs_chdir()
1054 **************************************************************************************/
1055
1056connection_struct *make_connection_with_chdir(const char *service_in,
1057 DATA_BLOB password,
1058 const char *dev, uint16 vuid,
1059 NTSTATUS *status)
1060{
1061 connection_struct *conn = NULL;
1062
1063 conn = make_connection(service_in, password, dev, vuid, status);
1064
1065 /*
1066 * make_connection() does not change the directory for us any more
1067 * so we have to do it as a separate step --jerry
1068 */
1069
1070 if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) {
1071 DEBUG(0,("move_driver_to_download_area: Can't change "
1072 "directory to %s for [print$] (%s)\n",
1073 conn->connectpath,strerror(errno)));
1074 yield_connection(conn, lp_servicename(SNUM(conn)));
1075 conn_free(conn);
1076 *status = NT_STATUS_UNSUCCESSFUL;
1077 return NULL;
1078 }
1079
1080 return conn;
1081}
1082
1083/****************************************************************************
1084 Make a connection to a service.
1085 *
1086 * @param service
1087****************************************************************************/
1088
1089connection_struct *make_connection(const char *service_in, DATA_BLOB password,
1090 const char *pdev, uint16 vuid,
1091 NTSTATUS *status)
1092{
1093 uid_t euid;
1094 user_struct *vuser = NULL;
1095 fstring service;
1096 fstring dev;
1097 int snum = -1;
1098
1099 fstrcpy(dev, pdev);
1100
1101 /* This must ONLY BE CALLED AS ROOT. As it exits this function as
1102 * root. */
1103 if (!non_root_mode() && (euid = geteuid()) != 0) {
1104 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot "
1105 "(%u)\n", (unsigned int)euid ));
1106 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
1107 }
1108
1109 if (conn_num_open() > 2047) {
1110 *status = NT_STATUS_INSUFF_SERVER_RESOURCES;
1111 return NULL;
1112 }
1113
1114 if(lp_security() != SEC_SHARE) {
1115 vuser = get_valid_user_struct(vuid);
1116 if (!vuser) {
1117 DEBUG(1,("make_connection: refusing to connect with "
1118 "no session setup\n"));
1119 *status = NT_STATUS_ACCESS_DENIED;
1120 return NULL;
1121 }
1122 }
1123
1124 /* Logic to try and connect to the correct [homes] share, preferably
1125 without too many getpwnam() lookups. This is particulary nasty for
1126 winbind usernames, where the share name isn't the same as unix
1127 username.
1128
1129 The snum of the homes share is stored on the vuser at session setup
1130 time.
1131 */
1132
1133 if (strequal(service_in,HOMES_NAME)) {
1134 if(lp_security() != SEC_SHARE) {
1135 DATA_BLOB no_pw = data_blob(NULL, 0);
1136 if (vuser->homes_snum == -1) {
1137 DEBUG(2, ("[homes] share not available for "
1138 "this user because it was not found "
1139 "or created at session setup "
1140 "time\n"));
1141 *status = NT_STATUS_BAD_NETWORK_NAME;
1142 return NULL;
1143 }
1144 DEBUG(5, ("making a connection to [homes] service "
1145 "created at session setup time\n"));
1146 return make_connection_snum(vuser->homes_snum,
1147 vuser, no_pw,
1148 dev, status);
1149 } else {
1150 /* Security = share. Try with
1151 * current_user_info.smb_name as the username. */
1152 if (*current_user_info.smb_name) {
1153 fstring unix_username;
1154 fstrcpy(unix_username,
1155 current_user_info.smb_name);
1156 map_username(unix_username);
1157 snum = find_service(unix_username);
1158 }
1159 if (snum != -1) {
1160 DEBUG(5, ("making a connection to 'homes' "
1161 "service %s based on "
1162 "security=share\n", service_in));
1163 return make_connection_snum(snum, NULL,
1164 password,
1165 dev, status);
1166 }
1167 }
1168 } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
1169 && strequal(service_in,
1170 lp_servicename(vuser->homes_snum))) {
1171 DATA_BLOB no_pw = data_blob(NULL, 0);
1172 DEBUG(5, ("making a connection to 'homes' service [%s] "
1173 "created at session setup time\n", service_in));
1174 return make_connection_snum(vuser->homes_snum,
1175 vuser, no_pw,
1176 dev, status);
1177 }
1178
1179 fstrcpy(service, service_in);
1180
1181 strlower_m(service);
1182
1183 snum = find_service(service);
1184
1185 if (snum < 0) {
1186 if (strequal(service,"IPC$") ||
1187 (lp_enable_asu_support() && strequal(service,"ADMIN$"))) {
1188 DEBUG(3,("refusing IPC connection to %s\n", service));
1189 *status = NT_STATUS_ACCESS_DENIED;
1190 return NULL;
1191 }
1192
1193 DEBUG(0,("%s (%s) couldn't find service %s\n",
1194 get_remote_machine_name(), client_addr(), service));
1195 *status = NT_STATUS_BAD_NETWORK_NAME;
1196 return NULL;
1197 }
1198
1199 /* Handle non-Dfs clients attempting connections to msdfs proxy */
1200 if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0')) {
1201 DEBUG(3, ("refusing connection to dfs proxy share '%s' "
1202 "(pointing to %s)\n",
1203 service, lp_msdfs_proxy(snum)));
1204 *status = NT_STATUS_BAD_NETWORK_NAME;
1205 return NULL;
1206 }
1207
1208 DEBUG(5, ("making a connection to 'normal' service %s\n", service));
1209
1210 return make_connection_snum(snum, vuser,
1211 password,
1212 dev, status);
1213}
1214
1215/****************************************************************************
1216 Close a cnum.
1217****************************************************************************/
1218
1219void close_cnum(connection_struct *conn, uint16 vuid)
1220{
1221 if (IS_IPC(conn)) {
1222 pipe_close_conn(conn);
1223 } else {
1224 file_close_conn(conn);
1225 dptr_closecnum(conn);
1226 }
1227
1228 change_to_root_user();
1229
1230 DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
1231 get_remote_machine_name(),
1232 conn->client_address,
1233 lp_servicename(SNUM(conn))));
1234
1235 /* Call VFS disconnect hook */
1236 SMB_VFS_DISCONNECT(conn);
1237
1238 yield_connection(conn, lp_servicename(SNUM(conn)));
1239
1240 /* make sure we leave the directory available for unmount */
1241 vfs_ChDir(conn, "/");
1242
1243 /* execute any "postexec = " line */
1244 if (*lp_postexec(SNUM(conn)) &&
1245 change_to_user(conn, vuid)) {
1246 pstring cmd;
1247 pstrcpy(cmd,lp_postexec(SNUM(conn)));
1248 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
1249 conn->connectpath, conn->gid,
1250 get_current_username(),
1251 current_user_info.domain,
1252 cmd, sizeof(cmd));
1253 smbrun(cmd,NULL);
1254 change_to_root_user();
1255 }
1256
1257 change_to_root_user();
1258 /* execute any "root postexec = " line */
1259 if (*lp_rootpostexec(SNUM(conn))) {
1260 pstring cmd;
1261 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
1262 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
1263 conn->connectpath, conn->gid,
1264 get_current_username(),
1265 current_user_info.domain,
1266 cmd, sizeof(cmd));
1267 smbrun(cmd,NULL);
1268 }
1269
1270 conn_free(conn);
1271}
Note: See TracBrowser for help on using the repository browser.