2 * Unix SMB/CIFS implementation.
3 * RPC Pipe client / server routines for Dfs
4 * Copyright (C) Shirish Kalele 2000.
5 * Copyright (C) Jeremy Allison 2001-2007.
6 * Copyright (C) Jelmer Vernooij 2005-2006.
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.
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.
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/>.
22 /* This is the implementation of the dfs pipe. */
26 #include "../librpc/gen_ndr/srv_dfs.h"
28 #include "smbd/smbd.h"
29 #include "smbd/globals.h"
33 #define DBGC_CLASS DBGC_MSDFS
35 /* This function does not return a WERROR or NTSTATUS code but rather 1 if
36 dfs exists, or 0 otherwise. */
38 void _dfs_GetManagerVersion(struct pipes_struct
*p
, struct dfs_GetManagerVersion
*r
)
40 if (lp_host_msdfs()) {
41 *r
->out
.version
= DFS_MANAGER_VERSION_NT4
;
43 *r
->out
.version
= (enum dfs_ManagerVersion
)0;
47 WERROR
_dfs_Add(struct pipes_struct
*p
, struct dfs_Add
*r
)
49 struct junction_map
*jn
= NULL
;
50 struct referral
*old_referral_list
= NULL
;
51 bool self_ref
= False
;
55 TALLOC_CTX
*ctx
= talloc_tos();
57 if (p
->session_info
->unix_token
->uid
!= sec_initial_uid()) {
58 DEBUG(10,("_dfs_add: uid != 0. Access denied.\n"));
59 return WERR_ACCESS_DENIED
;
62 jn
= talloc_zero(ctx
, struct junction_map
);
67 DEBUG(5,("init_reply_dfs_add: Request to add %s -> %s\\%s.\n",
68 r
->in
.path
, r
->in
.server
, r
->in
.share
));
70 altpath
= talloc_asprintf(ctx
, "%s\\%s",
77 /* The following call can change the cwd. */
78 status
= get_referred_path(ctx
, r
->in
.path
,
79 true, /*allow_broken_path */
80 jn
, &consumedcnt
, &self_ref
);
81 if(!NT_STATUS_IS_OK(status
)) {
82 return ntstatus_to_werror(status
);
85 jn
->referral_count
+= 1;
86 old_referral_list
= jn
->referral_list
;
88 if (jn
->referral_count
< 1) {
92 jn
->referral_list
= talloc_array(ctx
, struct referral
, jn
->referral_count
);
93 if(jn
->referral_list
== NULL
) {
94 DEBUG(0,("init_reply_dfs_add: talloc failed for referral list!\n"));
95 return WERR_DFS_INTERNAL_ERROR
;
98 if(old_referral_list
&& jn
->referral_list
) {
99 memcpy(jn
->referral_list
, old_referral_list
,
100 sizeof(struct referral
)*jn
->referral_count
-1);
103 jn
->referral_list
[jn
->referral_count
-1].proximity
= 0;
104 jn
->referral_list
[jn
->referral_count
-1].ttl
= REFERRAL_TTL
;
105 jn
->referral_list
[jn
->referral_count
-1].alternate_path
= altpath
;
107 if(!create_msdfs_link(jn
)) {
108 return WERR_DFS_CANT_CREATE_JUNCT
;
114 WERROR
_dfs_Remove(struct pipes_struct
*p
, struct dfs_Remove
*r
)
116 struct junction_map
*jn
= NULL
;
117 bool self_ref
= False
;
120 TALLOC_CTX
*ctx
= talloc_tos();
121 char *altpath
= NULL
;
124 if (p
->session_info
->unix_token
->uid
!= sec_initial_uid()) {
125 DEBUG(10,("_dfs_remove: uid != 0. Access denied.\n"));
126 return WERR_ACCESS_DENIED
;
129 jn
= talloc_zero(ctx
, struct junction_map
);
134 if (r
->in
.servername
&& r
->in
.sharename
) {
135 altpath
= talloc_asprintf(ctx
, "%s\\%s",
141 if (!strlower_m(altpath
)) {
142 return WERR_INVALID_PARAM
;
144 DEBUG(5,("init_reply_dfs_remove: Request to remove %s -> %s\\%s.\n",
145 r
->in
.dfs_entry_path
, r
->in
.servername
, r
->in
.sharename
));
148 status
= get_referred_path(ctx
, r
->in
.dfs_entry_path
,
149 true, /*allow_broken_path */
150 jn
, &consumedcnt
, &self_ref
);
151 if(!NT_STATUS_IS_OK(status
)) {
152 return WERR_DFS_NO_SUCH_VOL
;
155 /* if no server-share pair given, remove the msdfs link completely */
156 if(!r
->in
.servername
&& !r
->in
.sharename
) {
157 if(!remove_msdfs_link(jn
)) {
158 return WERR_DFS_NO_SUCH_VOL
;
162 /* compare each referral in the list with the one to remove */
163 DEBUG(10,("altpath: .%s. refcnt: %d\n", altpath
, jn
->referral_count
));
164 for(i
=0;i
<jn
->referral_count
;i
++) {
165 char *refpath
= talloc_strdup(ctx
,
166 jn
->referral_list
[i
].alternate_path
);
170 trim_char(refpath
, '\\', '\\');
171 DEBUG(10,("_dfs_remove: refpath: .%s.\n", refpath
));
172 if(strequal(refpath
, altpath
)) {
173 *(jn
->referral_list
[i
].alternate_path
)='\0';
174 DEBUG(10,("_dfs_remove: Removal request matches referral %s\n",
181 return WERR_DFS_NO_SUCH_SHARE
;
184 /* Only one referral, remove it */
185 if(jn
->referral_count
== 1) {
186 if(!remove_msdfs_link(jn
)) {
187 return WERR_DFS_NO_SUCH_VOL
;
190 if(!create_msdfs_link(jn
)) {
191 return WERR_DFS_CANT_CREATE_JUNCT
;
199 static bool init_reply_dfs_info_1(TALLOC_CTX
*mem_ctx
, struct junction_map
* j
,struct dfs_Info1
* dfs1
)
201 dfs1
->path
= talloc_asprintf(mem_ctx
,
202 "\\\\%s\\%s\\%s", lp_netbios_name(),
203 j
->service_name
, j
->volume_name
);
204 if (dfs1
->path
== NULL
)
207 DEBUG(5,("init_reply_dfs_info_1: initing entrypath: %s\n",dfs1
->path
));
211 static bool init_reply_dfs_info_2(TALLOC_CTX
*mem_ctx
, struct junction_map
* j
, struct dfs_Info2
* dfs2
)
213 dfs2
->path
= talloc_asprintf(mem_ctx
,
214 "\\\\%s\\%s\\%s", lp_netbios_name(), j
->service_name
, j
->volume_name
);
215 if (dfs2
->path
== NULL
)
217 dfs2
->comment
= talloc_strdup(mem_ctx
, j
->comment
);
218 dfs2
->state
= 1; /* set up state of dfs junction as OK */
219 dfs2
->num_stores
= j
->referral_count
;
223 static bool init_reply_dfs_info_3(TALLOC_CTX
*mem_ctx
, struct junction_map
* j
, struct dfs_Info3
* dfs3
)
226 if (j
->volume_name
[0] == '\0')
227 dfs3
->path
= talloc_asprintf(mem_ctx
, "\\\\%s\\%s",
228 lp_netbios_name(), j
->service_name
);
230 dfs3
->path
= talloc_asprintf(mem_ctx
, "\\\\%s\\%s\\%s", lp_netbios_name(),
231 j
->service_name
, j
->volume_name
);
233 if (dfs3
->path
== NULL
)
236 dfs3
->comment
= talloc_strdup(mem_ctx
, j
->comment
);
238 dfs3
->num_stores
= j
->referral_count
;
240 /* also enumerate the stores */
241 if (j
->referral_count
) {
242 dfs3
->stores
= talloc_array(mem_ctx
, struct dfs_StorageInfo
, j
->referral_count
);
245 memset(dfs3
->stores
, '\0', j
->referral_count
* sizeof(struct dfs_StorageInfo
));
250 for(ii
=0;ii
<j
->referral_count
;ii
++) {
253 struct dfs_StorageInfo
* stor
= &(dfs3
->stores
[ii
]);
254 struct referral
* ref
= &(j
->referral_list
[ii
]);
256 path
= talloc_strdup(mem_ctx
, ref
->alternate_path
);
260 trim_char(path
,'\\','\0');
261 p
= strrchr_m(path
,'\\');
263 DEBUG(4,("init_reply_dfs_info_3: invalid path: no \\ found in %s\n",path
));
267 DEBUG(5,("storage %d: %s.%s\n",ii
,path
,p
+1));
268 stor
->state
= 2; /* set all stores as ONLINE */
269 stor
->server
= talloc_strdup(mem_ctx
, path
);
270 stor
->share
= talloc_strdup(mem_ctx
, p
+1);
275 static bool init_reply_dfs_info_100(TALLOC_CTX
*mem_ctx
, struct junction_map
* j
, struct dfs_Info100
* dfs100
)
277 dfs100
->comment
= talloc_strdup(mem_ctx
, j
->comment
);
281 WERROR
_dfs_Enum(struct pipes_struct
*p
, struct dfs_Enum
*r
)
283 struct junction_map
*jn
= NULL
;
286 TALLOC_CTX
*ctx
= talloc_tos();
288 jn
= enum_msdfs_links(ctx
, &num_jn
);
289 if (!jn
|| num_jn
== 0) {
294 DEBUG(5,("_dfs_Enum: %u junctions found in Dfs, doing level %d\n",
295 (unsigned int)num_jn
, r
->in
.level
));
297 *r
->out
.total
= num_jn
;
299 /* Create the return array */
300 switch (r
->in
.level
) {
303 if ((r
->out
.info
->e
.info1
->s
= talloc_array(ctx
, struct dfs_Info1
, num_jn
)) == NULL
) {
307 r
->out
.info
->e
.info1
->s
= NULL
;
309 r
->out
.info
->e
.info1
->count
= num_jn
;
313 if ((r
->out
.info
->e
.info2
->s
= talloc_array(ctx
, struct dfs_Info2
, num_jn
)) == NULL
) {
317 r
->out
.info
->e
.info2
->s
= NULL
;
319 r
->out
.info
->e
.info2
->count
= num_jn
;
323 if ((r
->out
.info
->e
.info3
->s
= talloc_array(ctx
, struct dfs_Info3
, num_jn
)) == NULL
) {
327 r
->out
.info
->e
.info3
->s
= NULL
;
329 r
->out
.info
->e
.info3
->count
= num_jn
;
332 return WERR_INVALID_PARAM
;
335 for (i
= 0; i
< num_jn
; i
++) {
336 switch (r
->in
.level
) {
338 init_reply_dfs_info_1(ctx
, &jn
[i
], &r
->out
.info
->e
.info1
->s
[i
]);
341 init_reply_dfs_info_2(ctx
, &jn
[i
], &r
->out
.info
->e
.info2
->s
[i
]);
344 init_reply_dfs_info_3(ctx
, &jn
[i
], &r
->out
.info
->e
.info3
->s
[i
]);
347 return WERR_INVALID_PARAM
;
354 WERROR
_dfs_GetInfo(struct pipes_struct
*p
, struct dfs_GetInfo
*r
)
356 int consumedcnt
= strlen(r
->in
.dfs_entry_path
);
357 struct junction_map
*jn
= NULL
;
358 bool self_ref
= False
;
359 TALLOC_CTX
*ctx
= talloc_tos();
363 jn
= talloc_zero(ctx
, struct junction_map
);
368 ret
= create_junction(ctx
, r
->in
.dfs_entry_path
,
369 true, /* allow broken_path */
372 return WERR_DFS_NO_SUCH_SERVER
;
375 /* The following call can change the cwd. */
376 status
= get_referred_path(ctx
, r
->in
.dfs_entry_path
,
377 true, /*allow_broken_path */
378 jn
, &consumedcnt
, &self_ref
);
379 if(!NT_STATUS_IS_OK(status
) ||
380 consumedcnt
< strlen(r
->in
.dfs_entry_path
)) {
381 return WERR_DFS_NO_SUCH_VOL
;
384 switch (r
->in
.level
) {
386 r
->out
.info
->info1
= talloc_zero(ctx
,struct dfs_Info1
);
387 if (!r
->out
.info
->info1
) {
390 ret
= init_reply_dfs_info_1(ctx
, jn
, r
->out
.info
->info1
);
393 r
->out
.info
->info2
= talloc_zero(ctx
,struct dfs_Info2
);
394 if (!r
->out
.info
->info2
) {
397 ret
= init_reply_dfs_info_2(ctx
, jn
, r
->out
.info
->info2
);
400 r
->out
.info
->info3
= talloc_zero(ctx
,struct dfs_Info3
);
401 if (!r
->out
.info
->info3
) {
404 ret
= init_reply_dfs_info_3(ctx
, jn
, r
->out
.info
->info3
);
407 r
->out
.info
->info100
= talloc_zero(ctx
,struct dfs_Info100
);
408 if (!r
->out
.info
->info100
) {
411 ret
= init_reply_dfs_info_100(ctx
, jn
, r
->out
.info
->info100
);
414 r
->out
.info
->info1
= NULL
;
415 return WERR_INVALID_PARAM
;
419 return WERR_INVALID_PARAM
;
424 WERROR
_dfs_SetInfo(struct pipes_struct
*p
, struct dfs_SetInfo
*r
)
426 /* FIXME: Implement your code here */
427 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
428 return WERR_NOT_SUPPORTED
;
431 WERROR
_dfs_Rename(struct pipes_struct
*p
, struct dfs_Rename
*r
)
433 /* FIXME: Implement your code here */
434 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
435 return WERR_NOT_SUPPORTED
;
438 WERROR
_dfs_Move(struct pipes_struct
*p
, struct dfs_Move
*r
)
440 /* FIXME: Implement your code here */
441 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
442 return WERR_NOT_SUPPORTED
;
445 WERROR
_dfs_ManagerGetConfigInfo(struct pipes_struct
*p
, struct dfs_ManagerGetConfigInfo
*r
)
447 /* FIXME: Implement your code here */
448 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
449 return WERR_NOT_SUPPORTED
;
452 WERROR
_dfs_ManagerSendSiteInfo(struct pipes_struct
*p
, struct dfs_ManagerSendSiteInfo
*r
)
454 /* FIXME: Implement your code here */
455 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
456 return WERR_NOT_SUPPORTED
;
459 WERROR
_dfs_AddFtRoot(struct pipes_struct
*p
, struct dfs_AddFtRoot
*r
)
461 /* FIXME: Implement your code here */
462 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
463 return WERR_NOT_SUPPORTED
;
466 WERROR
_dfs_RemoveFtRoot(struct pipes_struct
*p
, struct dfs_RemoveFtRoot
*r
)
468 /* FIXME: Implement your code here */
469 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
470 return WERR_NOT_SUPPORTED
;
473 WERROR
_dfs_AddStdRoot(struct pipes_struct
*p
, struct dfs_AddStdRoot
*r
)
475 /* FIXME: Implement your code here */
476 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
477 return WERR_NOT_SUPPORTED
;
480 WERROR
_dfs_RemoveStdRoot(struct pipes_struct
*p
, struct dfs_RemoveStdRoot
*r
)
482 /* FIXME: Implement your code here */
483 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
484 return WERR_NOT_SUPPORTED
;
487 WERROR
_dfs_ManagerInitialize(struct pipes_struct
*p
, struct dfs_ManagerInitialize
*r
)
489 /* FIXME: Implement your code here */
490 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
491 return WERR_NOT_SUPPORTED
;
494 WERROR
_dfs_AddStdRootForced(struct pipes_struct
*p
, struct dfs_AddStdRootForced
*r
)
496 /* FIXME: Implement your code here */
497 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
498 return WERR_NOT_SUPPORTED
;
501 WERROR
_dfs_GetDcAddress(struct pipes_struct
*p
, struct dfs_GetDcAddress
*r
)
503 /* FIXME: Implement your code here */
504 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
505 return WERR_NOT_SUPPORTED
;
508 WERROR
_dfs_SetDcAddress(struct pipes_struct
*p
, struct dfs_SetDcAddress
*r
)
510 /* FIXME: Implement your code here */
511 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
512 return WERR_NOT_SUPPORTED
;
515 WERROR
_dfs_FlushFtTable(struct pipes_struct
*p
, struct dfs_FlushFtTable
*r
)
517 /* FIXME: Implement your code here */
518 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
519 return WERR_NOT_SUPPORTED
;
522 WERROR
_dfs_Add2(struct pipes_struct
*p
, struct dfs_Add2
*r
)
524 /* FIXME: Implement your code here */
525 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
526 return WERR_NOT_SUPPORTED
;
529 WERROR
_dfs_Remove2(struct pipes_struct
*p
, struct dfs_Remove2
*r
)
531 /* FIXME: Implement your code here */
532 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
533 return WERR_NOT_SUPPORTED
;
536 WERROR
_dfs_EnumEx(struct pipes_struct
*p
, struct dfs_EnumEx
*r
)
538 /* FIXME: Implement your code here */
539 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
540 return WERR_NOT_SUPPORTED
;
543 WERROR
_dfs_SetInfo2(struct pipes_struct
*p
, struct dfs_SetInfo2
*r
)
545 /* FIXME: Implement your code here */
546 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
547 return WERR_NOT_SUPPORTED
;