source: trunk/samba-3.0.25pre1/source/smbd/service.c@ 1

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

Initial code import

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