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.
6 * Copyright (C) Jelmer Vernooij 2005.
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 2 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, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 /* This is the implementation of the dfs pipe. */
28 #define DBGC_CLASS DBGC_MSDFS
30 /* This function does not return a WERROR or NTSTATUS code but rather 1 if
31 dfs exists, or 0 otherwise. */
33 uint32
_dfs_GetManagerVersion(pipes_struct
*p
, NETDFS_Q_DFS_GETMANAGERVERSION
*q_u
, NETDFS_R_DFS_GETMANAGERVERSION
*r_u
)
41 WERROR
_dfs_Add(pipes_struct
*p
, NETDFS_Q_DFS_ADD
* q_u
, NETDFS_R_DFS_ADD
*r_u
)
43 struct current_user user
;
44 struct junction_map jn
;
45 struct referral
* old_referral_list
= NULL
;
46 BOOL self_ref
= False
;
50 pstring dfspath
, servername
, sharename
;
53 get_current_user(&user
,p
);
55 if (user
.ut
.uid
!= 0) {
56 DEBUG(10,("_dfs_add: uid != 0. Access denied.\n"));
57 return WERR_ACCESS_DENIED
;
60 unistr2_to_ascii(dfspath
, &q_u
->path
, sizeof(dfspath
)-1);
61 unistr2_to_ascii(servername
, &q_u
->server
, sizeof(servername
)-1);
62 unistr2_to_ascii(sharename
, &q_u
->share
, sizeof(sharename
)-1);
64 DEBUG(5,("init_reply_dfs_add: Request to add %s -> %s\\%s.\n",
65 dfspath
, servername
, sharename
));
67 pstrcpy(altpath
, servername
);
68 pstrcat(altpath
, "\\");
69 pstrcat(altpath
, sharename
);
71 /* The following call can change the cwd. */
72 if(NT_STATUS_IS_OK(get_referred_path(p
->mem_ctx
, dfspath
, &jn
, &consumedcnt
, &self_ref
))) {
74 jn
.referral_count
+= 1;
75 old_referral_list
= jn
.referral_list
;
77 jn
.referral_count
= 1;
80 vfs_ChDir(p
->conn
,p
->conn
->connectpath
);
82 jn
.referral_list
= TALLOC_ARRAY(p
->mem_ctx
, struct referral
, jn
.referral_count
);
83 if(jn
.referral_list
== NULL
) {
84 DEBUG(0,("init_reply_dfs_add: talloc failed for referral list!\n"));
85 return WERR_DFS_INTERNAL_ERROR
;
88 if(old_referral_list
) {
89 memcpy(jn
.referral_list
, old_referral_list
, sizeof(struct referral
)*jn
.referral_count
-1);
92 jn
.referral_list
[jn
.referral_count
-1].proximity
= 0;
93 jn
.referral_list
[jn
.referral_count
-1].ttl
= REFERRAL_TTL
;
95 pstrcpy(jn
.referral_list
[jn
.referral_count
-1].alternate_path
, altpath
);
97 if(!create_msdfs_link(&jn
, exists
)) {
98 vfs_ChDir(p
->conn
,p
->conn
->connectpath
);
99 return WERR_DFS_CANT_CREATE_JUNCT
;
101 vfs_ChDir(p
->conn
,p
->conn
->connectpath
);
106 WERROR
_dfs_Remove(pipes_struct
*p
, NETDFS_Q_DFS_REMOVE
*q_u
,
107 NETDFS_R_DFS_REMOVE
*r_u
)
109 struct current_user user
;
110 struct junction_map jn
;
111 BOOL self_ref
= False
;
115 pstring dfspath
, servername
, sharename
;
118 get_current_user(&user
,p
);
120 if (user
.ut
.uid
!= 0) {
121 DEBUG(10,("_dfs_remove: uid != 0. Access denied.\n"));
122 return WERR_ACCESS_DENIED
;
125 unistr2_to_ascii(dfspath
, &q_u
->path
, sizeof(dfspath
)-1);
126 if(q_u
->ptr0_server
) {
127 unistr2_to_ascii(servername
, &q_u
->server
, sizeof(servername
)-1);
130 if(q_u
->ptr0_share
) {
131 unistr2_to_ascii(sharename
, &q_u
->share
, sizeof(sharename
)-1);
134 if(q_u
->ptr0_server
&& q_u
->ptr0_share
) {
135 pstrcpy(altpath
, servername
);
136 pstrcat(altpath
, "\\");
137 pstrcat(altpath
, sharename
);
141 DEBUG(5,("init_reply_dfs_remove: Request to remove %s -> %s\\%s.\n",
142 dfspath
, servername
, sharename
));
144 if(!NT_STATUS_IS_OK(get_referred_path(p
->mem_ctx
, dfspath
, &jn
, &consumedcnt
, &self_ref
))) {
145 return WERR_DFS_NO_SUCH_VOL
;
148 /* if no server-share pair given, remove the msdfs link completely */
149 if(!q_u
->ptr0_server
&& !q_u
->ptr0_share
) {
150 if(!remove_msdfs_link(&jn
)) {
151 vfs_ChDir(p
->conn
,p
->conn
->connectpath
);
152 return WERR_DFS_NO_SUCH_VOL
;
154 vfs_ChDir(p
->conn
,p
->conn
->connectpath
);
157 /* compare each referral in the list with the one to remove */
158 DEBUG(10,("altpath: .%s. refcnt: %d\n", altpath
, jn
.referral_count
));
159 for(i
=0;i
<jn
.referral_count
;i
++) {
161 pstrcpy(refpath
,jn
.referral_list
[i
].alternate_path
);
162 trim_char(refpath
, '\\', '\\');
163 DEBUG(10,("_dfs_remove: refpath: .%s.\n", refpath
));
164 if(strequal(refpath
, altpath
)) {
165 *(jn
.referral_list
[i
].alternate_path
)='\0';
166 DEBUG(10,("_dfs_remove: Removal request matches referral %s\n",
173 return WERR_DFS_NO_SUCH_SHARE
;
176 /* Only one referral, remove it */
177 if(jn
.referral_count
== 1) {
178 if(!remove_msdfs_link(&jn
)) {
179 vfs_ChDir(p
->conn
,p
->conn
->connectpath
);
180 return WERR_DFS_NO_SUCH_VOL
;
183 if(!create_msdfs_link(&jn
, True
)) {
184 vfs_ChDir(p
->conn
,p
->conn
->connectpath
);
185 return WERR_DFS_CANT_CREATE_JUNCT
;
188 vfs_ChDir(p
->conn
,p
->conn
->connectpath
);
194 static BOOL
init_reply_dfs_info_1(struct junction_map
* j
, NETDFS_DFS_INFO1
* dfs1
)
198 slprintf(str
, sizeof(pstring
)-1, "\\\\%s\\%s\\%s", global_myname(),
199 j
->service_name
, j
->volume_name
);
200 DEBUG(5,("init_reply_dfs_info_1: initing entrypath: %s\n",str
));
201 init_unistr2(&dfs1
->path
,str
,UNI_STR_TERMINATE
);
205 static BOOL
init_reply_dfs_info_2(struct junction_map
* j
, NETDFS_DFS_INFO2
* dfs2
)
209 slprintf(str
, sizeof(pstring
)-1, "\\\\%s\\%s\\%s", global_myname(),
210 j
->service_name
, j
->volume_name
);
211 init_unistr2(&dfs2
->path
, str
, UNI_STR_TERMINATE
);
212 dfs2
->ptr0_comment
= 0;
213 init_unistr2(&dfs2
->comment
, j
->comment
, UNI_STR_TERMINATE
);
214 dfs2
->state
= 1; /* set up state of dfs junction as OK */
215 dfs2
->num_stores
= j
->referral_count
;
219 static BOOL
init_reply_dfs_info_3(TALLOC_CTX
*ctx
, struct junction_map
* j
, NETDFS_DFS_INFO3
* dfs3
)
224 if (j
->volume_name
[0] == '\0')
225 slprintf(str
, sizeof(pstring
)-1, "\\\\%s\\%s",
226 global_myname(), j
->service_name
);
228 slprintf(str
, sizeof(pstring
)-1, "\\\\%s\\%s\\%s", global_myname(),
229 j
->service_name
, j
->volume_name
);
231 init_unistr2(&dfs3
->path
, str
, UNI_STR_TERMINATE
);
232 dfs3
->ptr0_comment
= 1;
233 init_unistr2(&dfs3
->comment
, j
->comment
, UNI_STR_TERMINATE
);
235 dfs3
->num_stores
= dfs3
->size_stores
= j
->referral_count
;
237 /* also enumerate the stores */
238 if (j
->referral_count
) {
239 dfs3
->stores
= TALLOC_ARRAY(ctx
, NETDFS_DFS_STORAGEINFO
, j
->referral_count
);
242 memset(dfs3
->stores
, '\0', j
->referral_count
* sizeof(NETDFS_DFS_STORAGEINFO
));
243 dfs3
->ptr0_stores
= 1;
246 dfs3
->ptr0_stores
= 0;
249 for(ii
=0;ii
<j
->referral_count
;ii
++) {
252 NETDFS_DFS_STORAGEINFO
* stor
= &(dfs3
->stores
[ii
]);
253 struct referral
* ref
= &(j
->referral_list
[ii
]);
255 pstrcpy(path
, ref
->alternate_path
);
256 trim_char(path
,'\\','\0');
257 p
= strrchr_m(path
,'\\');
259 DEBUG(4,("init_reply_dfs_info_3: invalid path: no \\ found in %s\n",path
));
263 DEBUG(5,("storage %d: %s.%s\n",ii
,path
,p
+1));
264 stor
->state
= 2; /* set all stores as ONLINE */
265 init_unistr2(&stor
->server
, path
, UNI_STR_TERMINATE
);
266 init_unistr2(&stor
->share
, p
+1, UNI_STR_TERMINATE
);
267 stor
->ptr0_server
= stor
->ptr0_share
= 1;
272 static BOOL
init_reply_dfs_info_100(struct junction_map
* j
, NETDFS_DFS_INFO100
* dfs100
)
274 dfs100
->ptr0_comment
= 1;
275 init_unistr2(&dfs100
->comment
, j
->comment
, UNI_STR_TERMINATE
);
280 WERROR
_dfs_Enum(pipes_struct
*p
, NETDFS_Q_DFS_ENUM
*q_u
, NETDFS_R_DFS_ENUM
*r_u
)
282 uint32 level
= q_u
->level
;
283 struct junction_map jn
[MAX_MSDFS_JUNCTIONS
];
287 num_jn
= enum_msdfs_links(p
->mem_ctx
, jn
, ARRAY_SIZE(jn
));
288 vfs_ChDir(p
->conn
,p
->conn
->connectpath
);
290 DEBUG(5,("_dfs_Enum: %d junctions found in Dfs, doing level %d\n", num_jn
, level
));
292 r_u
->ptr0_info
= q_u
->ptr0_info
;
293 r_u
->ptr0_total
= q_u
->ptr0_total
;
296 r_u
->info
= q_u
->info
;
298 /* Create the return array */
301 r_u
->info
.e
.u
.info1
.count
= num_jn
;
303 if ((r_u
->info
.e
.u
.info1
.s
= TALLOC_ARRAY(p
->mem_ctx
, NETDFS_DFS_INFO1
, num_jn
)) == NULL
) {
306 r_u
->info
.e
.u
.info1
.ptr0_s
= 1;
307 r_u
->info
.e
.u
.info1
.size_s
= num_jn
;
311 r_u
->info
.e
.u
.info2
.count
= num_jn
;
313 if ((r_u
->info
.e
.u
.info2
.s
= TALLOC_ARRAY(p
->mem_ctx
, NETDFS_DFS_INFO2
, num_jn
)) == NULL
) {
316 r_u
->info
.e
.u
.info2
.ptr0_s
= 1;
317 r_u
->info
.e
.u
.info2
.size_s
= num_jn
;
321 r_u
->info
.e
.u
.info3
.count
= num_jn
;
323 if ((r_u
->info
.e
.u
.info3
.s
= TALLOC_ARRAY(p
->mem_ctx
, NETDFS_DFS_INFO3
, num_jn
)) == NULL
) {
326 r_u
->info
.e
.u
.info3
.ptr0_s
= 1;
327 r_u
->info
.e
.u
.info3
.size_s
= num_jn
;
331 return WERR_INVALID_PARAM
;
334 for (i
= 0; i
< num_jn
; i
++) {
337 init_reply_dfs_info_1(&jn
[i
], &r_u
->info
.e
.u
.info1
.s
[i
]);
340 init_reply_dfs_info_2(&jn
[i
], &r_u
->info
.e
.u
.info2
.s
[i
]);
343 init_reply_dfs_info_3(p
->mem_ctx
, &jn
[i
], &r_u
->info
.e
.u
.info3
.s
[i
]);
346 return WERR_INVALID_PARAM
;
350 r_u
->status
= WERR_OK
;
355 WERROR
_dfs_GetInfo(pipes_struct
*p
, NETDFS_Q_DFS_GETINFO
*q_u
,
356 NETDFS_R_DFS_GETINFO
*r_u
)
358 UNISTR2
* uni_path
= &q_u
->path
;
359 uint32 level
= q_u
->level
;
360 int consumedcnt
= sizeof(pstring
);
363 BOOL self_ref
= False
;
364 struct junction_map jn
;
366 unistr2_to_ascii(path
, uni_path
, sizeof(path
)-1);
367 if(!create_junction(path
, &jn
))
368 return WERR_DFS_NO_SUCH_SERVER
;
370 /* The following call can change the cwd. */
371 if(!NT_STATUS_IS_OK(get_referred_path(p
->mem_ctx
, path
, &jn
, &consumedcnt
, &self_ref
)) || consumedcnt
< strlen(path
)) {
372 vfs_ChDir(p
->conn
,p
->conn
->connectpath
);
373 return WERR_DFS_NO_SUCH_VOL
;
376 vfs_ChDir(p
->conn
,p
->conn
->connectpath
);
377 r_u
->info
.switch_value
= level
;
379 r_u
->status
= WERR_OK
;
382 case 1: ret
= init_reply_dfs_info_1(&jn
, &r_u
->info
.u
.info1
); break;
383 case 2: ret
= init_reply_dfs_info_2(&jn
, &r_u
->info
.u
.info2
); break;
384 case 3: ret
= init_reply_dfs_info_3(p
->mem_ctx
, &jn
, &r_u
->info
.u
.info3
); break;
385 case 100: ret
= init_reply_dfs_info_100(&jn
, &r_u
->info
.u
.info100
); break;
388 r_u
->info
.switch_value
= 0;
389 r_u
->status
= WERR_OK
;
395 r_u
->status
= WERR_INVALID_PARAM
;
400 WERROR
_dfs_SetInfo(pipes_struct
*p
, NETDFS_Q_DFS_SETINFO
*q_u
, NETDFS_R_DFS_SETINFO
*r_u
)
402 /* FIXME: Implement your code here */
403 return WERR_NOT_SUPPORTED
;
406 WERROR
_dfs_Rename(pipes_struct
*p
, NETDFS_Q_DFS_RENAME
*q_u
, NETDFS_R_DFS_RENAME
*r_u
)
408 /* FIXME: Implement your code here */
409 return WERR_NOT_SUPPORTED
;
412 WERROR
_dfs_Move(pipes_struct
*p
, NETDFS_Q_DFS_MOVE
*q_u
, NETDFS_R_DFS_MOVE
*r_u
)
414 /* FIXME: Implement your code here */
415 return WERR_NOT_SUPPORTED
;
418 WERROR
_dfs_ManagerGetConfigInfo(pipes_struct
*p
, NETDFS_Q_DFS_MANAGERGETCONFIGINFO
*q_u
, NETDFS_R_DFS_MANAGERGETCONFIGINFO
*r_u
)
420 /* FIXME: Implement your code here */
421 return WERR_NOT_SUPPORTED
;
424 WERROR
_dfs_ManagerSendSiteInfo(pipes_struct
*p
, NETDFS_Q_DFS_MANAGERSENDSITEINFO
*q_u
, NETDFS_R_DFS_MANAGERSENDSITEINFO
*r_u
)
426 /* FIXME: Implement your code here */
427 return WERR_NOT_SUPPORTED
;
430 WERROR
_dfs_AddFtRoot(pipes_struct
*p
, NETDFS_Q_DFS_ADDFTROOT
*q_u
, NETDFS_R_DFS_ADDFTROOT
*r_u
)
432 /* FIXME: Implement your code here */
433 return WERR_NOT_SUPPORTED
;
436 WERROR
_dfs_RemoveFtRoot(pipes_struct
*p
, NETDFS_Q_DFS_REMOVEFTROOT
*q_u
, NETDFS_R_DFS_REMOVEFTROOT
*r_u
)
438 /* FIXME: Implement your code here */
439 return WERR_NOT_SUPPORTED
;
442 WERROR
_dfs_AddStdRoot(pipes_struct
*p
, NETDFS_Q_DFS_ADDSTDROOT
*q_u
, NETDFS_R_DFS_ADDSTDROOT
*r_u
)
444 /* FIXME: Implement your code here */
445 return WERR_NOT_SUPPORTED
;
448 WERROR
_dfs_RemoveStdRoot(pipes_struct
*p
, NETDFS_Q_DFS_REMOVESTDROOT
*q_u
, NETDFS_R_DFS_REMOVESTDROOT
*r_u
)
450 /* FIXME: Implement your code here */
451 return WERR_NOT_SUPPORTED
;
454 WERROR
_dfs_ManagerInitialize(pipes_struct
*p
, NETDFS_Q_DFS_MANAGERINITIALIZE
*q_u
, NETDFS_R_DFS_MANAGERINITIALIZE
*r_u
)
456 /* FIXME: Implement your code here */
457 return WERR_NOT_SUPPORTED
;
460 WERROR
_dfs_AddStdRootForced(pipes_struct
*p
, NETDFS_Q_DFS_ADDSTDROOTFORCED
*q_u
, NETDFS_R_DFS_ADDSTDROOTFORCED
*r_u
)
462 /* FIXME: Implement your code here */
463 return WERR_NOT_SUPPORTED
;
466 WERROR
_dfs_GetDcAddress(pipes_struct
*p
, NETDFS_Q_DFS_GETDCADDRESS
*q_u
, NETDFS_R_DFS_GETDCADDRESS
*r_u
)
468 /* FIXME: Implement your code here */
469 return WERR_NOT_SUPPORTED
;
472 WERROR
_dfs_SetDcAddress(pipes_struct
*p
, NETDFS_Q_DFS_SETDCADDRESS
*q_u
, NETDFS_R_DFS_SETDCADDRESS
*r_u
)
474 /* FIXME: Implement your code here */
475 return WERR_NOT_SUPPORTED
;
478 WERROR
_dfs_FlushFtTable(pipes_struct
*p
, NETDFS_Q_DFS_FLUSHFTTABLE
*q_u
, NETDFS_R_DFS_FLUSHFTTABLE
*r_u
)
480 /* FIXME: Implement your code here */
481 return WERR_NOT_SUPPORTED
;
484 WERROR
_dfs_Add2(pipes_struct
*p
, NETDFS_Q_DFS_ADD2
*q_u
, NETDFS_R_DFS_ADD2
*r_u
)
486 /* FIXME: Implement your code here */
487 return WERR_NOT_SUPPORTED
;
490 WERROR
_dfs_Remove2(pipes_struct
*p
, NETDFS_Q_DFS_REMOVE2
*q_u
, NETDFS_R_DFS_REMOVE2
*r_u
)
492 /* FIXME: Implement your code here */
493 return WERR_NOT_SUPPORTED
;
496 WERROR
_dfs_EnumEx(pipes_struct
*p
, NETDFS_Q_DFS_ENUMEX
*q_u
, NETDFS_R_DFS_ENUMEX
*r_u
)
498 /* FIXME: Implement your code here */
499 return WERR_NOT_SUPPORTED
;
502 WERROR
_dfs_SetInfo2(pipes_struct
*p
, NETDFS_Q_DFS_SETINFO2
*q_u
, NETDFS_R_DFS_SETINFO2
*r_u
)
504 /* FIXME: Implement your code here */
505 return WERR_NOT_SUPPORTED
;