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