xref: /illumos-gate/usr/src/lib/smbsrv/libmlsvc/common/netdfs.c (revision 45ede40b2394db7967e59f19288fae9b62efd4aa)
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 
56 typedef 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 
68 static int netdfs_s_getver(void *, ndr_xa_t *);
69 static int netdfs_s_add(void *, ndr_xa_t *);
70 static int netdfs_s_remove(void *, ndr_xa_t *);
71 static int netdfs_s_setinfo(void *, ndr_xa_t *);
72 static int netdfs_s_getinfo(void *, ndr_xa_t *);
73 static int netdfs_s_enum(void *, ndr_xa_t *);
74 static int netdfs_s_move(void *, ndr_xa_t *);
75 static int netdfs_s_rename(void *, ndr_xa_t *);
76 static int netdfs_s_addstdroot(void *, ndr_xa_t *);
77 static int netdfs_s_remstdroot(void *, ndr_xa_t *);
78 static int netdfs_s_enumex(void *, ndr_xa_t *);
79 
80 static uint32_t netdfs_setinfo_100(dfs_path_t *, netdfs_info100_t *);
81 static uint32_t netdfs_setinfo_101(dfs_path_t *, netdfs_info101_t *,
82     const char *, const char *);
83 static uint32_t netdfs_setinfo_102(dfs_path_t *, netdfs_info102_t *);
84 static uint32_t netdfs_setinfo_103(dfs_path_t *, netdfs_info103_t *);
85 static uint32_t netdfs_setinfo_104(dfs_path_t *, netdfs_info104_t *,
86     const char *, const char *);
87 static uint32_t netdfs_setinfo_105(dfs_path_t *, netdfs_info105_t *);
88 
89 static uint32_t netdfs_info_1(netdfs_info1_t *, dfs_info_t *, ndr_xa_t *,
90     uint32_t *);
91 static uint32_t netdfs_info_2(netdfs_info2_t *, dfs_info_t *, ndr_xa_t *,
92     uint32_t *);
93 static uint32_t netdfs_info_3(netdfs_info3_t *, dfs_info_t *, ndr_xa_t *,
94     uint32_t *);
95 static uint32_t netdfs_info_4(netdfs_info4_t *, dfs_info_t *, ndr_xa_t *,
96     uint32_t *);
97 static uint32_t netdfs_info_5(netdfs_info5_t *, dfs_info_t *, ndr_xa_t *,
98     uint32_t *);
99 static uint32_t netdfs_info_6(netdfs_info6_t *, dfs_info_t *, ndr_xa_t *,
100     uint32_t *);
101 static uint32_t netdfs_info_100(netdfs_info100_t *, dfs_info_t *, ndr_xa_t *,
102     uint32_t *);
103 static uint32_t netdfs_info_300(netdfs_info300_t *, dfs_info_t *, ndr_xa_t *,
104     uint32_t *);
105 
106 static uint32_t netdfs_enum_common(netdfs_enumhandle_t *, ndr_xa_t *);
107 
108 static void netdfs_path_create(const char *);
109 static void netdfs_path_remove(smb_unc_t *);
110 static boolean_t netdfs_guid_fromstr(char *, netdfs_uuid_t *);
111 
112 static 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 
127 static 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  */
149 void
150 netdfs_initialize(void)
151 {
152 	(void) ndr_svc_register(&netdfs_service);
153 	dfs_init();
154 }
155 
156 void
157 netdfs_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*/
168 static int
169 netdfs_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  */
183 static int
184 netdfs_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  */
255 static int
256 netdfs_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*/
315 static int
316 netdfs_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  */
385 static int
386 netdfs_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 
484 getinfo_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*/
506 static int
507 netdfs_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 
655 enum_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*/
669 static int
670 netdfs_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*/
683 static int
684 netdfs_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*/
698 static int
699 netdfs_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*/
728 static int
729 netdfs_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*/
755 static int
756 netdfs_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  */
768 static uint32_t
769 netdfs_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  */
790 static uint32_t
791 netdfs_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  */
823 static uint32_t
824 netdfs_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  */
843 static uint32_t
844 netdfs_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  */
864 static uint32_t
865 netdfs_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  */
903 static uint32_t
904 netdfs_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  */
936 static uint32_t
937 netdfs_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  */
976 static uint32_t
977 netdfs_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  */
1019 static uint32_t
1020 netdfs_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  */
1037 static uint32_t
1038 netdfs_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  */
1066 static uint32_t
1067 netdfs_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  */
1095 static uint32_t
1096 netdfs_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  */
1128 static uint32_t
1129 netdfs_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  */
1163 static uint32_t
1164 netdfs_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  */
1198 static uint32_t
1199 netdfs_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  */
1216 static uint32_t
1217 netdfs_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  */
1235 static uint32_t
1236 netdfs_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  */
1328 static void
1329 netdfs_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  */
1349 static void
1350 netdfs_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  */
1372 static boolean_t
1373 netdfs_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