2 * Expand msdfs targets based on client IP
4 * Copyright (C) Volker Lendecke, 2004
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "system/filesys.h"
22 #include "smbd/smbd.h"
23 #include "../librpc/gen_ndr/ndr_netlogon.h"
24 #include "smbd/globals.h"
26 #include "../lib/tsocket/tsocket.h"
28 #include "source3/lib/substitute.h"
31 #define DBGC_CLASS DBGC_VFS
33 /**********************************************************
34 Under mapfile we expect a table of the following format:
36 IP-Prefix whitespace expansion
39 192.168.234 local.samba.org
40 192.168 remote.samba.org
43 This is to redirect a DFS client to a host close to it.
44 ***********************************************************/
46 static char *read_target_host(TALLOC_CTX
*ctx
, const char *mapfile
,
47 const char *clientaddr
)
54 f
= fopen(mapfile
, "r");
57 DEBUG(0,("can't open IP map %s. Error %s\n",
58 mapfile
, strerror(errno
) ));
62 DEBUG(10, ("Scanning mapfile [%s]\n", mapfile
));
64 while (fgets(buf
, sizeof(buf
), f
) != NULL
) {
66 if ((strlen(buf
) > 0) && (buf
[strlen(buf
)-1] == '\n'))
67 buf
[strlen(buf
)-1] = '\0';
69 DEBUG(10, ("Scanning line [%s]\n", buf
));
71 space
= strchr_m(buf
, ' ');
74 DEBUG(0, ("Ignoring invalid line %s\n", buf
));
80 if (strncmp(clientaddr
, buf
, strlen(buf
)) == 0) {
94 while (isspace(*space
))
97 return talloc_strdup(ctx
, space
);
100 /**********************************************************
102 Expand the msdfs target host using read_target_host
103 explained above. The syntax used in the msdfs link is
105 msdfs:@table-filename@/share
107 Everything between and including the two @-signs is
108 replaced by the substitution string found in the table
111 ***********************************************************/
113 static char *expand_msdfs_target(TALLOC_CTX
*ctx
,
114 connection_struct
*conn
,
117 const struct loadparm_substitution
*lp_sub
=
118 loadparm_s3_global_substitution();
119 char *mapfilename
= NULL
;
120 char *filename_start
= strchr_m(target
, '@');
121 char *filename_end
= NULL
;
122 int filename_len
= 0;
123 char *targethost
= NULL
;
124 char *new_target
= NULL
;
127 if (filename_start
== NULL
) {
128 DEBUG(10, ("No filename start in %s\n", target
));
132 filename_end
= strchr_m(filename_start
+1, '@');
134 if (filename_end
== NULL
) {
135 DEBUG(10, ("No filename end in %s\n", target
));
139 filename_len
= PTR_DIFF(filename_end
, filename_start
+1);
140 mapfilename
= talloc_strdup(ctx
, filename_start
+1);
144 mapfilename
[filename_len
] = '\0';
147 * dfs links returned have had '/' characters replaced with '\'.
148 * Return them to '/' so we can have absolute path mapfilenames.
150 string_replace(mapfilename
, '\\', '/');
152 DEBUG(10, ("Expanding from table [%s]\n", mapfilename
));
154 raddr
= tsocket_address_inet_addr_string(conn
->sconn
->remote_address
,
160 targethost
= read_target_host(ctx
, mapfilename
, raddr
);
161 if (targethost
== NULL
) {
162 DEBUG(1, ("Could not expand target host from file %s\n",
167 targethost
= talloc_sub_full(ctx
,
168 lp_servicename(talloc_tos(), lp_sub
, SNUM(conn
)),
169 conn
->session_info
->unix_info
->unix_name
,
171 conn
->session_info
->unix_token
->gid
,
172 conn
->session_info
->unix_info
->sanitized_username
,
173 conn
->session_info
->info
->domain_name
,
176 DEBUG(10, ("Expanded targethost to %s\n", targethost
));
178 /* Replace the part between '@...@' */
179 *filename_start
= '\0';
180 new_target
= talloc_asprintf(ctx
,
189 DEBUG(10, ("New DFS target: %s\n", new_target
));
193 static NTSTATUS
expand_read_dfs_pathat(struct vfs_handle_struct
*handle
,
195 struct files_struct
*dirfsp
,
196 struct smb_filename
*smb_fname
,
197 struct referral
**ppreflist
,
198 size_t *preferral_count
)
202 struct referral
*reflist
= NULL
;
204 TALLOC_CTX
*frame
= talloc_stackframe();
207 * Always call the NEXT function first, then
208 * modify the return if needed.
210 status
= SMB_VFS_NEXT_READ_DFS_PATHAT(handle
,
217 if (!NT_STATUS_IS_OK(status
)) {
223 * This function can be called to check if a pathname
224 * is an MSDFS link, but not return the values of it.
225 * In this case ppreflist and preferral_count are NULL,
226 * so don't bother trying to look at any returns.
228 if (ppreflist
== NULL
|| preferral_count
== NULL
) {
234 * We are always returning the values returned
235 * returned by the NEXT call, but we might mess
236 * with the reflist[i].alternate_path values,
237 * so use local pointers to minimise indirections.
239 count
= *preferral_count
;
240 reflist
= *ppreflist
;
242 for (i
= 0; i
< count
; i
++) {
243 if (strchr_m(reflist
[i
].alternate_path
, '@') != NULL
) {
244 char *new_altpath
= expand_msdfs_target(frame
,
246 reflist
[i
].alternate_path
);
247 if (new_altpath
== NULL
) {
248 TALLOC_FREE(*ppreflist
);
249 *preferral_count
= 0;
251 return NT_STATUS_NO_MEMORY
;
253 reflist
[i
].alternate_path
= talloc_move(reflist
,
261 static struct vfs_fn_pointers vfs_expand_msdfs_fns
= {
262 .read_dfs_pathat_fn
= expand_read_dfs_pathat
,
266 NTSTATUS
vfs_expand_msdfs_init(TALLOC_CTX
*ctx
)
268 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION
, "expand_msdfs",
269 &vfs_expand_msdfs_fns
);