xref: /titanic_51/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c (revision 0ca46ac5a61f0a757ca72f469fdbb1859c3fa490)
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 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Server Service RPC (SRVSVC) server-side interface definition.
28  * The server service provides a remote administration interface.
29  *
30  * This service uses NERR/Win32 error codes rather than NT status
31  * values.
32  */
33 
34 #include <sys/errno.h>
35 #include <unistd.h>
36 #include <netdb.h>
37 #include <strings.h>
38 #include <time.h>
39 #include <thread.h>
40 #include <ctype.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <sys/types.h>
44 #include <sys/socket.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
47 #include <libshare.h>
48 
49 #include <smbsrv/libsmb.h>
50 #include <smbsrv/libmlsvc.h>
51 #include <smbsrv/lmerr.h>
52 #include <smbsrv/nterror.h>
53 #include <smbsrv/nmpipes.h>
54 #include <smbsrv/cifs.h>
55 #include <smbsrv/netrauth.h>
56 #include <smbsrv/ndl/srvsvc.ndl>
57 #include <smbsrv/smb_common_door.h>
58 
59 #define	SV_TYPE_SENT_BY_ME (SV_TYPE_WORKSTATION | SV_TYPE_SERVER | SV_TYPE_NT)
60 
61 /*
62  * Qualifier types for NetConnectEnum.
63  */
64 #define	SRVSVC_CONNECT_ENUM_NULL	0
65 #define	SRVSVC_CONNECT_ENUM_SHARE	1
66 #define	SRVSVC_CONNECT_ENUM_WKSTN	2
67 
68 #define	SMB_SRVSVC_MAXBUFLEN	(8 * 1024 * 1024)
69 #define	SMB_SRVSVC_MAXPREFLEN	((uint32_t)(-1))
70 
71 /*
72  * prefmaxlen:    Client specified response buffer limit.
73  * resume_handle: Cookie used to track enumeration across multiple calls.
74  * n_total:       Total number of entries.
75  * n_enum:        Number of entries to enumerate (derived from prefmaxlen).
76  * n_skip:        Number of entries to skip (from incoming resume handle).
77  * n_read:        Number of objects returned for current enumeration request.
78  */
79 typedef struct srvsvc_enum {
80 	uint32_t se_level;
81 	uint32_t se_prefmaxlen;
82 	uint32_t se_resume_handle;
83 	uint32_t se_n_total;
84 	uint32_t se_n_enum;
85 	uint32_t se_n_skip;
86 	uint32_t se_n_read;
87 } srvsvc_enum_t;
88 
89 static DWORD srvsvc_s_NetConnectEnumLevel0(ndr_xa_t *,
90     srvsvc_NetConnectInfo0_t *);
91 static DWORD srvsvc_s_NetConnectEnumLevel1(ndr_xa_t *,
92     srvsvc_NetConnectInfo1_t *);
93 
94 static DWORD srvsvc_NetFileEnum2(ndr_xa_t *,
95     struct mslm_NetFileEnum *);
96 static DWORD srvsvc_NetFileEnum3(ndr_xa_t *,
97     struct mslm_NetFileEnum *);
98 
99 static DWORD mlsvc_NetSessionEnumLevel0(struct mslm_infonres *, DWORD,
100     ndr_xa_t *);
101 static DWORD mlsvc_NetSessionEnumLevel1(struct mslm_infonres *, DWORD,
102     ndr_xa_t *);
103 
104 static DWORD mlsvc_NetShareEnumLevel0(ndr_xa_t *,
105     struct mslm_infonres *, srvsvc_enum_t *, int);
106 static DWORD mlsvc_NetShareEnumLevel1(ndr_xa_t *,
107     struct mslm_infonres *, srvsvc_enum_t *, int);
108 static DWORD mlsvc_NetShareEnumLevel2(ndr_xa_t *,
109     struct mslm_infonres *, srvsvc_enum_t *, int);
110 static DWORD mlsvc_NetShareEnumLevel501(ndr_xa_t *,
111     struct mslm_infonres *, srvsvc_enum_t *, int);
112 static DWORD mlsvc_NetShareEnumLevel502(ndr_xa_t *,
113     struct mslm_infonres *, srvsvc_enum_t *, int);
114 static DWORD mlsvc_NetShareEnumCommon(ndr_xa_t *,
115     srvsvc_enum_t *, smb_share_t *, void *);
116 static boolean_t srvsvc_add_autohome(ndr_xa_t *, srvsvc_enum_t *,
117     void *);
118 static char *srvsvc_share_mkpath(ndr_xa_t *, char *);
119 
120 static int srvsvc_netconnect_qualifier(const char *);
121 static uint32_t srvsvc_estimate_objcnt(uint32_t, uint32_t, uint32_t);
122 
123 static uint32_t srvsvc_sa_add(char *, char *, char *);
124 static uint32_t srvsvc_sa_delete(char *);
125 
126 static char empty_string[1];
127 
128 static ndr_stub_table_t srvsvc_stub_table[];
129 
130 static ndr_service_t srvsvc_service = {
131 	"SRVSVC",			/* name */
132 	"Server services",		/* desc */
133 	"\\srvsvc",			/* endpoint */
134 	PIPE_NTSVCS,			/* sec_addr_port */
135 	"4b324fc8-1670-01d3-1278-5a47bf6ee188", 3,	/* abstract */
136 	NDR_TRANSFER_SYNTAX_UUID,		2,	/* transfer */
137 	0,				/* no bind_instance_size */
138 	0,				/* no bind_req() */
139 	0,				/* no unbind_and_close() */
140 	0,				/* use generic_call_stub() */
141 	&TYPEINFO(srvsvc_interface),	/* interface ti */
142 	srvsvc_stub_table		/* stub_table */
143 };
144 
145 /*
146  * srvsvc_initialize
147  *
148  * This function registers the SRVSVC RPC interface with the RPC runtime
149  * library. It must be called in order to use either the client side
150  * or the server side functions.
151  */
152 void
153 srvsvc_initialize(void)
154 {
155 	(void) ndr_svc_register(&srvsvc_service);
156 }
157 
158 /*
159  * srvsvc_s_NetConnectEnum
160  *
161  * List tree connections made to a share on this server or all tree
162  * connections established from a specific client.  Administrator,
163  * Server Operator, Print Operator or Power User group membership
164  * is required to use this interface.
165  *
166  * There are three information levels:  0, 1, and 50.  We don't support
167  * level 50, which is only used by Windows 9x clients.
168  *
169  * It seems Server Manger (srvmgr) only sends workstation as the qualifier
170  * and the Computer Management Interface on Windows 2000 doesn't request
171  * a list of connections.
172  *
173  * Return Values:
174  * ERROR_SUCCESS            Success
175  * ERROR_ACCESS_DENIED      Caller does not have access to this call.
176  * ERROR_INVALID_PARAMETER  One of the parameters is invalid.
177  * ERROR_INVALID_LEVEL      Unknown information level specified.
178  * ERROR_MORE_DATA          Partial date returned, more entries available.
179  * ERROR_NOT_ENOUGH_MEMORY  Insufficient memory is available.
180  * NERR_NetNameNotFound     The share qualifier cannot be found.
181  * NERR_BufTooSmall         The supplied buffer is too small.
182  */
183 static int
184 srvsvc_s_NetConnectEnum(void *arg, ndr_xa_t *mxa)
185 {
186 	struct mslm_NetConnectEnum *param = arg;
187 	srvsvc_NetConnectInfo0_t *info0;
188 	srvsvc_NetConnectInfo1_t *info1;
189 	char *qualifier;
190 	int qualtype;
191 	DWORD status = ERROR_SUCCESS;
192 
193 	if (!ndr_is_poweruser(mxa)) {
194 		bzero(param, sizeof (struct mslm_NetConnectEnum));
195 		param->status = ERROR_ACCESS_DENIED;
196 		return (NDR_DRC_OK);
197 	}
198 
199 	qualifier = (char *)param->qualifier;
200 	qualtype = srvsvc_netconnect_qualifier(qualifier);
201 
202 	if (qualtype == SRVSVC_CONNECT_ENUM_NULL) {
203 		bzero(param, sizeof (struct mslm_NetConnectEnum));
204 		param->status = NERR_NetNameNotFound;
205 		return (NDR_DRC_OK);
206 	}
207 
208 	switch (param->info.level) {
209 	case 0:
210 		info0 = NDR_NEW(mxa, srvsvc_NetConnectInfo0_t);
211 		if (info0 == NULL) {
212 			status = ERROR_NOT_ENOUGH_MEMORY;
213 			break;
214 		}
215 
216 		bzero(info0, sizeof (srvsvc_NetConnectInfo0_t));
217 		param->info.ru.info0 = info0;
218 
219 		status = srvsvc_s_NetConnectEnumLevel0(mxa, info0);
220 
221 		param->total_entries = info0->entries_read;
222 		param->resume_handle = NULL;
223 		break;
224 
225 	case 1:
226 		info1 = NDR_NEW(mxa, srvsvc_NetConnectInfo1_t);
227 		if (info1 == NULL) {
228 			status = ERROR_NOT_ENOUGH_MEMORY;
229 			break;
230 		}
231 
232 		bzero(info1, sizeof (srvsvc_NetConnectInfo1_t));
233 		param->info.ru.info1 = info1;
234 
235 		status = srvsvc_s_NetConnectEnumLevel1(mxa, info1);
236 
237 		param->total_entries = info1->entries_read;
238 		param->resume_handle = NULL;
239 		break;
240 
241 	case 50:
242 		status = ERROR_NOT_SUPPORTED;
243 		break;
244 
245 	default:
246 		status = ERROR_INVALID_LEVEL;
247 		break;
248 	}
249 
250 	if (status != ERROR_SUCCESS)
251 		bzero(param, sizeof (struct mslm_NetConnectEnum));
252 
253 	param->status = status;
254 	return (NDR_DRC_OK);
255 }
256 
257 static DWORD
258 srvsvc_s_NetConnectEnumLevel0(ndr_xa_t *mxa, srvsvc_NetConnectInfo0_t *info0)
259 {
260 	srvsvc_NetConnectInfoBuf0_t *ci0;
261 
262 	ci0 = NDR_NEW(mxa, srvsvc_NetConnectInfoBuf0_t);
263 	if (ci0 == NULL)
264 		return (ERROR_NOT_ENOUGH_MEMORY);
265 
266 	ci0->coni0_id = 0x17;
267 
268 	info0->ci0 = ci0;
269 	info0->entries_read = 1;
270 	return (ERROR_SUCCESS);
271 }
272 
273 static DWORD
274 srvsvc_s_NetConnectEnumLevel1(ndr_xa_t *mxa, srvsvc_NetConnectInfo1_t *info1)
275 {
276 	srvsvc_NetConnectInfoBuf1_t *ci1;
277 
278 	ci1 = NDR_NEW(mxa, srvsvc_NetConnectInfoBuf1_t);
279 	if (ci1 == NULL)
280 		return (ERROR_NOT_ENOUGH_MEMORY);
281 
282 	ci1->coni1_id = 0x17;
283 	ci1->coni1_type = STYPE_IPC;
284 	ci1->coni1_num_opens = 1;
285 	ci1->coni1_num_users = 1;
286 	ci1->coni1_time = 16;
287 	ci1->coni1_username = (uint8_t *)NDR_STRDUP(mxa, "Administrator");
288 	ci1->coni1_netname = (uint8_t *)NDR_STRDUP(mxa, "IPC$");
289 
290 	info1->ci1 = ci1;
291 	info1->entries_read = 1;
292 	return (ERROR_SUCCESS);
293 }
294 
295 /*
296  * srvsvc_netconnect_qualifier
297  *
298  * The qualifier is a string that specifies a share name or computer name
299  * for the connections of interest.  If it is a share name then all the
300  * connections made to that share name are listed.  If it is a computer
301  * name (it starts with two backslash characters), then NetConnectEnum
302  * lists all connections made from that computer to the specified server.
303  */
304 static int
305 srvsvc_netconnect_qualifier(const char *qualifier)
306 {
307 	if (qualifier == NULL || *qualifier == '\0')
308 		return (SRVSVC_CONNECT_ENUM_NULL);
309 
310 	if (strlen(qualifier) > MAXHOSTNAMELEN)
311 		return (SRVSVC_CONNECT_ENUM_NULL);
312 
313 	if (qualifier[0] == '\\' && qualifier[1] == '\\') {
314 		return (SRVSVC_CONNECT_ENUM_WKSTN);
315 	} else {
316 		if (!smb_shr_exists((char *)qualifier))
317 			return (SRVSVC_CONNECT_ENUM_NULL);
318 
319 		return (SRVSVC_CONNECT_ENUM_SHARE);
320 	}
321 }
322 
323 /*
324  * srvsvc_s_NetFileEnum
325  *
326  * Return information on open files or named pipes. Only members of the
327  * Administrators or Server Operators local groups are allowed to make
328  * this call. Currently, we only support Administrators.
329  *
330  * If basepath is null, all open resources are enumerated. If basepath
331  * is non-null, only resources that have basepath as a prefix should
332  * be returned.
333  *
334  * If username is specified (non-null), only files opened by username
335  * should be returned.
336  *
337  * Notes:
338  * 1. We don't validate the servername because we would have to check
339  * all primary IPs and the ROI seems unlikely to be worth it.
340  * 2. Both basepath and username are currently ignored because both
341  * Server Manger (NT 4.0) and CMI (Windows 2000) always set them to null.
342  *
343  * The level of information requested may be one of:
344  *
345  *  2   Return the file identification number.
346  *      This level is not supported on Windows Me/98/95.
347  *
348  *  3   Return information about the file.
349  *      This level is not supported on Windows Me/98/95.
350  *
351  *  50  Windows Me/98/95:  Return information about the file.
352  *
353  * Note:
354  * If pref_max_len is unlimited and resume_handle is null, the client
355  * expects to receive all data in a single call.
356  * If we are unable to do fit all data in a single response, we would
357  * normally return ERROR_MORE_DATA with a partial list.
358  *
359  * Unfortunately, when both of these conditions occur, Server Manager
360  * pops up an error box with the message "more data available" and
361  * doesn't display any of the returned data. In this case, it is
362  * probably better to return ERROR_SUCCESS with the partial list.
363  * Windows 2000 doesn't have this problem because it always sends a
364  * non-null resume_handle.
365  *
366  * Return Values:
367  * ERROR_SUCCESS            Success
368  * ERROR_ACCESS_DENIED      Caller does not have access to this call.
369  * ERROR_INVALID_PARAMETER  One of the parameters is invalid.
370  * ERROR_INVALID_LEVEL      Unknown information level specified.
371  * ERROR_MORE_DATA          Partial date returned, more entries available.
372  * ERROR_NOT_ENOUGH_MEMORY  Insufficient memory is available.
373  * NERR_BufTooSmall         The supplied buffer is too small.
374  */
375 static int
376 srvsvc_s_NetFileEnum(void *arg, ndr_xa_t *mxa)
377 {
378 	struct mslm_NetFileEnum *param = arg;
379 	DWORD status;
380 
381 	if (!ndr_is_admin(mxa)) {
382 		bzero(param, sizeof (struct mslm_NetFileEnum));
383 		param->status = ERROR_ACCESS_DENIED;
384 		return (NDR_DRC_OK);
385 	}
386 
387 	switch (param->info.switch_value) {
388 	case 2:
389 		status = srvsvc_NetFileEnum2(mxa, param);
390 		break;
391 
392 	case 3:
393 		status = srvsvc_NetFileEnum3(mxa, param);
394 		break;
395 
396 	case 50:
397 		status = ERROR_NOT_SUPPORTED;
398 		break;
399 
400 	default:
401 		status = ERROR_INVALID_LEVEL;
402 		break;
403 	}
404 
405 	if (status != ERROR_SUCCESS) {
406 		bzero(param, sizeof (struct mslm_NetFileEnum));
407 		param->status = status;
408 		return (NDR_DRC_OK);
409 	}
410 
411 	if (param->resume_handle)
412 		*param->resume_handle = 0;
413 
414 	param->status = ERROR_SUCCESS;
415 	return (NDR_DRC_OK);
416 }
417 
418 /*
419  * Build level 2 file information.
420  *
421  * On success, the caller expects that the info2, fi2 and entries_read
422  * fields have been set up.
423  */
424 static DWORD
425 srvsvc_NetFileEnum2(ndr_xa_t *mxa, struct mslm_NetFileEnum *param)
426 {
427 	struct mslm_NetFileInfoBuf2 *fi2;
428 	ndr_pipe_info_t pi;
429 	uint32_t entries_read = 0;
430 	int i;
431 
432 	param->info.ru.info2 = NDR_NEW(mxa, struct mslm_NetFileInfo2);
433 	if (param->info.ru.info3 == NULL)
434 		return (ERROR_NOT_ENOUGH_MEMORY);
435 
436 	fi2 = NDR_NEWN(mxa, struct mslm_NetFileInfoBuf2, 128);
437 	if (fi2 == NULL)
438 		return (ERROR_NOT_ENOUGH_MEMORY);
439 
440 	param->info.ru.info2->fi2 = fi2;
441 
442 	for (i = 0; i < 128; ++i) {
443 		if (ndr_pipe_getinfo(i, &pi) == -1)
444 			continue;
445 
446 		fi2->fi2_id = pi.npi_fid;
447 
448 		++entries_read;
449 		++fi2;
450 	}
451 
452 	param->info.ru.info2->entries_read = entries_read;
453 	param->total_entries = entries_read;
454 	return (ERROR_SUCCESS);
455 }
456 
457 /*
458  * Build level 3 file information.
459  *
460  * On success, the caller expects that the info3, fi3 and entries_read
461  * fields have been set up.
462  */
463 static DWORD
464 srvsvc_NetFileEnum3(ndr_xa_t *mxa, struct mslm_NetFileEnum *param)
465 {
466 	struct mslm_NetFileInfoBuf3 *fi3;
467 	ndr_pipe_info_t pi;
468 	uint32_t entries_read = 0;
469 	int i;
470 
471 	param->info.ru.info3 = NDR_NEW(mxa, struct mslm_NetFileInfo3);
472 	if (param->info.ru.info3 == NULL)
473 		return (ERROR_NOT_ENOUGH_MEMORY);
474 
475 	fi3 = NDR_NEWN(mxa, struct mslm_NetFileInfoBuf3, 128);
476 	if (fi3 == NULL)
477 		return (ERROR_NOT_ENOUGH_MEMORY);
478 
479 	param->info.ru.info3->fi3 = fi3;
480 
481 	for (i = 0; i < 128; ++i) {
482 		if (ndr_pipe_getinfo(i, &pi) == -1)
483 			continue;
484 
485 		fi3->fi3_id = pi.npi_fid;
486 		fi3->fi3_permissions = pi.npi_permissions;
487 		fi3->fi3_num_locks = pi.npi_num_locks;
488 		fi3->fi3_pathname = (uint8_t *)
489 		    NDR_STRDUP(mxa, pi.npi_pathname);
490 		fi3->fi3_username = (uint8_t *)
491 		    NDR_STRDUP(mxa, pi.npi_username);
492 
493 		++entries_read;
494 		++fi3;
495 	}
496 
497 	param->info.ru.info3->entries_read = entries_read;
498 	param->total_entries = entries_read;
499 	return (ERROR_SUCCESS);
500 }
501 
502 /*
503  * srvsvc_s_NetFileClose
504  *
505  * NetFileClose forces a file to close. This function can be used when
506  * an error prevents closure by any other means.  Use NetFileClose with
507  * caution because it does not flush data, cached on a client, to the
508  * file before closing the file.
509  *
510  * Return Values
511  * ERROR_SUCCESS            Operation succeeded.
512  * ERROR_ACCESS_DENIED      Operation denied.
513  * NERR_FileIdNotFound      No open file with the specified id.
514  *
515  * Note: MSDN suggests that the error code should be ERROR_FILE_NOT_FOUND
516  * but network captures using NT show NERR_FileIdNotFound.
517  * The NetFileClose2 MSDN page has the right error code.
518  */
519 static int
520 srvsvc_s_NetFileClose(void *arg, ndr_xa_t *mxa)
521 {
522 	struct mslm_NetFileClose *param = arg;
523 
524 	if (!ndr_is_admin(mxa)) {
525 		bzero(param, sizeof (struct mslm_NetFileClose));
526 		param->status = ERROR_ACCESS_DENIED;
527 		return (NDR_DRC_OK);
528 	}
529 
530 	bzero(param, sizeof (struct mslm_NetFileClose));
531 	param->status = ERROR_SUCCESS;
532 	return (NDR_DRC_OK);
533 }
534 
535 
536 /*
537  * srvsvc_s_NetShareGetInfo
538  *
539  * Returns Win32 error codes.
540  */
541 static int
542 srvsvc_s_NetShareGetInfo(void *arg, ndr_xa_t *mxa)
543 {
544 	struct mlsm_NetShareGetInfo *param = arg;
545 	struct mslm_NetShareInfo_0 *info0;
546 	struct mslm_NetShareInfo_1 *info1;
547 	struct mslm_NetShareInfo_2 *info2;
548 	struct mslm_NetShareInfo_501 *info501;
549 	struct mslm_NetShareInfo_502 *info502;
550 	struct mslm_NetShareInfo_1004 *info1004;
551 	struct mslm_NetShareInfo_1005 *info1005;
552 	struct mslm_NetShareInfo_1006 *info1006;
553 	smb_share_t si;
554 	DWORD status;
555 
556 	status = smb_shr_get((char *)param->netname, &si);
557 	if (status != NERR_Success) {
558 		bzero(param, sizeof (struct mlsm_NetShareGetInfo));
559 		param->status = status;
560 		return (NDR_DRC_OK);
561 	}
562 
563 	switch (param->level) {
564 	case 0:
565 		info0 = NDR_NEW(mxa, struct mslm_NetShareInfo_0);
566 		if (info0 == NULL) {
567 			status = ERROR_NOT_ENOUGH_MEMORY;
568 			break;
569 		}
570 
571 		info0->shi0_netname
572 		    = (uint8_t *)NDR_STRDUP(mxa, si.shr_name);
573 		if (info0->shi0_netname == NULL) {
574 			status = ERROR_NOT_ENOUGH_MEMORY;
575 			break;
576 		}
577 
578 		param->result.ru.info0 = info0;
579 		break;
580 
581 	case 1:
582 		info1 = NDR_NEW(mxa, struct mslm_NetShareInfo_1);
583 		if (info1 == NULL) {
584 			status = ERROR_NOT_ENOUGH_MEMORY;
585 			break;
586 		}
587 
588 		info1->shi1_netname = (uint8_t *)NDR_STRDUP(mxa, si.shr_name);
589 		info1->shi1_comment = (uint8_t *)NDR_STRDUP(mxa, si.shr_cmnt);
590 		if (info1->shi1_netname == NULL ||
591 		    info1->shi1_comment == NULL) {
592 			status = ERROR_NOT_ENOUGH_MEMORY;
593 			break;
594 		}
595 
596 		info1->shi1_type = si.shr_type;
597 		param->result.ru.info1 = info1;
598 		break;
599 
600 	case 2:
601 		info2 = NDR_NEW(mxa, struct mslm_NetShareInfo_2);
602 		if (info2 == NULL) {
603 			status = ERROR_NOT_ENOUGH_MEMORY;
604 			break;
605 		}
606 
607 		info2->shi2_netname = (uint8_t *)NDR_STRDUP(mxa, si.shr_name);
608 		info2->shi2_comment = (uint8_t *)NDR_STRDUP(mxa, si.shr_cmnt);
609 		if (info2->shi2_netname == NULL ||
610 		    info2->shi2_comment == NULL) {
611 			status = ERROR_NOT_ENOUGH_MEMORY;
612 			break;
613 		}
614 
615 		info2->shi2_path =
616 		    (uint8_t *)srvsvc_share_mkpath(mxa, si.shr_path);
617 		info2->shi2_passwd = 0;
618 		info2->shi2_type = si.shr_type;
619 		info2->shi2_permissions = 0;
620 		info2->shi2_max_uses = SHI_USES_UNLIMITED;
621 		info2->shi2_current_uses = 0;
622 		param->result.ru.info2 = info2;
623 		break;
624 
625 	case 1004:
626 		info1004 = NDR_NEW(mxa, struct mslm_NetShareInfo_1004);
627 		if (info1004 == NULL) {
628 			status = ERROR_NOT_ENOUGH_MEMORY;
629 			break;
630 		}
631 
632 		info1004->shi1004_comment =
633 		    (uint8_t *)NDR_STRDUP(mxa, si.shr_cmnt);
634 		if (info1004->shi1004_comment == NULL)
635 			status = ERROR_NOT_ENOUGH_MEMORY;
636 		break;
637 
638 	case 1005:
639 		info1005 = NDR_NEW(mxa, struct mslm_NetShareInfo_1005);
640 		if (info1005 == NULL) {
641 			status = ERROR_NOT_ENOUGH_MEMORY;
642 			break;
643 		}
644 
645 		info1005->shi1005_flags = 0;
646 
647 		switch (si.shr_flags & SMB_SHRF_CSC_MASK) {
648 		case SMB_SHRF_CSC_DISABLED:
649 			info1005->shi1005_flags |= CSC_CACHE_NONE;
650 			break;
651 		case SMB_SHRF_CSC_AUTO:
652 			info1005->shi1005_flags |= CSC_CACHE_AUTO_REINT;
653 			break;
654 		case SMB_SHRF_CSC_VDO:
655 			info1005->shi1005_flags |= CSC_CACHE_VDO;
656 			break;
657 		case SMB_SHRF_CSC_MANUAL:
658 		default:
659 			/*
660 			 * Default to CSC_CACHE_MANUAL_REINT.
661 			 */
662 			break;
663 		}
664 
665 		param->result.ru.info1005 = info1005;
666 		break;
667 
668 	case 1006:
669 		info1006 = NDR_NEW(mxa, struct mslm_NetShareInfo_1006);
670 		if (info1006 == NULL) {
671 			status = ERROR_NOT_ENOUGH_MEMORY;
672 			break;
673 		}
674 		info1006->shi1006_max_uses = SHI_USES_UNLIMITED;
675 		param->result.ru.info1006 = info1006;
676 		break;
677 
678 	case 501:
679 		/*
680 		 * Level 501 provides level 1 information.
681 		 */
682 		info501 = NDR_NEW(mxa, struct mslm_NetShareInfo_501);
683 		if (info501 == NULL) {
684 			status = ERROR_NOT_ENOUGH_MEMORY;
685 			break;
686 		}
687 
688 		info501->shi501_netname =
689 		    (uint8_t *)NDR_STRDUP(mxa, si.shr_name);
690 		info501->shi501_comment =
691 		    (uint8_t *)NDR_STRDUP(mxa, si.shr_cmnt);
692 		if (info501->shi501_netname == NULL ||
693 		    info501->shi501_comment == NULL) {
694 			status = ERROR_NOT_ENOUGH_MEMORY;
695 			break;
696 		}
697 
698 		info501->shi501_type = si.shr_type;
699 		info501->shi501_reserved = 0;
700 		param->result.ru.info501 = info501;
701 		break;
702 
703 	case 502:
704 		/*
705 		 * Level 502 provides level 2 information plus a
706 		 * security descriptor. We don't support security
707 		 * descriptors on shares yet.
708 		 */
709 		info502 = NDR_NEW(mxa, struct mslm_NetShareInfo_502);
710 		if (info502 == NULL) {
711 			status = ERROR_NOT_ENOUGH_MEMORY;
712 			break;
713 		}
714 
715 		info502->shi502_netname =
716 		    (uint8_t *)NDR_STRDUP(mxa, si.shr_name);
717 		info502->shi502_comment =
718 		    (uint8_t *)NDR_STRDUP(mxa, si.shr_cmnt);
719 		if (info502->shi502_netname == NULL ||
720 		    info502->shi502_comment == NULL) {
721 			status = ERROR_NOT_ENOUGH_MEMORY;
722 			break;
723 		}
724 
725 		info502->shi502_path =
726 		    (uint8_t *)srvsvc_share_mkpath(mxa, si.shr_path);
727 		info502->shi502_passwd = 0;
728 		info502->shi502_type = si.shr_type;
729 		info502->shi502_permissions = 0;
730 		info502->shi502_max_uses = SHI_USES_UNLIMITED;
731 		info502->shi502_current_uses = 0;
732 		info502->shi502_reserved = 0;
733 		info502->shi502_security_descriptor = 0;
734 		param->result.ru.info502 = info502;
735 		break;
736 
737 	default:
738 		status = ERROR_ACCESS_DENIED;
739 		break;
740 	}
741 
742 	if (status != ERROR_SUCCESS)
743 		bzero(param, sizeof (struct mlsm_NetShareGetInfo));
744 	else
745 		param->result.switch_value = param->level;
746 
747 	param->status = status;
748 	return (NDR_DRC_OK);
749 }
750 
751 
752 /*
753  * srvsvc_s_NetShareSetInfo
754  *
755  * This call is made by SrvMgr to set share information.
756  * Always returns ERROR_ACCESS_DENIED for now.
757  *
758  * Returns Win32 error codes.
759  */
760 static int
761 srvsvc_s_NetShareSetInfo(void *arg, ndr_xa_t *mxa)
762 {
763 	struct mlsm_NetShareSetInfo *param = arg;
764 
765 	(void) memset(param, 0, sizeof (struct mlsm_NetShareSetInfo));
766 	param->parm_err_ptr = (DWORD)(uintptr_t)NDR_MALLOC(mxa,
767 	    sizeof (DWORD));
768 	param->parm_err = 0;
769 
770 	if (!smb_config_getbool(SMB_CI_SRVSVC_SHRSET_ENABLE))
771 		param->status = ERROR_SUCCESS;
772 	else
773 		param->status = ERROR_ACCESS_DENIED;
774 
775 	return (NDR_DRC_OK);
776 }
777 
778 /*
779  * srvsvc_s_NetSessionEnum
780  *
781  * Level 1 request is made by (Server Manager (srvmgr) on NT Server when
782  * the user info icon is selected.
783  *
784  * On success, the return value is NERR_Success.
785  * On error, the return value can be one of the following error codes:
786  *
787  * ERROR_ACCESS_DENIED      The user does not have access to the requested
788  *                          information.
789  * ERROR_INVALID_LEVEL      The value specified for the level is invalid.
790  * ERROR_INVALID_PARAMETER  The specified parameter is invalid.
791  * ERROR_MORE_DATA          More entries are available. Specify a large
792  *                          enough buffer to receive all entries.
793  * ERROR_NOT_ENOUGH_MEMORY  Insufficient memory is available.
794  * NERR_ClientNameNotFound  A session does not exist with the computer name.
795  * NERR_InvalidComputer     The computer name is invalid.
796  * NERR_UserNotFound        The user name could not be found.
797  */
798 static int
799 srvsvc_s_NetSessionEnum(void *arg, ndr_xa_t *mxa)
800 {
801 	struct mslm_NetSessionEnum *param = arg;
802 	struct mslm_infonres *infonres;
803 	DWORD status;
804 	DWORD n_sessions;
805 
806 	infonres = NDR_NEW(mxa, struct mslm_infonres);
807 	if (infonres == NULL) {
808 		bzero(param, sizeof (struct mslm_NetSessionEnum));
809 		param->status = ERROR_NOT_ENOUGH_MEMORY;
810 		return (NDR_DRC_OK);
811 	}
812 
813 	infonres->entriesread = 0;
814 	infonres->entries = NULL;
815 	param->result.level = param->level;
816 	param->result.bufptr.p = infonres;
817 	param->total_entries = 0;
818 	param->resume_handle = NULL;
819 	param->status = ERROR_SUCCESS;
820 
821 	if ((n_sessions = (DWORD) mlsvc_get_num_users()) == 0)
822 		return (NDR_DRC_OK);
823 
824 	switch (param->level) {
825 	case 0:
826 		status = mlsvc_NetSessionEnumLevel0(infonres, n_sessions, mxa);
827 		break;
828 
829 	case 1:
830 		status = mlsvc_NetSessionEnumLevel1(infonres, n_sessions, mxa);
831 		break;
832 
833 	default:
834 		status = ERROR_INVALID_LEVEL;
835 		break;
836 	}
837 
838 	if (status != 0) {
839 		bzero(param, sizeof (struct mslm_NetSessionEnum));
840 		param->status = status;
841 		return (NDR_DRC_OK);
842 	}
843 
844 	param->total_entries = infonres->entriesread;
845 	param->status = status;
846 	return (NDR_DRC_OK);
847 }
848 
849 /*
850  * mlsvc_NetSessionEnumLevel0
851  *
852  * Build the level 0 session information.
853  */
854 static DWORD
855 mlsvc_NetSessionEnumLevel0(struct mslm_infonres *infonres, DWORD n_sessions,
856     ndr_xa_t *mxa)
857 {
858 	struct mslm_SESSION_INFO_0 *info0;
859 	smb_dr_ulist_t *ulist;
860 	smb_opipe_context_t *user;
861 	char *workstation;
862 	char ipaddr_buf[INET6_ADDRSTRLEN];
863 	int n_users;
864 	int offset = 0;
865 	int i;
866 
867 	if ((ulist = malloc(sizeof (smb_dr_ulist_t))) == NULL)
868 		return (ERROR_NOT_ENOUGH_MEMORY);
869 
870 	if ((n_users = mlsvc_get_user_list(offset, ulist)) == 0) {
871 		smb_dr_ulist_free(ulist);
872 		return (ERROR_NOT_ENOUGH_MEMORY);
873 	}
874 
875 	if (n_users < n_sessions)
876 		n_sessions = n_users;
877 
878 	info0 = NDR_NEWN(mxa, struct mslm_SESSION_INFO_0, n_sessions);
879 	if (info0 == NULL) {
880 		smb_dr_ulist_free(ulist);
881 		return (ERROR_NOT_ENOUGH_MEMORY);
882 	}
883 
884 	for (i = 0; i < n_sessions; ++i) {
885 		user = &ulist->dul_users[i];
886 
887 		workstation = user->oc_workstation;
888 		if (workstation == NULL || *workstation == '\0') {
889 			(void) smb_inet_ntop(&user->oc_ipaddr,
890 			    ipaddr_buf, SMB_IPSTRLEN(user->oc_ipaddr.a_family));
891 			workstation = ipaddr_buf;
892 		}
893 
894 		info0[i].sesi0_cname = NDR_STRDUP(mxa, workstation);
895 		if (info0[i].sesi0_cname == NULL) {
896 			smb_dr_ulist_free(ulist);
897 			return (ERROR_NOT_ENOUGH_MEMORY);
898 		}
899 	}
900 
901 	smb_dr_ulist_free(ulist);
902 	infonres->entriesread = n_sessions;
903 	infonres->entries = info0;
904 	return (ERROR_SUCCESS);
905 }
906 
907 /*
908  * mlsvc_NetSessionEnumLevel1
909  *
910  * Build the level 1 session information.
911  */
912 static DWORD
913 mlsvc_NetSessionEnumLevel1(struct mslm_infonres *infonres, DWORD n_sessions,
914     ndr_xa_t *mxa)
915 {
916 	struct mslm_SESSION_INFO_1 *info1;
917 	smb_dr_ulist_t *ulist;
918 	smb_opipe_context_t *user;
919 	char *workstation;
920 	char account[MAXNAMELEN];
921 	char ipaddr_buf[INET6_ADDRSTRLEN];
922 	int n_users;
923 	int offset = 0;
924 	int i;
925 
926 	if ((ulist = malloc(sizeof (smb_dr_ulist_t))) == NULL)
927 		return (ERROR_NOT_ENOUGH_MEMORY);
928 
929 	if ((n_users = mlsvc_get_user_list(offset, ulist)) == 0) {
930 		smb_dr_ulist_free(ulist);
931 		return (ERROR_NOT_ENOUGH_MEMORY);
932 	}
933 
934 	if (n_users < n_sessions)
935 		n_sessions = n_users;
936 
937 	info1 = NDR_NEWN(mxa, struct mslm_SESSION_INFO_1, n_sessions);
938 	if (info1 == NULL) {
939 		smb_dr_ulist_free(ulist);
940 		return (ERROR_NOT_ENOUGH_MEMORY);
941 	}
942 
943 	for (i = 0; i < n_sessions; ++i) {
944 		user = &ulist->dul_users[i];
945 
946 		workstation = user->oc_workstation;
947 		if (workstation == NULL || *workstation == '\0') {
948 			(void) smb_inet_ntop(&user->oc_ipaddr,
949 			    ipaddr_buf, SMB_IPSTRLEN(user->oc_ipaddr.a_family));
950 			workstation = ipaddr_buf;
951 		}
952 
953 		(void) snprintf(account, MAXNAMELEN, "%s\\%s",
954 		    user->oc_domain, user->oc_account);
955 
956 		info1[i].sesi1_cname = NDR_STRDUP(mxa, workstation);
957 		info1[i].sesi1_uname = NDR_STRDUP(mxa, account);
958 
959 		if (info1[i].sesi1_cname == NULL ||
960 		    info1[i].sesi1_uname == NULL) {
961 			smb_dr_ulist_free(ulist);
962 			return (ERROR_NOT_ENOUGH_MEMORY);
963 		}
964 
965 		info1[i].sesi1_nopens = 1;
966 		info1[i].sesi1_time = time(0) - user->oc_logon_time;
967 		info1[i].sesi1_itime = 0;
968 		info1[i].sesi1_uflags =
969 		    (user->oc_flags & SMB_ATF_GUEST) ? SESS_GUEST : 0;
970 	}
971 
972 	smb_dr_ulist_free(ulist);
973 	infonres->entriesread = n_sessions;
974 	infonres->entries = info1;
975 	return (ERROR_SUCCESS);
976 }
977 
978 /*
979  * srvsvc_s_NetSessionDel
980  *
981  * Ends a network session between a server and a workstation.
982  * On NT only members of the Administrators or Account Operators
983  * local groups are permitted to use NetSessionDel.
984  *
985  * Return Values
986  * If the function succeeds, the return value is NERR_Success/
987  * ERROR_SUCCESS. If the function fails, the return value can be
988  * one of the following error codes:
989  *
990  * ERROR_ACCESS_DENIED 		The user does not have access to the
991  * 							requested information.
992  * ERROR_INVALID_PARAMETER	The specified parameter is invalid.
993  * ERROR_NOT_ENOUGH_MEMORY	Insufficient memory is available.
994  * NERR_ClientNameNotFound	A session does not exist with that
995  *                          computer name.
996  */
997 static int
998 srvsvc_s_NetSessionDel(void *arg, ndr_xa_t *mxa)
999 {
1000 	struct mslm_NetSessionDel *param = arg;
1001 
1002 	if (!ndr_is_poweruser(mxa)) {
1003 		param->status = ERROR_ACCESS_DENIED;
1004 		return (NDR_DRC_OK);
1005 	}
1006 
1007 	param->status = ERROR_ACCESS_DENIED;
1008 	return (NDR_DRC_OK);
1009 }
1010 
1011 /*
1012  * SRVSVC NetServerGetInfo
1013  *
1014  *	IN	LPTSTR servername,
1015  *	IN	DWORD level,
1016  *	OUT	union switch(level) {
1017  *		case 100:	mslm_SERVER_INFO_100 *p100;
1018  *		case 101:	mslm_SERVER_INFO_101 *p101;
1019  *		case 102:	mslm_SERVER_INFO_102 *p102;
1020  *		default:	char *nullptr;
1021  *		} bufptr,
1022  *	OUT	DWORD status
1023  */
1024 static int
1025 srvsvc_s_NetServerGetInfo(void *arg, ndr_xa_t *mxa)
1026 {
1027 	struct mslm_NetServerGetInfo *param = arg;
1028 	struct mslm_SERVER_INFO_100 *info100;
1029 	struct mslm_SERVER_INFO_101 *info101;
1030 	struct mslm_SERVER_INFO_102 *info102;
1031 	char sys_comment[SMB_PI_MAX_COMMENT];
1032 	char hostname[NETBIOS_NAME_SZ];
1033 
1034 	if (smb_getnetbiosname(hostname, sizeof (hostname)) != 0) {
1035 netservergetinfo_no_memory:
1036 		bzero(param, sizeof (struct mslm_NetServerGetInfo));
1037 		return (ERROR_NOT_ENOUGH_MEMORY);
1038 	}
1039 
1040 	(void) smb_config_getstr(SMB_CI_SYS_CMNT, sys_comment,
1041 	    sizeof (sys_comment));
1042 	if (*sys_comment == '\0')
1043 		(void) strcpy(sys_comment, " ");
1044 
1045 	switch (param->level) {
1046 	case 100:
1047 		info100 = NDR_NEW(mxa, struct mslm_SERVER_INFO_100);
1048 		if (info100 == NULL)
1049 			goto netservergetinfo_no_memory;
1050 
1051 		bzero(info100, sizeof (struct mslm_SERVER_INFO_100));
1052 		info100->sv100_platform_id = SV_PLATFORM_ID_NT;
1053 		info100->sv100_name = (uint8_t *)NDR_STRDUP(mxa, hostname);
1054 		if (info100->sv100_name == NULL)
1055 			goto netservergetinfo_no_memory;
1056 
1057 		param->result.bufptr.bufptr100 = info100;
1058 		break;
1059 
1060 	case 101:
1061 		info101 = NDR_NEW(mxa, struct mslm_SERVER_INFO_101);
1062 		if (info101 == NULL)
1063 			goto netservergetinfo_no_memory;
1064 
1065 		bzero(info101, sizeof (struct mslm_SERVER_INFO_101));
1066 		info101->sv101_platform_id = SV_PLATFORM_ID_NT;
1067 		info101->sv101_version_major = 4;
1068 		info101->sv101_version_minor = 0;
1069 		info101->sv101_type = SV_TYPE_SENT_BY_ME;
1070 		info101->sv101_name = (uint8_t *)NDR_STRDUP(mxa, hostname);
1071 		info101->sv101_comment
1072 		    = (uint8_t *)NDR_STRDUP(mxa, sys_comment);
1073 
1074 		if (info101->sv101_name == NULL ||
1075 		    info101->sv101_comment == NULL)
1076 			goto netservergetinfo_no_memory;
1077 
1078 		param->result.bufptr.bufptr101 = info101;
1079 		break;
1080 
1081 	case 102:
1082 		info102 = NDR_NEW(mxa, struct mslm_SERVER_INFO_102);
1083 		if (info102 == NULL)
1084 			goto netservergetinfo_no_memory;
1085 
1086 		bzero(info102, sizeof (struct mslm_SERVER_INFO_102));
1087 		info102->sv102_platform_id = SV_PLATFORM_ID_NT;
1088 		info102->sv102_version_major = 4;
1089 		info102->sv102_version_minor = 0;
1090 		info102->sv102_type = SV_TYPE_SENT_BY_ME;
1091 		info102->sv102_name = (uint8_t *)NDR_STRDUP(mxa, hostname);
1092 		info102->sv102_comment
1093 		    = (uint8_t *)NDR_STRDUP(mxa, sys_comment);
1094 
1095 		/*
1096 		 * The following level 102 fields are defaulted to zero
1097 		 * by virtue of the call to bzero above.
1098 		 *
1099 		 * sv102_users
1100 		 * sv102_disc
1101 		 * sv102_hidden
1102 		 * sv102_announce
1103 		 * sv102_anndelta
1104 		 * sv102_licenses
1105 		 * sv102_userpath
1106 		 */
1107 		if (info102->sv102_name == NULL ||
1108 		    info102->sv102_comment == NULL)
1109 			goto netservergetinfo_no_memory;
1110 
1111 		param->result.bufptr.bufptr102 = info102;
1112 		break;
1113 
1114 	default:
1115 		bzero(&param->result,
1116 		    sizeof (struct mslm_NetServerGetInfo_result));
1117 		param->status = ERROR_ACCESS_DENIED;
1118 		return (NDR_DRC_OK);
1119 	}
1120 
1121 	param->result.level = param->level;
1122 	param->status = (ERROR_SUCCESS);
1123 	return (NDR_DRC_OK);
1124 }
1125 
1126 /*
1127  * NetRemoteTOD
1128  *
1129  * Returns information about the time of day on this server.
1130  *
1131  * typedef struct _TIME_OF_DAY_INFO {
1132  *	DWORD tod_elapsedt;  // seconds since 00:00:00 January 1 1970 GMT
1133  *	DWORD tod_msecs;     // arbitrary milliseconds (since reset)
1134  *	DWORD tod_hours;     // current hour [0-23]
1135  *	DWORD tod_mins;      // current minute [0-59]
1136  *	DWORD tod_secs;      // current second [0-59]
1137  *	DWORD tod_hunds;     // current hundredth (0.01) second [0-99]
1138  *	LONG tod_timezone;   // time zone of the server
1139  *	DWORD tod_tinterval; // clock tick time interval
1140  *	DWORD tod_day;       // day of the month [1-31]
1141  *	DWORD tod_month;     // month of the year [1-12]
1142  *	DWORD tod_year;      // current year
1143  *	DWORD tod_weekday;   // day of the week since Sunday [0-6]
1144  * } TIME_OF_DAY_INFO;
1145  *
1146  * The time zone of the server is calculated in minutes from Greenwich
1147  * Mean Time (GMT). For time zones west of Greenwich, the value is
1148  * positive; for time zones east of Greenwich, the value is negative.
1149  * A value of -1 indicates that the time zone is undefined.
1150  *
1151  * The clock tick value represents a resolution of one ten-thousandth
1152  * (0.0001) second.
1153  */
1154 static int
1155 srvsvc_s_NetRemoteTOD(void *arg, ndr_xa_t *mxa)
1156 {
1157 	struct mslm_NetRemoteTOD *param = arg;
1158 	struct mslm_TIME_OF_DAY_INFO *tod;
1159 	struct timeval		time_val;
1160 	struct tm		tm;
1161 
1162 	(void) gettimeofday(&time_val, 0);
1163 	(void) gmtime_r(&time_val.tv_sec, &tm);
1164 
1165 	tod = NDR_NEW(mxa, struct mslm_TIME_OF_DAY_INFO);
1166 	if (tod == NULL) {
1167 		bzero(param, sizeof (struct mslm_NetRemoteTOD));
1168 		return (ERROR_NOT_ENOUGH_MEMORY);
1169 	}
1170 
1171 	tod->tod_elapsedt = time_val.tv_sec;
1172 	tod->tod_msecs = time_val.tv_usec;
1173 	tod->tod_hours = tm.tm_hour;
1174 	tod->tod_mins = tm.tm_min;
1175 	tod->tod_secs = tm.tm_sec;
1176 	tod->tod_hunds = 0;
1177 	tod->tod_tinterval = 1000;
1178 	tod->tod_day = tm.tm_mday;
1179 	tod->tod_month = tm.tm_mon+1;
1180 	tod->tod_year = tm.tm_year+1900;
1181 	tod->tod_weekday = tm.tm_wday;
1182 
1183 	(void) localtime_r(&time_val.tv_sec, &tm);
1184 
1185 	param->bufptr = tod;
1186 	param->status = ERROR_SUCCESS;
1187 	return (NDR_DRC_OK);
1188 }
1189 
1190 /*
1191  * srvsvc_s_NetNameValidate
1192  *
1193  * Perform name validation.
1194  *
1195  * The share name is considered invalid if it contains any of the
1196  * following character (MSDN 236388).
1197  *
1198  * " / \ [ ] : | < > + ; , ? * =
1199  *
1200  * Returns Win32 error codes.
1201  */
1202 /*ARGSUSED*/
1203 static int
1204 srvsvc_s_NetNameValidate(void *arg, ndr_xa_t *mxa)
1205 {
1206 	struct mslm_NetNameValidate *param = arg;
1207 	char *name;
1208 	int len;
1209 
1210 	if ((name = (char *)param->pathname) == NULL) {
1211 		param->status = ERROR_INVALID_PARAMETER;
1212 		return (NDR_DRC_OK);
1213 	}
1214 
1215 	len = strlen(name);
1216 
1217 	if ((param->flags == 0 && len > 81) ||
1218 	    (param->flags == 0x80000000 && len > 13)) {
1219 		param->status = ERROR_INVALID_NAME;
1220 		return (NDR_DRC_OK);
1221 	}
1222 
1223 	switch (param->type) {
1224 	case NAMETYPE_SHARE:
1225 		if (smb_shr_chkname(name))
1226 			param->status = ERROR_SUCCESS;
1227 		else
1228 			param->status = ERROR_INVALID_NAME;
1229 		break;
1230 
1231 	case NAMETYPE_USER:
1232 	case NAMETYPE_PASSWORD:
1233 	case NAMETYPE_GROUP:
1234 	case NAMETYPE_COMPUTER:
1235 	case NAMETYPE_EVENT:
1236 	case NAMETYPE_DOMAIN:
1237 	case NAMETYPE_SERVICE:
1238 	case NAMETYPE_NET:
1239 	case NAMETYPE_MESSAGE:
1240 	case NAMETYPE_MESSAGEDEST:
1241 	case NAMETYPE_SHAREPASSWORD:
1242 	case NAMETYPE_WORKGROUP:
1243 		param->status = ERROR_NOT_SUPPORTED;
1244 		break;
1245 
1246 	default:
1247 		param->status = ERROR_INVALID_PARAMETER;
1248 		break;
1249 	}
1250 
1251 	return (NDR_DRC_OK);
1252 }
1253 
1254 /*
1255  * srvsvc_s_NetShareAdd
1256  *
1257  * Add a new share. We support info levels 2 and 502 but ignore the
1258  * security descriptor in level 502 requests. Only the administrator,
1259  * or a member of the domain administrators group, is allowed to add
1260  * shares.
1261  *
1262  * This interface is used by the rmtshare command from the NT resource
1263  * kit. Rmtshare allows a client to add or remove shares on a server
1264  * from the client's command line.
1265  *
1266  * Note that we don't support security descriptors on a share. If the
1267  * /grant is used, the share will be created but the subsequent attempt
1268  * to manipulate the security descriptor (NetShareGetInfo) will fail.
1269  * Similarly for the /remove option.
1270  *
1271  * Returns Win32 error codes.
1272  */
1273 static int
1274 srvsvc_s_NetShareAdd(void *arg, ndr_xa_t *mxa)
1275 {
1276 	static DWORD parm_err = 0;
1277 	DWORD parm_stat;
1278 	struct mslm_NetShareAdd *param = arg;
1279 	struct mslm_NetShareInfo_2 *info2;
1280 	char realpath[MAXPATHLEN];
1281 	int32_t native_os;
1282 
1283 	native_os = ndr_native_os(mxa);
1284 
1285 	if (!ndr_is_poweruser(mxa)) {
1286 		bzero(param, sizeof (struct mslm_NetShareAdd));
1287 		param->status = ERROR_ACCESS_DENIED;
1288 		return (NDR_DRC_OK);
1289 	}
1290 
1291 	switch (param->level) {
1292 	case 2:
1293 		info2 = param->info.un.info2;
1294 		break;
1295 
1296 	case 502:
1297 		info2 = (struct mslm_NetShareInfo_2 *)param->info.un.info502;
1298 		break;
1299 
1300 	default:
1301 		bzero(param, sizeof (struct mslm_NetShareAdd));
1302 		param->status = ERROR_ACCESS_DENIED;
1303 		return (NDR_DRC_OK);
1304 	}
1305 
1306 	if (info2->shi2_netname == NULL || info2->shi2_path == NULL) {
1307 		bzero(param, sizeof (struct mslm_NetShareAdd));
1308 		param->status = NERR_NetNameNotFound;
1309 		return (NDR_DRC_OK);
1310 	}
1311 
1312 	if (smb_shr_is_restricted((char *)info2->shi2_netname)) {
1313 		bzero(param, sizeof (struct mslm_NetShareAdd));
1314 		param->status = ERROR_ACCESS_DENIED;
1315 		return (NDR_DRC_OK);
1316 	}
1317 
1318 	if (info2->shi2_comment == NULL)
1319 		info2->shi2_comment = (uint8_t *)"";
1320 
1321 	/*
1322 	 * Derive the real path which will be stored in the
1323 	 * directory field of the smb_share_t structure
1324 	 * from the path field in this RPC request.
1325 	 */
1326 	parm_stat = smb_shr_get_realpath((const char *)info2->shi2_path,
1327 	    realpath, MAXPATHLEN);
1328 
1329 	if (parm_stat != NERR_Success) {
1330 		bzero(param, sizeof (struct mslm_NetShareAdd));
1331 		param->status = parm_stat;
1332 		param->parm_err
1333 		    = (native_os == NATIVE_OS_WIN95) ? 0 : &parm_err;
1334 		return (NDR_DRC_OK);
1335 	}
1336 
1337 	param->status = srvsvc_sa_add((char *)info2->shi2_netname, realpath,
1338 	    (char *)info2->shi2_comment);
1339 	if (param->status == NERR_Success) {
1340 		smb_share_t si;
1341 		/*
1342 		 * Lookup the share, which will bring it into the cache.
1343 		 */
1344 		(void) smb_shr_get((char *)info2->shi2_netname, &si);
1345 	}
1346 	param->parm_err = (native_os == NATIVE_OS_WIN95) ? 0 : &parm_err;
1347 	return (NDR_DRC_OK);
1348 }
1349 
1350 /*
1351  * srvsvc_estimate_objcnt
1352  *
1353  * Estimate the number of objects that will fit in prefmaxlen.
1354  */
1355 static uint32_t
1356 srvsvc_estimate_objcnt(uint32_t prefmaxlen, uint32_t n_obj, uint32_t obj_size)
1357 {
1358 	DWORD max_cnt;
1359 
1360 	if (obj_size == 0)
1361 		return (0);
1362 
1363 	if ((max_cnt = (prefmaxlen / obj_size)) == 0)
1364 		return (0);
1365 
1366 	if (n_obj > max_cnt)
1367 		n_obj = max_cnt;
1368 
1369 	return (n_obj);
1370 }
1371 
1372 /*
1373  * srvsvc_s_NetShareEnum
1374  *
1375  * Enumerate all shares (see also NetShareEnumSticky).
1376  *
1377  * Request for various levels of information about our shares.
1378  * Level 0: share names.
1379  * Level 1: share name, share type and comment field.
1380  * Level 2: everything that we know about the shares.
1381  * Level 501: level 1 + flags (flags must be zero).
1382  * Level 502: level 2 + security descriptor.
1383  */
1384 static int
1385 srvsvc_s_NetShareEnum(void *arg, ndr_xa_t *mxa)
1386 {
1387 	struct mslm_NetShareEnum *param = arg;
1388 	struct mslm_infonres *infonres;
1389 	srvsvc_enum_t se;
1390 	DWORD status;
1391 
1392 	infonres = NDR_NEW(mxa, struct mslm_infonres);
1393 	if (infonres == NULL) {
1394 		bzero(param, sizeof (struct mslm_NetShareEnum));
1395 		param->status = ERROR_NOT_ENOUGH_MEMORY;
1396 		return (NDR_DRC_OK);
1397 	}
1398 
1399 	infonres->entriesread = 0;
1400 	infonres->entries = NULL;
1401 	param->result.level = param->level;
1402 	param->result.bufptr.p = infonres;
1403 
1404 	bzero(&se, sizeof (srvsvc_enum_t));
1405 	se.se_level = param->level;
1406 	se.se_n_total = smb_shr_count();
1407 
1408 	if (param->prefmaxlen == SMB_SRVSVC_MAXPREFLEN ||
1409 	    param->prefmaxlen > SMB_SRVSVC_MAXBUFLEN)
1410 		se.se_prefmaxlen = SMB_SRVSVC_MAXBUFLEN;
1411 	else
1412 		se.se_prefmaxlen = param->prefmaxlen;
1413 
1414 	if (param->resume_handle) {
1415 		se.se_resume_handle = *param->resume_handle;
1416 		se.se_n_skip = se.se_resume_handle;
1417 	}
1418 
1419 	switch (param->level) {
1420 	case 0:
1421 		status = mlsvc_NetShareEnumLevel0(mxa, infonres, &se, 0);
1422 		break;
1423 
1424 	case 1:
1425 		status = mlsvc_NetShareEnumLevel1(mxa, infonres, &se, 0);
1426 		break;
1427 
1428 	case 2:
1429 		status = mlsvc_NetShareEnumLevel2(mxa, infonres, &se, 0);
1430 		break;
1431 
1432 	case 501:
1433 		status = mlsvc_NetShareEnumLevel501(mxa, infonres, &se, 0);
1434 		break;
1435 
1436 	case 502:
1437 		status = mlsvc_NetShareEnumLevel502(mxa, infonres, &se, 0);
1438 		break;
1439 
1440 	default:
1441 		status = ERROR_INVALID_PARAMETER;
1442 		break;
1443 	}
1444 
1445 	if (status != 0) {
1446 		bzero(param, sizeof (struct mslm_NetShareEnum));
1447 		param->status = status;
1448 		return (NDR_DRC_OK);
1449 	}
1450 
1451 	if (se.se_n_enum == 0) {
1452 		if (param->resume_handle)
1453 			*param->resume_handle = 0;
1454 		param->status = ERROR_SUCCESS;
1455 		return (NDR_DRC_OK);
1456 	}
1457 
1458 	if (param->resume_handle &&
1459 	    param->prefmaxlen != SMB_SRVSVC_MAXPREFLEN) {
1460 		if (se.se_resume_handle < se.se_n_total) {
1461 			*param->resume_handle = se.se_resume_handle;
1462 			status = ERROR_MORE_DATA;
1463 		} else {
1464 			*param->resume_handle = 0;
1465 		}
1466 	}
1467 
1468 	param->totalentries = se.se_n_total;
1469 	param->status = status;
1470 	return (NDR_DRC_OK);
1471 }
1472 
1473 /*
1474  * srvsvc_s_NetShareEnumSticky
1475  *
1476  * Enumerate sticky shares: all shares except those marked STYPE_SPECIAL.
1477  * Except for excluding STYPE_SPECIAL shares, NetShareEnumSticky is the
1478  * same as NetShareEnum.
1479  *
1480  * Request for various levels of information about our shares.
1481  * Level 0: share names.
1482  * Level 1: share name, share type and comment field.
1483  * Level 2: everything that we know about the shares.
1484  * Level 501: not valid for this request.
1485  * Level 502: level 2 + security descriptor.
1486  *
1487  * We set n_skip to resume_handle, which is used to find the appropriate
1488  * place to resume.  The resume_handle is similar to the readdir cookie.
1489  */
1490 static int
1491 srvsvc_s_NetShareEnumSticky(void *arg, ndr_xa_t *mxa)
1492 {
1493 	struct mslm_NetShareEnum *param = arg;
1494 	struct mslm_infonres *infonres;
1495 	srvsvc_enum_t se;
1496 	DWORD status;
1497 
1498 	infonres = NDR_NEW(mxa, struct mslm_infonres);
1499 	if (infonres == NULL) {
1500 		bzero(param, sizeof (struct mslm_NetShareEnum));
1501 		param->status = ERROR_NOT_ENOUGH_MEMORY;
1502 		return (NDR_DRC_OK);
1503 	}
1504 
1505 	infonres->entriesread = 0;
1506 	infonres->entries = NULL;
1507 	param->result.level = param->level;
1508 	param->result.bufptr.p = infonres;
1509 
1510 	bzero(&se, sizeof (srvsvc_enum_t));
1511 	se.se_level = param->level;
1512 	se.se_n_total = smb_shr_count();
1513 
1514 	if (param->prefmaxlen == SMB_SRVSVC_MAXPREFLEN ||
1515 	    param->prefmaxlen > SMB_SRVSVC_MAXBUFLEN)
1516 		se.se_prefmaxlen = SMB_SRVSVC_MAXBUFLEN;
1517 	else
1518 		se.se_prefmaxlen = param->prefmaxlen;
1519 
1520 	if (param->resume_handle) {
1521 		se.se_resume_handle = *param->resume_handle;
1522 		se.se_n_skip = se.se_resume_handle;
1523 	}
1524 
1525 	switch (param->level) {
1526 	case 0:
1527 		status = mlsvc_NetShareEnumLevel0(mxa, infonres, &se, 1);
1528 		break;
1529 
1530 	case 1:
1531 		status = mlsvc_NetShareEnumLevel1(mxa, infonres, &se, 1);
1532 		break;
1533 
1534 	case 2:
1535 		status = mlsvc_NetShareEnumLevel2(mxa, infonres, &se, 1);
1536 		break;
1537 
1538 	case 502:
1539 		status = mlsvc_NetShareEnumLevel502(mxa, infonres, &se, 1);
1540 		break;
1541 
1542 	default:
1543 		status = ERROR_INVALID_LEVEL;
1544 		break;
1545 	}
1546 
1547 	if (status != ERROR_SUCCESS) {
1548 		bzero(param, sizeof (struct mslm_NetShareEnum));
1549 		param->status = status;
1550 		return (NDR_DRC_OK);
1551 	}
1552 
1553 	if (se.se_n_enum == 0) {
1554 		if (param->resume_handle)
1555 			*param->resume_handle = 0;
1556 		param->status = ERROR_SUCCESS;
1557 		return (NDR_DRC_OK);
1558 	}
1559 
1560 	if (param->resume_handle &&
1561 	    param->prefmaxlen != SMB_SRVSVC_MAXPREFLEN) {
1562 		if (se.se_resume_handle < se.se_n_total) {
1563 			*param->resume_handle = se.se_resume_handle;
1564 			status = ERROR_MORE_DATA;
1565 		} else {
1566 			*param->resume_handle = 0;
1567 		}
1568 	}
1569 
1570 	param->totalentries = se.se_n_total;
1571 	param->status = status;
1572 	return (NDR_DRC_OK);
1573 }
1574 
1575 /*
1576  * NetShareEnum Level 0
1577  */
1578 static DWORD
1579 mlsvc_NetShareEnumLevel0(ndr_xa_t *mxa,
1580     struct mslm_infonres *infonres, srvsvc_enum_t *se, int sticky)
1581 {
1582 	struct mslm_NetShareInfo_0 *info0;
1583 	smb_shriter_t iterator;
1584 	smb_share_t *si;
1585 	DWORD status;
1586 
1587 	se->se_n_enum = srvsvc_estimate_objcnt(se->se_prefmaxlen,
1588 	    se->se_n_total, sizeof (struct mslm_NetShareInfo_0) + MAXNAMELEN);
1589 	if (se->se_n_enum == 0)
1590 		return (ERROR_SUCCESS);
1591 
1592 	info0 = NDR_NEWN(mxa, struct mslm_NetShareInfo_0, se->se_n_enum);
1593 	if (info0 == NULL)
1594 		return (ERROR_NOT_ENOUGH_MEMORY);
1595 
1596 	smb_shr_iterinit(&iterator);
1597 
1598 	se->se_n_read = 0;
1599 	while ((si = smb_shr_iterate(&iterator)) != NULL) {
1600 		if (se->se_n_skip > 0) {
1601 			--se->se_n_skip;
1602 			continue;
1603 		}
1604 
1605 		++se->se_resume_handle;
1606 
1607 		if (sticky && (si->shr_flags & SMB_SHRF_TRANS))
1608 			continue;
1609 
1610 		if (si->shr_flags & SMB_SHRF_AUTOHOME)
1611 			continue;
1612 
1613 		if (se->se_n_read >= se->se_n_enum) {
1614 			se->se_n_read = se->se_n_enum;
1615 			break;
1616 		}
1617 
1618 		status = mlsvc_NetShareEnumCommon(mxa, se, si, (void *)info0);
1619 		if (status != ERROR_SUCCESS)
1620 			break;
1621 
1622 		++se->se_n_read;
1623 	}
1624 
1625 	if (se->se_n_read < se->se_n_enum) {
1626 		if (srvsvc_add_autohome(mxa, se, (void *)info0))
1627 			++se->se_n_read;
1628 	}
1629 
1630 	infonres->entriesread = se->se_n_read;
1631 	infonres->entries = info0;
1632 	return (ERROR_SUCCESS);
1633 }
1634 
1635 /*
1636  * NetShareEnum Level 1
1637  */
1638 static DWORD
1639 mlsvc_NetShareEnumLevel1(ndr_xa_t *mxa,
1640     struct mslm_infonres *infonres, srvsvc_enum_t *se, int sticky)
1641 {
1642 	struct mslm_NetShareInfo_1 *info1;
1643 	smb_shriter_t iterator;
1644 	smb_share_t *si;
1645 	DWORD status;
1646 
1647 	se->se_n_enum = srvsvc_estimate_objcnt(se->se_prefmaxlen,
1648 	    se->se_n_total, sizeof (struct mslm_NetShareInfo_1) + MAXNAMELEN);
1649 	if (se->se_n_enum == 0)
1650 		return (ERROR_SUCCESS);
1651 
1652 	info1 = NDR_NEWN(mxa, struct mslm_NetShareInfo_1, se->se_n_enum);
1653 	if (info1 == NULL)
1654 		return (ERROR_NOT_ENOUGH_MEMORY);
1655 
1656 	smb_shr_iterinit(&iterator);
1657 
1658 	se->se_n_read = 0;
1659 	while ((si = smb_shr_iterate(&iterator)) != 0) {
1660 		if (se->se_n_skip > 0) {
1661 			--se->se_n_skip;
1662 			continue;
1663 		}
1664 
1665 		++se->se_resume_handle;
1666 
1667 		if (sticky && (si->shr_flags & SMB_SHRF_TRANS))
1668 			continue;
1669 
1670 		if (si->shr_flags & SMB_SHRF_AUTOHOME)
1671 			continue;
1672 
1673 		if (se->se_n_read >= se->se_n_enum) {
1674 			se->se_n_read = se->se_n_enum;
1675 			break;
1676 		}
1677 
1678 		status = mlsvc_NetShareEnumCommon(mxa, se, si, (void *)info1);
1679 		if (status != ERROR_SUCCESS)
1680 			break;
1681 
1682 		++se->se_n_read;
1683 	}
1684 
1685 	if (se->se_n_read < se->se_n_enum) {
1686 		if (srvsvc_add_autohome(mxa, se, (void *)info1))
1687 			++se->se_n_read;
1688 	}
1689 
1690 	infonres->entriesread = se->se_n_read;
1691 	infonres->entries = info1;
1692 	return (ERROR_SUCCESS);
1693 }
1694 
1695 /*
1696  * NetShareEnum Level 2
1697  */
1698 static DWORD
1699 mlsvc_NetShareEnumLevel2(ndr_xa_t *mxa,
1700     struct mslm_infonres *infonres, srvsvc_enum_t *se, int sticky)
1701 {
1702 	struct mslm_NetShareInfo_2 *info2;
1703 	smb_shriter_t iterator;
1704 	smb_share_t *si;
1705 	DWORD status;
1706 
1707 	se->se_n_enum = srvsvc_estimate_objcnt(se->se_prefmaxlen,
1708 	    se->se_n_total, sizeof (struct mslm_NetShareInfo_2) + MAXNAMELEN);
1709 	if (se->se_n_enum == 0)
1710 		return (ERROR_SUCCESS);
1711 
1712 	info2 = NDR_NEWN(mxa, struct mslm_NetShareInfo_2, se->se_n_enum);
1713 	if (info2 == NULL)
1714 		return (ERROR_NOT_ENOUGH_MEMORY);
1715 
1716 	smb_shr_iterinit(&iterator);
1717 
1718 	se->se_n_read = 0;
1719 	while ((si = smb_shr_iterate(&iterator)) != 0) {
1720 		if (se->se_n_skip > 0) {
1721 			--se->se_n_skip;
1722 			continue;
1723 		}
1724 
1725 		++se->se_resume_handle;
1726 
1727 		if (sticky && (si->shr_flags & SMB_SHRF_TRANS))
1728 			continue;
1729 
1730 		if (si->shr_flags & SMB_SHRF_AUTOHOME)
1731 			continue;
1732 
1733 		if (se->se_n_read >= se->se_n_enum) {
1734 			se->se_n_read = se->se_n_enum;
1735 			break;
1736 		}
1737 
1738 		status = mlsvc_NetShareEnumCommon(mxa, se, si, (void *)info2);
1739 		if (status != ERROR_SUCCESS)
1740 			break;
1741 
1742 		++se->se_n_read;
1743 	}
1744 
1745 	if (se->se_n_read < se->se_n_enum) {
1746 		if (srvsvc_add_autohome(mxa, se, (void *)info2))
1747 			++se->se_n_read;
1748 	}
1749 
1750 	infonres->entriesread = se->se_n_read;
1751 	infonres->entries = info2;
1752 	return (ERROR_SUCCESS);
1753 }
1754 
1755 /*
1756  * NetShareEnum Level 501
1757  */
1758 static DWORD
1759 mlsvc_NetShareEnumLevel501(ndr_xa_t *mxa,
1760     struct mslm_infonres *infonres, srvsvc_enum_t *se, int sticky)
1761 {
1762 	struct mslm_NetShareInfo_501 *info501;
1763 	smb_shriter_t iterator;
1764 	smb_share_t *si;
1765 	DWORD status;
1766 
1767 	se->se_n_enum = srvsvc_estimate_objcnt(se->se_prefmaxlen,
1768 	    se->se_n_total, sizeof (struct mslm_NetShareInfo_501) + MAXNAMELEN);
1769 	if (se->se_n_enum == 0)
1770 		return (ERROR_SUCCESS);
1771 
1772 	info501 = NDR_NEWN(mxa, struct mslm_NetShareInfo_501,
1773 	    se->se_n_enum);
1774 	if (info501 == NULL)
1775 		return (ERROR_NOT_ENOUGH_MEMORY);
1776 
1777 	smb_shr_iterinit(&iterator);
1778 
1779 	se->se_n_read = 0;
1780 	while ((si = smb_shr_iterate(&iterator)) != 0) {
1781 		if (se->se_n_skip > 0) {
1782 			--se->se_n_skip;
1783 			continue;
1784 		}
1785 
1786 		++se->se_resume_handle;
1787 
1788 		if (sticky && (si->shr_flags & SMB_SHRF_TRANS))
1789 			continue;
1790 
1791 		if (si->shr_flags & SMB_SHRF_AUTOHOME)
1792 			continue;
1793 
1794 		if (se->se_n_read >= se->se_n_enum) {
1795 			se->se_n_read = se->se_n_enum;
1796 			break;
1797 		}
1798 
1799 		status = mlsvc_NetShareEnumCommon(mxa, se, si, (void *)info501);
1800 		if (status != ERROR_SUCCESS)
1801 			break;
1802 
1803 		++se->se_n_read;
1804 	}
1805 
1806 	if (se->se_n_read < se->se_n_enum) {
1807 		if (srvsvc_add_autohome(mxa, se, (void *)info501))
1808 			++se->se_n_read;
1809 	}
1810 
1811 	infonres->entriesread = se->se_n_read;
1812 	infonres->entries = info501;
1813 	return (ERROR_SUCCESS);
1814 }
1815 
1816 /*
1817  * NetShareEnum Level 502
1818  */
1819 static DWORD
1820 mlsvc_NetShareEnumLevel502(ndr_xa_t *mxa,
1821     struct mslm_infonres *infonres, srvsvc_enum_t *se, int sticky)
1822 {
1823 	struct mslm_NetShareInfo_502 *info502;
1824 	smb_shriter_t iterator;
1825 	smb_share_t *si;
1826 	DWORD status;
1827 
1828 	se->se_n_enum = srvsvc_estimate_objcnt(se->se_prefmaxlen,
1829 	    se->se_n_total, sizeof (struct mslm_NetShareInfo_502) + MAXNAMELEN);
1830 	if (se->se_n_enum == 0)
1831 		return (ERROR_SUCCESS);
1832 
1833 	info502 = NDR_NEWN(mxa, struct mslm_NetShareInfo_502,
1834 	    se->se_n_enum);
1835 	if (info502 == NULL)
1836 		return (ERROR_NOT_ENOUGH_MEMORY);
1837 
1838 	smb_shr_iterinit(&iterator);
1839 
1840 	se->se_n_read = 0;
1841 	while ((si = smb_shr_iterate(&iterator)) != NULL) {
1842 		if (se->se_n_skip > 0) {
1843 			--se->se_n_skip;
1844 			continue;
1845 		}
1846 
1847 		++se->se_resume_handle;
1848 
1849 		if (sticky && (si->shr_flags & SMB_SHRF_TRANS))
1850 			continue;
1851 
1852 		if (si->shr_flags & SMB_SHRF_AUTOHOME)
1853 			continue;
1854 
1855 		if (se->se_n_read >= se->se_n_enum) {
1856 			se->se_n_read = se->se_n_enum;
1857 			break;
1858 		}
1859 
1860 		status = mlsvc_NetShareEnumCommon(mxa, se, si, (void *)info502);
1861 		if (status != ERROR_SUCCESS)
1862 			break;
1863 
1864 		++se->se_n_read;
1865 	}
1866 
1867 	if (se->se_n_read < se->se_n_enum) {
1868 		if (srvsvc_add_autohome(mxa, se, (void *)info502))
1869 			++se->se_n_read;
1870 	}
1871 
1872 	infonres->entriesread = se->se_n_read;
1873 	infonres->entries = info502;
1874 	return (ERROR_SUCCESS);
1875 }
1876 
1877 /*
1878  * mlsvc_NetShareEnumCommon
1879  *
1880  * Build the levels 0, 1, 2, 501 and 502 share information. This function
1881  * is called by the various NetShareEnum levels for each share. If
1882  * we cannot build the share data for some reason, we return an error
1883  * but the actual value of the error is not important to the caller.
1884  * The caller just needs to know not to include this info in the RPC
1885  * response.
1886  *
1887  * Returns:
1888  *	ERROR_SUCCESS
1889  *	ERROR_NOT_ENOUGH_MEMORY
1890  *	ERROR_INVALID_LEVEL
1891  */
1892 static DWORD
1893 mlsvc_NetShareEnumCommon(ndr_xa_t *mxa, srvsvc_enum_t *se,
1894     smb_share_t *si, void *infop)
1895 {
1896 	struct mslm_NetShareInfo_0 *info0;
1897 	struct mslm_NetShareInfo_1 *info1;
1898 	struct mslm_NetShareInfo_2 *info2;
1899 	struct mslm_NetShareInfo_501 *info501;
1900 	struct mslm_NetShareInfo_502 *info502;
1901 	int i = se->se_n_read;
1902 
1903 	switch (se->se_level) {
1904 	case 0:
1905 		info0 = (struct mslm_NetShareInfo_0 *)infop;
1906 		info0[i].shi0_netname
1907 		    = (uint8_t *)NDR_STRDUP(mxa, si->shr_name);
1908 
1909 		if (info0[i].shi0_netname == NULL)
1910 			return (ERROR_NOT_ENOUGH_MEMORY);
1911 		break;
1912 
1913 	case 1:
1914 		info1 = (struct mslm_NetShareInfo_1 *)infop;
1915 		info1[i].shi1_netname
1916 		    = (uint8_t *)NDR_STRDUP(mxa, si->shr_name);
1917 		info1[i].shi1_comment
1918 		    = (uint8_t *)NDR_STRDUP(mxa, si->shr_cmnt);
1919 
1920 		info1[i].shi1_type = si->shr_type;
1921 
1922 		if (!info1[i].shi1_netname || !info1[i].shi1_comment)
1923 			return (ERROR_NOT_ENOUGH_MEMORY);
1924 		break;
1925 
1926 	case 2:
1927 		info2 = (struct mslm_NetShareInfo_2 *)infop;
1928 		info2[i].shi2_netname
1929 		    = (uint8_t *)NDR_STRDUP(mxa, si->shr_name);
1930 		info2[i].shi2_comment
1931 		    = (uint8_t *)NDR_STRDUP(mxa, si->shr_cmnt);
1932 
1933 		info2[i].shi2_path
1934 		    = (uint8_t *)srvsvc_share_mkpath(mxa, si->shr_path);
1935 
1936 		info2[i].shi2_type = si->shr_type;
1937 		info2[i].shi2_permissions = 0;
1938 		info2[i].shi2_max_uses = SHI_USES_UNLIMITED;
1939 		info2[i].shi2_current_uses = 0;
1940 		info2[i].shi2_passwd
1941 		    = (uint8_t *)NDR_STRDUP(mxa, empty_string);
1942 
1943 		if (!info2[i].shi2_netname || !info2[i].shi2_comment ||
1944 		    !info2[i].shi2_passwd || !info2[i].shi2_path)
1945 			return (ERROR_NOT_ENOUGH_MEMORY);
1946 
1947 		break;
1948 
1949 	case 501:
1950 		info501 = (struct mslm_NetShareInfo_501 *)infop;
1951 		info501[i].shi501_netname
1952 		    = (uint8_t *)NDR_STRDUP(mxa, si->shr_name);
1953 		info501[i].shi501_comment
1954 		    = (uint8_t *)NDR_STRDUP(mxa, si->shr_cmnt);
1955 
1956 		info501[i].shi501_type = si->shr_type;
1957 		info501[i].shi501_reserved = 0;
1958 
1959 		if (!info501[i].shi501_netname || !info501[i].shi501_comment)
1960 			return (ERROR_NOT_ENOUGH_MEMORY);
1961 		break;
1962 
1963 	case 502:
1964 		info502 = (struct mslm_NetShareInfo_502 *)infop;
1965 		info502[i].shi502_netname
1966 		    = (uint8_t *)NDR_STRDUP(mxa, si->shr_name);
1967 		info502[i].shi502_comment
1968 		    = (uint8_t *)NDR_STRDUP(mxa, si->shr_cmnt);
1969 
1970 		info502[i].shi502_path
1971 		    = (uint8_t *)srvsvc_share_mkpath(mxa, si->shr_path);
1972 
1973 		info502[i].shi502_type = si->shr_type;
1974 		info502[i].shi502_permissions = 0;
1975 		info502[i].shi502_max_uses = SHI_USES_UNLIMITED;
1976 		info502[i].shi502_current_uses = 0;
1977 		info502[i].shi502_passwd
1978 		    = (uint8_t *)NDR_STRDUP(mxa, empty_string);
1979 
1980 		info502[i].shi502_reserved = 0;
1981 		info502[i].shi502_security_descriptor = 0;
1982 
1983 		if (!info502[i].shi502_netname || !info502[i].shi502_comment ||
1984 		    !info502[i].shi502_passwd || !info502[i].shi502_path)
1985 			return (ERROR_NOT_ENOUGH_MEMORY);
1986 		break;
1987 
1988 	default:
1989 		return (ERROR_INVALID_LEVEL);
1990 	}
1991 
1992 	return (ERROR_SUCCESS);
1993 }
1994 
1995 /*
1996  * srvsvc_add_autohome
1997  *
1998  * Add the autohome share for the user. The share must not be a permanent
1999  * share to avoid duplicates.
2000  */
2001 static boolean_t
2002 srvsvc_add_autohome(ndr_xa_t *mxa, srvsvc_enum_t *se, void *infop)
2003 {
2004 	smb_opipe_context_t *ctx = &mxa->pipe->np_ctx;
2005 	char *username = ctx->oc_account;
2006 	smb_share_t si;
2007 	DWORD status;
2008 
2009 	if (smb_shr_get(username, &si) != NERR_Success)
2010 		return (B_FALSE);
2011 
2012 	if ((si.shr_flags & SMB_SHRF_AUTOHOME) == 0)
2013 		return (B_FALSE);
2014 
2015 	status = mlsvc_NetShareEnumCommon(mxa, se, &si, infop);
2016 	return (status == ERROR_SUCCESS);
2017 }
2018 
2019 /*
2020  * srvsvc_share_mkpath
2021  *
2022  * Create the share path required by the share enum calls. The path
2023  * is created in a heap buffer ready for use by the caller.
2024  *
2025  * Some Windows over-the-wire backup applications do not work unless a
2026  * drive letter is present in the share path.  We don't care about the
2027  * drive letter since the path is fully qualified with the volume name.
2028  *
2029  * Windows clients seem to be mostly okay with forward slashes in
2030  * share paths but they cannot handle one immediately after the drive
2031  * letter, i.e. B:/.  For consistency we convert all the slashes in
2032  * the path.
2033  *
2034  * Returns a pointer to a heap buffer containing the share path, which
2035  * could be a null pointer if the heap allocation fails.
2036  */
2037 static char *
2038 srvsvc_share_mkpath(ndr_xa_t *mxa, char *path)
2039 {
2040 	char tmpbuf[MAXPATHLEN];
2041 	char *p;
2042 
2043 	if (strlen(path) == 0)
2044 		return (NDR_STRDUP(mxa, path));
2045 
2046 	/*
2047 	 * Strip the volume name from the path (/vol1/home -> /home).
2048 	 */
2049 	p = path;
2050 	p += strspn(p, "/");
2051 	p += strcspn(p, "/");
2052 	p += strspn(p, "/");
2053 	(void) snprintf(tmpbuf, MAXPATHLEN, "%c:/%s", 'B', p);
2054 	(void) strsubst(tmpbuf, '/', '\\');
2055 
2056 	return (NDR_STRDUP(mxa, tmpbuf));
2057 }
2058 
2059 /*
2060  * srvsvc_s_NetShareDel
2061  *
2062  * Delete a share. Only the administrator, or a member of the domain
2063  * administrators group, is allowed to delete shares.
2064  *
2065  * This interface is used by the rmtshare command from the NT resource
2066  * kit. Rmtshare allows a client to add or remove shares on a server
2067  * from the client's command line.
2068  *
2069  * Returns Win32 error codes.
2070  */
2071 static int
2072 srvsvc_s_NetShareDel(void *arg, ndr_xa_t *mxa)
2073 {
2074 	struct mslm_NetShareDel *param = arg;
2075 
2076 	if (!ndr_is_poweruser(mxa) ||
2077 	    smb_shr_is_restricted((char *)param->netname)) {
2078 		param->status = ERROR_ACCESS_DENIED;
2079 		return (NDR_DRC_OK);
2080 	}
2081 
2082 	param->status = srvsvc_sa_delete((char *)param->netname);
2083 	return (NDR_DRC_OK);
2084 }
2085 
2086 /*
2087  * srvsvc_s_NetGetFileSecurity
2088  *
2089  * Get security descriptor of the requested file/folder
2090  *
2091  * Right now, just returns ERROR_ACCESS_DENIED, because we cannot
2092  * get the requested SD here in RPC code.
2093  */
2094 /*ARGSUSED*/
2095 static int
2096 srvsvc_s_NetGetFileSecurity(void *arg, ndr_xa_t *mxa)
2097 {
2098 	struct mslm_NetGetFileSecurity *param = arg;
2099 
2100 	param->length = 0;
2101 	param->status = ERROR_ACCESS_DENIED;
2102 	return (NDR_DRC_OK);
2103 }
2104 
2105 /*
2106  * srvsvc_s_NetSetFileSecurity
2107  *
2108  * Set the given security descriptor for the requested file/folder
2109  *
2110  * Right now, just returns ERROR_ACCESS_DENIED, because we cannot
2111  * set the requested SD here in RPC code.
2112  */
2113 /*ARGSUSED*/
2114 static int
2115 srvsvc_s_NetSetFileSecurity(void *arg, ndr_xa_t *mxa)
2116 {
2117 	struct mslm_NetSetFileSecurity *param = arg;
2118 
2119 	param->status = ERROR_ACCESS_DENIED;
2120 	return (NDR_DRC_OK);
2121 }
2122 
2123 /*
2124  * If the default "smb" share group exists then return the group
2125  * handle, otherwise create the group and return the handle.
2126  *
2127  * All shares created via the srvsvc will be added to the "smb"
2128  * group.
2129  */
2130 static sa_group_t
2131 srvsvc_sa_get_smbgrp(sa_handle_t handle)
2132 {
2133 	sa_group_t group = NULL;
2134 	int err;
2135 
2136 	group = sa_get_group(handle, SMB_DEFAULT_SHARE_GROUP);
2137 	if (group != NULL)
2138 		return (group);
2139 
2140 	group = sa_create_group(handle, SMB_DEFAULT_SHARE_GROUP, &err);
2141 	if (group == NULL)
2142 		return (NULL);
2143 
2144 	if (sa_create_optionset(group, SMB_DEFAULT_SHARE_GROUP) == NULL) {
2145 		(void) sa_remove_group(group);
2146 		group = NULL;
2147 	}
2148 
2149 	return (group);
2150 }
2151 
2152 /*
2153  * Stores the given share in sharemgr
2154  */
2155 static uint32_t
2156 srvsvc_sa_add(char *sharename, char *path, char *cmnt)
2157 {
2158 	sa_handle_t handle;
2159 	sa_share_t share;
2160 	sa_group_t group;
2161 	sa_resource_t resource;
2162 	boolean_t new_share = B_FALSE;
2163 	uint32_t status = NERR_Success;
2164 	int err;
2165 
2166 	if ((handle = smb_shr_sa_enter()) == NULL)
2167 		return (NERR_InternalError);
2168 
2169 	share = sa_find_share(handle, path);
2170 	if (share == NULL) {
2171 		group = srvsvc_sa_get_smbgrp(handle);
2172 		if (group == NULL) {
2173 			smb_shr_sa_exit();
2174 			return (NERR_InternalError);
2175 		}
2176 
2177 		share = sa_add_share(group, path, SA_SHARE_PERMANENT, &err);
2178 		if (share == NULL) {
2179 			smb_shr_sa_exit();
2180 			return (NERR_InternalError);
2181 		}
2182 		new_share = B_TRUE;
2183 	}
2184 
2185 	resource = sa_get_share_resource(share, sharename);
2186 	if (resource == NULL) {
2187 		resource = sa_add_resource(share, sharename,
2188 		    SA_SHARE_PERMANENT, &err);
2189 		if (resource == NULL) {
2190 			if (new_share)
2191 				(void) sa_remove_share(share);
2192 			smb_shr_sa_exit();
2193 			return (NERR_InternalError);
2194 		}
2195 	}
2196 
2197 	(void) sa_set_resource_description(resource, cmnt);
2198 
2199 	smb_shr_sa_exit();
2200 	return (status);
2201 }
2202 
2203 /*
2204  * Removes the share from sharemgr
2205  */
2206 static uint32_t
2207 srvsvc_sa_delete(char *sharename)
2208 {
2209 	sa_handle_t handle;
2210 	sa_resource_t resource;
2211 	uint32_t status;
2212 
2213 	if ((handle = smb_shr_sa_enter()) == NULL)
2214 		return (NERR_InternalError);
2215 
2216 	status = NERR_InternalError;
2217 	if ((resource = sa_find_resource(handle, sharename)) != NULL) {
2218 		if (sa_remove_resource(resource) == SA_OK)
2219 			status = NERR_Success;
2220 	}
2221 
2222 	smb_shr_sa_exit();
2223 	return (status);
2224 }
2225 
2226 static ndr_stub_table_t srvsvc_stub_table[] = {
2227 	{ srvsvc_s_NetConnectEnum,	SRVSVC_OPNUM_NetConnectEnum },
2228 	{ srvsvc_s_NetFileEnum,		SRVSVC_OPNUM_NetFileEnum },
2229 	{ srvsvc_s_NetFileClose,	SRVSVC_OPNUM_NetFileClose },
2230 	{ srvsvc_s_NetShareGetInfo,	SRVSVC_OPNUM_NetShareGetInfo },
2231 	{ srvsvc_s_NetShareSetInfo,	SRVSVC_OPNUM_NetShareSetInfo },
2232 	{ srvsvc_s_NetSessionEnum,	SRVSVC_OPNUM_NetSessionEnum },
2233 	{ srvsvc_s_NetSessionDel,	SRVSVC_OPNUM_NetSessionDel },
2234 	{ srvsvc_s_NetServerGetInfo,	SRVSVC_OPNUM_NetServerGetInfo },
2235 	{ srvsvc_s_NetRemoteTOD,	SRVSVC_OPNUM_NetRemoteTOD },
2236 	{ srvsvc_s_NetNameValidate,	SRVSVC_OPNUM_NetNameValidate },
2237 	{ srvsvc_s_NetShareAdd,		SRVSVC_OPNUM_NetShareAdd },
2238 	{ srvsvc_s_NetShareDel,		SRVSVC_OPNUM_NetShareDel },
2239 	{ srvsvc_s_NetShareEnum,	SRVSVC_OPNUM_NetShareEnum },
2240 	{ srvsvc_s_NetShareEnumSticky,	SRVSVC_OPNUM_NetShareEnumSticky },
2241 	{ srvsvc_s_NetGetFileSecurity,	SRVSVC_OPNUM_NetGetFileSecurity },
2242 	{ srvsvc_s_NetSetFileSecurity,	SRVSVC_OPNUM_NetSetFileSecurity },
2243 	{0}
2244 };
2245