xref: /illumos-gate/usr/src/lib/smbsrv/libmlsvc/common/netdfs.c (revision da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0)
1*da6c28aaSamw /*
2*da6c28aaSamw  * CDDL HEADER START
3*da6c28aaSamw  *
4*da6c28aaSamw  * The contents of this file are subject to the terms of the
5*da6c28aaSamw  * Common Development and Distribution License (the "License").
6*da6c28aaSamw  * You may not use this file except in compliance with the License.
7*da6c28aaSamw  *
8*da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10*da6c28aaSamw  * See the License for the specific language governing permissions
11*da6c28aaSamw  * and limitations under the License.
12*da6c28aaSamw  *
13*da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14*da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16*da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17*da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18*da6c28aaSamw  *
19*da6c28aaSamw  * CDDL HEADER END
20*da6c28aaSamw  */
21*da6c28aaSamw /*
22*da6c28aaSamw  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23*da6c28aaSamw  * Use is subject to license terms.
24*da6c28aaSamw  */
25*da6c28aaSamw 
26*da6c28aaSamw #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*da6c28aaSamw 
28*da6c28aaSamw /*
29*da6c28aaSamw  * Net DFS server side RPC service.
30*da6c28aaSamw  */
31*da6c28aaSamw 
32*da6c28aaSamw #include <sys/types.h>
33*da6c28aaSamw #include <strings.h>
34*da6c28aaSamw #include <string.h>
35*da6c28aaSamw 
36*da6c28aaSamw #include <smbsrv/libsmb.h>
37*da6c28aaSamw #include <smbsrv/lmerr.h>
38*da6c28aaSamw #include <smbsrv/lmdfs.h>
39*da6c28aaSamw #include <smbsrv/nmpipes.h>
40*da6c28aaSamw #include <smbsrv/nterror.h>
41*da6c28aaSamw #include <smbsrv/mlrpc.h>
42*da6c28aaSamw #include <smbsrv/ndl/netdfs.ndl>
43*da6c28aaSamw 
44*da6c28aaSamw typedef struct {
45*da6c28aaSamw 	char *server;
46*da6c28aaSamw 	char *share;
47*da6c28aaSamw 	char *path;
48*da6c28aaSamw 	char *buf;
49*da6c28aaSamw } netdfs_unc_t;
50*da6c28aaSamw 
51*da6c28aaSamw static int netdfs_unc_parse(struct mlrpc_xaction *, const char *,
52*da6c28aaSamw     netdfs_unc_t *);
53*da6c28aaSamw 
54*da6c28aaSamw static int netdfs_s_getver(void *, struct mlrpc_xaction *);
55*da6c28aaSamw static int netdfs_s_add(void *, struct mlrpc_xaction *);
56*da6c28aaSamw static int netdfs_s_remove(void *, struct mlrpc_xaction *);
57*da6c28aaSamw static int netdfs_s_setinfo(void *, struct mlrpc_xaction *);
58*da6c28aaSamw static int netdfs_s_getinfo(void *, struct mlrpc_xaction *);
59*da6c28aaSamw static int netdfs_s_enum(void *, struct mlrpc_xaction *);
60*da6c28aaSamw static int netdfs_s_move(void *, struct mlrpc_xaction *);
61*da6c28aaSamw static int netdfs_s_rename(void *, struct mlrpc_xaction *);
62*da6c28aaSamw static int netdfs_s_addstdroot(void *, struct mlrpc_xaction *);
63*da6c28aaSamw static int netdfs_s_remstdroot(void *, struct mlrpc_xaction *);
64*da6c28aaSamw static int netdfs_s_enumex(void *, struct mlrpc_xaction *);
65*da6c28aaSamw 
66*da6c28aaSamw static mlrpc_stub_table_t netdfs_stub_table[] = {
67*da6c28aaSamw 	{ netdfs_s_getver,	NETDFS_OPNUM_GETVER },
68*da6c28aaSamw 	{ netdfs_s_add,		NETDFS_OPNUM_ADD },
69*da6c28aaSamw 	{ netdfs_s_remove,	NETDFS_OPNUM_REMOVE },
70*da6c28aaSamw 	{ netdfs_s_setinfo,	NETDFS_OPNUM_SETINFO },
71*da6c28aaSamw 	{ netdfs_s_getinfo,	NETDFS_OPNUM_GETINFO },
72*da6c28aaSamw 	{ netdfs_s_enum,	NETDFS_OPNUM_ENUM },
73*da6c28aaSamw 	{ netdfs_s_rename,	NETDFS_OPNUM_RENAME },
74*da6c28aaSamw 	{ netdfs_s_move,	NETDFS_OPNUM_MOVE },
75*da6c28aaSamw 	{ netdfs_s_addstdroot,	NETDFS_OPNUM_ADDSTDROOT },
76*da6c28aaSamw 	{ netdfs_s_remstdroot,	NETDFS_OPNUM_REMSTDROOT },
77*da6c28aaSamw 	{ netdfs_s_enumex,	NETDFS_OPNUM_ENUMEX },
78*da6c28aaSamw 	{0}
79*da6c28aaSamw };
80*da6c28aaSamw 
81*da6c28aaSamw static mlrpc_service_t netdfs_service = {
82*da6c28aaSamw 	"NETDFS",			/* name */
83*da6c28aaSamw 	"DFS",				/* desc */
84*da6c28aaSamw 	"\\dfs",			/* endpoint */
85*da6c28aaSamw 	PIPE_NTSVCS,			/* sec_addr_port */
86*da6c28aaSamw 	NETDFS_ABSTRACT_UUID,	NETDFS_ABSTRACT_VERS,
87*da6c28aaSamw 	NETDFS_TRANSFER_UUID,	NETDFS_TRANSFER_VERS,
88*da6c28aaSamw 
89*da6c28aaSamw 	0,				/* no bind_instance_size */
90*da6c28aaSamw 	0,				/* no bind_req() */
91*da6c28aaSamw 	0,				/* no unbind_and_close() */
92*da6c28aaSamw 	0,				/* use generic_call_stub() */
93*da6c28aaSamw 
94*da6c28aaSamw 	&TYPEINFO(netdfs_interface),	/* interface ti */
95*da6c28aaSamw 	netdfs_stub_table		/* stub_table */
96*da6c28aaSamw };
97*da6c28aaSamw 
98*da6c28aaSamw /*
99*da6c28aaSamw  * Register the NETDFS RPC interface with the RPC runtime library.
100*da6c28aaSamw  * The service must be registered in order to use either the client
101*da6c28aaSamw  * side or the server side functions.
102*da6c28aaSamw  */
103*da6c28aaSamw void
104*da6c28aaSamw netdfs_initialize(void)
105*da6c28aaSamw {
106*da6c28aaSamw 	(void) mlrpc_register_service(&netdfs_service);
107*da6c28aaSamw }
108*da6c28aaSamw 
109*da6c28aaSamw /*
110*da6c28aaSamw  * Return the version.
111*da6c28aaSamw  *
112*da6c28aaSamw  * We have to indicate that we emulate a Windows 2003 Server or the
113*da6c28aaSamw  * client will not use the EnumEx RPC and this would limit support
114*da6c28aaSamw  * to a single DFS root.
115*da6c28aaSamw  */
116*da6c28aaSamw /*ARGSUSED*/
117*da6c28aaSamw static int
118*da6c28aaSamw netdfs_s_getver(void *arg, struct mlrpc_xaction *mxa)
119*da6c28aaSamw {
120*da6c28aaSamw 	struct netdfs_getver *param = arg;
121*da6c28aaSamw 
122*da6c28aaSamw 	param->version = DFS_MANAGER_VERSION_W2K3;
123*da6c28aaSamw 	return (MLRPC_DRC_OK);
124*da6c28aaSamw }
125*da6c28aaSamw 
126*da6c28aaSamw /*
127*da6c28aaSamw  * Add a new volume or additional storage for an existing volume at
128*da6c28aaSamw  * dfs_path.
129*da6c28aaSamw  */
130*da6c28aaSamw static int
131*da6c28aaSamw netdfs_s_add(void *arg, struct mlrpc_xaction *mxa)
132*da6c28aaSamw {
133*da6c28aaSamw 	struct netdfs_add *param = arg;
134*da6c28aaSamw 	netdfs_unc_t unc;
135*da6c28aaSamw 	DWORD status = ERROR_SUCCESS;
136*da6c28aaSamw 
137*da6c28aaSamw 	if (param->dfs_path == NULL || param->server == NULL ||
138*da6c28aaSamw 	    param->share == NULL) {
139*da6c28aaSamw 		bzero(param, sizeof (struct netdfs_add));
140*da6c28aaSamw 		param->status = ERROR_INVALID_PARAMETER;
141*da6c28aaSamw 		return (MLRPC_DRC_OK);
142*da6c28aaSamw 	}
143*da6c28aaSamw 
144*da6c28aaSamw 	if (netdfs_unc_parse(mxa, (char *)param->dfs_path, &unc) != 0) {
145*da6c28aaSamw 		status = ERROR_INVALID_PARAMETER;
146*da6c28aaSamw 	} else {
147*da6c28aaSamw 		if (unc.path == NULL)
148*da6c28aaSamw 			status = ERROR_BAD_PATHNAME;
149*da6c28aaSamw 
150*da6c28aaSamw 		if (unc.share == NULL)
151*da6c28aaSamw 			status = ERROR_INVALID_SHARENAME;
152*da6c28aaSamw 	}
153*da6c28aaSamw 
154*da6c28aaSamw 	if (param->status != ERROR_SUCCESS) {
155*da6c28aaSamw 		bzero(param, sizeof (struct netdfs_add));
156*da6c28aaSamw 		param->status = status;
157*da6c28aaSamw 		return (MLRPC_DRC_OK);
158*da6c28aaSamw 	}
159*da6c28aaSamw 
160*da6c28aaSamw 	bzero(param, sizeof (struct netdfs_add));
161*da6c28aaSamw 	param->status = ERROR_ACCESS_DENIED;
162*da6c28aaSamw 	return (MLRPC_DRC_OK);
163*da6c28aaSamw }
164*da6c28aaSamw 
165*da6c28aaSamw /*
166*da6c28aaSamw  * netdfs_s_remove
167*da6c28aaSamw  *
168*da6c28aaSamw  * Remove a volume or additional storage for volume from the DFS at
169*da6c28aaSamw  * dfs_path. When applied to the last storage in a volume, removes
170*da6c28aaSamw  * the volume from the DFS.
171*da6c28aaSamw  */
172*da6c28aaSamw static int
173*da6c28aaSamw netdfs_s_remove(void *arg, struct mlrpc_xaction *mxa)
174*da6c28aaSamw {
175*da6c28aaSamw 	struct netdfs_remove *param = arg;
176*da6c28aaSamw 	netdfs_unc_t unc;
177*da6c28aaSamw 	DWORD status = ERROR_SUCCESS;
178*da6c28aaSamw 
179*da6c28aaSamw 	if (param->dfs_path == NULL || param->server == NULL ||
180*da6c28aaSamw 	    param->share == NULL) {
181*da6c28aaSamw 		bzero(param, sizeof (struct netdfs_remove));
182*da6c28aaSamw 		param->status = ERROR_INVALID_PARAMETER;
183*da6c28aaSamw 		return (MLRPC_DRC_OK);
184*da6c28aaSamw 	}
185*da6c28aaSamw 
186*da6c28aaSamw 	if (netdfs_unc_parse(mxa, (char *)param->dfs_path, &unc) != 0) {
187*da6c28aaSamw 		status = ERROR_INVALID_PARAMETER;
188*da6c28aaSamw 	} else {
189*da6c28aaSamw 		if (unc.path == NULL)
190*da6c28aaSamw 			status = ERROR_BAD_PATHNAME;
191*da6c28aaSamw 
192*da6c28aaSamw 		if (unc.share == NULL)
193*da6c28aaSamw 			status = ERROR_INVALID_SHARENAME;
194*da6c28aaSamw 	}
195*da6c28aaSamw 
196*da6c28aaSamw 	if (param->status != ERROR_SUCCESS) {
197*da6c28aaSamw 		bzero(param, sizeof (struct netdfs_remove));
198*da6c28aaSamw 		param->status = status;
199*da6c28aaSamw 		return (MLRPC_DRC_OK);
200*da6c28aaSamw 	}
201*da6c28aaSamw 
202*da6c28aaSamw 	bzero(param, sizeof (struct netdfs_remove));
203*da6c28aaSamw 	param->status = ERROR_ACCESS_DENIED;
204*da6c28aaSamw 	return (MLRPC_DRC_OK);
205*da6c28aaSamw }
206*da6c28aaSamw 
207*da6c28aaSamw /*
208*da6c28aaSamw  * Set information about the volume or storage. If the server and share
209*da6c28aaSamw  * are specified, the information set is specific to that server and
210*da6c28aaSamw  * share. Otherwise the information is specific to the volume as a whole.
211*da6c28aaSamw  *
212*da6c28aaSamw  * Valid levels are 100-102.
213*da6c28aaSamw  */
214*da6c28aaSamw /*ARGSUSED*/
215*da6c28aaSamw static int
216*da6c28aaSamw netdfs_s_setinfo(void *arg, struct mlrpc_xaction *mxa)
217*da6c28aaSamw {
218*da6c28aaSamw 	struct netdfs_setinfo *param = arg;
219*da6c28aaSamw 	netdfs_unc_t unc;
220*da6c28aaSamw 	DWORD status = ERROR_SUCCESS;
221*da6c28aaSamw 
222*da6c28aaSamw 	if (param->dfs_path == NULL) {
223*da6c28aaSamw 		bzero(param, sizeof (struct netdfs_setinfo));
224*da6c28aaSamw 		param->status = ERROR_INVALID_PARAMETER;
225*da6c28aaSamw 		return (MLRPC_DRC_OK);
226*da6c28aaSamw 	}
227*da6c28aaSamw 
228*da6c28aaSamw 	if (netdfs_unc_parse(mxa, (char *)param->dfs_path, &unc) != 0) {
229*da6c28aaSamw 		status = ERROR_INVALID_PARAMETER;
230*da6c28aaSamw 	} else {
231*da6c28aaSamw 		if (unc.share == NULL)
232*da6c28aaSamw 			status = ERROR_INVALID_SHARENAME;
233*da6c28aaSamw 	}
234*da6c28aaSamw 
235*da6c28aaSamw 	if (param->status != ERROR_SUCCESS) {
236*da6c28aaSamw 		bzero(param, sizeof (struct netdfs_setinfo));
237*da6c28aaSamw 		param->status = status;
238*da6c28aaSamw 		return (MLRPC_DRC_OK);
239*da6c28aaSamw 	}
240*da6c28aaSamw 
241*da6c28aaSamw 	switch (param->info.level) {
242*da6c28aaSamw 	case 100:
243*da6c28aaSamw 	case 101:
244*da6c28aaSamw 	case 102:
245*da6c28aaSamw 		break;
246*da6c28aaSamw 
247*da6c28aaSamw 	default:
248*da6c28aaSamw 		bzero(param, sizeof (struct netdfs_setinfo));
249*da6c28aaSamw 		param->status = ERROR_INVALID_LEVEL;
250*da6c28aaSamw 		return (MLRPC_DRC_OK);
251*da6c28aaSamw 	}
252*da6c28aaSamw 
253*da6c28aaSamw 	bzero(param, sizeof (struct netdfs_setinfo));
254*da6c28aaSamw 	param->status = ERROR_ACCESS_DENIED;
255*da6c28aaSamw 	return (MLRPC_DRC_OK);
256*da6c28aaSamw }
257*da6c28aaSamw 
258*da6c28aaSamw /*
259*da6c28aaSamw  * Get information about the volume or storage. If the server and share
260*da6c28aaSamw  * are specified, the information returned is specific to that server
261*da6c28aaSamw  * and share. Otherwise the information is specific to the volume as a
262*da6c28aaSamw  * whole.
263*da6c28aaSamw  *
264*da6c28aaSamw  * Valid levels are 1-4, 100-104.
265*da6c28aaSamw  */
266*da6c28aaSamw /*ARGSUSED*/
267*da6c28aaSamw static int
268*da6c28aaSamw netdfs_s_getinfo(void *arg, struct mlrpc_xaction *mxa)
269*da6c28aaSamw {
270*da6c28aaSamw 	struct netdfs_getinfo *param = arg;
271*da6c28aaSamw 	netdfs_unc_t unc;
272*da6c28aaSamw 	DWORD status = ERROR_SUCCESS;
273*da6c28aaSamw 
274*da6c28aaSamw 	if (param->dfs_path == NULL) {
275*da6c28aaSamw 		bzero(param, sizeof (struct netdfs_getinfo));
276*da6c28aaSamw 		param->status = ERROR_INVALID_PARAMETER;
277*da6c28aaSamw 		return (MLRPC_DRC_OK);
278*da6c28aaSamw 	}
279*da6c28aaSamw 
280*da6c28aaSamw 	if (netdfs_unc_parse(mxa, (char *)param->dfs_path, &unc) != 0) {
281*da6c28aaSamw 		status = ERROR_INVALID_PARAMETER;
282*da6c28aaSamw 	} else {
283*da6c28aaSamw 		if (unc.share == NULL)
284*da6c28aaSamw 			status = ERROR_INVALID_SHARENAME;
285*da6c28aaSamw 	}
286*da6c28aaSamw 
287*da6c28aaSamw 	if (param->status != ERROR_SUCCESS) {
288*da6c28aaSamw 		bzero(param, sizeof (struct netdfs_getinfo));
289*da6c28aaSamw 		param->status = status;
290*da6c28aaSamw 		return (MLRPC_DRC_OK);
291*da6c28aaSamw 	}
292*da6c28aaSamw 
293*da6c28aaSamw 	switch (param->level) {
294*da6c28aaSamw 	case 1:
295*da6c28aaSamw 	case 2:
296*da6c28aaSamw 	case 3:
297*da6c28aaSamw 	case 4:
298*da6c28aaSamw 	case 100:
299*da6c28aaSamw 	case 101:
300*da6c28aaSamw 	case 102:
301*da6c28aaSamw 	case 103:
302*da6c28aaSamw 	case 104:
303*da6c28aaSamw 		break;
304*da6c28aaSamw 
305*da6c28aaSamw 	default:
306*da6c28aaSamw 		bzero(param, sizeof (struct netdfs_getinfo));
307*da6c28aaSamw 		param->status = ERROR_INVALID_LEVEL;
308*da6c28aaSamw 		return (MLRPC_DRC_OK);
309*da6c28aaSamw 	}
310*da6c28aaSamw 
311*da6c28aaSamw 	bzero(param, sizeof (struct netdfs_getinfo));
312*da6c28aaSamw 	param->status = ERROR_ACCESS_DENIED;
313*da6c28aaSamw 	return (MLRPC_DRC_OK);
314*da6c28aaSamw }
315*da6c28aaSamw 
316*da6c28aaSamw /*
317*da6c28aaSamw  * Get information about all of the volumes in the DFS. dfs_name is
318*da6c28aaSamw  * the "server" part of the UNC name used to refer to this particular
319*da6c28aaSamw  * DFS.
320*da6c28aaSamw  *
321*da6c28aaSamw  * Valid levels are 1-3.
322*da6c28aaSamw  */
323*da6c28aaSamw /*ARGSUSED*/
324*da6c28aaSamw static int
325*da6c28aaSamw netdfs_s_enum(void *arg, struct mlrpc_xaction *mxa)
326*da6c28aaSamw {
327*da6c28aaSamw 	struct netdfs_enum *param = arg;
328*da6c28aaSamw 
329*da6c28aaSamw 	switch (param->level) {
330*da6c28aaSamw 	case 1:
331*da6c28aaSamw 	case 2:
332*da6c28aaSamw 	case 3:
333*da6c28aaSamw 		break;
334*da6c28aaSamw 
335*da6c28aaSamw 	default:
336*da6c28aaSamw 		(void) bzero(param, sizeof (struct netdfs_enum));
337*da6c28aaSamw 		param->status = ERROR_INVALID_LEVEL;
338*da6c28aaSamw 		return (MLRPC_DRC_OK);
339*da6c28aaSamw 	}
340*da6c28aaSamw 
341*da6c28aaSamw 	(void) bzero(param, sizeof (struct netdfs_enum));
342*da6c28aaSamw 	param->status = ERROR_ACCESS_DENIED;
343*da6c28aaSamw 	return (MLRPC_DRC_OK);
344*da6c28aaSamw }
345*da6c28aaSamw 
346*da6c28aaSamw /*
347*da6c28aaSamw  * Move a DFS volume and all subordinate volumes from one place in the
348*da6c28aaSamw  * DFS to another place in the DFS.
349*da6c28aaSamw  */
350*da6c28aaSamw /*ARGSUSED*/
351*da6c28aaSamw static int
352*da6c28aaSamw netdfs_s_move(void *arg, struct mlrpc_xaction *mxa)
353*da6c28aaSamw {
354*da6c28aaSamw 	struct netdfs_move *param = arg;
355*da6c28aaSamw 
356*da6c28aaSamw 	if (param->dfs_path == NULL || param->new_path == NULL) {
357*da6c28aaSamw 		bzero(param, sizeof (struct netdfs_move));
358*da6c28aaSamw 		param->status = ERROR_INVALID_PARAMETER;
359*da6c28aaSamw 		return (MLRPC_DRC_OK);
360*da6c28aaSamw 	}
361*da6c28aaSamw 
362*da6c28aaSamw 	bzero(param, sizeof (struct netdfs_move));
363*da6c28aaSamw 	param->status = ERROR_ACCESS_DENIED;
364*da6c28aaSamw 	return (MLRPC_DRC_OK);
365*da6c28aaSamw }
366*da6c28aaSamw 
367*da6c28aaSamw /*
368*da6c28aaSamw  * Rename the current path in a DFS to a new path in the same DFS.
369*da6c28aaSamw  */
370*da6c28aaSamw /*ARGSUSED*/
371*da6c28aaSamw static int
372*da6c28aaSamw netdfs_s_rename(void *arg, struct mlrpc_xaction *mxa)
373*da6c28aaSamw {
374*da6c28aaSamw 	struct netdfs_rename *param = arg;
375*da6c28aaSamw 
376*da6c28aaSamw 	if (param->dfs_path == NULL || param->new_path == NULL) {
377*da6c28aaSamw 		bzero(param, sizeof (struct netdfs_rename));
378*da6c28aaSamw 		param->status = ERROR_INVALID_PARAMETER;
379*da6c28aaSamw 		return (MLRPC_DRC_OK);
380*da6c28aaSamw 	}
381*da6c28aaSamw 
382*da6c28aaSamw 	bzero(param, sizeof (struct netdfs_rename));
383*da6c28aaSamw 	param->status = ERROR_ACCESS_DENIED;
384*da6c28aaSamw 	return (MLRPC_DRC_OK);
385*da6c28aaSamw }
386*da6c28aaSamw 
387*da6c28aaSamw /*
388*da6c28aaSamw  * Add a DFS root share.
389*da6c28aaSamw  */
390*da6c28aaSamw /*ARGSUSED*/
391*da6c28aaSamw static int
392*da6c28aaSamw netdfs_s_addstdroot(void *arg, struct mlrpc_xaction *mxa)
393*da6c28aaSamw {
394*da6c28aaSamw 	struct netdfs_addstdroot *param = arg;
395*da6c28aaSamw 
396*da6c28aaSamw 	bzero(param, sizeof (struct netdfs_addstdroot));
397*da6c28aaSamw 	param->status = ERROR_INVALID_PARAMETER;
398*da6c28aaSamw 	return (MLRPC_DRC_OK);
399*da6c28aaSamw }
400*da6c28aaSamw 
401*da6c28aaSamw /*
402*da6c28aaSamw  * Remove a DFS root share.
403*da6c28aaSamw  */
404*da6c28aaSamw /*ARGSUSED*/
405*da6c28aaSamw static int
406*da6c28aaSamw netdfs_s_remstdroot(void *arg, struct mlrpc_xaction *mxa)
407*da6c28aaSamw {
408*da6c28aaSamw 	struct netdfs_remstdroot *param = arg;
409*da6c28aaSamw 
410*da6c28aaSamw 	bzero(param, sizeof (struct netdfs_remstdroot));
411*da6c28aaSamw 	param->status = ERROR_INVALID_PARAMETER;
412*da6c28aaSamw 	return (MLRPC_DRC_OK);
413*da6c28aaSamw }
414*da6c28aaSamw 
415*da6c28aaSamw /*
416*da6c28aaSamw  * Get information about all of the volumes in the DFS. dfs_path is
417*da6c28aaSamw  * the "server" part of the UNC name used to refer to this particular
418*da6c28aaSamw  * DFS.
419*da6c28aaSamw  *
420*da6c28aaSamw  * Valid levels are 1-3, 300.
421*da6c28aaSamw  */
422*da6c28aaSamw static int
423*da6c28aaSamw netdfs_s_enumex(void *arg, struct mlrpc_xaction *mxa)
424*da6c28aaSamw {
425*da6c28aaSamw 	struct netdfs_enumex *param = arg;
426*da6c28aaSamw 	netdfs_unc_t unc;
427*da6c28aaSamw 	DWORD status = ERROR_SUCCESS;
428*da6c28aaSamw 
429*da6c28aaSamw 	if (param->dfs_path == NULL) {
430*da6c28aaSamw 		bzero(param, sizeof (struct netdfs_enumex));
431*da6c28aaSamw 		param->status = ERROR_INVALID_PARAMETER;
432*da6c28aaSamw 		return (MLRPC_DRC_OK);
433*da6c28aaSamw 	}
434*da6c28aaSamw 
435*da6c28aaSamw 	if (param->resume_handle == NULL)
436*da6c28aaSamw 		param->resume_handle = MLRPC_HEAP_NEW(mxa, DWORD);
437*da6c28aaSamw 
438*da6c28aaSamw 	if (param->resume_handle)
439*da6c28aaSamw 		*(param->resume_handle) = 0;
440*da6c28aaSamw 
441*da6c28aaSamw 	if (netdfs_unc_parse(mxa, (char *)param->dfs_path, &unc) != 0) {
442*da6c28aaSamw 		status = ERROR_INVALID_PARAMETER;
443*da6c28aaSamw 	} else {
444*da6c28aaSamw 		if (unc.path == NULL)
445*da6c28aaSamw 			status = ERROR_BAD_PATHNAME;
446*da6c28aaSamw 
447*da6c28aaSamw 		if (unc.share == NULL)
448*da6c28aaSamw 			status = ERROR_INVALID_SHARENAME;
449*da6c28aaSamw 	}
450*da6c28aaSamw 
451*da6c28aaSamw 	if (param->status != ERROR_SUCCESS) {
452*da6c28aaSamw 		bzero(param, sizeof (struct netdfs_enumex));
453*da6c28aaSamw 		param->status = status;
454*da6c28aaSamw 		return (MLRPC_DRC_OK);
455*da6c28aaSamw 	}
456*da6c28aaSamw 
457*da6c28aaSamw 	param->info = MLRPC_HEAP_NEW(mxa, struct netdfs_enum_info);
458*da6c28aaSamw 	if (param->info == NULL) {
459*da6c28aaSamw 		bzero(param, sizeof (struct netdfs_enumex));
460*da6c28aaSamw 		param->status = ERROR_NOT_ENOUGH_MEMORY;
461*da6c28aaSamw 		return (MLRPC_DRC_OK);
462*da6c28aaSamw 	}
463*da6c28aaSamw 
464*da6c28aaSamw 	bzero(param->info, sizeof (struct netdfs_enumex));
465*da6c28aaSamw 	param->status = ERROR_SUCCESS;
466*da6c28aaSamw 	return (MLRPC_DRC_OK);
467*da6c28aaSamw }
468*da6c28aaSamw 
469*da6c28aaSamw /*
470*da6c28aaSamw  * Parse a UNC path (\\server\share\path) into components.
471*da6c28aaSamw  * Path separators are converted to forward slashes.
472*da6c28aaSamw  *
473*da6c28aaSamw  * Returns 0 on success, otherwise -1 to indicate an error.
474*da6c28aaSamw  */
475*da6c28aaSamw static int
476*da6c28aaSamw netdfs_unc_parse(struct mlrpc_xaction *mxa, const char *path, netdfs_unc_t *unc)
477*da6c28aaSamw {
478*da6c28aaSamw 	char *p;
479*da6c28aaSamw 
480*da6c28aaSamw 	if (path == NULL || unc == NULL)
481*da6c28aaSamw 		return (-1);
482*da6c28aaSamw 
483*da6c28aaSamw 	if ((unc->buf = MLRPC_HEAP_STRSAVE(mxa, (char *)path)) == NULL)
484*da6c28aaSamw 		return (-1);
485*da6c28aaSamw 
486*da6c28aaSamw 	if ((p = strchr(unc->buf, '\n')) != NULL)
487*da6c28aaSamw 		*p = '\0';
488*da6c28aaSamw 
489*da6c28aaSamw 	(void) strsubst(unc->buf, '\\', '/');
490*da6c28aaSamw 	(void) strcanon(unc->buf, "/");
491*da6c28aaSamw 
492*da6c28aaSamw 	unc->server = unc->buf;
493*da6c28aaSamw 	unc->server += strspn(unc->buf, "/");
494*da6c28aaSamw 
495*da6c28aaSamw 	if (unc->server) {
496*da6c28aaSamw 		unc->share = strchr(unc->server, '/');
497*da6c28aaSamw 		if ((p = unc->share) != NULL) {
498*da6c28aaSamw 			unc->share += strspn(unc->share, "/");
499*da6c28aaSamw 			*p = '\0';
500*da6c28aaSamw 		}
501*da6c28aaSamw 	}
502*da6c28aaSamw 
503*da6c28aaSamw 	if (unc->share) {
504*da6c28aaSamw 		unc->path = strchr(unc->share, '/');
505*da6c28aaSamw 		if ((p = unc->path) != NULL) {
506*da6c28aaSamw 			unc->path += strspn(unc->path, "/");
507*da6c28aaSamw 			*p = '\0';
508*da6c28aaSamw 		}
509*da6c28aaSamw 	}
510*da6c28aaSamw 
511*da6c28aaSamw 	if (unc->path) {
512*da6c28aaSamw 		if ((p = strchr(unc->path, '\0')) != NULL) {
513*da6c28aaSamw 			if (*(--p) == '/')
514*da6c28aaSamw 				*p = '\0';
515*da6c28aaSamw 		}
516*da6c28aaSamw 	}
517*da6c28aaSamw 
518*da6c28aaSamw 	return (0);
519*da6c28aaSamw }
520