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