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

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

Updated source to 3.0.25rc1

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