Line data Source code
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 : Copyright (C) Robin McCorkell 2015
8 :
9 : This program is free software; you can redistribute it and/or modify
10 : it under the terms of the GNU General Public License as published by
11 : the Free Software Foundation; either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program. If not, see <http://www.gnu.org/licenses/>.
21 :
22 : */
23 :
24 : #define DBGC_CLASS DBGC_MSDFS
25 : #include "includes.h"
26 : #include "system/filesys.h"
27 : #include "smbd/smbd.h"
28 : #include "smbd/globals.h"
29 : #include "msdfs.h"
30 : #include "auth.h"
31 : #include "../auth/auth_util.h"
32 : #include "lib/param/loadparm.h"
33 : #include "libcli/security/security.h"
34 : #include "librpc/gen_ndr/ndr_dfsblobs.h"
35 : #include "lib/tsocket/tsocket.h"
36 : #include "lib/global_contexts.h"
37 : #include "source3/lib/substitute.h"
38 :
39 : /**********************************************************************
40 : Function to determine if a given sharename matches a connection.
41 : **********************************************************************/
42 :
43 1048 : static bool msdfs_servicename_matches_connection(struct connection_struct *conn,
44 : const char *servicename,
45 : const char *vfs_user)
46 : {
47 : const struct loadparm_substitution *lp_sub =
48 1048 : loadparm_s3_global_substitution();
49 1048 : char *conn_servicename = NULL;
50 : int snum;
51 1048 : bool match = false;
52 :
53 1048 : snum = SNUM(conn);
54 :
55 1048 : conn_servicename = lp_servicename(talloc_tos(), lp_sub, snum);
56 1048 : if (conn_servicename == NULL) {
57 0 : DBG_ERR("lp_servicename() failed, OOM!\n");
58 0 : return false;
59 : }
60 :
61 1048 : if (strequal(servicename, conn_servicename)) {
62 1048 : match = true;
63 1048 : goto done;
64 : }
65 0 : if (strequal(servicename, HOMES_NAME)) {
66 0 : match = true;
67 0 : goto done;
68 : }
69 0 : if (strequal(vfs_user, conn_servicename)) {
70 0 : match = true;
71 0 : goto done;
72 : }
73 0 : done:
74 1048 : TALLOC_FREE(conn_servicename);
75 1048 : return match;
76 : }
77 :
78 : /**********************************************************************
79 : Parse a DFS pathname of the form(s)
80 :
81 : \hostname\service - self referral
82 : \hostname\service\remainingpath - Windows referral path
83 :
84 : FIXME! Should we also parse:
85 : \hostname\service/remainingpath - POSIX referral path
86 : as currently nothing uses this ?
87 :
88 : into the dfs_path components. Strict form.
89 :
90 : Checks DFS path starts with separator.
91 : Checks hostname is ours.
92 : Ensures servicename (share) is sent, and
93 : if so, terminates the name or is followed by
94 : \pathname.
95 :
96 : If returned, remainingpath is untouched. Caller must call
97 : check_path_syntaxXXX() on it.
98 :
99 : Called by all non-fileserver processing (DFS RPC, FSCTL_DFS_GET_REFERRALS)
100 : etc. Errors out on any inconsistency in the path.
101 : **********************************************************************/
102 :
103 1661 : static NTSTATUS parse_dfs_path_strict(TALLOC_CTX *ctx,
104 : const char *pathname,
105 : char **_hostname,
106 : char **_servicename,
107 : char **_remaining_path)
108 : {
109 1661 : char *pathname_local = NULL;
110 1661 : char *p = NULL;
111 1661 : const char *hostname = NULL;
112 1661 : const char *servicename = NULL;
113 1661 : const char *reqpath = NULL;
114 1661 : bool my_hostname = false;
115 : NTSTATUS status;
116 :
117 1661 : DBG_DEBUG("path = |%s|\n", pathname);
118 :
119 1661 : pathname_local = talloc_strdup(talloc_tos(), pathname);
120 1661 : if (pathname_local == NULL) {
121 0 : return NT_STATUS_NO_MEMORY;
122 : }
123 : /*
124 : * parse_dfs_path_strict() is called from
125 : * get_referred_path() and create_junction()
126 : * which use Windows DFS paths of \server\share.
127 : */
128 :
129 : /*
130 : * Strict DFS paths *must* start with the
131 : * path separator '\\'.
132 : */
133 :
134 1661 : if (pathname_local[0] != '\\') {
135 0 : DBG_ERR("path %s doesn't start with \\\n",
136 : pathname_local);
137 0 : status = NT_STATUS_NOT_FOUND;
138 0 : goto out;
139 : }
140 :
141 : /* Now tokenize. */
142 : /* Parse out hostname. */
143 1661 : p = strchr(pathname_local + 1, '\\');
144 1661 : if (p == NULL) {
145 0 : DBG_ERR("can't parse hostname from path %s\n",
146 : pathname_local);
147 0 : status = NT_STATUS_NOT_FOUND;
148 0 : goto out;
149 : }
150 1661 : *p = '\0';
151 1661 : hostname = &pathname_local[1];
152 :
153 1661 : DBG_DEBUG("hostname: %s\n", hostname);
154 :
155 : /* Is this really our hostname ? */
156 1661 : my_hostname = is_myname_or_ipaddr(hostname);
157 1661 : if (!my_hostname) {
158 0 : DBG_ERR("Hostname %s is not ours.\n",
159 : hostname);
160 0 : status = NT_STATUS_NOT_FOUND;
161 0 : goto out;
162 : }
163 :
164 1661 : servicename = p + 1;
165 :
166 : /*
167 : * Find the end of servicename by looking for
168 : * a directory separator character. The character
169 : * should be '\\' for a Windows path.
170 : * If there is no separator, then this is a self-referral
171 : * of "\server\share".
172 : */
173 :
174 1661 : p = strchr(servicename, '\\');
175 1661 : if (p != NULL) {
176 836 : *p = '\0';
177 : }
178 :
179 1661 : DBG_DEBUG("servicename: %s\n", servicename);
180 :
181 1661 : if (p == NULL) {
182 : /* Client sent self referral "\server\share". */
183 825 : reqpath = "";
184 : } else {
185 : /* Step past the '\0' we just replaced '\\' with. */
186 836 : reqpath = p + 1;
187 : }
188 :
189 1661 : DBG_DEBUG("rest of the path: %s\n", reqpath);
190 :
191 1661 : if (_hostname != NULL) {
192 0 : *_hostname = talloc_strdup(ctx, hostname);
193 0 : if (*_hostname == NULL) {
194 0 : status = NT_STATUS_NO_MEMORY;
195 0 : goto out;
196 : }
197 : }
198 1661 : if (_servicename != NULL) {
199 1661 : *_servicename = talloc_strdup(ctx, servicename);
200 1661 : if (*_servicename == NULL) {
201 0 : status = NT_STATUS_NO_MEMORY;
202 0 : goto out;
203 : }
204 : }
205 1661 : if (_remaining_path != NULL) {
206 1661 : *_remaining_path = talloc_strdup(ctx, reqpath);
207 1661 : if (*_remaining_path == NULL) {
208 0 : status = NT_STATUS_NO_MEMORY;
209 0 : goto out;
210 : }
211 : }
212 :
213 1661 : status = NT_STATUS_OK;
214 1661 : out:
215 1661 : TALLOC_FREE(pathname_local);
216 1661 : return status;
217 : }
218 :
219 : /**********************************************************************
220 : Parse a DFS pathname of the form /hostname/service/reqpath
221 : into the dfs_path structure.
222 :
223 : NB. srvstr_get_path_internal() now *always* calls
224 : check_path_syntax_XXX() on an incoming name, so
225 : the path separator is now always '/', even from
226 : Windows clients.
227 :
228 : Unfortunately, due to broken clients who might set the
229 : SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then
230 : send a local path, we have to cope with that too....
231 :
232 : If conn != NULL then ensure the provided service is
233 : the one pointed to by the connection.
234 :
235 : This version does everything using pointers within one copy of the
236 : pathname string, talloced on the struct dfs_path pointer (which
237 : must be talloced). This may be too clever to live....
238 : JRA.
239 : **********************************************************************/
240 :
241 1048 : static NTSTATUS parse_dfs_path(TALLOC_CTX *ctx,
242 : connection_struct *conn,
243 : const char *pathname,
244 : char **_hostname,
245 : char **_servicename,
246 : char **_remaining_path)
247 : {
248 1048 : char *hostname = NULL;
249 1048 : char *pathname_local = NULL;
250 1048 : char *p = NULL;
251 1048 : char *servicename = NULL;
252 1048 : char *reqpath = NULL;
253 1048 : char *eos_ptr = NULL;
254 1048 : bool servicename_matches = false;
255 1048 : bool using_smb1 = !conn->sconn->using_smb2;
256 :
257 1048 : pathname_local = talloc_strdup(ctx, pathname);
258 1048 : if (pathname_local == NULL) {
259 0 : return NT_STATUS_NO_MEMORY;
260 : }
261 : /*
262 : * parse_dfs_path() is only called from
263 : * dfs_filename_convert() with SMB1/2/3 DFS
264 : * names. Ensure we only have to cope with
265 : * '/' separators.
266 : */
267 1048 : string_replace(pathname_local, '\\', '/');
268 :
269 : /* Get a pointer to the terminating '\0' */
270 1048 : eos_ptr = &pathname_local[strlen(pathname_local)];
271 1048 : p = pathname_local;
272 :
273 : /*
274 : * SMB1 DFS paths sent to the fileserver should start with
275 : * the path separator '/'. However, libsmbclient libraries
276 : * will set the DFS bit on SMB1 calls and then send non-DFS
277 : * paths. We must cope with this.
278 : *
279 : * Note SMB2 paths sent to the fileserver never start with
280 : * the path separator '/'.
281 : */
282 :
283 1048 : if (using_smb1 && (*p != '/')) {
284 0 : DBG_ERR("path %s doesn't start with /\n", p);
285 : /*
286 : * Possibly client sent a local path by mistake.
287 : * Try and convert to a local path.
288 : * Note that this is an SMB1-only fallback
289 : * to cope with known broken SMB1 clients.
290 : */
291 :
292 0 : hostname = eos_ptr; /* "" */
293 0 : servicename = eos_ptr; /* "" */
294 :
295 0 : DBG_ERR("trying to convert %s to a local path\n", p);
296 0 : goto local_path;
297 : }
298 :
299 : /*
300 : * Safe to use on talloc'ed string as it only shrinks.
301 : * It also doesn't affect the eos_ptr.
302 : */
303 1048 : trim_char(p, '/', '/');
304 :
305 1048 : DBG_DEBUG("p = |%s| after trimming /'s\n", p);
306 :
307 : /* Now tokenize. */
308 : /* Parse out hostname. */
309 1048 : p = strchr(p,'/');
310 1048 : if(p == NULL) {
311 0 : DBG_ERR("can't parse hostname from path %s\n", pathname_local);
312 : /*
313 : * Possibly client sent a local path by mistake.
314 : * Try and convert to a local path.
315 : */
316 :
317 0 : hostname = eos_ptr; /* "" */
318 0 : servicename = eos_ptr; /* "" */
319 :
320 0 : p = pathname_local;
321 0 : DBG_ERR("trying to convert %s to a local path\n", p);
322 0 : goto local_path;
323 : }
324 1048 : *p = '\0';
325 1048 : hostname = pathname_local;
326 :
327 1048 : DBG_DEBUG("hostname: %s\n", hostname);
328 :
329 : /* Parse out servicename. */
330 1048 : servicename = p+1;
331 1048 : p = strchr(servicename, '/');
332 1048 : if (p) {
333 964 : *p = '\0';
334 : }
335 :
336 : /* Is this really our servicename ? */
337 1048 : servicename_matches = msdfs_servicename_matches_connection(
338 : conn,
339 : servicename,
340 : get_current_username());
341 :
342 1048 : if (!servicename_matches) {
343 0 : DBG_ERR("%s is not our servicename\n", servicename);
344 :
345 : /*
346 : * Possibly client sent a local path by mistake.
347 : * Try and convert to a local path.
348 : */
349 :
350 : /* Repair the path - replace the sepchar's
351 : we nulled out */
352 0 : servicename--;
353 0 : *servicename = '/';
354 0 : if (p) {
355 0 : *p = '/';
356 : }
357 :
358 0 : hostname = eos_ptr; /* "" */
359 0 : servicename = eos_ptr; /* "" */
360 :
361 0 : p = pathname_local;
362 0 : DBG_ERR("trying to convert %s to a local path\n",
363 : pathname_local);
364 0 : goto local_path;
365 : }
366 :
367 1048 : servicename = servicename;
368 :
369 1048 : DBG_DEBUG("servicename: %s\n", servicename);
370 :
371 1048 : if(p == NULL) {
372 : /* Client sent self referral \server\share. */
373 84 : reqpath = eos_ptr; /* "" */
374 84 : goto out;
375 : }
376 :
377 964 : p++;
378 :
379 964 : local_path:
380 :
381 : /*
382 : * As check_path_syntax_XXX() has already been
383 : * called we know this is a normal path containing
384 : * '/' separators.
385 : */
386 :
387 964 : reqpath = p;
388 :
389 1048 : out:
390 :
391 1048 : DBG_DEBUG("rest of the path: %s\n", reqpath);
392 :
393 1048 : if (_hostname != NULL) {
394 0 : *_hostname = talloc_strdup(ctx, hostname);
395 0 : if (*_hostname == NULL) {
396 0 : return NT_STATUS_NO_MEMORY;
397 : }
398 : }
399 1048 : if (_servicename != NULL) {
400 0 : *_servicename = talloc_strdup(ctx, servicename);
401 0 : if (*_servicename == NULL) {
402 0 : return NT_STATUS_NO_MEMORY;
403 : }
404 : }
405 1048 : if (_remaining_path != NULL) {
406 1048 : *_remaining_path = talloc_strdup(ctx, reqpath);
407 1048 : if (*_remaining_path == NULL) {
408 0 : return NT_STATUS_NO_MEMORY;
409 : }
410 : }
411 1048 : TALLOC_FREE(pathname_local);
412 1048 : return NT_STATUS_OK;
413 : }
414 :
415 : /********************************************************
416 : Fake up a connection struct for the VFS layer, for use in
417 : applications (such as the python bindings), that do not want the
418 : global working directory changed under them.
419 :
420 : SMB_VFS_CONNECT requires root privileges.
421 : *********************************************************/
422 :
423 2355 : static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx,
424 : struct tevent_context *ev,
425 : struct messaging_context *msg,
426 : connection_struct **pconn,
427 : int snum,
428 : const char *path,
429 : const struct auth_session_info *session_info)
430 : {
431 : connection_struct *conn;
432 : char *connpath;
433 : const char *vfs_user;
434 : struct smbd_server_connection *sconn;
435 2355 : const char *servicename = lp_const_servicename(snum);
436 : bool ok;
437 :
438 2355 : sconn = talloc_zero(ctx, struct smbd_server_connection);
439 2355 : if (sconn == NULL) {
440 0 : return NT_STATUS_NO_MEMORY;
441 : }
442 :
443 2355 : sconn->ev_ctx = ev;
444 2355 : sconn->msg_ctx = msg;
445 :
446 2355 : conn = conn_new(sconn);
447 2355 : if (conn == NULL) {
448 0 : TALLOC_FREE(sconn);
449 0 : return NT_STATUS_NO_MEMORY;
450 : }
451 :
452 : /* Now we have conn, we need to make sconn a child of conn,
453 : * for a proper talloc tree */
454 2355 : talloc_steal(conn, sconn);
455 :
456 2355 : if (snum == -1 && servicename == NULL) {
457 378 : servicename = "Unknown Service (snum == -1)";
458 : }
459 :
460 2355 : connpath = talloc_strdup(conn, path);
461 2355 : if (!connpath) {
462 0 : TALLOC_FREE(conn);
463 0 : return NT_STATUS_NO_MEMORY;
464 : }
465 2355 : connpath = talloc_string_sub(conn,
466 : connpath,
467 : "%S",
468 : servicename);
469 2355 : if (!connpath) {
470 0 : TALLOC_FREE(conn);
471 0 : return NT_STATUS_NO_MEMORY;
472 : }
473 :
474 : /* needed for smbd_vfs_init() */
475 :
476 2355 : conn->params->service = snum;
477 2355 : conn->cnum = TID_FIELD_INVALID;
478 :
479 2355 : SMB_ASSERT(session_info != NULL);
480 :
481 2355 : conn->session_info = copy_session_info(conn, session_info);
482 2355 : if (conn->session_info == NULL) {
483 0 : DBG_ERR("copy_serverinfo failed\n");
484 0 : TALLOC_FREE(conn);
485 0 : return NT_STATUS_NO_MEMORY;
486 : }
487 :
488 : /* unix_info could be NULL in session_info */
489 2355 : if (conn->session_info->unix_info != NULL) {
490 2355 : vfs_user = conn->session_info->unix_info->unix_name;
491 : } else {
492 0 : vfs_user = get_current_username();
493 : }
494 :
495 2355 : conn_setup_case_options(conn);
496 :
497 2355 : set_conn_connectpath(conn, connpath);
498 :
499 : /*
500 : * New code to check if there's a share security descriptor
501 : * added from NT server manager. This is done after the
502 : * smb.conf checks are done as we need a uid and token. JRA.
503 : *
504 : */
505 2355 : share_access_check(conn->session_info->security_token,
506 : servicename,
507 : MAXIMUM_ALLOWED_ACCESS,
508 2355 : &conn->share_access);
509 :
510 2355 : if ((conn->share_access & FILE_WRITE_DATA) == 0) {
511 0 : if ((conn->share_access & FILE_READ_DATA) == 0) {
512 : /* No access, read or write. */
513 0 : DBG_WARNING("connection to %s "
514 : "denied due to security "
515 : "descriptor.\n",
516 : servicename);
517 0 : conn_free(conn);
518 0 : return NT_STATUS_ACCESS_DENIED;
519 : }
520 0 : conn->read_only = true;
521 : }
522 :
523 2355 : if (!smbd_vfs_init(conn)) {
524 0 : NTSTATUS status = map_nt_error_from_unix(errno);
525 0 : DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
526 0 : conn_free(conn);
527 0 : return status;
528 : }
529 :
530 : /* this must be the first filesystem operation that we do */
531 2355 : if (SMB_VFS_CONNECT(conn, servicename, vfs_user) < 0) {
532 0 : DEBUG(0,("VFS connect failed!\n"));
533 0 : conn_free(conn);
534 0 : return NT_STATUS_UNSUCCESSFUL;
535 : }
536 :
537 2355 : ok = canonicalize_connect_path(conn);
538 2355 : if (!ok) {
539 0 : DBG_ERR("Failed to canonicalize sharepath\n");
540 0 : conn_free(conn);
541 0 : return NT_STATUS_ACCESS_DENIED;
542 : }
543 :
544 2355 : conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
545 2355 : conn->tcon_done = true;
546 2355 : *pconn = talloc_move(ctx, &conn);
547 :
548 2355 : return NT_STATUS_OK;
549 : }
550 :
551 2355 : static int conn_struct_tos_destructor(struct conn_struct_tos *c)
552 : {
553 2355 : if (c->oldcwd_fname != NULL) {
554 836 : vfs_ChDir(c->conn, c->oldcwd_fname);
555 836 : TALLOC_FREE(c->oldcwd_fname);
556 : }
557 2355 : SMB_VFS_DISCONNECT(c->conn);
558 2355 : conn_free(c->conn);
559 2355 : return 0;
560 : }
561 :
562 : /********************************************************
563 : Fake up a connection struct for the VFS layer, for use in
564 : applications (such as the python bindings), that do not want the
565 : global working directory changed under them.
566 :
567 : SMB_VFS_CONNECT requires root privileges.
568 : This temporary uses become_root() and unbecome_root().
569 :
570 : But further impersonation has to be cone by the caller.
571 : *********************************************************/
572 2355 : NTSTATUS create_conn_struct_tos(struct messaging_context *msg,
573 : int snum,
574 : const char *path,
575 : const struct auth_session_info *session_info,
576 : struct conn_struct_tos **_c)
577 : {
578 2355 : struct conn_struct_tos *c = NULL;
579 2355 : struct tevent_context *ev = NULL;
580 : NTSTATUS status;
581 :
582 2355 : *_c = NULL;
583 :
584 2355 : c = talloc_zero(talloc_tos(), struct conn_struct_tos);
585 2355 : if (c == NULL) {
586 0 : return NT_STATUS_NO_MEMORY;
587 : }
588 :
589 2355 : ev = samba_tevent_context_init(c);
590 2355 : if (ev == NULL) {
591 0 : TALLOC_FREE(c);
592 0 : return NT_STATUS_NO_MEMORY;
593 : }
594 :
595 2355 : become_root();
596 2355 : status = create_conn_struct_as_root(c,
597 : ev,
598 : msg,
599 2355 : &c->conn,
600 : snum,
601 : path,
602 : session_info);
603 2355 : unbecome_root();
604 2355 : if (!NT_STATUS_IS_OK(status)) {
605 0 : TALLOC_FREE(c);
606 0 : return status;
607 : }
608 :
609 2355 : talloc_set_destructor(c, conn_struct_tos_destructor);
610 :
611 2355 : *_c = c;
612 2355 : return NT_STATUS_OK;
613 : }
614 :
615 : /********************************************************
616 : Fake up a connection struct for the VFS layer.
617 : Note: this performs a vfs connect and CHANGES CWD !!!! JRA.
618 :
619 : See also the comment for create_conn_struct_tos() above!
620 :
621 : The CWD change is reverted by the destructor of
622 : conn_struct_tos when the current talloc_tos() is destroyed.
623 : *********************************************************/
624 836 : NTSTATUS create_conn_struct_tos_cwd(struct messaging_context *msg,
625 : int snum,
626 : const char *path,
627 : const struct auth_session_info *session_info,
628 : struct conn_struct_tos **_c)
629 : {
630 836 : struct conn_struct_tos *c = NULL;
631 836 : struct smb_filename smb_fname_connectpath = {0};
632 : NTSTATUS status;
633 :
634 836 : *_c = NULL;
635 :
636 836 : status = create_conn_struct_tos(msg,
637 : snum,
638 : path,
639 : session_info,
640 : &c);
641 836 : if (!NT_STATUS_IS_OK(status)) {
642 0 : return status;
643 : }
644 :
645 : /*
646 : * Windows seems to insist on doing trans2getdfsreferral() calls on
647 : * the IPC$ share as the anonymous user. If we try to chdir as that
648 : * user we will fail.... WTF ? JRA.
649 : */
650 :
651 836 : c->oldcwd_fname = vfs_GetWd(c, c->conn);
652 836 : if (c->oldcwd_fname == NULL) {
653 0 : status = map_nt_error_from_unix(errno);
654 0 : DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno)));
655 0 : TALLOC_FREE(c);
656 0 : return status;
657 : }
658 :
659 836 : smb_fname_connectpath = (struct smb_filename) {
660 836 : .base_name = c->conn->connectpath
661 : };
662 :
663 836 : if (vfs_ChDir(c->conn, &smb_fname_connectpath) != 0) {
664 0 : status = map_nt_error_from_unix(errno);
665 0 : DBG_NOTICE("Can't ChDir to new conn path %s. "
666 : "Error was %s\n",
667 : c->conn->connectpath, strerror(errno));
668 0 : TALLOC_FREE(c->oldcwd_fname);
669 0 : TALLOC_FREE(c);
670 0 : return status;
671 : }
672 :
673 836 : *_c = c;
674 836 : return NT_STATUS_OK;
675 : }
676 :
677 : /********************************************************
678 : Fake up a connection struct for the VFS layer.
679 : This takes an TALLOC_CTX and tevent_context from the
680 : caller and the resulting connection_struct is stable
681 : across the lifetime of mem_ctx and ev.
682 :
683 : Note: this performs a vfs connect and changes cwd.
684 :
685 : See also the comment for create_conn_struct_tos() above!
686 : *********************************************************/
687 :
688 0 : NTSTATUS create_conn_struct_cwd(TALLOC_CTX *mem_ctx,
689 : struct tevent_context *ev,
690 : struct messaging_context *msg,
691 : const struct auth_session_info *session_info,
692 : int snum,
693 : const char *path,
694 : struct connection_struct **c)
695 : {
696 : NTSTATUS status;
697 :
698 0 : become_root();
699 0 : status = create_conn_struct_as_root(mem_ctx,
700 : ev,
701 : msg,
702 : c,
703 : snum,
704 : path,
705 : session_info);
706 0 : unbecome_root();
707 0 : return status;
708 : }
709 :
710 442 : static void shuffle_strlist(char **list, int count)
711 : {
712 : int i;
713 : uint32_t r;
714 : char *tmp;
715 :
716 868 : for (i = count; i > 1; i--) {
717 426 : r = generate_random() % i;
718 :
719 426 : tmp = list[i-1];
720 426 : list[i-1] = list[r];
721 426 : list[r] = tmp;
722 : }
723 442 : }
724 :
725 : /**********************************************************************
726 : Parse the contents of a symlink to verify if it is an msdfs referral
727 : A valid referral is of the form:
728 :
729 : msdfs:server1\share1,server2\share2
730 : msdfs:server1\share1\pathname,server2\share2\pathname
731 : msdfs:server1/share1,server2/share2
732 : msdfs:server1/share1/pathname,server2/share2/pathname.
733 :
734 : Note that the alternate paths returned here must be of the canonicalized
735 : form:
736 :
737 : \server\share or
738 : \server\share\path\to\file,
739 :
740 : even in posix path mode. This is because we have no knowledge if the
741 : server we're referring to understands posix paths.
742 : **********************************************************************/
743 :
744 836 : bool parse_msdfs_symlink(TALLOC_CTX *ctx,
745 : bool shuffle_referrals,
746 : const char *target,
747 : struct referral **ppreflist,
748 : size_t *prefcount)
749 : {
750 836 : char *temp = NULL;
751 : char *prot;
752 836 : char **alt_path = NULL;
753 836 : size_t count = 0, i;
754 836 : struct referral *reflist = NULL;
755 : char *saveptr;
756 :
757 836 : temp = talloc_strdup(ctx, target);
758 836 : if (!temp) {
759 0 : return false;
760 : }
761 836 : prot = strtok_r(temp, ":", &saveptr);
762 836 : if (!prot) {
763 0 : DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
764 0 : TALLOC_FREE(temp);
765 0 : return false;
766 : }
767 :
768 836 : alt_path = talloc_array(ctx, char *, MAX_REFERRAL_COUNT);
769 836 : if (!alt_path) {
770 0 : TALLOC_FREE(temp);
771 0 : return false;
772 : }
773 :
774 : /* parse out the alternate paths */
775 2492 : while((count<MAX_REFERRAL_COUNT) &&
776 2492 : ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
777 1656 : count++;
778 : }
779 :
780 : /* shuffle alternate paths */
781 836 : if (shuffle_referrals) {
782 442 : shuffle_strlist(alt_path, count);
783 : }
784 :
785 836 : DBG_DEBUG("count=%zu\n", count);
786 :
787 836 : if (count) {
788 836 : reflist = talloc_zero_array(ctx,
789 : struct referral, count);
790 836 : if(reflist == NULL) {
791 0 : TALLOC_FREE(temp);
792 0 : TALLOC_FREE(alt_path);
793 0 : return false;
794 : }
795 : } else {
796 0 : reflist = NULL;
797 : }
798 :
799 2492 : for(i=0;i<count;i++) {
800 : char *p;
801 :
802 : /* Canonicalize link target.
803 : * Replace all /'s in the path by a \ */
804 1656 : string_replace(alt_path[i], '/', '\\');
805 :
806 : /* Remove leading '\\'s */
807 1656 : p = alt_path[i];
808 1656 : while (*p && (*p == '\\')) {
809 0 : p++;
810 : }
811 :
812 1656 : reflist[i].alternate_path = talloc_asprintf(reflist,
813 : "\\%s",
814 : p);
815 1656 : if (!reflist[i].alternate_path) {
816 0 : TALLOC_FREE(temp);
817 0 : TALLOC_FREE(alt_path);
818 0 : TALLOC_FREE(reflist);
819 0 : return false;
820 : }
821 :
822 1656 : reflist[i].proximity = 0;
823 1656 : reflist[i].ttl = REFERRAL_TTL;
824 1656 : DBG_DEBUG("Created alt path: %s\n",
825 : reflist[i].alternate_path);
826 : }
827 :
828 836 : if (ppreflist != NULL) {
829 836 : *ppreflist = reflist;
830 : } else {
831 0 : TALLOC_FREE(reflist);
832 : }
833 836 : if (prefcount != NULL) {
834 836 : *prefcount = count;
835 : }
836 836 : TALLOC_FREE(temp);
837 836 : TALLOC_FREE(alt_path);
838 836 : return true;
839 : }
840 :
841 : /**********************************************************************
842 : Returns true if the unix path is a valid msdfs symlink.
843 : **********************************************************************/
844 :
845 10398 : bool is_msdfs_link(struct files_struct *dirfsp,
846 : struct smb_filename *atname)
847 : {
848 10398 : NTSTATUS status = SMB_VFS_READ_DFS_PATHAT(dirfsp->conn,
849 : talloc_tos(),
850 : dirfsp,
851 : atname,
852 : NULL,
853 : NULL);
854 10398 : return (NT_STATUS_IS_OK(status));
855 : }
856 :
857 : /*****************************************************************
858 : Used by other functions to decide if a dfs path is remote,
859 : and to get the list of referred locations for that remote path.
860 :
861 : consumedcntp: how much of the dfs path is being redirected. the client
862 : should try the remaining path on the redirected server.
863 : *****************************************************************/
864 :
865 836 : static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
866 : connection_struct *conn,
867 : const char *dfspath, /* Incoming complete dfs path */
868 : const char *reqpath, /* Parsed out remaining path. */
869 : uint32_t ucf_flags,
870 : size_t *consumedcntp,
871 : struct referral **ppreflist,
872 : size_t *preferral_count)
873 : {
874 : NTSTATUS status;
875 836 : struct smb_filename *parent_smb_fname = NULL;
876 836 : struct smb_filename *smb_fname_rel = NULL;
877 836 : NTTIME twrp = 0;
878 836 : char *local_pathname = NULL;
879 836 : char *last_component = NULL;
880 836 : char *atname = NULL;
881 836 : size_t removed_components = 0;
882 836 : bool posix = (ucf_flags & UCF_POSIX_PATHNAMES);
883 836 : char *p = NULL;
884 836 : char *canon_dfspath = NULL;
885 :
886 836 : DBG_DEBUG("Conn path = %s reqpath = %s\n", conn->connectpath, reqpath);
887 :
888 836 : local_pathname = talloc_strdup(ctx, reqpath);
889 836 : if (local_pathname == NULL) {
890 0 : status = NT_STATUS_NO_MEMORY;
891 0 : goto out;
892 : }
893 :
894 : /* We know reqpath isn't a DFS path. */
895 836 : ucf_flags &= ~UCF_DFS_PATHNAME;
896 :
897 836 : if (ucf_flags & UCF_GMT_PATHNAME) {
898 0 : extract_snapshot_token(local_pathname, &twrp);
899 0 : ucf_flags &= ~UCF_GMT_PATHNAME;
900 : }
901 :
902 : /*
903 : * We should have been given a DFS path to resolve.
904 : * This should return NT_STATUS_PATH_NOT_COVERED.
905 : *
906 : * Do a pathname walk, stripping off components
907 : * until we get NT_STATUS_OK instead of
908 : * NT_STATUS_PATH_NOT_COVERED.
909 : *
910 : * Fail on any other error.
911 : */
912 :
913 9506 : for (;;) {
914 10342 : TALLOC_CTX *frame = NULL;
915 10342 : struct files_struct *dirfsp = NULL;
916 10342 : struct smb_filename *smb_fname_walk = NULL;
917 :
918 10342 : TALLOC_FREE(parent_smb_fname);
919 :
920 : /*
921 : * Use a local stackframe as filename_convert_dirfsp()
922 : * opens handles on the last two components in the path.
923 : * Allow these to be freed as we step back through
924 : * the local_pathname.
925 : */
926 10342 : frame = talloc_stackframe();
927 10342 : status = filename_convert_dirfsp(frame,
928 : conn,
929 : local_pathname,
930 : ucf_flags,
931 : twrp,
932 : &dirfsp,
933 : &smb_fname_walk);
934 : /* If we got a name, save it. */
935 10342 : if (smb_fname_walk != NULL) {
936 836 : parent_smb_fname = talloc_move(ctx, &smb_fname_walk);
937 : }
938 10342 : TALLOC_FREE(frame);
939 :
940 10342 : if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
941 : /*
942 : * For any other status than NT_STATUS_PATH_NOT_COVERED
943 : * (including NT_STATUS_OK) we exit the walk.
944 : * If it's an error we catch it outside the loop.
945 : */
946 836 : break;
947 : }
948 :
949 : /* Step back one component and save it off as last_component. */
950 9506 : TALLOC_FREE(last_component);
951 9506 : p = strrchr(local_pathname, '/');
952 9506 : if (p == NULL) {
953 : /*
954 : * We removed all components.
955 : * Go around once more to make
956 : * sure we can open the root '\0'.
957 : */
958 820 : last_component = talloc_strdup(ctx, local_pathname);
959 820 : *local_pathname = '\0';
960 : } else {
961 8686 : last_component = talloc_strdup(ctx, p+1);
962 8686 : *p = '\0';
963 : }
964 9506 : if (last_component == NULL) {
965 0 : status = NT_STATUS_NO_MEMORY;
966 0 : goto out;
967 : }
968 : /* Integer wrap check. */
969 9506 : if (removed_components + 1 < removed_components) {
970 0 : status = NT_STATUS_INVALID_PARAMETER;
971 0 : goto out;
972 : }
973 9506 : removed_components++;
974 : }
975 :
976 836 : if (!NT_STATUS_IS_OK(status)) {
977 0 : DBG_DEBUG("dfspath = %s. reqpath = %s. Error %s.\n",
978 : dfspath,
979 : reqpath,
980 : nt_errstr(status));
981 0 : goto out;
982 : }
983 :
984 836 : if (parent_smb_fname->fsp == NULL) {
985 : /* Unable to open parent. */
986 0 : DBG_DEBUG("dfspath = %s. reqpath = %s. "
987 : "Unable to open parent directory (%s).\n",
988 : dfspath,
989 : reqpath,
990 : smb_fname_str_dbg(parent_smb_fname));
991 0 : status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
992 0 : goto out;
993 : }
994 :
995 836 : if (removed_components == 0) {
996 : /*
997 : * We never got NT_STATUS_PATH_NOT_COVERED.
998 : * There was no DFS redirect.
999 : */
1000 0 : DBG_DEBUG("dfspath = %s. reqpath = %s. "
1001 : "No removed components.\n",
1002 : dfspath,
1003 : reqpath);
1004 0 : status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1005 0 : goto out;
1006 : }
1007 :
1008 : /*
1009 : * One of the removed_components was the MSDFS link
1010 : * at the end. We need to count this in the resolved
1011 : * path below, so remove one from removed_components.
1012 : */
1013 836 : removed_components--;
1014 :
1015 : /*
1016 : * Now parent_smb_fname->fsp is the parent directory dirfsp,
1017 : * last_component is the untranslated MS-DFS link name.
1018 : * Search for it in the parent directory to get the real
1019 : * filename on disk.
1020 : */
1021 836 : status = get_real_filename_at(parent_smb_fname->fsp,
1022 : last_component,
1023 : ctx,
1024 : &atname);
1025 :
1026 836 : if (!NT_STATUS_IS_OK(status)) {
1027 0 : DBG_DEBUG("dfspath = %s. reqpath = %s "
1028 : "get_real_filename_at(%s, %s) error (%s)\n",
1029 : dfspath,
1030 : reqpath,
1031 : smb_fname_str_dbg(parent_smb_fname),
1032 : last_component,
1033 : nt_errstr(status));
1034 0 : goto out;
1035 : }
1036 :
1037 836 : smb_fname_rel = synthetic_smb_fname(ctx,
1038 : atname,
1039 : NULL,
1040 : NULL,
1041 : twrp,
1042 : posix ? SMB_FILENAME_POSIX_PATH : 0);
1043 836 : if (smb_fname_rel == NULL) {
1044 0 : status = NT_STATUS_NO_MEMORY;
1045 0 : goto out;
1046 : }
1047 :
1048 : /* Get the referral to return. */
1049 836 : status = SMB_VFS_READ_DFS_PATHAT(conn,
1050 : ctx,
1051 : parent_smb_fname->fsp,
1052 : smb_fname_rel,
1053 : ppreflist,
1054 : preferral_count);
1055 836 : if (!NT_STATUS_IS_OK(status)) {
1056 0 : DBG_DEBUG("dfspath = %s. reqpath = %s. "
1057 : "SMB_VFS_READ_DFS_PATHAT(%s, %s) error (%s)\n",
1058 : dfspath,
1059 : reqpath,
1060 : smb_fname_str_dbg(parent_smb_fname),
1061 : smb_fname_str_dbg(smb_fname_rel),
1062 : nt_errstr(status));
1063 0 : goto out;
1064 : }
1065 :
1066 : /*
1067 : * Now we must work out how much of the
1068 : * given pathname we consumed.
1069 : */
1070 836 : canon_dfspath = talloc_strdup(ctx, dfspath);
1071 836 : if (!canon_dfspath) {
1072 0 : status = NT_STATUS_NO_MEMORY;
1073 0 : goto out;
1074 : }
1075 : /* Canonicalize the raw dfspath. */
1076 836 : string_replace(canon_dfspath, '\\', '/');
1077 :
1078 : /*
1079 : * reqpath comes out of parse_dfs_path(), so it has
1080 : * no trailing backslash. Make sure that canon_dfspath hasn't either.
1081 : */
1082 836 : trim_char(canon_dfspath, 0, '/');
1083 :
1084 836 : DBG_DEBUG("Unconsumed path: %s\n", canon_dfspath);
1085 :
1086 9506 : while (removed_components > 0) {
1087 8670 : p = strrchr(canon_dfspath, '/');
1088 8670 : if (p != NULL) {
1089 8670 : *p = '\0';
1090 : }
1091 8670 : removed_components--;
1092 8670 : if (p == NULL && removed_components != 0) {
1093 0 : DBG_ERR("Component mismatch. path = %s, "
1094 : "%zu components left\n",
1095 : canon_dfspath,
1096 : removed_components);
1097 0 : status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1098 0 : goto out;
1099 : }
1100 : }
1101 836 : *consumedcntp = strlen(canon_dfspath);
1102 836 : DBG_DEBUG("Path consumed: %s (%zu)\n", canon_dfspath, *consumedcntp);
1103 836 : status = NT_STATUS_OK;
1104 :
1105 836 : out:
1106 :
1107 836 : TALLOC_FREE(parent_smb_fname);
1108 836 : TALLOC_FREE(local_pathname);
1109 836 : TALLOC_FREE(last_component);
1110 836 : TALLOC_FREE(atname);
1111 836 : TALLOC_FREE(smb_fname_rel);
1112 836 : TALLOC_FREE(canon_dfspath);
1113 836 : return status;
1114 : }
1115 :
1116 : /*****************************************************************
1117 : Decides if a dfs pathname should be redirected or not.
1118 : If not, the pathname is converted to a tcon-relative local unix path
1119 : This is now a simple wrapper around parse_dfs_path()
1120 : as it does all the required checks.
1121 : *****************************************************************/
1122 :
1123 1048 : NTSTATUS dfs_filename_convert(TALLOC_CTX *ctx,
1124 : connection_struct *conn,
1125 : uint32_t ucf_flags,
1126 : const char *dfs_path_in,
1127 : char **pp_path_out)
1128 : {
1129 1048 : char *reqpath = NULL;
1130 : NTSTATUS status;
1131 :
1132 : /*
1133 : * We must use the non-strict version of parse_dfs_path for
1134 : * pathnames sent to the fileserver over SMB1/2/3.
1135 : * libsmbclient callers always set the FLAGS2_DFS_PATHNAMES
1136 : * but then don't send a DFS path in (for example) FindFirst
1137 : * or other calls. This is a problem with our client libraries
1138 : * for both SMB1 and SMB2+ and will remain so whilst broken
1139 : * versions of libsmbclient are being used.
1140 : */
1141 :
1142 1048 : status = parse_dfs_path(ctx,
1143 : conn,
1144 : dfs_path_in,
1145 : NULL, /* hostname */
1146 : NULL, /* servicename */
1147 : &reqpath);
1148 1048 : if (!NT_STATUS_IS_OK(status)) {
1149 0 : return status;
1150 : }
1151 :
1152 : /*
1153 : * If parse_dfs_path fell back to a local path
1154 : * after skipping hostname or servicename, ensure
1155 : * we still have called check_path_syntax()
1156 : * on the full returned local path. check_path_syntax()
1157 : * is idempotent so this is safe.
1158 : */
1159 1048 : if (ucf_flags & UCF_POSIX_PATHNAMES) {
1160 0 : status = check_path_syntax_posix(reqpath);
1161 : } else {
1162 1048 : status = check_path_syntax(reqpath);
1163 : }
1164 1048 : if (!NT_STATUS_IS_OK(status)) {
1165 0 : return status;
1166 : }
1167 : /*
1168 : * Previous (and current logic) just ignores
1169 : * the server, share components if a DFS
1170 : * path is sent on a non-DFS share except to
1171 : * check that they match an existing share. Should
1172 : * we tighten this up to return an error here ?
1173 : */
1174 1048 : *pp_path_out = reqpath;
1175 1048 : return NT_STATUS_OK;
1176 : }
1177 :
1178 : /**********************************************************************
1179 : Return a self referral.
1180 : **********************************************************************/
1181 :
1182 44 : static NTSTATUS self_ref(TALLOC_CTX *ctx,
1183 : const char *dfs_path,
1184 : struct junction_map *jucn,
1185 : size_t *consumedcntp,
1186 : bool *self_referralp)
1187 : {
1188 : struct referral *ref;
1189 :
1190 44 : *self_referralp = True;
1191 :
1192 44 : jucn->referral_count = 1;
1193 44 : if((ref = talloc_zero(ctx, struct referral)) == NULL) {
1194 0 : return NT_STATUS_NO_MEMORY;
1195 : }
1196 :
1197 44 : ref->alternate_path = talloc_strdup(ctx, dfs_path);
1198 44 : if (!ref->alternate_path) {
1199 0 : TALLOC_FREE(ref);
1200 0 : return NT_STATUS_NO_MEMORY;
1201 : }
1202 44 : ref->proximity = 0;
1203 44 : ref->ttl = REFERRAL_TTL;
1204 44 : jucn->referral_list = ref;
1205 44 : *consumedcntp = strlen(dfs_path);
1206 44 : return NT_STATUS_OK;
1207 : }
1208 :
1209 : /**********************************************************************
1210 : Gets valid referrals for a dfs path and fills up the
1211 : junction_map structure.
1212 : **********************************************************************/
1213 :
1214 1661 : NTSTATUS get_referred_path(TALLOC_CTX *ctx,
1215 : struct auth_session_info *session_info,
1216 : const char *dfs_path,
1217 : const struct tsocket_address *remote_address,
1218 : const struct tsocket_address *local_address,
1219 : struct junction_map *jucn,
1220 : size_t *consumedcntp,
1221 : bool *self_referralp)
1222 : {
1223 1661 : TALLOC_CTX *frame = talloc_stackframe();
1224 : const struct loadparm_substitution *lp_sub =
1225 1661 : loadparm_s3_global_substitution();
1226 1661 : struct conn_struct_tos *c = NULL;
1227 1661 : struct connection_struct *conn = NULL;
1228 1661 : char *servicename = NULL;
1229 1661 : char *reqpath = NULL;
1230 : int snum;
1231 1661 : NTSTATUS status = NT_STATUS_NOT_FOUND;
1232 :
1233 1661 : *self_referralp = False;
1234 :
1235 1661 : status = parse_dfs_path_strict(
1236 : frame,
1237 : dfs_path,
1238 : NULL, /* hostname */
1239 : &servicename,
1240 : &reqpath);
1241 1661 : if (!NT_STATUS_IS_OK(status)) {
1242 0 : TALLOC_FREE(frame);
1243 0 : return status;
1244 : }
1245 :
1246 : /* Path referrals are always non-POSIX. */
1247 1661 : status = check_path_syntax(reqpath);
1248 1661 : if (!NT_STATUS_IS_OK(status)) {
1249 0 : TALLOC_FREE(frame);
1250 0 : return status;
1251 : }
1252 :
1253 1661 : jucn->service_name = talloc_strdup(ctx, servicename);
1254 1661 : jucn->volume_name = talloc_strdup(ctx, reqpath);
1255 1661 : if (!jucn->service_name || !jucn->volume_name) {
1256 0 : TALLOC_FREE(frame);
1257 0 : return NT_STATUS_NO_MEMORY;
1258 : }
1259 :
1260 : /* Verify the share is a dfs root */
1261 1661 : snum = lp_servicenumber(jucn->service_name);
1262 1661 : if(snum < 0) {
1263 2 : char *service_name = NULL;
1264 2 : if ((snum = find_service(ctx, jucn->service_name, &service_name)) < 0) {
1265 2 : TALLOC_FREE(frame);
1266 2 : return NT_STATUS_NOT_FOUND;
1267 : }
1268 0 : if (!service_name) {
1269 0 : TALLOC_FREE(frame);
1270 0 : return NT_STATUS_NO_MEMORY;
1271 : }
1272 0 : TALLOC_FREE(jucn->service_name);
1273 0 : jucn->service_name = talloc_strdup(ctx, service_name);
1274 0 : if (!jucn->service_name) {
1275 0 : TALLOC_FREE(frame);
1276 0 : return NT_STATUS_NO_MEMORY;
1277 : }
1278 : }
1279 :
1280 1659 : if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(talloc_tos(), lp_sub, snum) == '\0')) {
1281 779 : DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
1282 : "a dfs root.\n",
1283 : servicename, dfs_path));
1284 779 : TALLOC_FREE(frame);
1285 779 : return NT_STATUS_NOT_FOUND;
1286 : }
1287 :
1288 : /*
1289 : * Self referrals are tested with a anonymous IPC connection and
1290 : * a GET_DFS_REFERRAL call to \\server\share. (which means
1291 : * dp.reqpath[0] points to an empty string). create_conn_struct cd's
1292 : * into the directory and will fail if it cannot (as the anonymous
1293 : * user). Cope with this.
1294 : */
1295 :
1296 880 : if (reqpath[0] == '\0') {
1297 : char *tmp;
1298 : struct referral *ref;
1299 : size_t refcount;
1300 :
1301 44 : if (*lp_msdfs_proxy(talloc_tos(), lp_sub, snum) == '\0') {
1302 44 : TALLOC_FREE(frame);
1303 44 : return self_ref(ctx,
1304 : dfs_path,
1305 : jucn,
1306 : consumedcntp,
1307 : self_referralp);
1308 : }
1309 :
1310 : /*
1311 : * It's an msdfs proxy share. Redirect to
1312 : * the configured target share.
1313 : */
1314 :
1315 0 : tmp = talloc_asprintf(frame, "msdfs:%s",
1316 : lp_msdfs_proxy(frame, lp_sub, snum));
1317 0 : if (tmp == NULL) {
1318 0 : TALLOC_FREE(frame);
1319 0 : return NT_STATUS_NO_MEMORY;
1320 : }
1321 :
1322 0 : if (!parse_msdfs_symlink(ctx,
1323 0 : lp_msdfs_shuffle_referrals(snum),
1324 : tmp,
1325 : &ref,
1326 : &refcount)) {
1327 0 : TALLOC_FREE(frame);
1328 0 : return NT_STATUS_INVALID_PARAMETER;
1329 : }
1330 0 : jucn->referral_count = refcount;
1331 0 : jucn->referral_list = ref;
1332 0 : *consumedcntp = strlen(dfs_path);
1333 0 : TALLOC_FREE(frame);
1334 0 : return NT_STATUS_OK;
1335 : }
1336 :
1337 836 : status = create_conn_struct_tos_cwd(global_messaging_context(),
1338 : snum,
1339 836 : lp_path(frame, lp_sub, snum),
1340 : session_info,
1341 : &c);
1342 836 : if (!NT_STATUS_IS_OK(status)) {
1343 0 : TALLOC_FREE(frame);
1344 0 : return status;
1345 : }
1346 836 : conn = c->conn;
1347 :
1348 : /*
1349 : * TODO
1350 : *
1351 : * The remote and local address should be passed down to
1352 : * create_conn_struct_cwd.
1353 : */
1354 836 : if (conn->sconn->remote_address == NULL) {
1355 1672 : conn->sconn->remote_address =
1356 836 : tsocket_address_copy(remote_address, conn->sconn);
1357 836 : if (conn->sconn->remote_address == NULL) {
1358 0 : TALLOC_FREE(frame);
1359 0 : return NT_STATUS_NO_MEMORY;
1360 : }
1361 : }
1362 836 : if (conn->sconn->local_address == NULL) {
1363 1672 : conn->sconn->local_address =
1364 836 : tsocket_address_copy(local_address, conn->sconn);
1365 836 : if (conn->sconn->local_address == NULL) {
1366 0 : TALLOC_FREE(frame);
1367 0 : return NT_STATUS_NO_MEMORY;
1368 : }
1369 : }
1370 :
1371 836 : status = dfs_path_lookup(ctx,
1372 : conn,
1373 : dfs_path,
1374 : reqpath,
1375 : 0, /* ucf_flags */
1376 : consumedcntp,
1377 : &jucn->referral_list,
1378 : &jucn->referral_count);
1379 :
1380 836 : if (!NT_STATUS_IS_OK(status)) {
1381 0 : DBG_NOTICE("No valid referrals for path %s (%s)\n",
1382 : dfs_path,
1383 : nt_errstr(status));
1384 : }
1385 :
1386 836 : TALLOC_FREE(frame);
1387 836 : return status;
1388 : }
1389 :
1390 : /******************************************************************
1391 : Set up the DFS referral for the dfs pathname. This call returns
1392 : the amount of the path covered by this server, and where the
1393 : client should be redirected to. This is the meat of the
1394 : TRANS2_GET_DFS_REFERRAL call.
1395 : ******************************************************************/
1396 :
1397 1661 : int setup_dfs_referral(connection_struct *orig_conn,
1398 : const char *dfs_path,
1399 : int max_referral_level,
1400 : char **ppdata, NTSTATUS *pstatus)
1401 : {
1402 1661 : char *pdata = *ppdata;
1403 1661 : int reply_size = 0;
1404 : struct dfs_GetDFSReferral *r;
1405 1661 : DATA_BLOB blob = data_blob_null;
1406 : NTSTATUS status;
1407 : enum ndr_err_code ndr_err;
1408 :
1409 1661 : r = talloc_zero(talloc_tos(), struct dfs_GetDFSReferral);
1410 1661 : if (r == NULL) {
1411 0 : *pstatus = NT_STATUS_NO_MEMORY;
1412 0 : return -1;
1413 : }
1414 :
1415 1661 : r->in.req.max_referral_level = max_referral_level;
1416 1661 : r->in.req.servername = talloc_strdup(r, dfs_path);
1417 1661 : if (r->in.req.servername == NULL) {
1418 0 : talloc_free(r);
1419 0 : *pstatus = NT_STATUS_NO_MEMORY;
1420 0 : return -1;
1421 : }
1422 :
1423 1661 : status = SMB_VFS_GET_DFS_REFERRALS(orig_conn, r);
1424 1661 : if (!NT_STATUS_IS_OK(status)) {
1425 781 : talloc_free(r);
1426 781 : *pstatus = status;
1427 781 : return -1;
1428 : }
1429 :
1430 880 : ndr_err = ndr_push_struct_blob(&blob, r,
1431 880 : r->out.resp,
1432 : (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1433 880 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1434 0 : TALLOC_FREE(r);
1435 0 : *pstatus = NT_STATUS_INVALID_PARAMETER;
1436 0 : return -1;
1437 : }
1438 :
1439 880 : pdata = (char *)SMB_REALLOC(pdata, blob.length);
1440 880 : if(pdata == NULL) {
1441 0 : TALLOC_FREE(r);
1442 0 : DEBUG(0,("referral setup:"
1443 : "malloc failed for Realloc!\n"));
1444 0 : return -1;
1445 : }
1446 880 : *ppdata = pdata;
1447 880 : reply_size = blob.length;
1448 880 : memcpy(pdata, blob.data, blob.length);
1449 880 : TALLOC_FREE(r);
1450 :
1451 880 : *pstatus = NT_STATUS_OK;
1452 880 : return reply_size;
1453 : }
1454 :
1455 : /**********************************************************************
1456 : The following functions are called by the NETDFS RPC pipe functions
1457 : **********************************************************************/
1458 :
1459 : /*********************************************************************
1460 : Creates a junction structure from a DFS pathname
1461 : **********************************************************************/
1462 :
1463 0 : bool create_junction(TALLOC_CTX *ctx,
1464 : const char *dfs_path,
1465 : struct junction_map *jucn)
1466 : {
1467 : const struct loadparm_substitution *lp_sub =
1468 0 : loadparm_s3_global_substitution();
1469 : int snum;
1470 0 : char *servicename = NULL;
1471 0 : char *reqpath = NULL;
1472 : NTSTATUS status;
1473 :
1474 0 : status = parse_dfs_path_strict(
1475 : ctx,
1476 : dfs_path,
1477 : NULL,
1478 : &servicename,
1479 : &reqpath);
1480 0 : if (!NT_STATUS_IS_OK(status)) {
1481 0 : return False;
1482 : }
1483 :
1484 : /* Check for a non-DFS share */
1485 0 : snum = lp_servicenumber(servicename);
1486 :
1487 0 : if(snum < 0 || !lp_msdfs_root(snum)) {
1488 0 : DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1489 : servicename));
1490 0 : return False;
1491 : }
1492 :
1493 : /* Junction create paths are always non-POSIX. */
1494 0 : status = check_path_syntax(reqpath);
1495 0 : if (!NT_STATUS_IS_OK(status)) {
1496 0 : return false;
1497 : }
1498 :
1499 0 : jucn->service_name = talloc_strdup(ctx, servicename);
1500 0 : jucn->volume_name = talloc_strdup(ctx, reqpath);
1501 0 : jucn->comment = lp_comment(ctx, lp_sub, snum);
1502 :
1503 0 : if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1504 0 : return False;
1505 : }
1506 0 : return True;
1507 : }
1508 :
1509 : /**********************************************************************
1510 : Forms a valid Unix pathname from the junction
1511 : **********************************************************************/
1512 :
1513 0 : static bool junction_to_local_path_tos(const struct junction_map *jucn,
1514 : struct auth_session_info *session_info,
1515 : char **pp_path_out,
1516 : connection_struct **conn_out)
1517 : {
1518 : const struct loadparm_substitution *lp_sub =
1519 0 : loadparm_s3_global_substitution();
1520 0 : struct conn_struct_tos *c = NULL;
1521 : int snum;
1522 0 : char *path_out = NULL;
1523 : NTSTATUS status;
1524 :
1525 0 : snum = lp_servicenumber(jucn->service_name);
1526 0 : if(snum < 0) {
1527 0 : return False;
1528 : }
1529 0 : status = create_conn_struct_tos_cwd(global_messaging_context(),
1530 : snum,
1531 0 : lp_path(talloc_tos(), lp_sub, snum),
1532 : session_info,
1533 : &c);
1534 0 : if (!NT_STATUS_IS_OK(status)) {
1535 0 : return False;
1536 : }
1537 :
1538 0 : path_out = talloc_asprintf(c,
1539 : "%s/%s",
1540 : lp_path(talloc_tos(), lp_sub, snum),
1541 0 : jucn->volume_name);
1542 0 : if (path_out == NULL) {
1543 0 : TALLOC_FREE(c);
1544 0 : return False;
1545 : }
1546 0 : *pp_path_out = path_out;
1547 0 : *conn_out = c->conn;
1548 0 : return True;
1549 : }
1550 :
1551 : /*
1552 : * Create a msdfs string in Samba format we can store
1553 : * in a filesystem object (currently a symlink).
1554 : */
1555 :
1556 0 : char *msdfs_link_string(TALLOC_CTX *ctx,
1557 : const struct referral *reflist,
1558 : size_t referral_count)
1559 : {
1560 0 : char *refpath = NULL;
1561 0 : bool insert_comma = false;
1562 0 : char *msdfs_link = NULL;
1563 : size_t i;
1564 :
1565 : /* Form the msdfs_link contents */
1566 0 : msdfs_link = talloc_strdup(ctx, "msdfs:");
1567 0 : if (msdfs_link == NULL) {
1568 0 : goto err;
1569 : }
1570 :
1571 0 : for( i= 0; i < referral_count; i++) {
1572 0 : refpath = talloc_strdup(ctx, reflist[i].alternate_path);
1573 :
1574 0 : if (refpath == NULL) {
1575 0 : goto err;
1576 : }
1577 :
1578 : /* Alternate paths always use Windows separators. */
1579 0 : trim_char(refpath, '\\', '\\');
1580 0 : if (*refpath == '\0') {
1581 0 : if (i == 0) {
1582 0 : insert_comma = false;
1583 : }
1584 0 : continue;
1585 : }
1586 0 : if (i > 0 && insert_comma) {
1587 0 : msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1588 : ",%s",
1589 : refpath);
1590 : } else {
1591 0 : msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1592 : "%s",
1593 : refpath);
1594 : }
1595 :
1596 0 : if (msdfs_link == NULL) {
1597 0 : goto err;
1598 : }
1599 :
1600 0 : if (!insert_comma) {
1601 0 : insert_comma = true;
1602 : }
1603 :
1604 0 : TALLOC_FREE(refpath);
1605 : }
1606 :
1607 0 : return msdfs_link;
1608 :
1609 0 : err:
1610 :
1611 0 : TALLOC_FREE(refpath);
1612 0 : TALLOC_FREE(msdfs_link);
1613 0 : return NULL;
1614 : }
1615 :
1616 0 : bool create_msdfs_link(const struct junction_map *jucn,
1617 : struct auth_session_info *session_info)
1618 : {
1619 0 : TALLOC_CTX *frame = talloc_stackframe();
1620 0 : char *path = NULL;
1621 : connection_struct *conn;
1622 0 : struct smb_filename *smb_fname = NULL;
1623 0 : struct smb_filename *parent_fname = NULL;
1624 0 : struct smb_filename *at_fname = NULL;
1625 : bool ok;
1626 : NTSTATUS status;
1627 0 : bool ret = false;
1628 :
1629 0 : ok = junction_to_local_path_tos(jucn, session_info, &path, &conn);
1630 0 : if (!ok) {
1631 0 : goto out;
1632 : }
1633 :
1634 0 : if (!CAN_WRITE(conn)) {
1635 : const struct loadparm_substitution *lp_sub =
1636 0 : loadparm_s3_global_substitution();
1637 0 : int snum = lp_servicenumber(jucn->service_name);
1638 :
1639 0 : DBG_WARNING("Can't create DFS entry on read-only share %s\n",
1640 : lp_servicename(frame, lp_sub, snum));
1641 0 : goto out;
1642 : }
1643 :
1644 0 : smb_fname = synthetic_smb_fname(frame,
1645 : path,
1646 : NULL,
1647 : NULL,
1648 : 0,
1649 : 0);
1650 0 : if (smb_fname == NULL) {
1651 0 : goto out;
1652 : }
1653 :
1654 0 : status = parent_pathref(frame,
1655 0 : conn->cwd_fsp,
1656 : smb_fname,
1657 : &parent_fname,
1658 : &at_fname);
1659 0 : if (!NT_STATUS_IS_OK(status)) {
1660 0 : goto out;
1661 : }
1662 :
1663 0 : status = SMB_VFS_CREATE_DFS_PATHAT(conn,
1664 : parent_fname->fsp,
1665 : at_fname,
1666 : jucn->referral_list,
1667 : jucn->referral_count);
1668 0 : if (!NT_STATUS_IS_OK(status)) {
1669 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1670 0 : int retval = SMB_VFS_UNLINKAT(conn,
1671 : parent_fname->fsp,
1672 : at_fname,
1673 : 0);
1674 0 : if (retval != 0) {
1675 0 : goto out;
1676 : }
1677 : }
1678 0 : status = SMB_VFS_CREATE_DFS_PATHAT(conn,
1679 : parent_fname->fsp,
1680 : at_fname,
1681 : jucn->referral_list,
1682 : jucn->referral_count);
1683 0 : if (!NT_STATUS_IS_OK(status)) {
1684 0 : DBG_WARNING("SMB_VFS_CREATE_DFS_PATHAT failed "
1685 : "%s - Error: %s\n",
1686 : path,
1687 : nt_errstr(status));
1688 0 : goto out;
1689 : }
1690 : }
1691 :
1692 0 : ret = true;
1693 :
1694 0 : out:
1695 0 : TALLOC_FREE(frame);
1696 0 : return ret;
1697 : }
1698 :
1699 0 : bool remove_msdfs_link(const struct junction_map *jucn,
1700 : struct auth_session_info *session_info)
1701 : {
1702 0 : TALLOC_CTX *frame = talloc_stackframe();
1703 0 : char *path = NULL;
1704 : connection_struct *conn;
1705 0 : bool ret = False;
1706 : struct smb_filename *smb_fname;
1707 0 : struct smb_filename *parent_fname = NULL;
1708 0 : struct smb_filename *at_fname = NULL;
1709 : NTSTATUS status;
1710 : bool ok;
1711 : int retval;
1712 :
1713 0 : ok = junction_to_local_path_tos(jucn, session_info, &path, &conn);
1714 0 : if (!ok) {
1715 0 : TALLOC_FREE(frame);
1716 0 : return false;
1717 : }
1718 :
1719 0 : if (!CAN_WRITE(conn)) {
1720 : const struct loadparm_substitution *lp_sub =
1721 0 : loadparm_s3_global_substitution();
1722 0 : int snum = lp_servicenumber(jucn->service_name);
1723 :
1724 0 : DBG_WARNING("Can't remove DFS entry on read-only share %s\n",
1725 : lp_servicename(frame, lp_sub, snum));
1726 0 : TALLOC_FREE(frame);
1727 0 : return false;
1728 : }
1729 :
1730 0 : smb_fname = synthetic_smb_fname(frame,
1731 : path,
1732 : NULL,
1733 : NULL,
1734 : 0,
1735 : 0);
1736 0 : if (smb_fname == NULL) {
1737 0 : TALLOC_FREE(frame);
1738 0 : errno = ENOMEM;
1739 0 : return false;
1740 : }
1741 :
1742 0 : status = parent_pathref(frame,
1743 0 : conn->cwd_fsp,
1744 : smb_fname,
1745 : &parent_fname,
1746 : &at_fname);
1747 0 : if (!NT_STATUS_IS_OK(status)) {
1748 0 : TALLOC_FREE(frame);
1749 0 : return false;
1750 : }
1751 :
1752 0 : retval = SMB_VFS_UNLINKAT(conn,
1753 : parent_fname->fsp,
1754 : at_fname,
1755 : 0);
1756 0 : if (retval == 0) {
1757 0 : ret = True;
1758 : }
1759 :
1760 0 : TALLOC_FREE(frame);
1761 0 : return ret;
1762 : }
1763 :
1764 : /*********************************************************************
1765 : Return the number of DFS links at the root of this share.
1766 : *********************************************************************/
1767 :
1768 0 : static size_t count_dfs_links(TALLOC_CTX *ctx,
1769 : struct auth_session_info *session_info,
1770 : int snum)
1771 : {
1772 0 : TALLOC_CTX *frame = talloc_stackframe();
1773 : const struct loadparm_substitution *lp_sub =
1774 0 : loadparm_s3_global_substitution();
1775 0 : size_t cnt = 0;
1776 0 : const char *dname = NULL;
1777 0 : char *talloced = NULL;
1778 0 : const char *connect_path = lp_path(frame, lp_sub, snum);
1779 0 : const char *msdfs_proxy = lp_msdfs_proxy(frame, lp_sub, snum);
1780 0 : struct conn_struct_tos *c = NULL;
1781 0 : connection_struct *conn = NULL;
1782 : NTSTATUS status;
1783 0 : struct smb_filename *smb_fname = NULL;
1784 0 : struct smb_Dir *dir_hnd = NULL;
1785 0 : long offset = 0;
1786 :
1787 0 : if(*connect_path == '\0') {
1788 0 : TALLOC_FREE(frame);
1789 0 : return 0;
1790 : }
1791 :
1792 : /*
1793 : * Fake up a connection struct for the VFS layer.
1794 : */
1795 :
1796 0 : status = create_conn_struct_tos_cwd(global_messaging_context(),
1797 : snum,
1798 : connect_path,
1799 : session_info,
1800 : &c);
1801 0 : if (!NT_STATUS_IS_OK(status)) {
1802 0 : DEBUG(3, ("create_conn_struct failed: %s\n",
1803 : nt_errstr(status)));
1804 0 : TALLOC_FREE(frame);
1805 0 : return 0;
1806 : }
1807 0 : conn = c->conn;
1808 :
1809 : /* Count a link for the msdfs root - convention */
1810 0 : cnt = 1;
1811 :
1812 : /* No more links if this is an msdfs proxy. */
1813 0 : if (*msdfs_proxy != '\0') {
1814 0 : goto out;
1815 : }
1816 :
1817 0 : smb_fname = synthetic_smb_fname(frame,
1818 : ".",
1819 : NULL,
1820 : NULL,
1821 : 0,
1822 : 0);
1823 0 : if (smb_fname == NULL) {
1824 0 : goto out;
1825 : }
1826 :
1827 : /* Now enumerate all dfs links */
1828 0 : status = OpenDir(frame,
1829 : conn,
1830 : smb_fname,
1831 : NULL,
1832 : 0,
1833 : &dir_hnd);
1834 0 : if (!NT_STATUS_IS_OK(status)) {
1835 0 : errno = map_errno_from_nt_status(status);
1836 0 : goto out;
1837 : }
1838 :
1839 0 : while ((dname = ReadDirName(dir_hnd, &offset, NULL, &talloced))
1840 0 : != NULL)
1841 : {
1842 : struct smb_filename *smb_dname =
1843 0 : synthetic_smb_fname(frame,
1844 : dname,
1845 : NULL,
1846 : NULL,
1847 : 0,
1848 : 0);
1849 0 : if (smb_dname == NULL) {
1850 0 : goto out;
1851 : }
1852 0 : if (is_msdfs_link(dir_hnd_fetch_fsp(dir_hnd), smb_dname)) {
1853 0 : if (cnt + 1 < cnt) {
1854 0 : cnt = 0;
1855 0 : goto out;
1856 : }
1857 0 : cnt++;
1858 : }
1859 0 : TALLOC_FREE(talloced);
1860 0 : TALLOC_FREE(smb_dname);
1861 : }
1862 :
1863 0 : out:
1864 0 : TALLOC_FREE(frame);
1865 0 : return cnt;
1866 : }
1867 :
1868 : /*********************************************************************
1869 : *********************************************************************/
1870 :
1871 0 : static int form_junctions(TALLOC_CTX *ctx,
1872 : struct auth_session_info *session_info,
1873 : int snum,
1874 : struct junction_map *jucn,
1875 : size_t jn_remain)
1876 : {
1877 0 : TALLOC_CTX *frame = talloc_stackframe();
1878 : const struct loadparm_substitution *lp_sub =
1879 0 : loadparm_s3_global_substitution();
1880 0 : size_t cnt = 0;
1881 0 : const char *dname = NULL;
1882 0 : char *talloced = NULL;
1883 0 : const char *connect_path = lp_path(frame, lp_sub, snum);
1884 0 : char *service_name = lp_servicename(frame, lp_sub, snum);
1885 0 : const char *msdfs_proxy = lp_msdfs_proxy(frame, lp_sub, snum);
1886 0 : struct conn_struct_tos *c = NULL;
1887 0 : connection_struct *conn = NULL;
1888 0 : struct referral *ref = NULL;
1889 0 : struct smb_filename *smb_fname = NULL;
1890 0 : struct smb_Dir *dir_hnd = NULL;
1891 0 : long offset = 0;
1892 : NTSTATUS status;
1893 :
1894 0 : if (jn_remain == 0) {
1895 0 : TALLOC_FREE(frame);
1896 0 : return 0;
1897 : }
1898 :
1899 0 : if(*connect_path == '\0') {
1900 0 : TALLOC_FREE(frame);
1901 0 : return 0;
1902 : }
1903 :
1904 : /*
1905 : * Fake up a connection struct for the VFS layer.
1906 : */
1907 :
1908 0 : status = create_conn_struct_tos_cwd(global_messaging_context(),
1909 : snum,
1910 : connect_path,
1911 : session_info,
1912 : &c);
1913 0 : if (!NT_STATUS_IS_OK(status)) {
1914 0 : DEBUG(3, ("create_conn_struct failed: %s\n",
1915 : nt_errstr(status)));
1916 0 : TALLOC_FREE(frame);
1917 0 : return 0;
1918 : }
1919 0 : conn = c->conn;
1920 :
1921 : /* form a junction for the msdfs root - convention
1922 : DO NOT REMOVE THIS: NT clients will not work with us
1923 : if this is not present
1924 : */
1925 0 : jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1926 0 : jucn[cnt].volume_name = talloc_strdup(ctx, "");
1927 0 : if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1928 0 : goto out;
1929 : }
1930 0 : jucn[cnt].comment = "";
1931 0 : jucn[cnt].referral_count = 1;
1932 :
1933 0 : ref = jucn[cnt].referral_list = talloc_zero(ctx, struct referral);
1934 0 : if (jucn[cnt].referral_list == NULL) {
1935 0 : goto out;
1936 : }
1937 :
1938 0 : ref->proximity = 0;
1939 0 : ref->ttl = REFERRAL_TTL;
1940 0 : if (*msdfs_proxy != '\0') {
1941 0 : ref->alternate_path = talloc_strdup(ctx,
1942 : msdfs_proxy);
1943 : } else {
1944 0 : ref->alternate_path = talloc_asprintf(ctx,
1945 : "\\\\%s\\%s",
1946 : get_local_machine_name(),
1947 : service_name);
1948 : }
1949 :
1950 0 : if (!ref->alternate_path) {
1951 0 : goto out;
1952 : }
1953 0 : cnt++;
1954 :
1955 : /* Don't enumerate if we're an msdfs proxy. */
1956 0 : if (*msdfs_proxy != '\0') {
1957 0 : goto out;
1958 : }
1959 :
1960 0 : smb_fname = synthetic_smb_fname(frame,
1961 : ".",
1962 : NULL,
1963 : NULL,
1964 : 0,
1965 : 0);
1966 0 : if (smb_fname == NULL) {
1967 0 : goto out;
1968 : }
1969 :
1970 : /* Now enumerate all dfs links */
1971 0 : status = OpenDir(frame,
1972 : conn,
1973 : smb_fname,
1974 : NULL,
1975 : 0,
1976 : &dir_hnd);
1977 0 : if (!NT_STATUS_IS_OK(status)) {
1978 0 : errno = map_errno_from_nt_status(status);
1979 0 : goto out;
1980 : }
1981 :
1982 0 : while ((dname = ReadDirName(dir_hnd, &offset, NULL, &talloced))
1983 0 : != NULL)
1984 : {
1985 0 : struct smb_filename *smb_dname = NULL;
1986 :
1987 0 : if (cnt >= jn_remain) {
1988 0 : DEBUG(2, ("form_junctions: ran out of MSDFS "
1989 : "junction slots"));
1990 0 : TALLOC_FREE(talloced);
1991 0 : goto out;
1992 : }
1993 0 : smb_dname = synthetic_smb_fname(talloc_tos(),
1994 : dname,
1995 : NULL,
1996 : NULL,
1997 : 0,
1998 : 0);
1999 0 : if (smb_dname == NULL) {
2000 0 : TALLOC_FREE(talloced);
2001 0 : goto out;
2002 : }
2003 :
2004 0 : status = SMB_VFS_READ_DFS_PATHAT(conn,
2005 : ctx,
2006 : conn->cwd_fsp,
2007 : smb_dname,
2008 : &jucn[cnt].referral_list,
2009 : &jucn[cnt].referral_count);
2010 :
2011 0 : if (NT_STATUS_IS_OK(status)) {
2012 0 : jucn[cnt].service_name = talloc_strdup(ctx,
2013 : service_name);
2014 0 : jucn[cnt].volume_name = talloc_strdup(ctx, dname);
2015 0 : if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
2016 0 : TALLOC_FREE(talloced);
2017 0 : goto out;
2018 : }
2019 0 : jucn[cnt].comment = "";
2020 0 : cnt++;
2021 : }
2022 0 : TALLOC_FREE(talloced);
2023 0 : TALLOC_FREE(smb_dname);
2024 : }
2025 :
2026 0 : out:
2027 0 : TALLOC_FREE(frame);
2028 0 : return cnt;
2029 : }
2030 :
2031 0 : struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx,
2032 : struct auth_session_info *session_info,
2033 : size_t *p_num_jn)
2034 : {
2035 0 : struct junction_map *jn = NULL;
2036 0 : int i=0;
2037 0 : size_t jn_count = 0;
2038 0 : int sharecount = 0;
2039 :
2040 0 : *p_num_jn = 0;
2041 0 : if(!lp_host_msdfs()) {
2042 0 : return NULL;
2043 : }
2044 :
2045 : /* Ensure all the usershares are loaded. */
2046 0 : become_root();
2047 0 : load_registry_shares();
2048 0 : sharecount = load_usershare_shares(NULL, connections_snum_used);
2049 0 : unbecome_root();
2050 :
2051 0 : for(i=0;i < sharecount;i++) {
2052 0 : if(lp_msdfs_root(i)) {
2053 0 : jn_count += count_dfs_links(ctx, session_info, i);
2054 : }
2055 : }
2056 0 : if (jn_count == 0) {
2057 0 : return NULL;
2058 : }
2059 0 : jn = talloc_array(ctx, struct junction_map, jn_count);
2060 0 : if (!jn) {
2061 0 : return NULL;
2062 : }
2063 0 : for(i=0; i < sharecount; i++) {
2064 0 : if (*p_num_jn >= jn_count) {
2065 0 : break;
2066 : }
2067 0 : if(lp_msdfs_root(i)) {
2068 0 : *p_num_jn += form_junctions(ctx,
2069 : session_info,
2070 : i,
2071 0 : &jn[*p_num_jn],
2072 0 : jn_count - *p_num_jn);
2073 : }
2074 : }
2075 0 : return jn;
2076 : }
|