2 * Unix SMB/CIFS implementation.
3 * RPC Pipe client / server routines for Dfs
4 * Copyright (C) Andrew Tridgell 1992-1997,
5 * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
6 * Copyright (C) Shirish Kalele 2000.
7 * Copyright (C) Jeremy Allison 2001.
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 2 of the License, or
12 * (at your option) any later version.
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.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 /* This is the implementation of the dfs pipe. */
30 #define DBGC_CLASS DBGC_RPC_SRV
32 #define MAX_MSDFS_JUNCTIONS 256
34 /* This function does not return a WERROR or NTSTATUS code but rather 1 if
35 dfs exists, or 0 otherwise. */
37 uint32
_dfs_exist(pipes_struct
*p
, DFS_Q_DFS_EXIST
*q_u
, DFS_R_DFS_EXIST
*r_u
)
45 WERROR
_dfs_add(pipes_struct
*p
, DFS_Q_DFS_ADD
* q_u
, DFS_R_DFS_ADD
*r_u
)
47 struct current_user user
;
48 struct junction_map jn
;
49 struct referral
* old_referral_list
= NULL
;
52 pstring dfspath
, servername
, sharename
;
55 get_current_user(&user
,p
);
58 DEBUG(10,("_dfs_add: uid != 0. Access denied.\n"));
59 return WERR_ACCESS_DENIED
;
62 unistr2_to_ascii(dfspath
, &q_u
->DfsEntryPath
, sizeof(dfspath
)-1);
63 unistr2_to_ascii(servername
, &q_u
->ServerName
, sizeof(servername
)-1);
64 unistr2_to_ascii(sharename
, &q_u
->ShareName
, sizeof(sharename
)-1);
66 DEBUG(5,("init_reply_dfs_add: Request to add %s -> %s\\%s.\n",
67 dfspath
, servername
, sharename
));
69 pstrcpy(altpath
, servername
);
70 pstrcat(altpath
, "\\");
71 pstrcat(altpath
, sharename
);
73 /* The following call can change the cwd. */
74 if(get_referred_path(dfspath
, &jn
, NULL
, NULL
)) {
76 jn
.referral_count
+= 1;
77 old_referral_list
= jn
.referral_list
;
79 jn
.referral_count
= 1;
82 vfs_ChDir(p
->conn
,p
->conn
->connectpath
);
84 jn
.referral_list
= TALLOC_ARRAY(p
->mem_ctx
, struct referral
, jn
.referral_count
);
85 if(jn
.referral_list
== NULL
) {
86 DEBUG(0,("init_reply_dfs_add: talloc failed for referral list!\n"));
87 return WERR_DFS_INTERNAL_ERROR
;
90 if(old_referral_list
) {
91 memcpy(jn
.referral_list
, old_referral_list
, sizeof(struct referral
)*jn
.referral_count
-1);
92 SAFE_FREE(old_referral_list
);
95 jn
.referral_list
[jn
.referral_count
-1].proximity
= 0;
96 jn
.referral_list
[jn
.referral_count
-1].ttl
= REFERRAL_TTL
;
98 pstrcpy(jn
.referral_list
[jn
.referral_count
-1].alternate_path
, altpath
);
100 if(!create_msdfs_link(&jn
, exists
)) {
101 vfs_ChDir(p
->conn
,p
->conn
->connectpath
);
102 return WERR_DFS_CANT_CREATE_JUNCT
;
104 vfs_ChDir(p
->conn
,p
->conn
->connectpath
);
109 WERROR
_dfs_remove(pipes_struct
*p
, DFS_Q_DFS_REMOVE
*q_u
,
110 DFS_R_DFS_REMOVE
*r_u
)
112 struct current_user user
;
113 struct junction_map jn
;
116 pstring dfspath
, servername
, sharename
;
119 get_current_user(&user
,p
);
122 DEBUG(10,("_dfs_remove: uid != 0. Access denied.\n"));
123 return WERR_ACCESS_DENIED
;
126 unistr2_to_ascii(dfspath
, &q_u
->DfsEntryPath
, sizeof(dfspath
)-1);
127 if(q_u
->ptr_ServerName
) {
128 unistr2_to_ascii(servername
, &q_u
->ServerName
, sizeof(servername
)-1);
131 if(q_u
->ptr_ShareName
) {
132 unistr2_to_ascii(sharename
, &q_u
->ShareName
, sizeof(sharename
)-1);
135 if(q_u
->ptr_ServerName
&& q_u
->ptr_ShareName
) {
136 pstrcpy(altpath
, servername
);
137 pstrcat(altpath
, "\\");
138 pstrcat(altpath
, sharename
);
142 DEBUG(5,("init_reply_dfs_remove: Request to remove %s -> %s\\%s.\n",
143 dfspath
, servername
, sharename
));
145 if(!get_referred_path(dfspath
, &jn
, NULL
, NULL
)) {
146 return WERR_DFS_NO_SUCH_VOL
;
149 /* if no server-share pair given, remove the msdfs link completely */
150 if(!q_u
->ptr_ServerName
&& !q_u
->ptr_ShareName
) {
151 if(!remove_msdfs_link(&jn
)) {
152 vfs_ChDir(p
->conn
,p
->conn
->connectpath
);
153 return WERR_DFS_NO_SUCH_VOL
;
155 vfs_ChDir(p
->conn
,p
->conn
->connectpath
);
158 /* compare each referral in the list with the one to remove */
159 DEBUG(10,("altpath: .%s. refcnt: %d\n", altpath
, jn
.referral_count
));
160 for(i
=0;i
<jn
.referral_count
;i
++) {
162 pstrcpy(refpath
,jn
.referral_list
[i
].alternate_path
);
163 trim_char(refpath
, '\\', '\\');
164 DEBUG(10,("_dfs_remove: refpath: .%s.\n", refpath
));
165 if(strequal(refpath
, altpath
)) {
166 *(jn
.referral_list
[i
].alternate_path
)='\0';
167 DEBUG(10,("_dfs_remove: Removal request matches referral %s\n",
174 return WERR_DFS_NO_SUCH_SHARE
;
177 /* Only one referral, remove it */
178 if(jn
.referral_count
== 1) {
179 if(!remove_msdfs_link(&jn
)) {
180 vfs_ChDir(p
->conn
,p
->conn
->connectpath
);
181 return WERR_DFS_NO_SUCH_VOL
;
184 if(!create_msdfs_link(&jn
, True
)) {
185 vfs_ChDir(p
->conn
,p
->conn
->connectpath
);
186 return WERR_DFS_CANT_CREATE_JUNCT
;
189 vfs_ChDir(p
->conn
,p
->conn
->connectpath
);
195 static BOOL
init_reply_dfs_info_1(struct junction_map
* j
, DFS_INFO_1
* dfs1
, int num_j
)
198 for(i
=0;i
<num_j
;i
++) {
200 dfs1
[i
].ptr_entrypath
= 1;
201 slprintf(str
, sizeof(pstring
)-1, "\\\\%s\\%s\\%s", global_myname(),
202 j
[i
].service_name
, j
[i
].volume_name
);
203 DEBUG(5,("init_reply_dfs_info_1: %d) initing entrypath: %s\n",i
,str
));
204 init_unistr2(&dfs1
[i
].entrypath
,str
,UNI_STR_TERMINATE
);
209 static BOOL
init_reply_dfs_info_2(struct junction_map
* j
, DFS_INFO_2
* dfs2
, int num_j
)
212 for(i
=0;i
<num_j
;i
++) {
214 dfs2
[i
].ptr_entrypath
= 1;
215 slprintf(str
, sizeof(pstring
)-1, "\\\\%s\\%s\\%s", global_myname(),
216 j
[i
].service_name
, j
[i
].volume_name
);
217 init_unistr2(&dfs2
[i
].entrypath
, str
, UNI_STR_TERMINATE
);
218 dfs2
[i
].ptr_comment
= 0;
219 dfs2
[i
].state
= 1; /* set up state of dfs junction as OK */
220 dfs2
[i
].num_storages
= j
[i
].referral_count
;
225 static BOOL
init_reply_dfs_info_3(TALLOC_CTX
*ctx
, struct junction_map
* j
, DFS_INFO_3
* dfs3
, int num_j
)
228 for(i
=0;i
<num_j
;i
++) {
230 dfs3
[i
].ptr_entrypath
= 1;
231 if (j
[i
].volume_name
[0] == '\0')
232 slprintf(str
, sizeof(pstring
)-1, "\\\\%s\\%s",
233 global_myname(), j
[i
].service_name
);
235 slprintf(str
, sizeof(pstring
)-1, "\\\\%s\\%s\\%s", global_myname(),
236 j
[i
].service_name
, j
[i
].volume_name
);
238 init_unistr2(&dfs3
[i
].entrypath
, str
, UNI_STR_TERMINATE
);
239 dfs3
[i
].ptr_comment
= 1;
240 init_unistr2(&dfs3
[i
].comment
, "", UNI_STR_TERMINATE
);
242 dfs3
[i
].num_storages
= dfs3
[i
].num_storage_infos
= j
[i
].referral_count
;
243 dfs3
[i
].ptr_storages
= 1;
245 /* also enumerate the storages */
246 dfs3
[i
].storages
= TALLOC_ARRAY(ctx
, DFS_STORAGE_INFO
, j
[i
].referral_count
);
247 if (!dfs3
[i
].storages
)
250 memset(dfs3
[i
].storages
, '\0', j
[i
].referral_count
* sizeof(DFS_STORAGE_INFO
));
252 for(ii
=0;ii
<j
[i
].referral_count
;ii
++) {
255 DFS_STORAGE_INFO
* stor
= &(dfs3
[i
].storages
[ii
]);
256 struct referral
* ref
= &(j
[i
].referral_list
[ii
]);
258 pstrcpy(path
, ref
->alternate_path
);
259 trim_char(path
,'\\','\0');
260 p
= strrchr_m(path
,'\\');
262 DEBUG(4,("init_reply_dfs_info_3: invalid path: no \\ found in %s\n",path
));
266 DEBUG(5,("storage %d: %s.%s\n",ii
,path
,p
+1));
267 stor
->state
= 2; /* set all storages as ONLINE */
268 init_unistr2(&stor
->servername
, path
, UNI_STR_TERMINATE
);
269 init_unistr2(&stor
->sharename
, p
+1, UNI_STR_TERMINATE
);
270 stor
->ptr_servername
= stor
->ptr_sharename
= 1;
276 static WERROR
init_reply_dfs_ctr(TALLOC_CTX
*ctx
, uint32 level
,
277 DFS_INFO_CTR
* ctr
, struct junction_map
* jn
,
285 dfs1
= TALLOC_ARRAY(ctx
, DFS_INFO_1
, num_jn
);
288 init_reply_dfs_info_1(jn
, dfs1
, num_jn
);
289 ctr
->dfs
.info1
= dfs1
;
295 dfs2
= TALLOC_ARRAY(ctx
, DFS_INFO_2
, num_jn
);
298 init_reply_dfs_info_2(jn
, dfs2
, num_jn
);
299 ctr
->dfs
.info2
= dfs2
;
305 dfs3
= TALLOC_ARRAY(ctx
, DFS_INFO_3
, num_jn
);
308 init_reply_dfs_info_3(ctx
, jn
, dfs3
, num_jn
);
309 ctr
->dfs
.info3
= dfs3
;
313 return WERR_INVALID_PARAM
;
318 WERROR
_dfs_enum(pipes_struct
*p
, DFS_Q_DFS_ENUM
*q_u
, DFS_R_DFS_ENUM
*r_u
)
320 uint32 level
= q_u
->level
;
321 struct junction_map jn
[MAX_MSDFS_JUNCTIONS
];
324 num_jn
= enum_msdfs_links(jn
);
325 vfs_ChDir(p
->conn
,p
->conn
->connectpath
);
327 DEBUG(5,("make_reply_dfs_enum: %d junctions found in Dfs, doing level %d\n", num_jn
, level
));
329 r_u
->ptr_buffer
= level
;
330 r_u
->level
= r_u
->level2
= level
;
331 r_u
->ptr_num_entries
= r_u
->ptr_num_entries2
= 1;
332 r_u
->num_entries
= r_u
->num_entries2
= num_jn
;
333 r_u
->reshnd
.ptr_hnd
= 1;
334 r_u
->reshnd
.handle
= num_jn
;
336 r_u
->ctr
= TALLOC_P(p
->mem_ctx
, DFS_INFO_CTR
);
339 ZERO_STRUCTP(r_u
->ctr
);
340 r_u
->ctr
->switch_value
= level
;
341 r_u
->ctr
->num_entries
= num_jn
;
342 r_u
->ctr
->ptr_dfs_ctr
= 1;
344 r_u
->status
= init_reply_dfs_ctr(p
->mem_ctx
, level
, r_u
->ctr
, jn
, num_jn
);
349 WERROR
_dfs_get_info(pipes_struct
*p
, DFS_Q_DFS_GET_INFO
*q_u
,
350 DFS_R_DFS_GET_INFO
*r_u
)
352 UNISTR2
* uni_path
= &q_u
->uni_path
;
353 uint32 level
= q_u
->level
;
354 int consumedcnt
= sizeof(pstring
);
356 struct junction_map jn
;
358 unistr2_to_ascii(path
, uni_path
, sizeof(path
)-1);
359 if(!create_junction(path
, &jn
))
360 return WERR_DFS_NO_SUCH_SERVER
;
362 /* The following call can change the cwd. */
363 if(!get_referred_path(path
, &jn
, &consumedcnt
, NULL
) || consumedcnt
< strlen(path
)) {
364 vfs_ChDir(p
->conn
,p
->conn
->connectpath
);
365 return WERR_DFS_NO_SUCH_VOL
;
368 vfs_ChDir(p
->conn
,p
->conn
->connectpath
);
371 r_u
->status
= init_reply_dfs_ctr(p
->mem_ctx
, level
, &r_u
->ctr
, &jn
, 1);