Line data Source code
1 : /*
2 : * Expand msdfs targets based on client IP
3 : *
4 : * Copyright (C) Volker Lendecke, 2004
5 : *
6 : * This program is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU General Public License as published by
8 : * the Free Software Foundation; either version 3 of the License, or
9 : * (at your option) any later version.
10 : *
11 : * This program is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License
17 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "includes.h"
21 : #include "system/filesys.h"
22 : #include "smbd/smbd.h"
23 : #include "../librpc/gen_ndr/ndr_netlogon.h"
24 : #include "smbd/globals.h"
25 : #include "auth.h"
26 : #include "../lib/tsocket/tsocket.h"
27 : #include "msdfs.h"
28 : #include "source3/lib/substitute.h"
29 :
30 : #undef DBGC_CLASS
31 : #define DBGC_CLASS DBGC_VFS
32 :
33 : /**********************************************************
34 : Under mapfile we expect a table of the following format:
35 :
36 : IP-Prefix whitespace expansion
37 :
38 : For example:
39 : 192.168.234 local.samba.org
40 : 192.168 remote.samba.org
41 : default.samba.org
42 :
43 : This is to redirect a DFS client to a host close to it.
44 : ***********************************************************/
45 :
46 0 : static char *read_target_host(TALLOC_CTX *ctx, const char *mapfile,
47 : const char *clientaddr)
48 : {
49 : FILE *f;
50 : char buf[1024];
51 0 : char *space = buf;
52 0 : bool found = false;
53 :
54 0 : f = fopen(mapfile, "r");
55 :
56 0 : if (f == NULL) {
57 0 : DEBUG(0,("can't open IP map %s. Error %s\n",
58 : mapfile, strerror(errno) ));
59 0 : return NULL;
60 : }
61 :
62 0 : DEBUG(10, ("Scanning mapfile [%s]\n", mapfile));
63 :
64 0 : while (fgets(buf, sizeof(buf), f) != NULL) {
65 :
66 0 : if ((strlen(buf) > 0) && (buf[strlen(buf)-1] == '\n'))
67 0 : buf[strlen(buf)-1] = '\0';
68 :
69 0 : DEBUG(10, ("Scanning line [%s]\n", buf));
70 :
71 0 : space = strchr_m(buf, ' ');
72 :
73 0 : if (space == NULL) {
74 0 : DEBUG(0, ("Ignoring invalid line %s\n", buf));
75 0 : continue;
76 : }
77 :
78 0 : *space = '\0';
79 :
80 0 : if (strncmp(clientaddr, buf, strlen(buf)) == 0) {
81 0 : found = true;
82 0 : break;
83 : }
84 : }
85 :
86 0 : fclose(f);
87 :
88 0 : if (!found) {
89 0 : return NULL;
90 : }
91 :
92 0 : space += 1;
93 :
94 0 : while (isspace(*space))
95 0 : space += 1;
96 :
97 0 : return talloc_strdup(ctx, space);
98 : }
99 :
100 : /**********************************************************
101 :
102 : Expand the msdfs target host using read_target_host
103 : explained above. The syntax used in the msdfs link is
104 :
105 : msdfs:@table-filename@/share
106 :
107 : Everything between and including the two @-signs is
108 : replaced by the substitution string found in the table
109 : described above.
110 :
111 : ***********************************************************/
112 :
113 0 : static char *expand_msdfs_target(TALLOC_CTX *ctx,
114 : connection_struct *conn,
115 : char *target)
116 : {
117 : const struct loadparm_substitution *lp_sub =
118 0 : loadparm_s3_global_substitution();
119 0 : char *mapfilename = NULL;
120 0 : char *filename_start = strchr_m(target, '@');
121 0 : char *filename_end = NULL;
122 0 : int filename_len = 0;
123 0 : char *targethost = NULL;
124 0 : char *new_target = NULL;
125 : char *raddr;
126 :
127 0 : if (filename_start == NULL) {
128 0 : DEBUG(10, ("No filename start in %s\n", target));
129 0 : return NULL;
130 : }
131 :
132 0 : filename_end = strchr_m(filename_start+1, '@');
133 :
134 0 : if (filename_end == NULL) {
135 0 : DEBUG(10, ("No filename end in %s\n", target));
136 0 : return NULL;
137 : }
138 :
139 0 : filename_len = PTR_DIFF(filename_end, filename_start+1);
140 0 : mapfilename = talloc_strdup(ctx, filename_start+1);
141 0 : if (!mapfilename) {
142 0 : return NULL;
143 : }
144 0 : mapfilename[filename_len] = '\0';
145 :
146 : /*
147 : * dfs links returned have had '/' characters replaced with '\'.
148 : * Return them to '/' so we can have absolute path mapfilenames.
149 : */
150 0 : string_replace(mapfilename, '\\', '/');
151 :
152 0 : DEBUG(10, ("Expanding from table [%s]\n", mapfilename));
153 :
154 0 : raddr = tsocket_address_inet_addr_string(conn->sconn->remote_address,
155 : ctx);
156 0 : if (raddr == NULL) {
157 0 : return NULL;
158 : }
159 :
160 0 : targethost = read_target_host(ctx, mapfilename, raddr);
161 0 : if (targethost == NULL) {
162 0 : DEBUG(1, ("Could not expand target host from file %s\n",
163 : mapfilename));
164 0 : return NULL;
165 : }
166 :
167 0 : targethost = talloc_sub_full(ctx,
168 0 : lp_servicename(talloc_tos(), lp_sub, SNUM(conn)),
169 0 : conn->session_info->unix_info->unix_name,
170 0 : conn->connectpath,
171 0 : conn->session_info->unix_token->gid,
172 0 : conn->session_info->unix_info->sanitized_username,
173 0 : conn->session_info->info->domain_name,
174 : targethost);
175 :
176 0 : DEBUG(10, ("Expanded targethost to %s\n", targethost));
177 :
178 : /* Replace the part between '@...@' */
179 0 : *filename_start = '\0';
180 0 : new_target = talloc_asprintf(ctx,
181 : "%s%s%s",
182 : target,
183 : targethost,
184 : filename_end+1);
185 0 : if (!new_target) {
186 0 : return NULL;
187 : }
188 :
189 0 : DEBUG(10, ("New DFS target: %s\n", new_target));
190 0 : return new_target;
191 : }
192 :
193 0 : static NTSTATUS expand_read_dfs_pathat(struct vfs_handle_struct *handle,
194 : TALLOC_CTX *mem_ctx,
195 : struct files_struct *dirfsp,
196 : struct smb_filename *smb_fname,
197 : struct referral **ppreflist,
198 : size_t *preferral_count)
199 : {
200 : NTSTATUS status;
201 : size_t i;
202 0 : struct referral *reflist = NULL;
203 0 : size_t count = 0;
204 0 : TALLOC_CTX *frame = talloc_stackframe();
205 :
206 : /*
207 : * Always call the NEXT function first, then
208 : * modify the return if needed.
209 : */
210 0 : status = SMB_VFS_NEXT_READ_DFS_PATHAT(handle,
211 : mem_ctx,
212 : dirfsp,
213 : smb_fname,
214 : ppreflist,
215 : preferral_count);
216 :
217 0 : if (!NT_STATUS_IS_OK(status)) {
218 0 : TALLOC_FREE(frame);
219 0 : return status;
220 : }
221 :
222 : /*
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.
227 : */
228 0 : if (ppreflist == NULL || preferral_count == NULL) {
229 0 : TALLOC_FREE(frame);
230 0 : return status;
231 : }
232 :
233 : /*
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.
238 : */
239 0 : count = *preferral_count;
240 0 : reflist = *ppreflist;
241 :
242 0 : for (i = 0; i < count; i++) {
243 0 : if (strchr_m(reflist[i].alternate_path, '@') != NULL) {
244 0 : char *new_altpath = expand_msdfs_target(frame,
245 0 : handle->conn,
246 0 : reflist[i].alternate_path);
247 0 : if (new_altpath == NULL) {
248 0 : TALLOC_FREE(*ppreflist);
249 0 : *preferral_count = 0;
250 0 : TALLOC_FREE(frame);
251 0 : return NT_STATUS_NO_MEMORY;
252 : }
253 0 : reflist[i].alternate_path = talloc_move(reflist,
254 : &new_altpath);
255 : }
256 : }
257 0 : TALLOC_FREE(frame);
258 0 : return status;
259 : }
260 :
261 : static struct vfs_fn_pointers vfs_expand_msdfs_fns = {
262 : .read_dfs_pathat_fn = expand_read_dfs_pathat,
263 : };
264 :
265 : static_decl_vfs;
266 27 : NTSTATUS vfs_expand_msdfs_init(TALLOC_CTX *ctx)
267 : {
268 27 : return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "expand_msdfs",
269 : &vfs_expand_msdfs_fns);
270 : }
|