1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26/*
27 * Net DFS server side RPC service for managing DFS namespaces.
28 *
29 * For more details refer to following Microsoft specification:
30 * [MS-DFSNM]
31 *    Distributed File System (DFS): Namespace Management Protocol Specification
32 */
33
34#include <unistd.h>
35#include <libgen.h>
36#include <strings.h>
37#include <sys/sysmacros.h>
38
39#include <smbsrv/libmlsvc.h>
40#include <smbsrv/nmpipes.h>
41#include <smbsrv/ndl/netdfs.ndl>
42#include <dfs.h>
43
44/*
45 * Depends on the information level requested around 4000 or more links
46 * can be provided with this buffer size. The limitation here is due
47 * to some problem in NDR and/or opipe layer so:
48 *
49 * - Do NOT increase the buffer size until that problem is fixed
50 * - The buffer size should be increased when the problem is fixed
51 *   so the 4000 link limitation is removed.
52 */
53#define	NETDFS_MAXBUFLEN	(800 * 1024)
54#define	NETDFS_MAXPREFLEN	((uint32_t)(-1))
55
56typedef struct netdfs_enumhandle_t {
57	uint32_t	de_level;	/* level of detail being requested */
58	uint32_t	de_prefmaxlen;	/* client MAX size buffer preference */
59	uint32_t	de_resume;	/* client resume handle */
60	uint32_t	de_bavail;	/* remaining buffer space in bytes */
61	uint32_t	de_ntotal;	/* total number of objects */
62	uint32_t	de_nmax;	/* MAX number of objects to return */
63	uint32_t	de_nitems;	/* number of objects in buf */
64	uint32_t	de_nskip;	/* number of objects to skip */
65	void		*de_entries;	/* ndr buffer */
66} netdfs_enumhandle_t;
67
68static int netdfs_s_getver(void *, ndr_xa_t *);
69static int netdfs_s_add(void *, ndr_xa_t *);
70static int netdfs_s_remove(void *, ndr_xa_t *);
71static int netdfs_s_setinfo(void *, ndr_xa_t *);
72static int netdfs_s_getinfo(void *, ndr_xa_t *);
73static int netdfs_s_enum(void *, ndr_xa_t *);
74static int netdfs_s_move(void *, ndr_xa_t *);
75static int netdfs_s_rename(void *, ndr_xa_t *);
76static int netdfs_s_addstdroot(void *, ndr_xa_t *);
77static int netdfs_s_remstdroot(void *, ndr_xa_t *);
78static int netdfs_s_enumex(void *, ndr_xa_t *);
79
80static uint32_t netdfs_setinfo_100(dfs_path_t *, netdfs_info100_t *);
81static uint32_t netdfs_setinfo_101(dfs_path_t *, netdfs_info101_t *,
82    const char *, const char *);
83static uint32_t netdfs_setinfo_102(dfs_path_t *, netdfs_info102_t *);
84static uint32_t netdfs_setinfo_103(dfs_path_t *, netdfs_info103_t *);
85static uint32_t netdfs_setinfo_104(dfs_path_t *, netdfs_info104_t *,
86    const char *, const char *);
87static uint32_t netdfs_setinfo_105(dfs_path_t *, netdfs_info105_t *);
88
89static uint32_t netdfs_info_1(netdfs_info1_t *, dfs_info_t *, ndr_xa_t *,
90    uint32_t *);
91static uint32_t netdfs_info_2(netdfs_info2_t *, dfs_info_t *, ndr_xa_t *,
92    uint32_t *);
93static uint32_t netdfs_info_3(netdfs_info3_t *, dfs_info_t *, ndr_xa_t *,
94    uint32_t *);
95static uint32_t netdfs_info_4(netdfs_info4_t *, dfs_info_t *, ndr_xa_t *,
96    uint32_t *);
97static uint32_t netdfs_info_5(netdfs_info5_t *, dfs_info_t *, ndr_xa_t *,
98    uint32_t *);
99static uint32_t netdfs_info_6(netdfs_info6_t *, dfs_info_t *, ndr_xa_t *,
100    uint32_t *);
101static uint32_t netdfs_info_100(netdfs_info100_t *, dfs_info_t *, ndr_xa_t *,
102    uint32_t *);
103static uint32_t netdfs_info_300(netdfs_info300_t *, dfs_info_t *, ndr_xa_t *,
104    uint32_t *);
105
106static uint32_t netdfs_enum_common(netdfs_enumhandle_t *, ndr_xa_t *);
107
108static void netdfs_path_create(const char *);
109static void netdfs_path_remove(smb_unc_t *);
110static boolean_t netdfs_guid_fromstr(char *, netdfs_uuid_t *);
111
112static ndr_stub_table_t netdfs_stub_table[] = {
113	{ netdfs_s_getver,	NETDFS_OPNUM_GETVER },
114	{ netdfs_s_add,		NETDFS_OPNUM_ADD },
115	{ netdfs_s_remove,	NETDFS_OPNUM_REMOVE },
116	{ netdfs_s_setinfo,	NETDFS_OPNUM_SETINFO },
117	{ netdfs_s_getinfo,	NETDFS_OPNUM_GETINFO },
118	{ netdfs_s_enum,	NETDFS_OPNUM_ENUM },
119	{ netdfs_s_rename,	NETDFS_OPNUM_RENAME },
120	{ netdfs_s_move,	NETDFS_OPNUM_MOVE },
121	{ netdfs_s_addstdroot,	NETDFS_OPNUM_ADDSTDROOT },
122	{ netdfs_s_remstdroot,	NETDFS_OPNUM_REMSTDROOT },
123	{ netdfs_s_enumex,	NETDFS_OPNUM_ENUMEX },
124	{0}
125};
126
127static ndr_service_t netdfs_service = {
128	"NETDFS",			/* name */
129	"DFS",				/* desc */
130	"\\netdfs",			/* endpoint */
131	PIPE_NETDFS,			/* sec_addr_port */
132	NETDFS_ABSTRACT_UUID,	NETDFS_ABSTRACT_VERS,
133	NETDFS_TRANSFER_UUID,	NETDFS_TRANSFER_VERS,
134
135	0,				/* no bind_instance_size */
136	0,				/* no bind_req() */
137	0,				/* no unbind_and_close() */
138	0,				/* use generic_call_stub() */
139
140	&TYPEINFO(netdfs_interface),	/* interface ti */
141	netdfs_stub_table		/* stub_table */
142};
143
144/*
145 * Register the NETDFS RPC interface with the RPC runtime library.
146 * The service must be registered in order to use either the client
147 * side or the server side functions.
148 */
149void
150netdfs_initialize(void)
151{
152	(void) ndr_svc_register(&netdfs_service);
153	dfs_init();
154}
155
156void
157netdfs_finalize(void)
158{
159	dfs_fini();
160}
161
162/*
163 * Returns the version number of the DFS server in use on the server.
164 *
165 * [MS-DFSNM]: NetrDfsManagerGetVersion (Opnum 0)
166 */
167/*ARGSUSED*/
168static int
169netdfs_s_getver(void *arg, ndr_xa_t *mxa)
170{
171	struct netdfs_getver *param = arg;
172
173	param->version = DFS_MANAGER_VERSION_NT4;
174	return (NDR_DRC_OK);
175}
176
177/*
178 * Creates a new DFS link or adds a new target to an existing link of a
179 * DFS namespace.
180 *
181 * [MS-DFSNM]: NetrDfsAdd (Opnum 1)
182 */
183static int
184netdfs_s_add(void *arg, ndr_xa_t *mxa)
185{
186	netdfs_add_t *param = arg;
187	dfs_path_t path;
188	uint32_t status;
189	const char *uncpath = (const char *)param->dfs_path;
190	const char *fspath = (const char *)path.p_fspath;
191	boolean_t newlink;
192
193	if (!ndr_is_admin(mxa)) {
194		param->status = ERROR_ACCESS_DENIED;
195		return (NDR_DRC_OK);
196	}
197
198	if (param->server == NULL || param->share == NULL) {
199		param->status = ERROR_INVALID_PARAMETER;
200		return (NDR_DRC_OK);
201	}
202
203	switch (param->flags) {
204	case DFS_CREATE_VOLUME:
205	case DFS_ADD_VOLUME:
206	case DFS_RESTORE_VOLUME:
207	case (DFS_ADD_VOLUME | DFS_RESTORE_VOLUME):
208		break;
209	default:
210		param->status = ERROR_INVALID_PARAMETER;
211		return (NDR_DRC_OK);
212	}
213
214	status = dfs_path_parse(&path, uncpath, DFS_OBJECT_LINK);
215	if (status != ERROR_SUCCESS) {
216		param->status = status;
217		return (NDR_DRC_OK);
218	}
219
220	status = smb_name_validate_rpath(path.p_unc.unc_path);
221	if (status != ERROR_SUCCESS) {
222		dfs_path_free(&path);
223		param->status = status;
224		return (NDR_DRC_OK);
225	}
226
227	dfs_setpriv(PRIV_ON);
228
229	netdfs_path_create(fspath);
230
231	status = dfs_link_add(fspath, (const char *)param->server,
232	    (const char *)param->share, (const char *)param->comment,
233	    param->flags, &newlink);
234
235	if (newlink)
236		(void) dfs_cache_add_byname(path.p_unc.unc_share,
237		    path.p_unc.unc_path, DFS_OBJECT_LINK);
238
239	if (status != ERROR_SUCCESS)
240		netdfs_path_remove(&path.p_unc);
241
242	dfs_setpriv(PRIV_OFF);
243
244	dfs_path_free(&path);
245	param->status = status;
246	return (NDR_DRC_OK);
247}
248
249/*
250 * Removes a link or a link target from a DFS namespace. A link can be
251 * removed regardless of the number of targets associated with it.
252 *
253 * [MS-DFSNM]: NetrDfsRemove (Opnum 2)
254 */
255static int
256netdfs_s_remove(void *arg, ndr_xa_t *mxa)
257{
258	struct netdfs_remove *param = arg;
259	dfs_path_t path;
260	uint32_t status, stat;
261	const char *uncpath = (const char *)param->dfs_path;
262	const char *fspath = (const char *)path.p_fspath;
263
264	if (!ndr_is_admin(mxa)) {
265		param->status = ERROR_ACCESS_DENIED;
266		return (NDR_DRC_OK);
267	}
268
269	/* both server and share must be NULL or non-NULL */
270	if ((param->server == NULL && param->share != NULL) ||
271	    (param->server != NULL && param->share == NULL)) {
272		param->status = ERROR_INVALID_PARAMETER;
273		return (NDR_DRC_OK);
274	}
275
276	status = dfs_path_parse(&path, uncpath, DFS_OBJECT_LINK);
277	if (status != ERROR_SUCCESS) {
278		param->status = status;
279		return (NDR_DRC_OK);
280	}
281
282	dfs_setpriv(PRIV_ON);
283
284	status = dfs_link_remove(fspath, (const char *)param->server,
285	    (const char *)param->share);
286
287	if (status == ERROR_SUCCESS) {
288		if (dfs_link_stat(fspath, &stat) == ERROR_SUCCESS) {
289			if (stat != DFS_STAT_ISDFS)
290				dfs_cache_remove(path.p_unc.unc_share,
291				    path.p_unc.unc_path);
292			/*
293			 * if link is removed then try to remove its
294			 * empty parent directories if any
295			 */
296			if (stat == DFS_STAT_NOTFOUND)
297				netdfs_path_remove(&path.p_unc);
298		}
299	}
300
301	dfs_setpriv(PRIV_OFF);
302
303	dfs_path_free(&path);
304	param->status = status;
305	return (NDR_DRC_OK);
306}
307
308/*
309 * Sets or modifies information relevant to a specific DFS root, DFS root
310 * target, DFS link, or DFS link target
311 *
312 * [MS-DFSNM]: NetrDfsSetInfo (Opnum 3)
313 */
314/*ARGSUSED*/
315static int
316netdfs_s_setinfo(void *arg, ndr_xa_t *mxa)
317{
318	netdfs_setinfo_t *param = arg;
319	dfs_path_t path;
320	uint32_t status, stat;
321
322	/* both server and share must be NULL or non-NULL */
323	if ((param->server == NULL && param->share != NULL) ||
324	    (param->server != NULL && param->share == NULL)) {
325		param->status = ERROR_INVALID_PARAMETER;
326		return (NDR_DRC_OK);
327	}
328
329	status = dfs_path_parse(&path, (const char *)param->dfs_path,
330	    DFS_OBJECT_ANY);
331
332	if (status != ERROR_SUCCESS) {
333		param->status = status;
334		return (NDR_DRC_OK);
335	}
336
337	dfs_setpriv(PRIV_ON);
338	status = dfs_link_stat((const char *)path.p_fspath, &stat);
339
340	if ((path.p_type == DFS_OBJECT_LINK) && (stat != DFS_STAT_ISDFS)) {
341		dfs_setpriv(PRIV_OFF);
342		dfs_path_free(&path);
343		param->status = ERROR_NOT_FOUND;
344		return (NDR_DRC_OK);
345	}
346
347	switch (param->info.level) {
348	case 100:
349		status = netdfs_setinfo_100(&path, param->info.iu.info100);
350		break;
351	case 101:
352		status = netdfs_setinfo_101(&path, param->info.iu.info101,
353		    (const char *)param->server, (const char *)param->share);
354		break;
355	case 102:
356		status = netdfs_setinfo_102(&path, param->info.iu.info102);
357		break;
358	case 103:
359		status = netdfs_setinfo_103(&path, param->info.iu.info103);
360		break;
361	case 104:
362		status = netdfs_setinfo_104(&path, param->info.iu.info104,
363		    (const char *)param->server, (const char *)param->share);
364		break;
365	case 105:
366		status = netdfs_setinfo_105(&path, param->info.iu.info105);
367		break;
368	default:
369		status = ERROR_INVALID_LEVEL;
370		break;
371	}
372
373	dfs_setpriv(PRIV_OFF);
374	dfs_path_free(&path);
375	param->status = status;
376	return (NDR_DRC_OK);
377}
378
379/*
380 * Returns information about a DFS root or a DFS link of the specified
381 * DFS namespace.
382 *
383 * [MS-DFSNM]: NetrDfsGetInfo (Opnum 4)
384 */
385static int
386netdfs_s_getinfo(void *arg, ndr_xa_t *mxa)
387{
388	netdfs_getinfo_t *param = arg;
389	netdfs_info1_t *info1;
390	netdfs_info2_t *info2;
391	netdfs_info3_t *info3;
392	netdfs_info4_t *info4;
393	netdfs_info5_t *info5;
394	netdfs_info6_t *info6;
395	netdfs_info100_t *info100;
396	dfs_info_t info;
397	dfs_path_t path;
398	uint32_t status, stat;
399	const char *fspath;
400	uint32_t level = param->level;
401
402	status = dfs_path_parse(&path, (const char *)param->dfs_path,
403	    DFS_OBJECT_ANY);
404
405	if (status != ERROR_SUCCESS)
406		goto getinfo_error;
407
408	dfs_setpriv(PRIV_ON);
409
410	fspath = path.p_fspath;
411	if (path.p_type == DFS_OBJECT_LINK) {
412		status = dfs_link_stat(fspath, &stat);
413		if ((status != ERROR_SUCCESS) || (stat != DFS_STAT_ISDFS)) {
414			status = ERROR_NOT_FOUND;
415			goto getinfo_error;
416		}
417
418		status = dfs_link_getinfo(fspath, &info, param->level);
419	} else {
420		status = dfs_root_getinfo(fspath, &info, param->level);
421	}
422
423	if (status != ERROR_SUCCESS)
424		goto getinfo_error;
425
426	(void) strlcpy(info.i_uncpath, (char *)param->dfs_path,
427	    sizeof (info.i_uncpath));
428
429	dfs_info_trace("netdfs_s_getinfo", &info);
430
431	status = ERROR_NOT_ENOUGH_MEMORY;
432
433	switch (level) {
434	case 1:
435		if ((info1 = NDR_NEW(mxa, netdfs_info1_t)) != NULL) {
436			param->info.iu.info1 = info1;
437			status = netdfs_info_1(info1, &info, mxa, NULL);
438		}
439		break;
440	case 2:
441		if ((info2 = NDR_NEW(mxa, netdfs_info2_t)) != NULL) {
442			param->info.iu.info2 = info2;
443			status = netdfs_info_2(info2, &info, mxa, NULL);
444		}
445		break;
446	case 3:
447		if ((info3 = NDR_NEW(mxa, netdfs_info3_t)) != NULL) {
448			param->info.iu.info3 = info3;
449			status = netdfs_info_3(info3, &info, mxa, NULL);
450		}
451		break;
452	case 4:
453		if ((info4 = NDR_NEW(mxa, netdfs_info4_t)) != NULL) {
454			param->info.iu.info4 = info4;
455			status = netdfs_info_4(info4, &info, mxa, NULL);
456		}
457		break;
458	case 5:
459		if ((info5 = NDR_NEW(mxa, netdfs_info5_t)) != NULL) {
460			param->info.iu.info5 = info5;
461			status = netdfs_info_5(info5, &info, mxa, NULL);
462		}
463		break;
464	case 6:
465		if ((info6 = NDR_NEW(mxa, netdfs_info6_t)) != NULL) {
466			param->info.iu.info6 = info6;
467			status = netdfs_info_6(info6, &info, mxa, NULL);
468		}
469		break;
470	case 100:
471		if ((info100 = NDR_NEW(mxa, netdfs_info100_t)) != NULL) {
472			param->info.iu.info100 = info100;
473			status = netdfs_info_100(info100, &info, mxa, NULL);
474		}
475		break;
476
477	default:
478		status = ERROR_INVALID_LEVEL;
479		break;
480	}
481
482	dfs_info_free(&info);
483
484getinfo_error:
485	dfs_setpriv(PRIV_OFF);
486	dfs_path_free(&path);
487	if (status != ERROR_SUCCESS)
488		bzero(param, sizeof (netdfs_getinfo_t));
489
490	param->info.level = level;
491	param->status = status;
492	return (NDR_DRC_OK);
493}
494
495/*
496 * Enumerates the DFS root hosted on a server or the DFS links of the
497 * namespace hosted by a server. Depending on the information level,
498 * the targets of the root and links are also displayed.
499 *
500 * For unsupported levels, it should return ERROR_INVALID_LEVEL as
501 * Microsoft does for DFS server on Win2000 and NT.
502 *
503 * [MS-DFSNM]: NetrDfsEnum (Opnum 5)
504 */
505/*ARGSUSED*/
506static int
507netdfs_s_enum(void *arg, ndr_xa_t *mxa)
508{
509	netdfs_enum_t *param = arg;
510	netdfs_enumhandle_t de;
511	uint32_t level = param->level;
512	uint32_t status = ERROR_SUCCESS;
513	uint32_t nroot;
514	size_t entsize;
515
516	if (param->info == NULL) {
517		status = ERROR_INVALID_PARAMETER;
518		goto enum_error;
519	}
520
521	if ((nroot = dfs_namespace_count()) == 0)
522		status = ERROR_NOT_FOUND;
523	else if (nroot > 1)
524		status = ERROR_DEVICE_NOT_AVAILABLE;
525
526	if (status != ERROR_SUCCESS)
527		goto enum_error;
528
529	bzero(&de, sizeof (netdfs_enumhandle_t));
530	de.de_level = level;
531	de.de_ntotal = dfs_cache_num();
532
533	if (param->pref_max_len == NETDFS_MAXPREFLEN ||
534	    param->pref_max_len > NETDFS_MAXBUFLEN)
535		de.de_prefmaxlen = NETDFS_MAXBUFLEN;
536	else
537		de.de_prefmaxlen = param->pref_max_len;
538
539	de.de_bavail = de.de_prefmaxlen;
540
541	if (param->resume_handle != NULL) {
542		if (*param->resume_handle >= de.de_ntotal) {
543			status = ERROR_NO_MORE_ITEMS;
544			goto enum_error;
545		}
546		de.de_resume = *param->resume_handle;
547		de.de_nskip = de.de_resume;
548		*param->resume_handle = 0;
549	}
550
551	dfs_setpriv(PRIV_ON);
552
553	status = ERROR_NOT_ENOUGH_MEMORY;
554
555	switch (level) {
556	case 1:
557		entsize = sizeof (netdfs_info1_t);
558		de.de_nmax = MAX((de.de_prefmaxlen / entsize), 1);
559		de.de_entries = NDR_NEWN(mxa, netdfs_info1_t, de.de_nmax);
560		if (de.de_entries == NULL)
561			goto enum_error;
562
563		if ((status = netdfs_enum_common(&de, mxa)) == ERROR_SUCCESS) {
564			param->info->iu.info1->info1 = de.de_entries;
565			param->info->iu.info1->count = de.de_nitems;
566		}
567		break;
568	case 2:
569		entsize = sizeof (netdfs_info2_t);
570		de.de_nmax = MAX((de.de_prefmaxlen / entsize), 1);
571		de.de_entries = NDR_NEWN(mxa, netdfs_info2_t, de.de_nmax);
572		if (de.de_entries == NULL)
573			goto enum_error;
574
575		if ((status = netdfs_enum_common(&de, mxa)) == ERROR_SUCCESS) {
576			param->info->iu.info2->info2 = de.de_entries;
577			param->info->iu.info2->count = de.de_nitems;
578		}
579		break;
580	case 3:
581		entsize = sizeof (netdfs_info3_t) +
582		    sizeof (netdfs_storage_info_t);
583		de.de_nmax = MAX((de.de_prefmaxlen / entsize), 1);
584		de.de_entries = NDR_NEWN(mxa, netdfs_info3_t, de.de_nmax);
585		if (de.de_entries == NULL)
586			goto enum_error;
587
588		if ((status = netdfs_enum_common(&de, mxa)) == ERROR_SUCCESS) {
589			param->info->iu.info3->info3 = de.de_entries;
590			param->info->iu.info3->count = de.de_nitems;
591		}
592		break;
593	case 4:
594		entsize = sizeof (netdfs_info4_t) +
595		    sizeof (netdfs_storage_info_t);
596		de.de_nmax = MAX((de.de_prefmaxlen / entsize), 1);
597		de.de_entries = NDR_NEWN(mxa, netdfs_info4_t, de.de_nmax);
598		if (de.de_entries == NULL)
599			goto enum_error;
600
601		if ((status = netdfs_enum_common(&de, mxa)) == ERROR_SUCCESS) {
602			param->info->iu.info4->info4 = de.de_entries;
603			param->info->iu.info4->count = de.de_nitems;
604		}
605		break;
606
607	case 5:
608		entsize = sizeof (netdfs_info5_t);
609		de.de_nmax = MAX((de.de_prefmaxlen / entsize), 1);
610		de.de_entries = NDR_NEWN(mxa, netdfs_info5_t, de.de_nmax);
611		if (de.de_entries == NULL)
612			goto enum_error;
613
614		if ((status = netdfs_enum_common(&de, mxa)) == ERROR_SUCCESS) {
615			param->info->iu.info5->info5 = de.de_entries;
616			param->info->iu.info5->count = de.de_nitems;
617		}
618		break;
619
620	case 6:
621		entsize = sizeof (netdfs_info6_t) +
622		    sizeof (netdfs_storage_info1_t);
623		de.de_nmax = MAX((de.de_prefmaxlen / entsize), 1);
624		de.de_entries = NDR_NEWN(mxa, netdfs_info6_t, de.de_nmax);
625		if (de.de_entries == NULL)
626			goto enum_error;
627
628		if ((status = netdfs_enum_common(&de, mxa)) == ERROR_SUCCESS) {
629			param->info->iu.info6->info6 = de.de_entries;
630			param->info->iu.info6->count = de.de_nitems;
631		}
632		break;
633
634	case 300:
635		entsize = sizeof (netdfs_info300_t);
636		de.de_nmax = MAX((de.de_prefmaxlen / entsize), 1);
637		de.de_entries = NDR_NEWN(mxa, netdfs_info300_t, de.de_nmax);
638		if (de.de_entries == NULL)
639			goto enum_error;
640
641		if ((status = netdfs_enum_common(&de, mxa)) == ERROR_SUCCESS) {
642			param->info->iu.info300->info300 = de.de_entries;
643			param->info->iu.info300->count = de.de_nitems;
644		}
645		break;
646
647	default:
648		status = ERROR_INVALID_PARAMETER;
649		break;
650	}
651
652	if ((status == ERROR_SUCCESS) && (param->resume_handle != NULL))
653		*param->resume_handle = de.de_resume;
654
655enum_error:
656	dfs_setpriv(PRIV_OFF);
657	param->status = status;
658	return (NDR_DRC_OK);
659}
660
661/*
662 * Renames or moves a DFS link
663 *
664 * Does not need to be supported for DFS version 1
665 *
666 * [MS-DFSNM]: NetrDfsMove (Opnum 6)
667 */
668/*ARGSUSED*/
669static int
670netdfs_s_move(void *arg, ndr_xa_t *mxa)
671{
672	struct netdfs_move *param = arg;
673
674	param->status = ERROR_NOT_SUPPORTED;
675	return (NDR_DRC_OK);
676}
677
678/*
679 * According to [MS-DFSNM] spec this operation (opnum 7) is not
680 * used over the wire.
681 */
682/*ARGSUSED*/
683static int
684netdfs_s_rename(void *arg, ndr_xa_t *mxa)
685{
686	struct netdfs_rename *param = arg;
687
688	param->status = ERROR_NOT_SUPPORTED;
689	return (NDR_DRC_OK);
690}
691
692/*
693 * Creates a new standalone DFS namespace
694 *
695 * [MS-DFSNM]: NetrDfsAddStdRoot (Opnum 12)
696 */
697/*ARGSUSED*/
698static int
699netdfs_s_addstdroot(void *arg, ndr_xa_t *mxa)
700{
701	struct netdfs_addstdroot *param = arg;
702	const char *share = (const char *)param->share;
703	const char *comment = (const char *)param->comment;
704
705	if (!ndr_is_admin(mxa)) {
706		param->status = ERROR_ACCESS_DENIED;
707		return (NDR_DRC_OK);
708	}
709
710	dfs_setpriv(PRIV_ON);
711	/* For now only allow a single standalone namespace */
712	if (dfs_namespace_count() == 0)
713		param->status = dfs_namespace_add(share, comment);
714	else
715		param->status = ERROR_NOT_SUPPORTED;
716	dfs_setpriv(PRIV_OFF);
717
718	return (NDR_DRC_OK);
719}
720
721/*
722 * Deletes the specified stand-alone DFS namespace. The DFS namespace can be
723 * removed without first removing all of the links in it.
724 *
725 * [MS-DFSNM]: NetrDfsRemoveStdRoot (Opnum 13)
726 */
727/*ARGSUSED*/
728static int
729netdfs_s_remstdroot(void *arg, ndr_xa_t *mxa)
730{
731	struct netdfs_remstdroot *param = arg;
732	const char *share = (const char *)param->share;
733
734	dfs_setpriv(PRIV_ON);
735
736	if (ndr_is_admin(mxa))
737		param->status = dfs_namespace_remove(share);
738	else
739		param->status = ERROR_ACCESS_DENIED;
740
741	dfs_setpriv(PRIV_OFF);
742	return (NDR_DRC_OK);
743}
744
745/*
746 * Enumerates the DFS roots hosted on a server, or DFS links of a namespace
747 * hosted by the server. Depending on the information level, the targets
748 * associated with the roots and links are also displayed
749 *
750 * Does not need to be supported for DFS version 1
751 *
752 * [MS-DFSNM] NetrDfsEnumEx (Opnum 21)
753 */
754/*ARGSUSED*/
755static int
756netdfs_s_enumex(void *arg, ndr_xa_t *mxa)
757{
758	struct netdfs_enumex *param = arg;
759
760	bzero(param->info, sizeof (struct netdfs_enumex));
761	param->status = ERROR_NOT_SUPPORTED;
762	return (NDR_DRC_OK);
763}
764
765/*
766 * Sets the comment for the DFS link/root.
767 */
768static uint32_t
769netdfs_setinfo_100(dfs_path_t *path, netdfs_info100_t *netinfo)
770{
771	dfs_info_t info;
772	uint32_t status;
773	char *cmnt = (char *)netinfo->comment;
774
775	bzero(&info, sizeof (dfs_info_t));
776	if (cmnt != NULL)
777		(void) strlcpy(info.i_comment, cmnt, sizeof (info.i_comment));
778
779	if (path->p_type == DFS_OBJECT_LINK)
780		status = dfs_link_setinfo(path->p_fspath, &info, 100);
781	else
782		status = dfs_root_setinfo(path->p_fspath, &info, 100);
783
784	return (status);
785}
786
787/*
788 * Sets the state for the DFS root/link or its target.
789 */
790static uint32_t
791netdfs_setinfo_101(dfs_path_t *path, netdfs_info101_t *netinfo,
792    const char *t_server, const char *t_share)
793{
794	dfs_info_t info;
795	dfs_target_t target;
796	uint32_t status;
797
798	bzero(&info, sizeof (dfs_info_t));
799	bzero(&target, sizeof (dfs_target_t));
800
801	if (t_server == NULL && t_share == NULL) {
802		info.i_state = netinfo->state;
803	} else {
804		target.t_state = netinfo->state;
805		(void) strlcpy(target.t_server, t_server,
806		    sizeof (target.t_server));
807		(void) strlcpy(target.t_share, t_share,
808		    sizeof (target.t_share));
809		info.i_targets = &target;
810	}
811
812	if (path->p_type == DFS_OBJECT_LINK)
813		status = dfs_link_setinfo(path->p_fspath, &info, 101);
814	else
815		status = dfs_root_setinfo(path->p_fspath, &info, 101);
816
817	return (status);
818}
819
820/*
821 * Sets the timeout value of the DFS link/root.
822 */
823static uint32_t
824netdfs_setinfo_102(dfs_path_t *path, netdfs_info102_t *netinfo)
825{
826	dfs_info_t info;
827	uint32_t status;
828
829	bzero(&info, sizeof (dfs_info_t));
830	info.i_timeout = netinfo->timeout;
831
832	if (path->p_type == DFS_OBJECT_LINK)
833		status = dfs_link_setinfo(path->p_fspath, &info, 102);
834	else
835		status = dfs_root_setinfo(path->p_fspath, &info, 102);
836
837	return (status);
838}
839
840/*
841 * Sets the property flags for the root or link.
842 */
843static uint32_t
844netdfs_setinfo_103(dfs_path_t *path, netdfs_info103_t *netinfo)
845{
846	dfs_info_t info;
847	uint32_t status;
848
849	bzero(&info, sizeof (dfs_info_t));
850	info.i_propflags =
851	    netinfo->property_flags & netinfo->property_flag_mask;
852
853	if (path->p_type == DFS_OBJECT_LINK)
854		status = dfs_link_setinfo(path->p_fspath, &info, 103);
855	else
856		status = dfs_root_setinfo(path->p_fspath, &info, 103);
857
858	return (status);
859}
860
861/*
862 * Sets the target priority rank and class for the root target or link target
863 */
864static uint32_t
865netdfs_setinfo_104(dfs_path_t *path, netdfs_info104_t *netinfo,
866    const char *t_server, const char *t_share)
867{
868	dfs_info_t info;
869	dfs_target_t target;
870	uint32_t status;
871
872	if ((t_server == NULL) || (t_share == NULL))
873		return (ERROR_INVALID_PARAMETER);
874
875	if (netinfo->priority_class > DfsGlobalLowPriorityClass)
876		return (ERROR_INVALID_PARAMETER);
877
878	if (netinfo->priority_rank > DFS_PRIORITY_RANK_MAX)
879		return (ERROR_INVALID_PARAMETER);
880
881	bzero(&info, sizeof (dfs_info_t));
882	bzero(&target, sizeof (dfs_target_t));
883
884	target.t_priority.p_class = netinfo->priority_class;
885	target.t_priority.p_rank = netinfo->priority_rank;
886	(void) strlcpy(target.t_server, t_server, sizeof (target.t_server));
887	(void) strlcpy(target.t_share, t_share, sizeof (target.t_share));
888	info.i_targets = &target;
889
890	if (path->p_type == DFS_OBJECT_LINK)
891		status = dfs_link_setinfo(path->p_fspath, &info, 104);
892	else
893		status = dfs_root_setinfo(path->p_fspath, &info, 104);
894
895	return (status);
896}
897
898/*
899 * Sets the comment, state, time-out information, and property flags for the
900 * namespace root or link specified in DfsInfo. Does not apply to a root target
901 * or link target.
902 */
903static uint32_t
904netdfs_setinfo_105(dfs_path_t *path, netdfs_info105_t *netinfo)
905{
906	dfs_info_t info;
907	uint32_t status, flavor;
908	char *cmnt = (char *)netinfo->comment;
909
910	bzero(&info, sizeof (dfs_info_t));
911
912	flavor = dfs_namespace_getflavor(path->p_unc.unc_share);
913	if (flavor == 0)
914		return (ERROR_INTERNAL_ERROR);
915	info.i_flavor = flavor;
916
917	if (cmnt != NULL)
918		(void) strlcpy(info.i_comment, cmnt, sizeof (info.i_comment));
919	info.i_state = netinfo->state;
920	info.i_timeout = netinfo->timeout;
921	info.i_propflag_mask = netinfo->property_flag_mask;
922	info.i_propflags =
923	    netinfo->property_flags & netinfo->property_flag_mask;
924
925	if (path->p_type == DFS_OBJECT_LINK)
926		status = dfs_link_setinfo(path->p_fspath, &info, 105);
927	else
928		status = dfs_root_setinfo(path->p_fspath, &info, 105);
929
930	return (status);
931}
932
933/*
934 * DFS_STORAGE_INFO: target information
935 */
936static uint32_t
937netdfs_info_storage(netdfs_storage_info_t **sinfo, dfs_info_t *info,
938    ndr_xa_t *mxa, uint32_t *size)
939{
940	netdfs_storage_info_t *storage;
941	dfs_target_t *target;
942	int i;
943
944	*sinfo = NULL;
945	if (info->i_ntargets == 0)
946		return (ERROR_SUCCESS);
947
948	*sinfo = NDR_NEWN(mxa, netdfs_storage_info_t, info->i_ntargets);
949	if (*sinfo == NULL)
950		return (ERROR_NOT_ENOUGH_MEMORY);
951
952	if (size != NULL)
953		*size += info->i_ntargets * sizeof (netdfs_storage_info_t);
954
955	target = info->i_targets;
956	storage = *sinfo;
957	for (i = 0; i < info->i_ntargets; i++, target++, storage++) {
958		storage->state = target->t_state;
959		storage->server = NDR_STRDUP(mxa, target->t_server);
960		storage->share = NDR_STRDUP(mxa, target->t_share);
961
962		if (storage->server == NULL || storage->share == NULL)
963			return (ERROR_NOT_ENOUGH_MEMORY);
964
965		if (size != NULL)
966			*size += smb_wcequiv_strlen(target->t_server) +
967			    smb_wcequiv_strlen(target->t_share);
968	}
969
970	return (ERROR_SUCCESS);
971}
972
973/*
974 * DFS_STORAGE_INFO_1: target information
975 */
976static uint32_t
977netdfs_info_storage1(netdfs_storage_info1_t **sinfo, dfs_info_t *info,
978    ndr_xa_t *mxa, uint32_t *size)
979{
980	netdfs_storage_info1_t *storage;
981	dfs_target_t *target;
982	int i;
983
984	*sinfo = NULL;
985	if (info->i_ntargets == 0)
986		return (ERROR_SUCCESS);
987
988	*sinfo = NDR_NEWN(mxa, netdfs_storage_info1_t, info->i_ntargets);
989	if (*sinfo == NULL)
990		return (ERROR_NOT_ENOUGH_MEMORY);
991
992	if (size != NULL)
993		*size += info->i_ntargets * sizeof (netdfs_storage_info1_t);
994
995	target = info->i_targets;
996	storage = *sinfo;
997	for (i = 0; i < info->i_ntargets; i++, target++, storage++) {
998		storage->state = target->t_state;
999		storage->server = NDR_STRDUP(mxa, target->t_server);
1000		storage->share = NDR_STRDUP(mxa, target->t_share);
1001		storage->p_class = target->t_priority.p_class;
1002		storage->p_rank = target->t_priority.p_rank;
1003		storage->p_reserved = 0;
1004
1005		if (storage->server == NULL || storage->share == NULL)
1006			return (ERROR_NOT_ENOUGH_MEMORY);
1007
1008		if (size != NULL)
1009			*size += smb_wcequiv_strlen(target->t_server) +
1010			    smb_wcequiv_strlen(target->t_share);
1011	}
1012
1013	return (ERROR_SUCCESS);
1014}
1015
1016/*
1017 * Sets a DFS_INFO_1 for get/enum response
1018 */
1019static uint32_t
1020netdfs_info_1(netdfs_info1_t *info1, dfs_info_t *info, ndr_xa_t *mxa,
1021    uint32_t *size)
1022{
1023	info1->entry_path = NDR_STRDUP(mxa, info->i_uncpath);
1024	if (info1->entry_path == NULL)
1025		return (ERROR_NOT_ENOUGH_MEMORY);
1026
1027	if (size != NULL)
1028		*size = sizeof (netdfs_info1_t) +
1029		    smb_wcequiv_strlen(info->i_uncpath);
1030
1031	return (ERROR_SUCCESS);
1032}
1033
1034/*
1035 * Sets a DFS_INFO_2 for get/enum response
1036 */
1037static uint32_t
1038netdfs_info_2(netdfs_info2_t *info2, dfs_info_t *info, ndr_xa_t *mxa,
1039    uint32_t *size)
1040{
1041	void *entry_path;
1042	void *comment;
1043
1044	entry_path = NDR_STRDUP(mxa, info->i_uncpath);
1045	comment = NDR_STRDUP(mxa, info->i_comment);
1046
1047	if (entry_path == NULL || comment == NULL)
1048		return (ERROR_NOT_ENOUGH_MEMORY);
1049
1050	info2->entry_path = entry_path;
1051	info2->comment = comment;
1052	info2->state = info->i_state;
1053	info2->n_store = info->i_ntargets;
1054
1055	if (size != NULL)
1056		*size = sizeof (netdfs_info2_t) +
1057		    smb_wcequiv_strlen(info->i_uncpath) +
1058		    smb_wcequiv_strlen(info->i_comment);
1059
1060	return (ERROR_SUCCESS);
1061}
1062
1063/*
1064 * Sets a DFS_INFO_3 for get/enum response
1065 */
1066static uint32_t
1067netdfs_info_3(netdfs_info3_t *info3, dfs_info_t *info, ndr_xa_t *mxa,
1068    uint32_t *size)
1069{
1070	void *entry_path;
1071	void *comment;
1072
1073	entry_path = NDR_STRDUP(mxa, info->i_uncpath);
1074	comment = NDR_STRDUP(mxa, info->i_comment);
1075
1076	if (entry_path == NULL || comment == NULL)
1077		return (ERROR_NOT_ENOUGH_MEMORY);
1078
1079	info3->entry_path = entry_path;
1080	info3->comment = comment;
1081	info3->state = info->i_state;
1082	info3->n_store = info->i_ntargets;
1083
1084	if (size != NULL)
1085		*size = sizeof (netdfs_info3_t) +
1086		    smb_wcequiv_strlen(info->i_uncpath) +
1087		    smb_wcequiv_strlen(info->i_comment);
1088
1089	return (netdfs_info_storage(&info3->si, info, mxa, size));
1090}
1091
1092/*
1093 * Sets a DFS_INFO_4 for get/enum response
1094 */
1095static uint32_t
1096netdfs_info_4(netdfs_info4_t *info4, dfs_info_t *info, ndr_xa_t *mxa,
1097    uint32_t *size)
1098{
1099	void *entry_path;
1100	void *comment;
1101
1102	entry_path = NDR_STRDUP(mxa, info->i_uncpath);
1103	comment = NDR_STRDUP(mxa, info->i_comment);
1104
1105	if (entry_path == NULL || comment == NULL)
1106		return (ERROR_NOT_ENOUGH_MEMORY);
1107
1108	if (!netdfs_guid_fromstr(info->i_guid, &info4->guid))
1109		return (ERROR_INVALID_DATA);
1110
1111	info4->entry_path = entry_path;
1112	info4->comment = comment;
1113	info4->state = info->i_state;
1114	info4->timeout = info->i_timeout;
1115	info4->n_store = info->i_ntargets;
1116
1117	if (size != NULL)
1118		*size = sizeof (netdfs_info4_t) +
1119		    smb_wcequiv_strlen(info->i_uncpath) +
1120		    smb_wcequiv_strlen(info->i_comment);
1121
1122	return (netdfs_info_storage(&info4->si, info, mxa, size));
1123}
1124
1125/*
1126 * Sets a DFS_INFO_5 for get/enum response
1127 */
1128static uint32_t
1129netdfs_info_5(netdfs_info5_t *info5, dfs_info_t *info, ndr_xa_t *mxa,
1130    uint32_t *size)
1131{
1132	void *entry_path;
1133	void *comment;
1134
1135	entry_path = NDR_STRDUP(mxa, info->i_uncpath);
1136	comment = NDR_STRDUP(mxa, info->i_comment);
1137
1138	if (entry_path == NULL || comment == NULL)
1139		return (ERROR_NOT_ENOUGH_MEMORY);
1140
1141	if (!netdfs_guid_fromstr(info->i_guid, &info5->guid))
1142		return (ERROR_INVALID_DATA);
1143
1144	info5->entry_path = entry_path;
1145	info5->comment = comment;
1146	info5->state = info->i_state;
1147	info5->timeout = info->i_timeout;
1148	info5->flags = info->i_propflags;
1149	info5->metadata_sz = 0;
1150	info5->n_store = info->i_ntargets;
1151
1152	if (size != NULL)
1153		*size = sizeof (netdfs_info5_t) +
1154		    smb_wcequiv_strlen(info->i_uncpath) +
1155		    smb_wcequiv_strlen(info->i_comment);
1156
1157	return (ERROR_SUCCESS);
1158}
1159
1160/*
1161 * Sets a DFS_INFO_6 for get/enum response
1162 */
1163static uint32_t
1164netdfs_info_6(netdfs_info6_t *info6, dfs_info_t *info, ndr_xa_t *mxa,
1165    uint32_t *size)
1166{
1167	void *entry_path;
1168	void *comment;
1169
1170	entry_path = NDR_STRDUP(mxa, info->i_uncpath);
1171	comment = NDR_STRDUP(mxa, info->i_comment);
1172
1173	if (entry_path == NULL || comment == NULL)
1174		return (ERROR_NOT_ENOUGH_MEMORY);
1175
1176	if (!netdfs_guid_fromstr(info->i_guid, &info6->guid))
1177		return (ERROR_INVALID_DATA);
1178
1179	info6->entry_path = entry_path;
1180	info6->comment = comment;
1181	info6->state = info->i_state;
1182	info6->timeout = info->i_timeout;
1183	info6->flags = info->i_propflags;
1184	info6->metadata_sz = 0;
1185	info6->n_store = info->i_ntargets;
1186
1187	if (size != NULL)
1188		*size = sizeof (netdfs_info6_t) +
1189		    smb_wcequiv_strlen(info->i_uncpath) +
1190		    smb_wcequiv_strlen(info->i_comment);
1191
1192	return (netdfs_info_storage1(&info6->si, info, mxa, size));
1193}
1194
1195/*
1196 * Sets a DFS_INFO_100 for Get response
1197 */
1198static uint32_t
1199netdfs_info_100(netdfs_info100_t *info100, dfs_info_t *info, ndr_xa_t *mxa,
1200    uint32_t *size)
1201{
1202	info100->comment = NDR_STRDUP(mxa, info->i_comment);
1203	if (info100->comment == NULL)
1204		return (ERROR_NOT_ENOUGH_MEMORY);
1205
1206	if (size != NULL)
1207		*size = sizeof (netdfs_info100_t) +
1208		    smb_wcequiv_strlen(info->i_comment);
1209
1210	return (ERROR_SUCCESS);
1211}
1212
1213/*
1214 * Sets a DFS_INFO_300 for Enum response
1215 */
1216static uint32_t
1217netdfs_info_300(netdfs_info300_t *info300, dfs_info_t *info, ndr_xa_t *mxa,
1218    uint32_t *size)
1219{
1220	info300->dfsname = NDR_STRDUP(mxa, info->i_uncpath);
1221	if (info300->dfsname == NULL)
1222		return (ERROR_NOT_ENOUGH_MEMORY);
1223
1224	info300->flavor = DFS_VOLUME_FLAVOR_STANDALONE;
1225	if (size != NULL)
1226		*size = sizeof (netdfs_info300_t) +
1227		    smb_wcequiv_strlen(info->i_uncpath);
1228
1229	return (ERROR_SUCCESS);
1230}
1231
1232/*
1233 * Common enumeration function
1234 */
1235static uint32_t
1236netdfs_enum_common(netdfs_enumhandle_t *de, ndr_xa_t *mxa)
1237{
1238	netdfs_info1_t *info1 = de->de_entries;
1239	netdfs_info2_t *info2 = de->de_entries;
1240	netdfs_info3_t *info3 = de->de_entries;
1241	netdfs_info4_t *info4 = de->de_entries;
1242	netdfs_info5_t *info5 = de->de_entries;
1243	netdfs_info6_t *info6 = de->de_entries;
1244	netdfs_info300_t *info300 = de->de_entries;
1245	dfs_info_t dfsinfo;
1246	smb_cache_cursor_t cursor;
1247	dfs_nscnode_t nscnode;
1248	uint32_t status;
1249	uint32_t itemsz;
1250
1251	dfs_cache_iterinit(&cursor);
1252
1253	de->de_nitems = 0;
1254	while (dfs_cache_iterate(&cursor, &nscnode)) {
1255		if (de->de_nskip > 0) {
1256			de->de_nskip--;
1257			continue;
1258		}
1259
1260		if (de->de_nitems == de->de_nmax)
1261			break;
1262
1263		status = dfs_cache_getinfo(&nscnode, &dfsinfo, de->de_level);
1264		if (status != ERROR_SUCCESS)
1265			continue;
1266
1267		switch (de->de_level) {
1268		case 1:
1269			status = netdfs_info_1(info1, &dfsinfo, mxa, &itemsz);
1270			info1++;
1271			break;
1272		case 2:
1273			status = netdfs_info_2(info2, &dfsinfo, mxa, &itemsz);
1274			info2++;
1275			break;
1276		case 3:
1277			status = netdfs_info_3(info3, &dfsinfo, mxa, &itemsz);
1278			info3++;
1279			break;
1280		case 4:
1281			status = netdfs_info_4(info4, &dfsinfo, mxa, &itemsz);
1282			info4++;
1283			break;
1284		case 5:
1285			status = netdfs_info_5(info5, &dfsinfo, mxa, &itemsz);
1286			info5++;
1287			break;
1288		case 6:
1289			status = netdfs_info_6(info6, &dfsinfo, mxa, &itemsz);
1290			info6++;
1291			break;
1292		case 300:
1293			status = netdfs_info_300(info300, &dfsinfo, mxa,
1294			    &itemsz);
1295			info300++;
1296			break;
1297		default:
1298			status = ERROR_INVALID_LEVEL;
1299		}
1300
1301		dfs_info_free(&dfsinfo);
1302
1303		if (status != ERROR_SUCCESS)
1304			return (status);
1305
1306		if (de->de_nmax == 1) {
1307			de->de_nitems = 1;
1308			break;
1309		}
1310
1311		if (itemsz > de->de_bavail)
1312			break;
1313
1314		de->de_bavail -= itemsz;
1315		de->de_nitems++;
1316	}
1317
1318	de->de_resume += de->de_nitems;
1319	return (ERROR_SUCCESS);
1320}
1321
1322/*
1323 * Creates intermediate directories of a link from the root share path.
1324 *
1325 * TODO: directories should be created by smbsrv to get Windows compatible
1326 * ACL inheritance.
1327 */
1328static void
1329netdfs_path_create(const char *path)
1330{
1331	char dirpath[DFS_PATH_MAX];
1332	mode_t mode;
1333	char *p;
1334
1335	(void) strlcpy(dirpath, path, DFS_PATH_MAX);
1336
1337	/* drop the link itself from the path */
1338	if ((p = strrchr(dirpath, '/')) != NULL) {
1339		*p = '\0';
1340		mode = umask(0);
1341		(void) mkdirp(dirpath, 0777);
1342		(void) umask(mode);
1343	}
1344}
1345
1346/*
1347 * Removes empty directories
1348 */
1349static void
1350netdfs_path_remove(smb_unc_t *unc)
1351{
1352	char rootdir[DFS_PATH_MAX];
1353	char relpath[DFS_PATH_MAX];
1354	char dir[DFS_PATH_MAX];
1355	uint32_t status;
1356	char *p;
1357
1358	status = dfs_namespace_path(unc->unc_share, rootdir, DFS_PATH_MAX);
1359	if ((status == ERROR_SUCCESS) && (chdir(rootdir) == 0)) {
1360		(void) strlcpy(relpath, unc->unc_path, DFS_PATH_MAX);
1361		/* drop the link itself from the path */
1362		if ((p = strrchr(relpath, '/')) != NULL) {
1363			*p = '\0';
1364			(void) rmdirp(relpath, dir);
1365		}
1366	}
1367}
1368
1369/*
1370 * Converts the guid string into binary format in network byte order.
1371 */
1372static boolean_t
1373netdfs_guid_fromstr(char *guid_str, netdfs_uuid_t *guid)
1374{
1375	uuid_t uuid;
1376
1377	if (uuid_parse(guid_str, uuid) != 0)
1378		return (B_FALSE);
1379
1380	bcopy(&uuid, guid, sizeof (uuid_t));
1381
1382	guid->data1 = htonl(guid->data1);
1383	guid->data2 = htons(guid->data2);
1384	guid->data3 = htons(guid->data3);
1385
1386	return (B_TRUE);
1387}
1388