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/rpc/dcesrv_core.h"
27 #include "librpc/gen_ndr/ndr_dfs.h"
28 #include "librpc/gen_ndr/ndr_dfs_scompat.h"
30 #include "smbd/smbd.h"
31 #include "smbd/globals.h"
35 #define DBGC_CLASS DBGC_MSDFS
37 /* This function does not return a WERROR or NTSTATUS code but rather 1 if
38 dfs exists, or 0 otherwise. */
40 void _dfs_GetManagerVersion(struct pipes_struct
*p
, struct dfs_GetManagerVersion
*r
)
42 if (lp_host_msdfs()) {
43 *r
->out
.version
= DFS_MANAGER_VERSION_NT4
;
45 *r
->out
.version
= (enum dfs_ManagerVersion
)0;
49 WERROR
_dfs_Add(struct pipes_struct
*p
, struct dfs_Add
*r
)
51 struct dcesrv_call_state
*dce_call
= p
->dce_call
;
52 struct dcesrv_connection
*dcesrv_conn
= dce_call
->conn
;
53 const struct tsocket_address
*local_address
=
54 dcesrv_connection_get_local_address(dcesrv_conn
);
55 const struct tsocket_address
*remote_address
=
56 dcesrv_connection_get_remote_address(dcesrv_conn
);
57 struct auth_session_info
*session_info
=
58 dcesrv_call_session_info(dce_call
);
59 struct junction_map
*jn
= NULL
;
60 struct referral
*old_referral_list
= NULL
;
61 bool self_ref
= False
;
62 size_t consumedcnt
= 0;
65 TALLOC_CTX
*ctx
= talloc_tos();
66 const char *pathnamep
= r
->in
.path
;
68 if (session_info
->unix_token
->uid
!= sec_initial_uid()) {
69 DEBUG(10,("_dfs_add: uid != 0. Access denied.\n"));
70 return WERR_ACCESS_DENIED
;
73 jn
= talloc_zero(ctx
, struct junction_map
);
75 return WERR_NOT_ENOUGH_MEMORY
;
78 DEBUG(5,("init_reply_dfs_add: Request to add %s -> %s\\%s.\n",
79 r
->in
.path
, r
->in
.server
, r
->in
.share
));
81 altpath
= talloc_asprintf(ctx
, "%s\\%s",
85 return WERR_NOT_ENOUGH_MEMORY
;
88 while (IS_DIRECTORY_SEP(pathnamep
[0]) &&
89 IS_DIRECTORY_SEP(pathnamep
[1])) {
93 /* The following call can change the cwd. */
94 status
= get_referred_path(ctx
,
99 jn
, &consumedcnt
, &self_ref
);
100 if(!NT_STATUS_IS_OK(status
)) {
101 return ntstatus_to_werror(status
);
104 jn
->referral_count
+= 1;
105 old_referral_list
= jn
->referral_list
;
107 if (jn
->referral_count
< 1) {
108 return WERR_NOT_ENOUGH_MEMORY
;
111 jn
->referral_list
= talloc_array(ctx
, struct referral
, jn
->referral_count
);
112 if(jn
->referral_list
== NULL
) {
113 DEBUG(0,("init_reply_dfs_add: talloc failed for referral list!\n"));
114 return WERR_NERR_DFSINTERNALERROR
;
117 if(old_referral_list
&& jn
->referral_list
) {
118 memcpy(jn
->referral_list
, old_referral_list
,
119 sizeof(struct referral
)*jn
->referral_count
-1);
122 jn
->referral_list
[jn
->referral_count
-1].proximity
= 0;
123 jn
->referral_list
[jn
->referral_count
-1].ttl
= REFERRAL_TTL
;
124 jn
->referral_list
[jn
->referral_count
-1].alternate_path
= altpath
;
126 if (!create_msdfs_link(jn
, session_info
)) {
127 return WERR_NERR_DFSCANTCREATEJUNCTIONPOINT
;
133 WERROR
_dfs_Remove(struct pipes_struct
*p
, struct dfs_Remove
*r
)
135 struct dcesrv_call_state
*dce_call
= p
->dce_call
;
136 struct dcesrv_connection
*dcesrv_conn
= dce_call
->conn
;
137 const struct tsocket_address
*local_address
=
138 dcesrv_connection_get_local_address(dcesrv_conn
);
139 const struct tsocket_address
*remote_address
=
140 dcesrv_connection_get_remote_address(dcesrv_conn
);
141 struct auth_session_info
*session_info
=
142 dcesrv_call_session_info(dce_call
);
143 struct junction_map
*jn
= NULL
;
144 bool self_ref
= False
;
145 size_t consumedcnt
= 0;
147 TALLOC_CTX
*ctx
= talloc_tos();
148 char *altpath
= NULL
;
150 const char *pathnamep
= r
->in
.dfs_entry_path
;
152 if (session_info
->unix_token
->uid
!= sec_initial_uid()) {
153 DEBUG(10,("_dfs_remove: uid != 0. Access denied.\n"));
154 return WERR_ACCESS_DENIED
;
157 jn
= talloc_zero(ctx
, struct junction_map
);
159 return WERR_NOT_ENOUGH_MEMORY
;
162 if (r
->in
.servername
&& r
->in
.sharename
) {
163 altpath
= talloc_asprintf(ctx
, "%s\\%s",
167 return WERR_NOT_ENOUGH_MEMORY
;
169 if (!strlower_m(altpath
)) {
170 return WERR_INVALID_PARAMETER
;
172 DEBUG(5,("init_reply_dfs_remove: Request to remove %s -> %s\\%s.\n",
173 r
->in
.dfs_entry_path
, r
->in
.servername
, r
->in
.sharename
));
176 while (IS_DIRECTORY_SEP(pathnamep
[0]) &&
177 IS_DIRECTORY_SEP(pathnamep
[1])) {
181 status
= get_referred_path(ctx
,
186 jn
, &consumedcnt
, &self_ref
);
187 if(!NT_STATUS_IS_OK(status
)) {
188 return WERR_NERR_DFSNOSUCHVOLUME
;
191 /* if no server-share pair given, remove the msdfs link completely */
192 if(!r
->in
.servername
&& !r
->in
.sharename
) {
193 if(!remove_msdfs_link(jn
, session_info
)) {
194 return WERR_NERR_DFSNOSUCHVOLUME
;
198 /* compare each referral in the list with the one to remove */
199 DBG_DEBUG("altpath: .%s. refcnt: %zu\n",
202 for(i
=0;i
<jn
->referral_count
;i
++) {
203 char *refpath
= talloc_strdup(ctx
,
204 jn
->referral_list
[i
].alternate_path
);
206 return WERR_NOT_ENOUGH_MEMORY
;
208 trim_char(refpath
, '\\', '\\');
209 DEBUG(10,("_dfs_remove: refpath: .%s.\n", refpath
));
210 if(strequal(refpath
, altpath
)) {
211 *(jn
->referral_list
[i
].alternate_path
)='\0';
212 DEBUG(10,("_dfs_remove: Removal request matches referral %s\n",
219 return WERR_NERR_DFSNOSUCHSHARE
;
222 /* Only one referral, remove it */
223 if(jn
->referral_count
== 1) {
224 if(!remove_msdfs_link(jn
, session_info
)) {
225 return WERR_NERR_DFSNOSUCHVOLUME
;
228 if(!create_msdfs_link(jn
, session_info
)) {
229 return WERR_NERR_DFSCANTCREATEJUNCTIONPOINT
;
237 static bool init_reply_dfs_info_1(TALLOC_CTX
*mem_ctx
, struct junction_map
* j
,struct dfs_Info1
* dfs1
)
239 dfs1
->path
= talloc_asprintf(mem_ctx
,
240 "\\\\%s\\%s\\%s", lp_netbios_name(),
241 j
->service_name
, j
->volume_name
);
242 if (dfs1
->path
== NULL
)
245 DEBUG(5,("init_reply_dfs_info_1: initing entrypath: %s\n",dfs1
->path
));
249 static bool init_reply_dfs_info_2(TALLOC_CTX
*mem_ctx
, struct junction_map
* j
, struct dfs_Info2
* dfs2
)
251 dfs2
->path
= talloc_asprintf(mem_ctx
,
252 "\\\\%s\\%s\\%s", lp_netbios_name(), j
->service_name
, j
->volume_name
);
253 if (dfs2
->path
== NULL
)
255 dfs2
->comment
= talloc_strdup(mem_ctx
, j
->comment
);
256 dfs2
->state
= 1; /* set up state of dfs junction as OK */
257 dfs2
->num_stores
= j
->referral_count
;
261 static bool init_reply_dfs_info_3(TALLOC_CTX
*mem_ctx
, struct junction_map
* j
, struct dfs_Info3
* dfs3
)
264 if (j
->volume_name
[0] == '\0')
265 dfs3
->path
= talloc_asprintf(mem_ctx
, "\\\\%s\\%s",
266 lp_netbios_name(), j
->service_name
);
268 dfs3
->path
= talloc_asprintf(mem_ctx
, "\\\\%s\\%s\\%s", lp_netbios_name(),
269 j
->service_name
, j
->volume_name
);
271 if (dfs3
->path
== NULL
)
274 dfs3
->comment
= talloc_strdup(mem_ctx
, j
->comment
);
276 dfs3
->num_stores
= j
->referral_count
;
278 /* also enumerate the stores */
279 if (j
->referral_count
) {
280 dfs3
->stores
= talloc_array(mem_ctx
, struct dfs_StorageInfo
, j
->referral_count
);
283 memset(dfs3
->stores
, '\0', j
->referral_count
* sizeof(struct dfs_StorageInfo
));
288 for(ii
=0;ii
<j
->referral_count
;ii
++) {
291 struct dfs_StorageInfo
* stor
= &(dfs3
->stores
[ii
]);
292 struct referral
* ref
= &(j
->referral_list
[ii
]);
294 path
= talloc_strdup(mem_ctx
, ref
->alternate_path
);
298 trim_char(path
,'\\','\0');
299 p
= strrchr_m(path
,'\\');
301 DEBUG(4,("init_reply_dfs_info_3: invalid path: no \\ found in %s\n",path
));
305 DBG_INFO("storage %zu: %s.%s\n",ii
,path
,p
+1);
306 stor
->state
= 2; /* set all stores as ONLINE */
307 stor
->server
= talloc_strdup(mem_ctx
, path
);
308 stor
->share
= talloc_strdup(mem_ctx
, p
+1);
313 static bool init_reply_dfs_info_100(TALLOC_CTX
*mem_ctx
, struct junction_map
* j
, struct dfs_Info100
* dfs100
)
315 dfs100
->comment
= talloc_strdup(mem_ctx
, j
->comment
);
319 WERROR
_dfs_Enum(struct pipes_struct
*p
, struct dfs_Enum
*r
)
321 struct dcesrv_call_state
*dce_call
= p
->dce_call
;
322 struct auth_session_info
*session_info
=
323 dcesrv_call_session_info(dce_call
);
324 struct junction_map
*jn
= NULL
;
327 TALLOC_CTX
*ctx
= talloc_tos();
329 jn
= enum_msdfs_links(ctx
, session_info
, &num_jn
);
330 if (!jn
|| num_jn
== 0) {
335 DEBUG(5,("_dfs_Enum: %u junctions found in Dfs, doing level %d\n",
336 (unsigned int)num_jn
, r
->in
.level
));
338 *r
->out
.total
= num_jn
;
340 /* Create the return array */
341 switch (r
->in
.level
) {
344 if ((r
->out
.info
->e
.info1
->s
= talloc_array(ctx
, struct dfs_Info1
, num_jn
)) == NULL
) {
345 return WERR_NOT_ENOUGH_MEMORY
;
348 r
->out
.info
->e
.info1
->s
= NULL
;
350 r
->out
.info
->e
.info1
->count
= num_jn
;
354 if ((r
->out
.info
->e
.info2
->s
= talloc_array(ctx
, struct dfs_Info2
, num_jn
)) == NULL
) {
355 return WERR_NOT_ENOUGH_MEMORY
;
358 r
->out
.info
->e
.info2
->s
= NULL
;
360 r
->out
.info
->e
.info2
->count
= num_jn
;
364 if ((r
->out
.info
->e
.info3
->s
= talloc_array(ctx
, struct dfs_Info3
, num_jn
)) == NULL
) {
365 return WERR_NOT_ENOUGH_MEMORY
;
368 r
->out
.info
->e
.info3
->s
= NULL
;
370 r
->out
.info
->e
.info3
->count
= num_jn
;
373 return WERR_INVALID_PARAMETER
;
376 for (i
= 0; i
< num_jn
; i
++) {
377 switch (r
->in
.level
) {
379 init_reply_dfs_info_1(ctx
, &jn
[i
], &r
->out
.info
->e
.info1
->s
[i
]);
382 init_reply_dfs_info_2(ctx
, &jn
[i
], &r
->out
.info
->e
.info2
->s
[i
]);
385 init_reply_dfs_info_3(ctx
, &jn
[i
], &r
->out
.info
->e
.info3
->s
[i
]);
388 return WERR_INVALID_PARAMETER
;
395 WERROR
_dfs_GetInfo(struct pipes_struct
*p
, struct dfs_GetInfo
*r
)
397 struct dcesrv_call_state
*dce_call
= p
->dce_call
;
398 struct dcesrv_connection
*dcesrv_conn
= dce_call
->conn
;
399 const struct tsocket_address
*local_address
=
400 dcesrv_connection_get_local_address(dcesrv_conn
);
401 const struct tsocket_address
*remote_address
=
402 dcesrv_connection_get_remote_address(dcesrv_conn
);
403 struct auth_session_info
*session_info
=
404 dcesrv_call_session_info(dce_call
);
405 size_t consumedcnt
= 0;
406 struct junction_map
*jn
= NULL
;
407 bool self_ref
= False
;
408 TALLOC_CTX
*ctx
= talloc_tos();
411 const char *pathnamep
= r
->in
.dfs_entry_path
;
413 jn
= talloc_zero(ctx
, struct junction_map
);
415 return WERR_NOT_ENOUGH_MEMORY
;
418 while (IS_DIRECTORY_SEP(pathnamep
[0]) &&
419 IS_DIRECTORY_SEP(pathnamep
[1])) {
423 ret
= create_junction(ctx
, pathnamep
, jn
);
425 return WERR_NERR_DFSNOSUCHSERVER
;
428 /* The following call can change the cwd. */
429 status
= get_referred_path(ctx
,
434 jn
, &consumedcnt
, &self_ref
);
435 if(!NT_STATUS_IS_OK(status
) || consumedcnt
< strlen(pathnamep
)) {
436 return WERR_NERR_DFSNOSUCHVOLUME
;
439 switch (r
->in
.level
) {
441 r
->out
.info
->info1
= talloc_zero(ctx
,struct dfs_Info1
);
442 if (!r
->out
.info
->info1
) {
443 return WERR_NOT_ENOUGH_MEMORY
;
445 ret
= init_reply_dfs_info_1(ctx
, jn
, r
->out
.info
->info1
);
448 r
->out
.info
->info2
= talloc_zero(ctx
,struct dfs_Info2
);
449 if (!r
->out
.info
->info2
) {
450 return WERR_NOT_ENOUGH_MEMORY
;
452 ret
= init_reply_dfs_info_2(ctx
, jn
, r
->out
.info
->info2
);
455 r
->out
.info
->info3
= talloc_zero(ctx
,struct dfs_Info3
);
456 if (!r
->out
.info
->info3
) {
457 return WERR_NOT_ENOUGH_MEMORY
;
459 ret
= init_reply_dfs_info_3(ctx
, jn
, r
->out
.info
->info3
);
462 r
->out
.info
->info100
= talloc_zero(ctx
,struct dfs_Info100
);
463 if (!r
->out
.info
->info100
) {
464 return WERR_NOT_ENOUGH_MEMORY
;
466 ret
= init_reply_dfs_info_100(ctx
, jn
, r
->out
.info
->info100
);
469 r
->out
.info
->info1
= NULL
;
470 return WERR_INVALID_PARAMETER
;
474 return WERR_INVALID_PARAMETER
;
479 WERROR
_dfs_SetInfo(struct pipes_struct
*p
, struct dfs_SetInfo
*r
)
481 /* FIXME: Implement your code here */
482 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
483 return WERR_NOT_SUPPORTED
;
486 WERROR
_dfs_Rename(struct pipes_struct
*p
, struct dfs_Rename
*r
)
488 /* FIXME: Implement your code here */
489 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
490 return WERR_NOT_SUPPORTED
;
493 WERROR
_dfs_Move(struct pipes_struct
*p
, struct dfs_Move
*r
)
495 /* FIXME: Implement your code here */
496 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
497 return WERR_NOT_SUPPORTED
;
500 WERROR
_dfs_ManagerGetConfigInfo(struct pipes_struct
*p
, struct dfs_ManagerGetConfigInfo
*r
)
502 /* FIXME: Implement your code here */
503 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
504 return WERR_NOT_SUPPORTED
;
507 WERROR
_dfs_ManagerSendSiteInfo(struct pipes_struct
*p
, struct dfs_ManagerSendSiteInfo
*r
)
509 /* FIXME: Implement your code here */
510 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
511 return WERR_NOT_SUPPORTED
;
514 WERROR
_dfs_AddFtRoot(struct pipes_struct
*p
, struct dfs_AddFtRoot
*r
)
516 /* FIXME: Implement your code here */
517 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
518 return WERR_NOT_SUPPORTED
;
521 WERROR
_dfs_RemoveFtRoot(struct pipes_struct
*p
, struct dfs_RemoveFtRoot
*r
)
523 /* FIXME: Implement your code here */
524 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
525 return WERR_NOT_SUPPORTED
;
528 WERROR
_dfs_AddStdRoot(struct pipes_struct
*p
, struct dfs_AddStdRoot
*r
)
530 /* FIXME: Implement your code here */
531 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
532 return WERR_NOT_SUPPORTED
;
535 WERROR
_dfs_RemoveStdRoot(struct pipes_struct
*p
, struct dfs_RemoveStdRoot
*r
)
537 /* FIXME: Implement your code here */
538 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
539 return WERR_NOT_SUPPORTED
;
542 WERROR
_dfs_ManagerInitialize(struct pipes_struct
*p
, struct dfs_ManagerInitialize
*r
)
544 /* FIXME: Implement your code here */
545 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
546 return WERR_NOT_SUPPORTED
;
549 WERROR
_dfs_AddStdRootForced(struct pipes_struct
*p
, struct dfs_AddStdRootForced
*r
)
551 /* FIXME: Implement your code here */
552 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
553 return WERR_NOT_SUPPORTED
;
556 WERROR
_dfs_GetDcAddress(struct pipes_struct
*p
, struct dfs_GetDcAddress
*r
)
558 /* FIXME: Implement your code here */
559 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
560 return WERR_NOT_SUPPORTED
;
563 WERROR
_dfs_SetDcAddress(struct pipes_struct
*p
, struct dfs_SetDcAddress
*r
)
565 /* FIXME: Implement your code here */
566 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
567 return WERR_NOT_SUPPORTED
;
570 WERROR
_dfs_FlushFtTable(struct pipes_struct
*p
, struct dfs_FlushFtTable
*r
)
572 /* FIXME: Implement your code here */
573 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
574 return WERR_NOT_SUPPORTED
;
577 WERROR
_dfs_Add2(struct pipes_struct
*p
, struct dfs_Add2
*r
)
579 /* FIXME: Implement your code here */
580 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
581 return WERR_NOT_SUPPORTED
;
584 WERROR
_dfs_Remove2(struct pipes_struct
*p
, struct dfs_Remove2
*r
)
586 /* FIXME: Implement your code here */
587 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
588 return WERR_NOT_SUPPORTED
;
591 WERROR
_dfs_EnumEx(struct pipes_struct
*p
, struct dfs_EnumEx
*r
)
593 /* FIXME: Implement your code here */
594 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
595 return WERR_NOT_SUPPORTED
;
598 WERROR
_dfs_SetInfo2(struct pipes_struct
*p
, struct dfs_SetInfo2
*r
)
600 /* FIXME: Implement your code here */
601 p
->fault_state
= DCERPC_FAULT_OP_RNG_ERROR
;
602 return WERR_NOT_SUPPORTED
;
605 /* include the generated boilerplate */
606 #include "librpc/gen_ndr/ndr_dfs_scompat.c"