source: branches/samba-3.2.x/source/smbd/msdfs.c@ 198

Last change on this file since 198 was 138, checked in by Paul Smedley, 17 years ago

Update source to 3.2.0 GA level

File size: 42.7 KB
Line 
1/*
2 Unix SMB/Netbios implementation.
3 Version 3.0
4 MSDFS services for Samba
5 Copyright (C) Shirish Kalele 2000
6 Copyright (C) Jeremy Allison 2007
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20
21*/
22
23#define DBGC_CLASS DBGC_MSDFS
24#include "includes.h"
25
26extern uint32 global_client_caps;
27
28/**********************************************************************
29 Parse a DFS pathname of the form \hostname\service\reqpath
30 into the dfs_path structure.
31 If POSIX pathnames is true, the pathname may also be of the
32 form /hostname/service/reqpath.
33 We cope with either here.
34
35 Unfortunately, due to broken clients who might set the
36 SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then
37 send a local path, we have to cope with that too....
38
39 If conn != NULL then ensure the provided service is
40 the one pointed to by the connection.
41
42 This version does everything using pointers within one copy of the
43 pathname string, talloced on the struct dfs_path pointer (which
44 must be talloced). This may be too clever to live....
45 JRA.
46**********************************************************************/
47
48static NTSTATUS parse_dfs_path(connection_struct *conn,
49 const char *pathname,
50 bool allow_wcards,
51 struct dfs_path *pdp, /* MUST BE TALLOCED */
52 bool *ppath_contains_wcard)
53{
54 char *pathname_local;
55 char *p,*temp;
56 char *servicename;
57 char *eos_ptr;
58 NTSTATUS status = NT_STATUS_OK;
59 char sepchar;
60
61 ZERO_STRUCTP(pdp);
62
63 /*
64 * This is the only talloc we should need to do
65 * on the struct dfs_path. All the pointers inside
66 * it should point to offsets within this string.
67 */
68
69 pathname_local = talloc_strdup(pdp, pathname);
70 if (!pathname_local) {
71 return NT_STATUS_NO_MEMORY;
72 }
73 /* Get a pointer to the terminating '\0' */
74 eos_ptr = &pathname_local[strlen(pathname_local)];
75 p = temp = pathname_local;
76
77 pdp->posix_path = (lp_posix_pathnames() && *pathname == '/');
78
79 sepchar = pdp->posix_path ? '/' : '\\';
80
81 if (*pathname != sepchar) {
82 DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n",
83 pathname, sepchar ));
84 /*
85 * Possibly client sent a local path by mistake.
86 * Try and convert to a local path.
87 */
88
89 pdp->hostname = eos_ptr; /* "" */
90 pdp->servicename = eos_ptr; /* "" */
91
92 /* We've got no info about separators. */
93 pdp->posix_path = lp_posix_pathnames();
94 p = temp;
95 DEBUG(10,("parse_dfs_path: trying to convert %s to a "
96 "local path\n",
97 temp));
98 goto local_path;
99 }
100
101 /*
102 * Safe to use on talloc'ed string as it only shrinks.
103 * It also doesn't affect the eos_ptr.
104 */
105 trim_char(temp,sepchar,sepchar);
106
107 DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
108 temp, sepchar));
109
110 /* Now tokenize. */
111 /* Parse out hostname. */
112 p = strchr_m(temp,sepchar);
113 if(p == NULL) {
114 DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n",
115 temp));
116 /*
117 * Possibly client sent a local path by mistake.
118 * Try and convert to a local path.
119 */
120
121 pdp->hostname = eos_ptr; /* "" */
122 pdp->servicename = eos_ptr; /* "" */
123
124 p = temp;
125 DEBUG(10,("parse_dfs_path: trying to convert %s "
126 "to a local path\n",
127 temp));
128 goto local_path;
129 }
130 *p = '\0';
131 pdp->hostname = temp;
132
133 DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname));
134
135 /* Parse out servicename. */
136 servicename = p+1;
137 p = strchr_m(servicename,sepchar);
138 if (p) {
139 *p = '\0';
140 }
141
142 /* Is this really our servicename ? */
143 if (conn && !( strequal(servicename, lp_servicename(SNUM(conn)))
144 || (strequal(servicename, HOMES_NAME)
145 && strequal(lp_servicename(SNUM(conn)),
146 get_current_username()) )) ) {
147 DEBUG(10,("parse_dfs_path: %s is not our servicename\n",
148 servicename));
149
150 /*
151 * Possibly client sent a local path by mistake.
152 * Try and convert to a local path.
153 */
154
155 pdp->hostname = eos_ptr; /* "" */
156 pdp->servicename = eos_ptr; /* "" */
157
158 /* Repair the path - replace the sepchar's
159 we nulled out */
160 servicename--;
161 *servicename = sepchar;
162 if (p) {
163 *p = sepchar;
164 }
165
166 p = temp;
167 DEBUG(10,("parse_dfs_path: trying to convert %s "
168 "to a local path\n",
169 temp));
170 goto local_path;
171 }
172
173 pdp->servicename = servicename;
174
175 DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));
176
177 if(p == NULL) {
178 /* Client sent self referral \server\share. */
179 pdp->reqpath = eos_ptr; /* "" */
180 return NT_STATUS_OK;
181 }
182
183 p++;
184
185 local_path:
186
187 *ppath_contains_wcard = False;
188
189 pdp->reqpath = p;
190
191 /* Rest is reqpath. */
192 if (pdp->posix_path) {
193 status = check_path_syntax_posix(pdp->reqpath);
194 } else {
195 if (allow_wcards) {
196 status = check_path_syntax_wcard(pdp->reqpath,
197 ppath_contains_wcard);
198 } else {
199 status = check_path_syntax(pdp->reqpath);
200 }
201 }
202
203 if (!NT_STATUS_IS_OK(status)) {
204 DEBUG(10,("parse_dfs_path: '%s' failed with %s\n",
205 p, nt_errstr(status) ));
206 return status;
207 }
208
209 DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
210 return NT_STATUS_OK;
211}
212
213/********************************************************
214 Fake up a connection struct for the VFS layer.
215 Note this CHANGES CWD !!!! JRA.
216*********************************************************/
217
218static NTSTATUS create_conn_struct(TALLOC_CTX *ctx,
219 connection_struct *conn,
220 int snum,
221 const char *path)
222{
223 char *connpath;
224
225 ZERO_STRUCTP(conn);
226
227 connpath = talloc_strdup(ctx, path);
228 if (!connpath) {
229 return NT_STATUS_NO_MEMORY;
230 }
231 connpath = talloc_string_sub(ctx,
232 connpath,
233 "%S",
234 lp_servicename(snum));
235 if (!connpath) {
236 return NT_STATUS_NO_MEMORY;
237 }
238
239 /* needed for smbd_vfs_init() */
240
241 if ((conn->mem_ctx=talloc_init("connection_struct")) == NULL) {
242 DEBUG(0,("talloc_init(connection_struct) failed!\n"));
243 return NT_STATUS_NO_MEMORY;
244 }
245
246 if (!(conn->params = TALLOC_ZERO_P(conn->mem_ctx,
247 struct share_params))) {
248 DEBUG(0, ("TALLOC failed\n"));
249 return NT_STATUS_NO_MEMORY;
250 }
251
252 conn->params->service = snum;
253
254 set_conn_connectpath(conn, connpath);
255
256 if (!smbd_vfs_init(conn)) {
257 NTSTATUS status = map_nt_error_from_unix(errno);
258 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
259 conn_free_internal(conn);
260 return status;
261 }
262
263 /*
264 * Windows seems to insist on doing trans2getdfsreferral() calls on
265 * the IPC$ share as the anonymous user. If we try to chdir as that
266 * user we will fail.... WTF ? JRA.
267 */
268
269 if (vfs_ChDir(conn,conn->connectpath) != 0) {
270 NTSTATUS status = map_nt_error_from_unix(errno);
271 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. "
272 "Error was %s\n",
273 conn->connectpath, strerror(errno) ));
274 conn_free_internal(conn);
275 return status;
276 }
277
278 return NT_STATUS_OK;
279}
280
281/**********************************************************************
282 Parse the contents of a symlink to verify if it is an msdfs referral
283 A valid referral is of the form:
284
285 msdfs:server1\share1,server2\share2
286 msdfs:server1\share1\pathname,server2\share2\pathname
287 msdfs:server1/share1,server2/share2
288 msdfs:server1/share1/pathname,server2/share2/pathname.
289
290 Note that the alternate paths returned here must be of the canonicalized
291 form:
292
293 \server\share or
294 \server\share\path\to\file,
295
296 even in posix path mode. This is because we have no knowledge if the
297 server we're referring to understands posix paths.
298 **********************************************************************/
299
300static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
301 const char *target,
302 struct referral **preflist,
303 int *refcount)
304{
305 char *temp = NULL;
306 char *prot;
307 char **alt_path = NULL;
308 int count = 0, i;
309 struct referral *reflist;
310 char *saveptr;
311
312 temp = talloc_strdup(ctx, target);
313 if (!temp) {
314 return False;
315 }
316 prot = strtok_r(temp, ":", &saveptr);
317 if (!prot) {
318 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
319 return False;
320 }
321
322 alt_path = TALLOC_ARRAY(ctx, char *, MAX_REFERRAL_COUNT);
323 if (!alt_path) {
324 return False;
325 }
326
327 /* parse out the alternate paths */
328 while((count<MAX_REFERRAL_COUNT) &&
329 ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
330 count++;
331 }
332
333 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
334
335 if (count) {
336 reflist = *preflist = TALLOC_ZERO_ARRAY(ctx,
337 struct referral, count);
338 if(reflist == NULL) {
339 TALLOC_FREE(alt_path);
340 return False;
341 }
342 } else {
343 reflist = *preflist = NULL;
344 }
345
346 for(i=0;i<count;i++) {
347 char *p;
348
349 /* Canonicalize link target.
350 * Replace all /'s in the path by a \ */
351 string_replace(alt_path[i], '/', '\\');
352
353 /* Remove leading '\\'s */
354 p = alt_path[i];
355 while (*p && (*p == '\\')) {
356 p++;
357 }
358
359 reflist[i].alternate_path = talloc_asprintf(ctx,
360 "\\%s",
361 p);
362 if (!reflist[i].alternate_path) {
363 return False;
364 }
365
366 reflist[i].proximity = 0;
367 reflist[i].ttl = REFERRAL_TTL;
368 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
369 reflist[i].alternate_path));
370 }
371
372 *refcount = count;
373
374 TALLOC_FREE(alt_path);
375 return True;
376}
377
378/**********************************************************************
379 Returns true if the unix path is a valid msdfs symlink and also
380 returns the target string from inside the link.
381**********************************************************************/
382
383static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
384 connection_struct *conn,
385 const char *path,
386 char **pp_link_target,
387 SMB_STRUCT_STAT *sbufp)
388{
389 SMB_STRUCT_STAT st;
390 int referral_len = 0;
391 char link_target_buf[7];
392 size_t bufsize = 0;
393 char *link_target = NULL;
394
395 if (pp_link_target) {
396 bufsize = 1024;
397 link_target = TALLOC_ARRAY(ctx, char, bufsize);
398 if (!link_target) {
399 return False;
400 }
401 *pp_link_target = link_target;
402 } else {
403 bufsize = sizeof(link_target_buf);
404 link_target = link_target_buf;
405 }
406
407 if (sbufp == NULL) {
408 sbufp = &st;
409 }
410
411 if (SMB_VFS_LSTAT(conn, path, sbufp) != 0) {
412 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
413 path));
414 goto err;
415 }
416
417 if (!S_ISLNK(sbufp->st_mode)) {
418 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
419 path));
420 goto err;
421 }
422
423 referral_len = SMB_VFS_READLINK(conn, path, link_target, bufsize - 1);
424 if (referral_len == -1) {
425 DEBUG(0,("is_msdfs_link_read_target: Error reading "
426 "msdfs link %s: %s\n",
427 path, strerror(errno)));
428 goto err;
429 }
430 link_target[referral_len] = '\0';
431
432 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n",path,
433 link_target));
434
435 if (!strnequal(link_target, "msdfs:", 6)) {
436 goto err;
437 }
438 return True;
439
440 err:
441
442 if (link_target != link_target_buf) {
443 TALLOC_FREE(link_target);
444 }
445 return False;
446}
447
448/**********************************************************************
449 Returns true if the unix path is a valid msdfs symlink.
450**********************************************************************/
451
452bool is_msdfs_link(connection_struct *conn,
453 const char *path,
454 SMB_STRUCT_STAT *sbufp)
455{
456 return is_msdfs_link_internal(talloc_tos(),
457 conn,
458 path,
459 NULL,
460 sbufp);
461}
462
463/*****************************************************************
464 Used by other functions to decide if a dfs path is remote,
465 and to get the list of referred locations for that remote path.
466
467 search_flag: For findfirsts, dfs links themselves are not
468 redirected, but paths beyond the links are. For normal smb calls,
469 even dfs links need to be redirected.
470
471 consumedcntp: how much of the dfs path is being redirected. the client
472 should try the remaining path on the redirected server.
473
474 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
475 link redirect are in targetpath.
476*****************************************************************/
477
478static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
479 connection_struct *conn,
480 const char *dfspath, /* Incoming complete dfs path */
481 const struct dfs_path *pdp, /* Parsed out
482 server+share+extrapath. */
483 bool search_flag, /* Called from a findfirst ? */
484 int *consumedcntp,
485 char **pp_targetpath)
486{
487 char *p = NULL;
488 char *q = NULL;
489 SMB_STRUCT_STAT sbuf;
490 NTSTATUS status;
491 char *localpath = NULL;
492 char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
493 components). */
494
495 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
496 conn->connectpath, pdp->reqpath));
497
498 /*
499 * Note the unix path conversion here we're doing we can
500 * throw away. We're looking for a symlink for a dfs
501 * resolution, if we don't find it we'll do another
502 * unix_convert later in the codepath.
503 * If we needed to remember what we'd resolved in
504 * dp->reqpath (as the original code did) we'd
505 * copy (localhost, dp->reqpath) on any code
506 * path below that returns True - but I don't
507 * think this is needed. JRA.
508 */
509
510 status = unix_convert(ctx, conn, pdp->reqpath, search_flag, &localpath,
511 NULL, &sbuf);
512 if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status,
513 NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
514 return status;
515 }
516
517 /* Optimization - check if we can redirect the whole path. */
518
519 if (is_msdfs_link_internal(ctx, conn, localpath, pp_targetpath, NULL)) {
520 if (search_flag) {
521 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
522 "for dfs link %s.\n", dfspath));
523 return NT_STATUS_OK;
524 }
525
526 DEBUG(6,("dfs_path_lookup: %s resolves to a "
527 "valid dfs link %s.\n", dfspath,
528 pp_targetpath ? *pp_targetpath : ""));
529
530 if (consumedcntp) {
531 *consumedcntp = strlen(dfspath);
532 }
533 return NT_STATUS_PATH_NOT_COVERED;
534 }
535
536 /* Prepare to test only for '/' components in the given path,
537 * so if a Windows path replace all '\\' characters with '/'.
538 * For a POSIX DFS path we know all separators are already '/'. */
539
540 canon_dfspath = talloc_strdup(ctx, dfspath);
541 if (!canon_dfspath) {
542 return NT_STATUS_NO_MEMORY;
543 }
544 if (!pdp->posix_path) {
545 string_replace(canon_dfspath, '\\', '/');
546 }
547
548 /*
549 * localpath comes out of unix_convert, so it has
550 * no trailing backslash. Make sure that canon_dfspath hasn't either.
551 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
552 */
553
554 trim_char(canon_dfspath,0,'/');
555
556 /*
557 * Redirect if any component in the path is a link.
558 * We do this by walking backwards through the
559 * local path, chopping off the last component
560 * in both the local path and the canonicalized
561 * DFS path. If we hit a DFS link then we're done.
562 */
563
564 p = strrchr_m(localpath, '/');
565 if (consumedcntp) {
566 q = strrchr_m(canon_dfspath, '/');
567 }
568
569 while (p) {
570 *p = '\0';
571 if (q) {
572 *q = '\0';
573 }
574
575 if (is_msdfs_link_internal(ctx, conn,
576 localpath, pp_targetpath, NULL)) {
577 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
578 "parent %s is dfs link\n", dfspath, localpath));
579
580 if (consumedcntp) {
581 *consumedcntp = strlen(canon_dfspath);
582 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
583 "(%d)\n",
584 canon_dfspath,
585 *consumedcntp));
586 }
587
588 return NT_STATUS_PATH_NOT_COVERED;
589 }
590
591 /* Step back on the filesystem. */
592 p = strrchr_m(localpath, '/');
593
594 if (consumedcntp) {
595 /* And in the canonicalized dfs path. */
596 q = strrchr_m(canon_dfspath, '/');
597 }
598 }
599
600 return NT_STATUS_OK;
601}
602
603/*****************************************************************
604 Decides if a dfs pathname should be redirected or not.
605 If not, the pathname is converted to a tcon-relative local unix path
606
607 search_wcard_flag: this flag performs 2 functions both related
608 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
609 for details.
610
611 This function can return NT_STATUS_OK, meaning use the returned path as-is
612 (mapped into a local path).
613 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
614 any other NT_STATUS error which is a genuine error to be
615 returned to the client.
616*****************************************************************/
617
618static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
619 connection_struct *conn,
620 const char *path_in,
621 bool search_wcard_flag,
622 char **pp_path_out,
623 bool *ppath_contains_wcard)
624{
625 NTSTATUS status;
626 struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path);
627
628 if (!pdp) {
629 return NT_STATUS_NO_MEMORY;
630 }
631
632 status = parse_dfs_path(conn, path_in, search_wcard_flag, pdp,
633 ppath_contains_wcard);
634 if (!NT_STATUS_IS_OK(status)) {
635 TALLOC_FREE(pdp);
636 return status;
637 }
638
639 if (pdp->reqpath[0] == '\0') {
640 TALLOC_FREE(pdp);
641 *pp_path_out = talloc_strdup(ctx, "");
642 if (!*pp_path_out) {
643 return NT_STATUS_NO_MEMORY;
644 }
645 DEBUG(5,("dfs_redirect: self-referral.\n"));
646 return NT_STATUS_OK;
647 }
648
649 /* If dfs pathname for a non-dfs share, convert to tcon-relative
650 path and return OK */
651
652 if (!lp_msdfs_root(SNUM(conn))) {
653 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
654 TALLOC_FREE(pdp);
655 if (!*pp_path_out) {
656 return NT_STATUS_NO_MEMORY;
657 }
658 return NT_STATUS_OK;
659 }
660
661 /* If it looked like a local path (zero hostname/servicename)
662 * just treat as a tcon-relative path. */
663
664 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
665 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
666 TALLOC_FREE(pdp);
667 if (!*pp_path_out) {
668 return NT_STATUS_NO_MEMORY;
669 }
670 return NT_STATUS_OK;
671 }
672
673 status = dfs_path_lookup(ctx, conn, path_in, pdp,
674 search_wcard_flag, NULL, NULL);
675 if (!NT_STATUS_IS_OK(status)) {
676 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
677 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
678 } else {
679 DEBUG(10,("dfs_redirect: dfs_path_lookup "
680 "failed for %s with %s\n",
681 path_in, nt_errstr(status) ));
682 }
683 return status;
684 }
685
686 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
687
688 /* Form non-dfs tcon-relative path */
689 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
690 TALLOC_FREE(pdp);
691 if (!*pp_path_out) {
692 return NT_STATUS_NO_MEMORY;
693 }
694
695 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
696 path_in,
697 *pp_path_out));
698
699 return NT_STATUS_OK;
700}
701
702/**********************************************************************
703 Return a self referral.
704**********************************************************************/
705
706static NTSTATUS self_ref(TALLOC_CTX *ctx,
707 const char *dfs_path,
708 struct junction_map *jucn,
709 int *consumedcntp,
710 bool *self_referralp)
711{
712 struct referral *ref;
713
714 *self_referralp = True;
715
716 jucn->referral_count = 1;
717 if((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
718 return NT_STATUS_NO_MEMORY;
719 }
720
721 ref->alternate_path = talloc_strdup(ctx, dfs_path);
722 if (!ref->alternate_path) {
723 return NT_STATUS_NO_MEMORY;
724 }
725 ref->proximity = 0;
726 ref->ttl = REFERRAL_TTL;
727 jucn->referral_list = ref;
728 *consumedcntp = strlen(dfs_path);
729 return NT_STATUS_OK;
730}
731
732/**********************************************************************
733 Gets valid referrals for a dfs path and fills up the
734 junction_map structure.
735**********************************************************************/
736
737NTSTATUS get_referred_path(TALLOC_CTX *ctx,
738 const char *dfs_path,
739 struct junction_map *jucn,
740 int *consumedcntp,
741 bool *self_referralp)
742{
743 struct connection_struct conns;
744 struct connection_struct *conn = &conns;
745 char *targetpath = NULL;
746 int snum;
747 NTSTATUS status = NT_STATUS_NOT_FOUND;
748 bool dummy;
749 struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path);
750
751 if (!pdp) {
752 return NT_STATUS_NO_MEMORY;
753 }
754
755 ZERO_STRUCT(conns);
756 *self_referralp = False;
757
758 status = parse_dfs_path(NULL, dfs_path, False, pdp, &dummy);
759 if (!NT_STATUS_IS_OK(status)) {
760 return status;
761 }
762
763 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
764 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
765 if (!jucn->service_name || !jucn->volume_name) {
766 TALLOC_FREE(pdp);
767 return NT_STATUS_NO_MEMORY;
768 }
769
770 /* Verify the share is a dfs root */
771 snum = lp_servicenumber(jucn->service_name);
772 if(snum < 0) {
773 fstring service_name;
774 fstrcpy(service_name, jucn->service_name);
775 if ((snum = find_service(service_name)) < 0) {
776 return NT_STATUS_NOT_FOUND;
777 }
778 TALLOC_FREE(jucn->service_name);
779 jucn->service_name = talloc_strdup(ctx, service_name);
780 if (!jucn->service_name) {
781 TALLOC_FREE(pdp);
782 return NT_STATUS_NO_MEMORY;
783 }
784 }
785
786 if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(snum) == '\0')) {
787 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
788 "a dfs root.\n",
789 pdp->servicename, dfs_path));
790 TALLOC_FREE(pdp);
791 return NT_STATUS_NOT_FOUND;
792 }
793
794 /*
795 * Self referrals are tested with a anonymous IPC connection and
796 * a GET_DFS_REFERRAL call to \\server\share. (which means
797 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
798 * into the directory and will fail if it cannot (as the anonymous
799 * user). Cope with this.
800 */
801
802 if (pdp->reqpath[0] == '\0') {
803 char *tmp;
804 struct referral *ref;
805
806 if (*lp_msdfs_proxy(snum) == '\0') {
807 TALLOC_FREE(pdp);
808 return self_ref(ctx,
809 dfs_path,
810 jucn,
811 consumedcntp,
812 self_referralp);
813 }
814
815 /*
816 * It's an msdfs proxy share. Redirect to
817 * the configured target share.
818 */
819
820 jucn->referral_count = 1;
821 if ((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
822 TALLOC_FREE(pdp);
823 return NT_STATUS_NO_MEMORY;
824 }
825
826 if (!(tmp = talloc_strdup(ctx, lp_msdfs_proxy(snum)))) {
827 TALLOC_FREE(pdp);
828 return NT_STATUS_NO_MEMORY;
829 }
830
831 trim_string(tmp, "\\", 0);
832
833 ref->alternate_path = talloc_asprintf(ctx, "\\%s", tmp);
834 TALLOC_FREE(tmp);
835
836 if (!ref->alternate_path) {
837 TALLOC_FREE(pdp);
838 return NT_STATUS_NO_MEMORY;
839 }
840
841 if (pdp->reqpath[0] != '\0') {
842 ref->alternate_path = talloc_asprintf_append(
843 ref->alternate_path,
844 "%s",
845 pdp->reqpath);
846 if (!ref->alternate_path) {
847 TALLOC_FREE(pdp);
848 return NT_STATUS_NO_MEMORY;
849 }
850 }
851 ref->proximity = 0;
852 ref->ttl = REFERRAL_TTL;
853 jucn->referral_list = ref;
854 *consumedcntp = strlen(dfs_path);
855 TALLOC_FREE(pdp);
856 return NT_STATUS_OK;
857 }
858
859 status = create_conn_struct(ctx, conn, snum, lp_pathname(snum));
860 if (!NT_STATUS_IS_OK(status)) {
861 TALLOC_FREE(pdp);
862 return status;
863 }
864
865 /* If this is a DFS path dfs_lookup should return
866 * NT_STATUS_PATH_NOT_COVERED. */
867
868 status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
869 False, consumedcntp, &targetpath);
870
871 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
872 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
873 dfs_path));
874 conn_free_internal(conn);
875 TALLOC_FREE(pdp);
876 return status;
877 }
878
879 /* We know this is a valid dfs link. Parse the targetpath. */
880 if (!parse_msdfs_symlink(ctx, targetpath,
881 &jucn->referral_list,
882 &jucn->referral_count)) {
883 DEBUG(3,("get_referred_path: failed to parse symlink "
884 "target %s\n", targetpath ));
885 conn_free_internal(conn);
886 TALLOC_FREE(pdp);
887 return NT_STATUS_NOT_FOUND;
888 }
889
890 conn_free_internal(conn);
891 TALLOC_FREE(pdp);
892 return NT_STATUS_OK;
893}
894
895static int setup_ver2_dfs_referral(const char *pathname,
896 char **ppdata,
897 struct junction_map *junction,
898 int consumedcnt,
899 bool self_referral)
900{
901 char* pdata = *ppdata;
902
903 smb_ucs2_t *uni_requestedpath = NULL;
904 int uni_reqpathoffset1,uni_reqpathoffset2;
905 int uni_curroffset;
906 int requestedpathlen=0;
907 int offset;
908 int reply_size = 0;
909 int i=0;
910
911 DEBUG(10,("Setting up version2 referral\nRequested path:\n"));
912
913 requestedpathlen = rpcstr_push_talloc(talloc_tos(),
914 &uni_requestedpath, pathname);
915 if (uni_requestedpath == NULL || requestedpathlen == 0) {
916 return -1;
917 }
918
919 if (DEBUGLVL(10)) {
920 dump_data(0, (unsigned char *)uni_requestedpath,
921 requestedpathlen);
922 }
923
924 DEBUG(10,("ref count = %u\n",junction->referral_count));
925
926 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
927 VERSION2_REFERRAL_SIZE * junction->referral_count;
928
929 uni_reqpathoffset2 = uni_reqpathoffset1 + requestedpathlen;
930
931 uni_curroffset = uni_reqpathoffset2 + requestedpathlen;
932
933 reply_size = REFERRAL_HEADER_SIZE +
934 VERSION2_REFERRAL_SIZE*junction->referral_count +
935 2 * requestedpathlen;
936 DEBUG(10,("reply_size: %u\n",reply_size));
937
938 /* add up the unicode lengths of all the referral paths */
939 for(i=0;i<junction->referral_count;i++) {
940 DEBUG(10,("referral %u : %s\n",
941 i,
942 junction->referral_list[i].alternate_path));
943 reply_size +=
944 (strlen(junction->referral_list[i].alternate_path)+1)*2;
945 }
946
947 DEBUG(10,("reply_size = %u\n",reply_size));
948 /* add the unexplained 0x16 bytes */
949 reply_size += 0x16;
950
951 pdata = (char *)SMB_REALLOC(pdata,reply_size);
952 if(pdata == NULL) {
953 DEBUG(0,("Realloc failed!\n"));
954 return -1;
955 }
956 *ppdata = pdata;
957
958 /* copy in the dfs requested paths.. required for offset calculations */
959 memcpy(pdata+uni_reqpathoffset1,uni_requestedpath,requestedpathlen);
960 memcpy(pdata+uni_reqpathoffset2,uni_requestedpath,requestedpathlen);
961
962 /* create the header */
963 SSVAL(pdata,0,consumedcnt * 2); /* path consumed */
964 /* number of referral in this pkt */
965 SSVAL(pdata,2,junction->referral_count);
966 if(self_referral) {
967 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
968 } else {
969 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
970 }
971
972 offset = 8;
973 /* add the referral elements */
974 for(i=0;i<junction->referral_count;i++) {
975 struct referral* ref = &junction->referral_list[i];
976 int unilen;
977
978 SSVAL(pdata,offset,2); /* version 2 */
979 SSVAL(pdata,offset+2,VERSION2_REFERRAL_SIZE);
980 if(self_referral) {
981 SSVAL(pdata,offset+4,1);
982 } else {
983 SSVAL(pdata,offset+4,0);
984 }
985
986 /* ref_flags :use path_consumed bytes? */
987 SSVAL(pdata,offset+6,0);
988 SIVAL(pdata,offset+8,ref->proximity);
989 SIVAL(pdata,offset+12,ref->ttl);
990
991 SSVAL(pdata,offset+16,uni_reqpathoffset1-offset);
992 SSVAL(pdata,offset+18,uni_reqpathoffset2-offset);
993 /* copy referred path into current offset */
994 unilen = rpcstr_push(pdata+uni_curroffset,
995 ref->alternate_path,
996 reply_size - uni_curroffset,
997 STR_UNICODE);
998
999 SSVAL(pdata,offset+20,uni_curroffset-offset);
1000
1001 uni_curroffset += unilen;
1002 offset += VERSION2_REFERRAL_SIZE;
1003 }
1004 /* add in the unexplained 22 (0x16) bytes at the end */
1005 memset(pdata+uni_curroffset,'\0',0x16);
1006 return reply_size;
1007}
1008
1009static int setup_ver3_dfs_referral(const char *pathname,
1010 char **ppdata,
1011 struct junction_map *junction,
1012 int consumedcnt,
1013 bool self_referral)
1014{
1015 char *pdata = *ppdata;
1016
1017 smb_ucs2_t *uni_reqpath = NULL;
1018 int uni_reqpathoffset1, uni_reqpathoffset2;
1019 int uni_curroffset;
1020 int reply_size = 0;
1021
1022 int reqpathlen = 0;
1023 int offset,i=0;
1024
1025 DEBUG(10,("setting up version3 referral\n"));
1026
1027 reqpathlen = rpcstr_push_talloc(talloc_tos(), &uni_reqpath, pathname);
1028 if (uni_reqpath == NULL || reqpathlen == 0) {
1029 return -1;
1030 }
1031
1032 if (DEBUGLVL(10)) {
1033 dump_data(0, (unsigned char *)uni_reqpath,
1034 reqpathlen);
1035 }
1036
1037 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
1038 VERSION3_REFERRAL_SIZE * junction->referral_count;
1039 uni_reqpathoffset2 = uni_reqpathoffset1 + reqpathlen;
1040 reply_size = uni_curroffset = uni_reqpathoffset2 + reqpathlen;
1041
1042 for(i=0;i<junction->referral_count;i++) {
1043 DEBUG(10,("referral %u : %s\n",
1044 i,
1045 junction->referral_list[i].alternate_path));
1046 reply_size +=
1047 (strlen(junction->referral_list[i].alternate_path)+1)*2;
1048 }
1049
1050 pdata = (char *)SMB_REALLOC(pdata,reply_size);
1051 if(pdata == NULL) {
1052 DEBUG(0,("version3 referral setup:"
1053 "malloc failed for Realloc!\n"));
1054 return -1;
1055 }
1056 *ppdata = pdata;
1057
1058 /* create the header */
1059 SSVAL(pdata,0,consumedcnt * 2); /* path consumed */
1060 SSVAL(pdata,2,junction->referral_count); /* number of referral */
1061 if(self_referral) {
1062 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
1063 } else {
1064 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
1065 }
1066
1067 /* copy in the reqpaths */
1068 memcpy(pdata+uni_reqpathoffset1,uni_reqpath,reqpathlen);
1069 memcpy(pdata+uni_reqpathoffset2,uni_reqpath,reqpathlen);
1070
1071 offset = 8;
1072 for(i=0;i<junction->referral_count;i++) {
1073 struct referral* ref = &(junction->referral_list[i]);
1074 int unilen;
1075
1076 SSVAL(pdata,offset,3); /* version 3 */
1077 SSVAL(pdata,offset+2,VERSION3_REFERRAL_SIZE);
1078 if(self_referral) {
1079 SSVAL(pdata,offset+4,1);
1080 } else {
1081 SSVAL(pdata,offset+4,0);
1082 }
1083
1084 /* ref_flags :use path_consumed bytes? */
1085 SSVAL(pdata,offset+6,0);
1086 SIVAL(pdata,offset+8,ref->ttl);
1087
1088 SSVAL(pdata,offset+12,uni_reqpathoffset1-offset);
1089 SSVAL(pdata,offset+14,uni_reqpathoffset2-offset);
1090 /* copy referred path into current offset */
1091 unilen = rpcstr_push(pdata+uni_curroffset,ref->alternate_path,
1092 reply_size - uni_curroffset,
1093 STR_UNICODE | STR_TERMINATE);
1094 SSVAL(pdata,offset+16,uni_curroffset-offset);
1095 /* copy 0x10 bytes of 00's in the ServiceSite GUID */
1096 memset(pdata+offset+18,'\0',16);
1097
1098 uni_curroffset += unilen;
1099 offset += VERSION3_REFERRAL_SIZE;
1100 }
1101 return reply_size;
1102}
1103
1104/******************************************************************
1105 Set up the DFS referral for the dfs pathname. This call returns
1106 the amount of the path covered by this server, and where the
1107 client should be redirected to. This is the meat of the
1108 TRANS2_GET_DFS_REFERRAL call.
1109******************************************************************/
1110
1111int setup_dfs_referral(connection_struct *orig_conn,
1112 const char *dfs_path,
1113 int max_referral_level,
1114 char **ppdata, NTSTATUS *pstatus)
1115{
1116 struct junction_map *junction = NULL;
1117 int consumedcnt = 0;
1118 bool self_referral = False;
1119 int reply_size = 0;
1120 char *pathnamep = NULL;
1121 char *local_dfs_path = NULL;
1122 TALLOC_CTX *ctx;
1123
1124 if (!(ctx=talloc_init("setup_dfs_referral"))) {
1125 *pstatus = NT_STATUS_NO_MEMORY;
1126 return -1;
1127 }
1128
1129 /* get the junction entry */
1130 if (!dfs_path) {
1131 talloc_destroy(ctx);
1132 *pstatus = NT_STATUS_NOT_FOUND;
1133 return -1;
1134 }
1135
1136 /*
1137 * Trim pathname sent by client so it begins with only one backslash.
1138 * Two backslashes confuse some dfs clients
1139 */
1140
1141 local_dfs_path = talloc_strdup(ctx,dfs_path);
1142 if (!local_dfs_path) {
1143 *pstatus = NT_STATUS_NO_MEMORY;
1144 talloc_destroy(ctx);
1145 return -1;
1146 }
1147 pathnamep = local_dfs_path;
1148 while (IS_DIRECTORY_SEP(pathnamep[0]) &&
1149 IS_DIRECTORY_SEP(pathnamep[1])) {
1150 pathnamep++;
1151 }
1152
1153 junction = TALLOC_ZERO_P(ctx, struct junction_map);
1154 if (!junction) {
1155 *pstatus = NT_STATUS_NO_MEMORY;
1156 talloc_destroy(ctx);
1157 return -1;
1158 }
1159
1160 /* The following call can change cwd. */
1161 *pstatus = get_referred_path(ctx, pathnamep, junction,
1162 &consumedcnt, &self_referral);
1163 if (!NT_STATUS_IS_OK(*pstatus)) {
1164 vfs_ChDir(orig_conn,orig_conn->connectpath);
1165 talloc_destroy(ctx);
1166 return -1;
1167 }
1168 vfs_ChDir(orig_conn,orig_conn->connectpath);
1169
1170 if (!self_referral) {
1171 pathnamep[consumedcnt] = '\0';
1172
1173 if( DEBUGLVL( 3 ) ) {
1174 int i=0;
1175 dbgtext("setup_dfs_referral: Path %s to "
1176 "alternate path(s):",
1177 pathnamep);
1178 for(i=0;i<junction->referral_count;i++)
1179 dbgtext(" %s",
1180 junction->referral_list[i].alternate_path);
1181 dbgtext(".\n");
1182 }
1183 }
1184
1185 /* create the referral depeding on version */
1186 DEBUG(10,("max_referral_level :%d\n",max_referral_level));
1187
1188 if (max_referral_level < 2) {
1189 max_referral_level = 2;
1190 }
1191 if (max_referral_level > 3) {
1192 max_referral_level = 3;
1193 }
1194
1195 switch(max_referral_level) {
1196 case 2:
1197 reply_size = setup_ver2_dfs_referral(pathnamep,
1198 ppdata, junction,
1199 consumedcnt, self_referral);
1200 break;
1201 case 3:
1202 reply_size = setup_ver3_dfs_referral(pathnamep, ppdata,
1203 junction, consumedcnt, self_referral);
1204 break;
1205 default:
1206 DEBUG(0,("setup_dfs_referral: Invalid dfs referral "
1207 "version: %d\n",
1208 max_referral_level));
1209 talloc_destroy(ctx);
1210 *pstatus = NT_STATUS_INVALID_LEVEL;
1211 return -1;
1212 }
1213
1214 if (DEBUGLVL(10)) {
1215 DEBUGADD(0,("DFS Referral pdata:\n"));
1216 dump_data(0,(uint8 *)*ppdata,reply_size);
1217 }
1218
1219 talloc_destroy(ctx);
1220 *pstatus = NT_STATUS_OK;
1221 return reply_size;
1222}
1223
1224/**********************************************************************
1225 The following functions are called by the NETDFS RPC pipe functions
1226 **********************************************************************/
1227
1228/*********************************************************************
1229 Creates a junction structure from a DFS pathname
1230**********************************************************************/
1231
1232bool create_junction(TALLOC_CTX *ctx,
1233 const char *dfs_path,
1234 struct junction_map *jucn)
1235{
1236 int snum;
1237 bool dummy;
1238 struct dfs_path *pdp = TALLOC_P(ctx,struct dfs_path);
1239 NTSTATUS status;
1240
1241 if (!pdp) {
1242 return False;
1243 }
1244 status = parse_dfs_path(NULL, dfs_path, False, pdp, &dummy);
1245 if (!NT_STATUS_IS_OK(status)) {
1246 return False;
1247 }
1248
1249 /* check if path is dfs : validate first token */
1250 if (!is_myname_or_ipaddr(pdp->hostname)) {
1251 DEBUG(4,("create_junction: Invalid hostname %s "
1252 "in dfs path %s\n",
1253 pdp->hostname, dfs_path));
1254 TALLOC_FREE(pdp);
1255 return False;
1256 }
1257
1258 /* Check for a non-DFS share */
1259 snum = lp_servicenumber(pdp->servicename);
1260
1261 if(snum < 0 || !lp_msdfs_root(snum)) {
1262 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1263 pdp->servicename));
1264 TALLOC_FREE(pdp);
1265 return False;
1266 }
1267
1268 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1269 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1270 jucn->comment = talloc_strdup(ctx, lp_comment(snum));
1271
1272 TALLOC_FREE(pdp);
1273 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1274 return False;
1275 }
1276 return True;
1277}
1278
1279/**********************************************************************
1280 Forms a valid Unix pathname from the junction
1281 **********************************************************************/
1282
1283static bool junction_to_local_path(const struct junction_map *jucn,
1284 char **pp_path_out,
1285 connection_struct *conn_out)
1286{
1287 int snum;
1288
1289 snum = lp_servicenumber(jucn->service_name);
1290 if(snum < 0) {
1291 return False;
1292 }
1293 if (!NT_STATUS_IS_OK(create_conn_struct(talloc_tos(),
1294 conn_out, snum,
1295 lp_pathname(snum)))) {
1296 return False;
1297 }
1298
1299 *pp_path_out = talloc_asprintf(conn_out->mem_ctx,
1300 "%s/%s",
1301 lp_pathname(snum),
1302 jucn->volume_name);
1303 if (!*pp_path_out) {
1304 return False;
1305 }
1306 return True;
1307}
1308
1309bool create_msdfs_link(const struct junction_map *jucn)
1310{
1311 char *path = NULL;
1312 char *msdfs_link = NULL;
1313 connection_struct conns;
1314 connection_struct *conn = &conns;
1315 int i=0;
1316 bool insert_comma = False;
1317 bool ret = False;
1318
1319 ZERO_STRUCT(conns);
1320
1321 if(!junction_to_local_path(jucn, &path, conn)) {
1322 return False;
1323 }
1324
1325 /* Form the msdfs_link contents */
1326 msdfs_link = talloc_strdup(conn->mem_ctx, "msdfs:");
1327 if (!msdfs_link) {
1328 goto out;
1329 }
1330 for(i=0; i<jucn->referral_count; i++) {
1331 char *refpath = jucn->referral_list[i].alternate_path;
1332
1333 /* Alternate paths always use Windows separators. */
1334 trim_char(refpath, '\\', '\\');
1335 if(*refpath == '\0') {
1336 if (i == 0) {
1337 insert_comma = False;
1338 }
1339 continue;
1340 }
1341 if (i > 0 && insert_comma) {
1342 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1343 ",%s",
1344 refpath);
1345 } else {
1346 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1347 "%s",
1348 refpath);
1349 }
1350
1351 if (!msdfs_link) {
1352 goto out;
1353 }
1354 if (!insert_comma) {
1355 insert_comma = True;
1356 }
1357 }
1358
1359 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1360 path, msdfs_link));
1361
1362 if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1363 if (errno == EEXIST) {
1364 if(SMB_VFS_UNLINK(conn,path)!=0) {
1365 goto out;
1366 }
1367 }
1368 if (SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1369 DEBUG(1,("create_msdfs_link: symlink failed "
1370 "%s -> %s\nError: %s\n",
1371 path, msdfs_link, strerror(errno)));
1372 goto out;
1373 }
1374 }
1375
1376 ret = True;
1377
1378out:
1379
1380 conn_free_internal(conn);
1381 return ret;
1382}
1383
1384bool remove_msdfs_link(const struct junction_map *jucn)
1385{
1386 char *path = NULL;
1387 connection_struct conns;
1388 connection_struct *conn = &conns;
1389 bool ret = False;
1390
1391 ZERO_STRUCT(conns);
1392
1393 if( junction_to_local_path(jucn, &path, conn) ) {
1394 if( SMB_VFS_UNLINK(conn, path) == 0 ) {
1395 ret = True;
1396 }
1397 }
1398
1399 conn_free_internal(conn);
1400 return ret;
1401}
1402
1403/*********************************************************************
1404 Return the number of DFS links at the root of this share.
1405*********************************************************************/
1406
1407static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1408{
1409 size_t cnt = 0;
1410 SMB_STRUCT_DIR *dirp = NULL;
1411 char *dname = NULL;
1412 const char *connect_path = lp_pathname(snum);
1413 const char *msdfs_proxy = lp_msdfs_proxy(snum);
1414 connection_struct conn;
1415
1416 ZERO_STRUCT(conn);
1417
1418 if(*connect_path == '\0') {
1419 return 0;
1420 }
1421
1422 /*
1423 * Fake up a connection struct for the VFS layer.
1424 */
1425
1426 if (!NT_STATUS_IS_OK(create_conn_struct(talloc_tos(),
1427 &conn, snum, connect_path))) {
1428 return 0;
1429 }
1430
1431 /* Count a link for the msdfs root - convention */
1432 cnt = 1;
1433
1434 /* No more links if this is an msdfs proxy. */
1435 if (*msdfs_proxy != '\0') {
1436 goto out;
1437 }
1438
1439 /* Now enumerate all dfs links */
1440 dirp = SMB_VFS_OPENDIR(&conn, ".", NULL, 0);
1441 if(!dirp) {
1442 goto out;
1443 }
1444
1445 while ((dname = vfs_readdirname(&conn, dirp)) != NULL) {
1446 if (is_msdfs_link(&conn,
1447 dname,
1448 NULL)) {
1449 cnt++;
1450 }
1451 }
1452
1453 SMB_VFS_CLOSEDIR(&conn,dirp);
1454
1455out:
1456
1457 conn_free_internal(&conn);
1458 return cnt;
1459}
1460
1461/*********************************************************************
1462*********************************************************************/
1463
1464static int form_junctions(TALLOC_CTX *ctx,
1465 int snum,
1466 struct junction_map *jucn,
1467 size_t jn_remain)
1468{
1469 size_t cnt = 0;
1470 SMB_STRUCT_DIR *dirp = NULL;
1471 char *dname = NULL;
1472 const char *connect_path = lp_pathname(snum);
1473 char *service_name = lp_servicename(snum);
1474 const char *msdfs_proxy = lp_msdfs_proxy(snum);
1475 connection_struct conn;
1476 struct referral *ref = NULL;
1477
1478 ZERO_STRUCT(conn);
1479
1480 if (jn_remain == 0) {
1481 return 0;
1482 }
1483
1484 if(*connect_path == '\0') {
1485 return 0;
1486 }
1487
1488 /*
1489 * Fake up a connection struct for the VFS layer.
1490 */
1491
1492 if (!NT_STATUS_IS_OK(create_conn_struct(ctx, &conn, snum, connect_path))) {
1493 return 0;
1494 }
1495
1496 /* form a junction for the msdfs root - convention
1497 DO NOT REMOVE THIS: NT clients will not work with us
1498 if this is not present
1499 */
1500 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1501 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1502 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1503 goto out;
1504 }
1505 jucn[cnt].comment = "";
1506 jucn[cnt].referral_count = 1;
1507
1508 ref = jucn[cnt].referral_list = TALLOC_ZERO_P(ctx, struct referral);
1509 if (jucn[cnt].referral_list == NULL) {
1510 goto out;
1511 }
1512
1513 ref->proximity = 0;
1514 ref->ttl = REFERRAL_TTL;
1515 if (*msdfs_proxy != '\0') {
1516 ref->alternate_path = talloc_strdup(ctx,
1517 msdfs_proxy);
1518 } else {
1519 ref->alternate_path = talloc_asprintf(ctx,
1520 "\\\\%s\\%s",
1521 get_local_machine_name(),
1522 service_name);
1523 }
1524
1525 if (!ref->alternate_path) {
1526 goto out;
1527 }
1528 cnt++;
1529
1530 /* Don't enumerate if we're an msdfs proxy. */
1531 if (*msdfs_proxy != '\0') {
1532 goto out;
1533 }
1534
1535 /* Now enumerate all dfs links */
1536 dirp = SMB_VFS_OPENDIR(&conn, ".", NULL, 0);
1537 if(!dirp) {
1538 goto out;
1539 }
1540
1541 while ((dname = vfs_readdirname(&conn, dirp)) != NULL) {
1542 char *link_target = NULL;
1543 if (cnt >= jn_remain) {
1544 DEBUG(2, ("form_junctions: ran out of MSDFS "
1545 "junction slots"));
1546 goto out;
1547 }
1548 if (is_msdfs_link_internal(ctx,
1549 &conn,
1550 dname, &link_target,
1551 NULL)) {
1552 if (parse_msdfs_symlink(ctx,
1553 link_target,
1554 &jucn[cnt].referral_list,
1555 &jucn[cnt].referral_count)) {
1556
1557 jucn[cnt].service_name = talloc_strdup(ctx,
1558 service_name);
1559 jucn[cnt].volume_name = talloc_strdup(ctx,
1560 dname);
1561 if (!jucn[cnt].service_name ||
1562 !jucn[cnt].volume_name) {
1563 goto out;
1564 }
1565 jucn[cnt].comment = "";
1566 cnt++;
1567 }
1568 TALLOC_FREE(link_target);
1569 }
1570 }
1571
1572out:
1573
1574 if (dirp) {
1575 SMB_VFS_CLOSEDIR(&conn,dirp);
1576 }
1577
1578 conn_free_internal(&conn);
1579 return cnt;
1580}
1581
1582struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1583{
1584 struct junction_map *jn = NULL;
1585 int i=0;
1586 size_t jn_count = 0;
1587 int sharecount = 0;
1588
1589 *p_num_jn = 0;
1590 if(!lp_host_msdfs()) {
1591 return NULL;
1592 }
1593
1594 /* Ensure all the usershares are loaded. */
1595 become_root();
1596 load_registry_shares();
1597 sharecount = load_usershare_shares();
1598 unbecome_root();
1599
1600 for(i=0;i < sharecount;i++) {
1601 if(lp_msdfs_root(i)) {
1602 jn_count += count_dfs_links(ctx, i);
1603 }
1604 }
1605 if (jn_count == 0) {
1606 return NULL;
1607 }
1608 jn = TALLOC_ARRAY(ctx, struct junction_map, jn_count);
1609 if (!jn) {
1610 return NULL;
1611 }
1612 for(i=0; i < sharecount; i++) {
1613 if (*p_num_jn >= jn_count) {
1614 break;
1615 }
1616 if(lp_msdfs_root(i)) {
1617 *p_num_jn += form_junctions(ctx, i,
1618 &jn[*p_num_jn],
1619 jn_count - *p_num_jn);
1620 }
1621 }
1622 return jn;
1623}
1624
1625/******************************************************************************
1626 Core function to resolve a dfs pathname.
1627******************************************************************************/
1628
1629NTSTATUS resolve_dfspath(TALLOC_CTX *ctx,
1630 connection_struct *conn,
1631 bool dfs_pathnames,
1632 const char *name_in,
1633 char **pp_name_out)
1634{
1635 NTSTATUS status = NT_STATUS_OK;
1636 bool dummy;
1637 if (dfs_pathnames) {
1638 status = dfs_redirect(ctx,
1639 conn,
1640 name_in,
1641 False,
1642 pp_name_out,
1643 &dummy);
1644 } else {
1645 /*
1646 * Cheat and just return a copy of the in ptr.
1647 * Once srvstr_get_path() uses talloc it'll
1648 * be a talloced ptr anyway.
1649 */
1650 *pp_name_out = CONST_DISCARD(char *,name_in);
1651 }
1652 return status;
1653}
1654
1655/******************************************************************************
1656 Core function to resolve a dfs pathname possibly containing a wildcard.
1657 This function is identical to the above except for the bool param to
1658 dfs_redirect but I need this to be separate so it's really clear when
1659 we're allowing wildcards and when we're not. JRA.
1660******************************************************************************/
1661
1662NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1663 connection_struct *conn,
1664 bool dfs_pathnames,
1665 const char *name_in,
1666 char **pp_name_out,
1667 bool *ppath_contains_wcard)
1668{
1669 NTSTATUS status = NT_STATUS_OK;
1670 if (dfs_pathnames) {
1671 status = dfs_redirect(ctx,
1672 conn,
1673 name_in,
1674 True,
1675 pp_name_out,
1676 ppath_contains_wcard);
1677 } else {
1678 /*
1679 * Cheat and just return a copy of the in ptr.
1680 * Once srvstr_get_path() uses talloc it'll
1681 * be a talloced ptr anyway.
1682 */
1683 *pp_name_out = CONST_DISCARD(char *,name_in);
1684 }
1685 return status;
1686}
Note: See TracBrowser for help on using the repository browser.