xref: /illumos-gate/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c (revision df3cd224ef765c29101e4110546062199562f757)
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 <sys/tzfile.h>
36 #include <unistd.h>
37 #include <netdb.h>
38 #include <strings.h>
39 #include <time.h>
40 #include <thread.h>
41 #include <ctype.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <sys/types.h>
45 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48 #include <libshare.h>
49 #include <libnvpair.h>
50 #include <smbsrv/libsmb.h>
51 #include <smbsrv/libmlsvc.h>
52 #include <smbsrv/lmerr.h>
53 #include <smbsrv/nmpipes.h>
54 #include <smbsrv/smb.h>
55 #include <smbsrv/netrauth.h>
56 #include <smbsrv/ndl/srvsvc.ndl>
57 #include <smbsrv/smb_common_door.h>
58 #include "mlsvc.h"
59 
60 /*
61  * Qualifier types for NetConnectEnum.
62  */
63 #define	SRVSVC_CONNECT_ENUM_NULL	0
64 #define	SRVSVC_CONNECT_ENUM_SHARE	1
65 #define	SRVSVC_CONNECT_ENUM_WKSTN	2
66 
67 #define	SMB_SRVSVC_MAXBUFLEN		(8 * 1024 * 1024)
68 #define	SMB_SRVSVC_MAXPREFLEN		((uint32_t)(-1))
69 
70 typedef struct srvsvc_sd {
71 	uint8_t *sd_buf;
72 	uint32_t sd_size;
73 } srvsvc_sd_t;
74 
75 typedef struct srvsvc_netshare_setinfo {
76 	char *nss_netname;
77 	char *nss_comment;
78 	char *nss_path;
79 	uint32_t nss_type;
80 	srvsvc_sd_t nss_sd;
81 } srvsvc_netshare_setinfo_t;
82 
83 typedef union srvsvc_netshare_getinfo {
84 	struct mslm_NetShareInfo_0 nsg_info0;
85 	struct mslm_NetShareInfo_1 nsg_info1;
86 	struct mslm_NetShareInfo_2 nsg_info2;
87 	struct mslm_NetShareInfo_501 nsg_info501;
88 	struct mslm_NetShareInfo_502 nsg_info502;
89 	struct mslm_NetShareInfo_503 nsg_info503;
90 	struct mslm_NetShareInfo_1004 nsg_info1004;
91 	struct mslm_NetShareInfo_1005 nsg_info1005;
92 	struct mslm_NetShareInfo_1006 nsg_info1006;
93 	struct mslm_NetShareInfo_1501 nsg_info1501;
94 } srvsvc_netshare_getinfo_t;
95 
96 typedef struct mslm_infonres srvsvc_infonres_t;
97 typedef struct mslm_NetConnectEnum srvsvc_NetConnectEnum_t;
98 
99 static uint32_t srvsvc_netconnectenum_level0(ndr_xa_t *, smb_svcenum_t *,
100     srvsvc_NetConnectEnum_t *);
101 static uint32_t srvsvc_netconnectenum_level1(ndr_xa_t *, smb_svcenum_t *,
102     srvsvc_NetConnectEnum_t *);
103 static uint32_t srvsvc_netconnectenum_common(ndr_xa_t *,
104     srvsvc_NetConnectInfo_t *, smb_netsvc_t *, smb_svcenum_t *);
105 
106 static DWORD srvsvc_NetFileEnum2(ndr_xa_t *, struct mslm_NetFileEnum *,
107     smb_svcenum_t *se);
108 static DWORD srvsvc_NetFileEnum3(ndr_xa_t *, struct mslm_NetFileEnum *,
109     smb_svcenum_t *se);
110 
111 static uint32_t srvsvc_NetSessionEnumCommon(ndr_xa_t *, srvsvc_infonres_t *,
112     smb_netsvc_t *, smb_svcenum_t *);
113 
114 static DWORD mlsvc_NetShareEnumLevel0(ndr_xa_t *, srvsvc_infonres_t *,
115     smb_svcenum_t *, int);
116 static DWORD mlsvc_NetShareEnumLevel1(ndr_xa_t *, srvsvc_infonres_t *,
117     smb_svcenum_t *, int);
118 static DWORD mlsvc_NetShareEnumLevel2(ndr_xa_t *, srvsvc_infonres_t *,
119     smb_svcenum_t *, int);
120 static DWORD mlsvc_NetShareEnumLevel501(ndr_xa_t *, srvsvc_infonres_t *,
121     smb_svcenum_t *, int);
122 static DWORD mlsvc_NetShareEnumLevel502(ndr_xa_t *, srvsvc_infonres_t *,
123     smb_svcenum_t *, int);
124 static DWORD mlsvc_NetShareEnumCommon(ndr_xa_t *, smb_svcenum_t *,
125     smb_share_t *, void *);
126 static boolean_t srvsvc_add_autohome(ndr_xa_t *, smb_svcenum_t *, void *);
127 static char *srvsvc_share_mkpath(ndr_xa_t *, char *);
128 static uint32_t srvsvc_share_getsd(ndr_xa_t *, smb_share_t *, srvsvc_sd_t *);
129 
130 static int srvsvc_netconnect_qualifier(const char *);
131 static void srvsvc_estimate_limit(smb_svcenum_t *, uint32_t);
132 static uint32_t srvsvc_open_sessions(void);
133 static uint32_t srvsvc_open_connections(uint32_t, const char *);
134 static uint32_t srvsvc_open_files(void);
135 
136 static uint32_t srvsvc_modify_share(smb_share_t *,
137     srvsvc_netshare_setinfo_t *);
138 static uint32_t srvsvc_modify_transient_share(smb_share_t *,
139     srvsvc_netshare_setinfo_t *);
140 static uint32_t srvsvc_update_share_flags(smb_share_t *, uint32_t);
141 static uint32_t srvsvc_get_share_flags(smb_share_t *);
142 
143 static uint32_t srvsvc_sa_add(char *, char *, char *);
144 static uint32_t srvsvc_sa_delete(char *);
145 static uint32_t srvsvc_sa_modify(smb_share_t *, srvsvc_netshare_setinfo_t *);
146 static uint32_t srvsvc_sa_setprop(smb_share_t *, nvlist_t *);
147 
148 static char empty_string[1];
149 
150 static ndr_stub_table_t srvsvc_stub_table[];
151 
152 static ndr_service_t srvsvc_service = {
153 	"SRVSVC",			/* name */
154 	"Server services",		/* desc */
155 	"\\srvsvc",			/* endpoint */
156 	PIPE_NTSVCS,			/* sec_addr_port */
157 	"4b324fc8-1670-01d3-1278-5a47bf6ee188", 3,	/* abstract */
158 	NDR_TRANSFER_SYNTAX_UUID,		2,	/* transfer */
159 	0,				/* no bind_instance_size */
160 	0,				/* no bind_req() */
161 	0,				/* no unbind_and_close() */
162 	0,				/* use generic_call_stub() */
163 	&TYPEINFO(srvsvc_interface),	/* interface ti */
164 	srvsvc_stub_table		/* stub_table */
165 };
166 
167 /*
168  * srvsvc_initialize
169  *
170  * This function registers the SRVSVC RPC interface with the RPC runtime
171  * library. It must be called in order to use either the client side
172  * or the server side functions.
173  */
174 void
175 srvsvc_initialize(void)
176 {
177 	(void) ndr_svc_register(&srvsvc_service);
178 }
179 
180 /*
181  * srvsvc_s_NetConnectEnum
182  *
183  * List tree connections made to a share on this server or all tree
184  * connections established from a specific client.  Administrator,
185  * Server Operator, Print Operator or Power User group membership
186  * is required to use this interface.
187  *
188  * There are three information levels:  0, 1, and 50.  We don't support
189  * level 50, which is only used by Windows 9x clients.
190  *
191  * It seems Server Manger (srvmgr) only sends workstation as the qualifier
192  * and the Computer Management Interface on Windows 2000 doesn't request
193  * a list of connections.
194  *
195  * Return Values:
196  * ERROR_SUCCESS            Success
197  * ERROR_ACCESS_DENIED      Caller does not have access to this call.
198  * ERROR_INVALID_PARAMETER  One of the parameters is invalid.
199  * ERROR_INVALID_LEVEL      Unknown information level specified.
200  * ERROR_MORE_DATA          Partial date returned, more entries available.
201  * ERROR_NOT_ENOUGH_MEMORY  Insufficient memory is available.
202  * NERR_NetNameNotFound     The share qualifier cannot be found.
203  * NERR_BufTooSmall         The supplied buffer is too small.
204  */
205 static int
206 srvsvc_s_NetConnectEnum(void *arg, ndr_xa_t *mxa)
207 {
208 	srvsvc_NetConnectEnum_t		*param = arg;
209 	smb_netsvc_t			*ns;
210 	smb_svcenum_t			se;
211 	char				*qualifier;
212 	int				qualtype;
213 	DWORD				status = ERROR_SUCCESS;
214 
215 	if (!ndr_is_poweruser(mxa)) {
216 		status = ERROR_ACCESS_DENIED;
217 		goto srvsvc_netconnectenum_error;
218 	}
219 
220 	qualifier = (char *)param->qualifier;
221 	qualtype = srvsvc_netconnect_qualifier(qualifier);
222 	if (qualtype == SRVSVC_CONNECT_ENUM_NULL) {
223 		status = NERR_NetNameNotFound;
224 		goto srvsvc_netconnectenum_error;
225 	}
226 
227 	param->total_entries = srvsvc_open_connections(qualtype, qualifier);
228 	if (param->total_entries == 0) {
229 		bzero(param, sizeof (srvsvc_NetConnectEnum_t));
230 		param->status = ERROR_SUCCESS;
231 		return (NDR_DRC_OK);
232 	}
233 
234 	bzero(&se, sizeof (smb_svcenum_t));
235 	se.se_type = SMB_SVCENUM_TYPE_TREE;
236 	se.se_level = param->info.level;
237 	se.se_ntotal = param->total_entries;
238 	se.se_nlimit = se.se_ntotal;
239 
240 	if (param->pref_max_len == SMB_SRVSVC_MAXPREFLEN ||
241 	    param->pref_max_len > SMB_SRVSVC_MAXBUFLEN)
242 		se.se_prefmaxlen = SMB_SRVSVC_MAXBUFLEN;
243 	else
244 		se.se_prefmaxlen = param->pref_max_len;
245 
246 	if (param->resume_handle) {
247 		se.se_resume = *param->resume_handle;
248 		se.se_nskip = se.se_resume;
249 		*param->resume_handle = 0;
250 	}
251 
252 	switch (param->info.level) {
253 	case 0:
254 		status = srvsvc_netconnectenum_level0(mxa, &se, param);
255 		break;
256 	case 1:
257 		status = srvsvc_netconnectenum_level1(mxa, &se, param);
258 		break;
259 	case 50:
260 		status = ERROR_NOT_SUPPORTED;
261 		break;
262 	default:
263 		status = ERROR_INVALID_LEVEL;
264 		break;
265 	}
266 
267 	if (status != ERROR_SUCCESS)
268 		goto srvsvc_netconnectenum_error;
269 
270 	if ((ns = smb_kmod_enum_init(&se)) == NULL) {
271 		status = ERROR_NOT_ENOUGH_MEMORY;
272 		goto srvsvc_netconnectenum_error;
273 	}
274 
275 	status = srvsvc_netconnectenum_common(mxa, &param->info, ns, &se);
276 	smb_kmod_enum_fini(ns);
277 
278 	if (status != ERROR_SUCCESS)
279 		goto srvsvc_netconnectenum_error;
280 
281 	if (param->resume_handle &&
282 	    param->pref_max_len != SMB_SRVSVC_MAXPREFLEN) {
283 		if (se.se_resume < param->total_entries) {
284 			*param->resume_handle = se.se_resume;
285 			status = ERROR_MORE_DATA;
286 		}
287 	}
288 
289 	param->status = status;
290 	return (NDR_DRC_OK);
291 
292 srvsvc_netconnectenum_error:
293 	bzero(param, sizeof (srvsvc_NetConnectEnum_t));
294 	param->status = status;
295 	return (NDR_DRC_OK);
296 }
297 
298 /*
299  * Allocate memory and estimate the number of objects that can
300  * be returned for NetConnectEnum level 0.
301  */
302 static uint32_t
303 srvsvc_netconnectenum_level0(ndr_xa_t *mxa, smb_svcenum_t *se,
304     srvsvc_NetConnectEnum_t *param)
305 {
306 	srvsvc_NetConnectInfo0_t	*info0;
307 	srvsvc_NetConnectInfoBuf0_t	*ci0;
308 
309 	if ((info0 = NDR_NEW(mxa, srvsvc_NetConnectInfo0_t)) == NULL)
310 		return (ERROR_NOT_ENOUGH_MEMORY);
311 
312 	bzero(info0, sizeof (srvsvc_NetConnectInfo0_t));
313 	param->info.ru.info0 = info0;
314 
315 	srvsvc_estimate_limit(se, sizeof (srvsvc_NetConnectInfoBuf0_t));
316 	if (se->se_nlimit == 0)
317 		return (NERR_BufTooSmall);
318 
319 	do {
320 		ci0 = NDR_NEWN(mxa, srvsvc_NetConnectInfoBuf0_t, se->se_nlimit);
321 		if (ci0 == NULL)
322 			se->se_nlimit >>= 1;
323 	} while ((se->se_nlimit > 0) && (ci0 == NULL));
324 
325 	if (ci0 == NULL)
326 		return (ERROR_NOT_ENOUGH_MEMORY);
327 
328 	info0->ci0 = ci0;
329 	info0->entries_read = 0;
330 	return (ERROR_SUCCESS);
331 }
332 
333 /*
334  * Allocate memory and estimate the number of objects that can
335  * be returned for NetConnectEnum level 1.
336  */
337 static uint32_t
338 srvsvc_netconnectenum_level1(ndr_xa_t *mxa, smb_svcenum_t *se,
339     srvsvc_NetConnectEnum_t *param)
340 {
341 	srvsvc_NetConnectInfo1_t	*info1;
342 	srvsvc_NetConnectInfoBuf1_t	*ci1;
343 
344 	if ((info1 = NDR_NEW(mxa, srvsvc_NetConnectInfo1_t)) == NULL)
345 		return (ERROR_NOT_ENOUGH_MEMORY);
346 
347 	bzero(info1, sizeof (srvsvc_NetConnectInfo1_t));
348 	param->info.ru.info1 = info1;
349 
350 	srvsvc_estimate_limit(se,
351 	    sizeof (srvsvc_NetConnectInfoBuf1_t) + MAXNAMELEN);
352 	if (se->se_nlimit == 0)
353 		return (NERR_BufTooSmall);
354 
355 	do {
356 		ci1 = NDR_NEWN(mxa, srvsvc_NetConnectInfoBuf1_t, se->se_nlimit);
357 		if (ci1 == NULL)
358 			se->se_nlimit >>= 1;
359 	} while ((se->se_nlimit > 0) && (ci1 == NULL));
360 
361 	if (ci1 == NULL)
362 		return (ERROR_NOT_ENOUGH_MEMORY);
363 
364 	info1->ci1 = ci1;
365 	info1->entries_read = 0;
366 	return (ERROR_SUCCESS);
367 }
368 
369 /*
370  * Request a list of connections from the kernel and set up
371  * the connection information to be returned to the client.
372  */
373 static uint32_t
374 srvsvc_netconnectenum_common(ndr_xa_t *mxa, srvsvc_NetConnectInfo_t *info,
375     smb_netsvc_t *ns, smb_svcenum_t *se)
376 {
377 	srvsvc_NetConnectInfo0_t	*info0;
378 	srvsvc_NetConnectInfo1_t	*info1;
379 	srvsvc_NetConnectInfoBuf0_t	*ci0;
380 	srvsvc_NetConnectInfoBuf1_t	*ci1;
381 	smb_netsvcitem_t		*item;
382 	smb_netconnectinfo_t		*tree;
383 
384 	if (smb_kmod_enum(ns) != 0)
385 		return (ERROR_INTERNAL_ERROR);
386 
387 	info0 = info->ru.info0;
388 	ci0 = info0->ci0;
389 
390 	info1 = info->ru.info1;
391 	ci1 = info1->ci1;
392 
393 	item = list_head(&ns->ns_list);
394 	while (item != NULL) {
395 		tree = &item->nsi_un.nsi_tree;
396 
397 		switch (se->se_level) {
398 		case 0:
399 			ci0->coni0_id = tree->ci_id;
400 			++ci0;
401 			++info0->entries_read;
402 			break;
403 		case 1:
404 			ci1->coni1_id = tree->ci_id;
405 			ci1->coni1_type = tree->ci_type;
406 			ci1->coni1_num_opens = tree->ci_numopens;
407 			ci1->coni1_num_users = tree->ci_numusers;
408 			ci1->coni1_time = tree->ci_time;
409 			ci1->coni1_username = (uint8_t *)
410 			    NDR_STRDUP(mxa, tree->ci_username);
411 			ci1->coni1_netname = (uint8_t *)
412 			    NDR_STRDUP(mxa, tree->ci_share);
413 			++ci1;
414 			++info1->entries_read;
415 			break;
416 		default:
417 			return (ERROR_INVALID_LEVEL);
418 		}
419 
420 		++se->se_resume;
421 		item = list_next(&ns->ns_list, item);
422 	}
423 
424 	return (ERROR_SUCCESS);
425 }
426 
427 /*
428  * srvsvc_netconnect_qualifier
429  *
430  * The qualifier is a string that specifies a share name or computer name
431  * for the connections of interest.  If it is a share name then all the
432  * connections made to that share name are listed.  If it is a computer
433  * name (it starts with two backslash characters), then NetConnectEnum
434  * lists all connections made from that computer to the specified server.
435  */
436 static int
437 srvsvc_netconnect_qualifier(const char *qualifier)
438 {
439 	if (qualifier == NULL || *qualifier == '\0')
440 		return (SRVSVC_CONNECT_ENUM_NULL);
441 
442 	if (strlen(qualifier) > MAXHOSTNAMELEN)
443 		return (SRVSVC_CONNECT_ENUM_NULL);
444 
445 	if (qualifier[0] == '\\' && qualifier[1] == '\\') {
446 		return (SRVSVC_CONNECT_ENUM_WKSTN);
447 	} else {
448 		if (!smb_shr_exists((char *)qualifier))
449 			return (SRVSVC_CONNECT_ENUM_NULL);
450 
451 		return (SRVSVC_CONNECT_ENUM_SHARE);
452 	}
453 }
454 
455 static uint32_t
456 srvsvc_open_sessions(void)
457 {
458 	smb_opennum_t	opennum;
459 
460 	bzero(&opennum, sizeof (smb_opennum_t));
461 	if (smb_kmod_get_open_num(&opennum) != 0)
462 		return (0);
463 
464 	return (opennum.open_users);
465 }
466 
467 static uint32_t
468 srvsvc_open_connections(uint32_t qualtype, const char *qualifier)
469 {
470 	smb_opennum_t	opennum;
471 
472 	bzero(&opennum, sizeof (smb_opennum_t));
473 	opennum.qualtype = qualtype;
474 	(void) strlcpy(opennum.qualifier, qualifier, MAXNAMELEN);
475 
476 	if (smb_kmod_get_open_num(&opennum) != 0)
477 		return (0);
478 
479 	return (opennum.open_trees);
480 }
481 
482 static uint32_t
483 srvsvc_open_files(void)
484 {
485 	smb_opennum_t	opennum;
486 
487 	bzero(&opennum, sizeof (smb_opennum_t));
488 	if (smb_kmod_get_open_num(&opennum) != 0)
489 		return (0);
490 
491 	return (opennum.open_files);
492 }
493 
494 /*
495  * srvsvc_s_NetFileEnum
496  *
497  * Return information on open files or named pipes. Only members of the
498  * Administrators or Server Operators local groups are allowed to make
499  * this call. Currently, we only support Administrators.
500  *
501  * If basepath is null, all open resources are enumerated. If basepath
502  * is non-null, only resources that have basepath as a prefix should
503  * be returned.
504  *
505  * If username is specified (non-null), only files opened by username
506  * should be returned.
507  *
508  * Notes:
509  * 1. We don't validate the servername because we would have to check
510  * all primary IPs and the ROI seems unlikely to be worth it.
511  * 2. Both basepath and username are currently ignored because both
512  * Server Manger (NT 4.0) and CMI (Windows 2000) always set them to null.
513  *
514  * The level of information requested may be one of:
515  *
516  *  2   Return the file identification number.
517  *      This level is not supported on Windows Me/98/95.
518  *
519  *  3   Return information about the file.
520  *      This level is not supported on Windows Me/98/95.
521  *
522  *  50  Windows Me/98/95:  Return information about the file.
523  *
524  * Note:
525  * If pref_max_len is unlimited and resume_handle is null, the client
526  * expects to receive all data in a single call.
527  * If we are unable to do fit all data in a single response, we would
528  * normally return ERROR_MORE_DATA with a partial list.
529  *
530  * Unfortunately, when both of these conditions occur, Server Manager
531  * pops up an error box with the message "more data available" and
532  * doesn't display any of the returned data. In this case, it is
533  * probably better to return ERROR_SUCCESS with the partial list.
534  * Windows 2000 doesn't have this problem because it always sends a
535  * non-null resume_handle.
536  *
537  * Return Values:
538  * ERROR_SUCCESS            Success
539  * ERROR_ACCESS_DENIED      Caller does not have access to this call.
540  * ERROR_INVALID_PARAMETER  One of the parameters is invalid.
541  * ERROR_INVALID_LEVEL      Unknown information level specified.
542  * ERROR_MORE_DATA          Partial date returned, more entries available.
543  * ERROR_NOT_ENOUGH_MEMORY  Insufficient memory is available.
544  * NERR_BufTooSmall         The supplied buffer is too small.
545  */
546 static int
547 srvsvc_s_NetFileEnum(void *arg, ndr_xa_t *mxa)
548 {
549 	struct mslm_NetFileEnum	*param = arg;
550 	smb_svcenum_t		se;
551 	DWORD			status;
552 
553 	if (!ndr_is_admin(mxa)) {
554 		bzero(param, sizeof (struct mslm_NetFileEnum));
555 		param->status = ERROR_ACCESS_DENIED;
556 		return (NDR_DRC_OK);
557 	}
558 
559 	if ((param->total_entries = srvsvc_open_files()) == 0) {
560 		bzero(param, sizeof (struct mslm_NetFileEnum));
561 		param->status = ERROR_SUCCESS;
562 		return (NDR_DRC_OK);
563 	}
564 
565 	bzero(&se, sizeof (smb_svcenum_t));
566 	se.se_type = SMB_SVCENUM_TYPE_FILE;
567 	se.se_level = param->info.switch_value;
568 	se.se_ntotal = param->total_entries;
569 	se.se_nlimit = se.se_ntotal;
570 
571 	if (param->pref_max_len == SMB_SRVSVC_MAXPREFLEN ||
572 	    param->pref_max_len > SMB_SRVSVC_MAXBUFLEN)
573 		se.se_prefmaxlen = SMB_SRVSVC_MAXBUFLEN;
574 	else
575 		se.se_prefmaxlen = param->pref_max_len;
576 
577 	if (param->resume_handle) {
578 		se.se_resume = *param->resume_handle;
579 		se.se_nskip = se.se_resume;
580 		*param->resume_handle = 0;
581 	}
582 
583 	switch (param->info.switch_value) {
584 	case 2:
585 		status = srvsvc_NetFileEnum2(mxa, param, &se);
586 		break;
587 
588 	case 3:
589 		status = srvsvc_NetFileEnum3(mxa, param, &se);
590 		break;
591 
592 	case 50:
593 		status = ERROR_NOT_SUPPORTED;
594 		break;
595 
596 	default:
597 		status = ERROR_INVALID_LEVEL;
598 		break;
599 	}
600 
601 	if (status != ERROR_SUCCESS) {
602 		bzero(param, sizeof (struct mslm_NetFileEnum));
603 		param->status = status;
604 		return (NDR_DRC_OK);
605 	}
606 
607 	if (param->resume_handle &&
608 	    param->pref_max_len != SMB_SRVSVC_MAXPREFLEN) {
609 		if (se.se_resume < param->total_entries) {
610 			*param->resume_handle = se.se_resume;
611 			status = ERROR_MORE_DATA;
612 		}
613 	}
614 
615 	param->status = status;
616 	return (NDR_DRC_OK);
617 }
618 
619 /*
620  * Build level 2 file information.
621  *
622  * SMB fids are 16-bit values but this interface expects 32-bit file ids.
623  * So we use the uniqid here.
624  *
625  * On success, the caller expects that the info2, fi2 and entries_read
626  * fields have been set up.
627  */
628 static DWORD
629 srvsvc_NetFileEnum2(ndr_xa_t *mxa, struct mslm_NetFileEnum *param,
630     smb_svcenum_t *se)
631 {
632 	struct mslm_NetFileInfoBuf2	*fi2;
633 	smb_netsvc_t			*ns;
634 	smb_netsvcitem_t		*item;
635 	smb_netfileinfo_t		*ofile;
636 	uint32_t			entries_read = 0;
637 
638 	param->info.ru.info2 = NDR_NEW(mxa, struct mslm_NetFileInfo2);
639 	if (param->info.ru.info2 == NULL)
640 		return (ERROR_NOT_ENOUGH_MEMORY);
641 
642 	srvsvc_estimate_limit(se, sizeof (struct mslm_NetFileInfoBuf2));
643 	if (se->se_nlimit == 0)
644 		return (NERR_BufTooSmall);
645 
646 	do {
647 		fi2 = NDR_NEWN(mxa, struct mslm_NetFileInfoBuf2, se->se_nlimit);
648 		if (fi2 == NULL)
649 			se->se_nlimit >>= 1;
650 	} while ((se->se_nlimit > 0) && (fi2 == NULL));
651 
652 	if (fi2 == NULL)
653 		return (ERROR_NOT_ENOUGH_MEMORY);
654 
655 	param->info.ru.info2->fi2 = fi2;
656 
657 	if ((ns = smb_kmod_enum_init(se)) == NULL)
658 		return (ERROR_NOT_ENOUGH_MEMORY);
659 
660 	if (smb_kmod_enum(ns) != 0) {
661 		smb_kmod_enum_fini(ns);
662 		return (ERROR_INTERNAL_ERROR);
663 	}
664 
665 	item = list_head(&ns->ns_list);
666 	while (item != NULL) {
667 		ofile = &item->nsi_un.nsi_ofile;
668 		fi2->fi2_id = ofile->fi_uniqid;
669 
670 		++entries_read;
671 		++fi2;
672 		item = list_next(&ns->ns_list, item);
673 	}
674 
675 	se->se_resume += entries_read;
676 	param->info.ru.info2->entries_read = entries_read;
677 	smb_kmod_enum_fini(ns);
678 	return (ERROR_SUCCESS);
679 }
680 
681 /*
682  * Build level 3 file information.
683  *
684  * SMB fids are 16-bit values but this interface expects 32-bit file ids.
685  * So we use the uniqid here.
686  *
687  * On success, the caller expects that the info3, fi3 and entries_read
688  * fields have been set up.
689  */
690 static DWORD
691 srvsvc_NetFileEnum3(ndr_xa_t *mxa, struct mslm_NetFileEnum *param,
692     smb_svcenum_t *se)
693 {
694 	struct mslm_NetFileInfoBuf3	*fi3;
695 	smb_netsvc_t			*ns;
696 	smb_netsvcitem_t		*item;
697 	smb_netfileinfo_t		*ofile;
698 	uint32_t			entries_read = 0;
699 
700 	param->info.ru.info3 = NDR_NEW(mxa, struct mslm_NetFileInfo3);
701 	if (param->info.ru.info3 == NULL)
702 		return (ERROR_NOT_ENOUGH_MEMORY);
703 
704 	srvsvc_estimate_limit(se,
705 	    sizeof (struct mslm_NetFileInfoBuf3) + MAXNAMELEN);
706 	if (se->se_nlimit == 0)
707 		return (NERR_BufTooSmall);
708 
709 	do {
710 		fi3 = NDR_NEWN(mxa, struct mslm_NetFileInfoBuf3, se->se_nlimit);
711 		if (fi3 == NULL)
712 			se->se_nlimit >>= 1;
713 	} while ((se->se_nlimit > 0) && (fi3 == NULL));
714 
715 	if (fi3 == NULL)
716 		return (ERROR_NOT_ENOUGH_MEMORY);
717 
718 	param->info.ru.info3->fi3 = fi3;
719 
720 	if ((ns = smb_kmod_enum_init(se)) == NULL)
721 		return (ERROR_NOT_ENOUGH_MEMORY);
722 
723 	if (smb_kmod_enum(ns) != 0) {
724 		smb_kmod_enum_fini(ns);
725 		return (ERROR_INTERNAL_ERROR);
726 	}
727 
728 	item = list_head(&ns->ns_list);
729 	while (item != NULL) {
730 		ofile = &item->nsi_un.nsi_ofile;
731 		fi3->fi3_id = ofile->fi_uniqid;
732 		fi3->fi3_permissions = ofile->fi_permissions;
733 		fi3->fi3_num_locks = ofile->fi_numlocks;
734 		fi3->fi3_pathname = (uint8_t *)
735 		    NDR_STRDUP(mxa, ofile->fi_path);
736 		fi3->fi3_username = (uint8_t *)
737 		    NDR_STRDUP(mxa, ofile->fi_username);
738 
739 		++entries_read;
740 		++fi3;
741 		item = list_next(&ns->ns_list, item);
742 	}
743 
744 	se->se_resume += entries_read;
745 	param->info.ru.info3->entries_read = entries_read;
746 	param->total_entries = entries_read;
747 	return (ERROR_SUCCESS);
748 }
749 
750 /*
751  * srvsvc_s_NetFileClose
752  *
753  * NetFileClose forces a file to close. This function can be used when
754  * an error prevents closure by other means.  Use NetFileClose with
755  * caution because it does not flush data, cached on a client, to the
756  * file before closing the file.
757  *
758  * SMB fids are 16-bit values but this interface expects 32-bit file ids.
759  * So we use the uniqid here.
760  *
761  * Return Values
762  * ERROR_SUCCESS            Operation succeeded.
763  * ERROR_ACCESS_DENIED      Operation denied.
764  * NERR_FileIdNotFound      No open file with the specified id.
765  *
766  * Note: MSDN suggests ERROR_FILE_NOT_FOUND for NetFileClose but network
767  * captures using NT show NERR_FileIdNotFound, which is consistent with
768  * the NetFileClose2 page on MSDN.
769  */
770 static int
771 srvsvc_s_NetFileClose(void *arg, ndr_xa_t *mxa)
772 {
773 	static struct {
774 		int errnum;
775 		int nerr;
776 	} errmap[] = {
777 		0,	ERROR_SUCCESS,
778 		EACCES,	ERROR_ACCESS_DENIED,
779 		EPERM,	ERROR_ACCESS_DENIED,
780 		EINVAL,	ERROR_INVALID_PARAMETER,
781 		ENOMEM,	ERROR_NOT_ENOUGH_MEMORY,
782 		ENOENT,	NERR_FileIdNotFound
783 	};
784 
785 	struct mslm_NetFileClose *param = arg;
786 	int		i;
787 	int		rc;
788 
789 	if (!ndr_is_admin(mxa)) {
790 		param->status = ERROR_ACCESS_DENIED;
791 		return (NDR_DRC_OK);
792 	}
793 
794 	rc = smb_kmod_file_close(param->file_id);
795 
796 	for (i = 0; i < (sizeof (errmap) / sizeof (errmap[0])); ++i) {
797 		if (rc == errmap[i].errnum) {
798 			param->status = errmap[i].nerr;
799 			return (NDR_DRC_OK);
800 		}
801 	}
802 
803 	param->status = ERROR_INTERNAL_ERROR;
804 	return (NDR_DRC_OK);
805 }
806 
807 /*
808  * srvsvc_s_NetShareGetInfo
809  *
810  * Returns Win32 error codes.
811  */
812 static int
813 srvsvc_s_NetShareGetInfo(void *arg, ndr_xa_t *mxa)
814 {
815 	struct mlsm_NetShareGetInfo *param = arg;
816 	struct mslm_NetShareInfo_0 *info0;
817 	struct mslm_NetShareInfo_1 *info1;
818 	struct mslm_NetShareInfo_2 *info2;
819 	struct mslm_NetShareInfo_501 *info501;
820 	struct mslm_NetShareInfo_502 *info502;
821 	struct mslm_NetShareInfo_503 *info503;
822 	struct mslm_NetShareInfo_1004 *info1004;
823 	struct mslm_NetShareInfo_1005 *info1005;
824 	struct mslm_NetShareInfo_1006 *info1006;
825 	struct mslm_NetShareInfo_1501 *info1501;
826 	srvsvc_netshare_getinfo_t *info;
827 	uint8_t *netname;
828 	uint8_t *comment;
829 	smb_share_t si;
830 	srvsvc_sd_t sd;
831 	DWORD status;
832 
833 	status = smb_shr_get((char *)param->netname, &si);
834 	if (status != NERR_Success) {
835 		bzero(param, sizeof (struct mlsm_NetShareGetInfo));
836 		param->status = status;
837 		return (NDR_DRC_OK);
838 	}
839 
840 	netname = (uint8_t *)NDR_STRDUP(mxa, si.shr_name);
841 	comment = (uint8_t *)NDR_STRDUP(mxa, si.shr_cmnt);
842 	info = NDR_NEW(mxa, srvsvc_netshare_getinfo_t);
843 
844 	if (netname == NULL || comment == NULL || info == NULL) {
845 		bzero(param, sizeof (struct mlsm_NetShareGetInfo));
846 		param->status = ERROR_NOT_ENOUGH_MEMORY;
847 		return (NDR_DRC_OK);
848 	}
849 
850 	switch (param->level) {
851 	case 0:
852 		info0 = &info->nsg_info0;
853 		info0->shi0_netname = netname;
854 		param->result.ru.info0 = info0;
855 		break;
856 
857 	case 1:
858 		info1 = &info->nsg_info1;
859 		info1->shi1_netname = netname;
860 		info1->shi1_comment = comment;
861 		info1->shi1_type = si.shr_type;
862 		param->result.ru.info1 = info1;
863 		break;
864 
865 	case 2:
866 		info2 = &info->nsg_info2;
867 		info2->shi2_netname = netname;
868 		info2->shi2_comment = comment;
869 		info2->shi2_path =
870 		    (uint8_t *)srvsvc_share_mkpath(mxa, si.shr_path);
871 		info2->shi2_passwd = 0;
872 		info2->shi2_type = si.shr_type;
873 		info2->shi2_permissions = 0;
874 		info2->shi2_max_uses = SHI_USES_UNLIMITED;
875 		info2->shi2_current_uses = 0;
876 		param->result.ru.info2 = info2;
877 		break;
878 
879 	case 501:
880 		info501 = &info->nsg_info501;
881 		info501->shi501_netname = netname;
882 		info501->shi501_comment = comment;
883 		info501->shi501_type = si.shr_type;
884 		info501->shi501_flags = srvsvc_get_share_flags(&si);
885 		param->result.ru.info501 = info501;
886 		break;
887 
888 	case 502:
889 		info502 = &info->nsg_info502;
890 		info502->shi502_netname = netname;
891 		info502->shi502_comment = comment;
892 		info502->shi502_path =
893 		    (uint8_t *)srvsvc_share_mkpath(mxa, si.shr_path);
894 		info502->shi502_passwd = 0;
895 		info502->shi502_type = si.shr_type;
896 		info502->shi502_permissions = 0;
897 		info502->shi502_max_uses = SHI_USES_UNLIMITED;
898 		info502->shi502_current_uses = 0;
899 
900 		status = srvsvc_share_getsd(mxa, &si, &sd);
901 		if (status == ERROR_SUCCESS) {
902 			info502->shi502_reserved = sd.sd_size;
903 			info502->shi502_security_descriptor = sd.sd_buf;
904 		} else {
905 			info502->shi502_reserved = 0;
906 			info502->shi502_security_descriptor = NULL;
907 		}
908 
909 		param->result.ru.info502 = info502;
910 		break;
911 
912 	case 503:
913 		info503 = &info->nsg_info503;
914 		info503->shi503_netname = netname;
915 		info503->shi503_comment = comment;
916 		info503->shi503_path =
917 		    (uint8_t *)srvsvc_share_mkpath(mxa, si.shr_path);
918 		info503->shi503_passwd = NULL;
919 		info503->shi503_type = si.shr_type;
920 		info503->shi503_permissions = 0;
921 		info503->shi503_max_uses = SHI_USES_UNLIMITED;
922 		info503->shi503_current_uses = 0;
923 		info503->shi503_servername = NULL;
924 
925 		status = srvsvc_share_getsd(mxa, &si, &sd);
926 		if (status == ERROR_SUCCESS) {
927 			info503->shi503_reserved = sd.sd_size;
928 			info503->shi503_security_descriptor = sd.sd_buf;
929 		} else {
930 			info503->shi503_reserved = 0;
931 			info503->shi503_security_descriptor = NULL;
932 		}
933 
934 		param->result.ru.info503 = info503;
935 		break;
936 
937 	case 1004:
938 		info1004 = &info->nsg_info1004;
939 		info1004->shi1004_comment = comment;
940 		param->result.ru.info1004 = info1004;
941 		break;
942 
943 	case 1005:
944 		info1005 = &info->nsg_info1005;
945 		info1005->shi1005_flags = srvsvc_get_share_flags(&si);
946 		param->result.ru.info1005 = info1005;
947 		break;
948 
949 	case 1006:
950 		info1006 = &info->nsg_info1006;
951 		info1006->shi1006_max_uses = SHI_USES_UNLIMITED;
952 		param->result.ru.info1006 = info1006;
953 		break;
954 
955 	case 1501:
956 		info1501 = &info->nsg_info1501;
957 
958 		status = srvsvc_share_getsd(mxa, &si, &sd);
959 		if (status == ERROR_SUCCESS) {
960 			info503->shi503_reserved = sd.sd_size;
961 			info503->shi503_security_descriptor = sd.sd_buf;
962 		} else {
963 			info503->shi503_reserved = 0;
964 			info503->shi503_security_descriptor = NULL;
965 		}
966 
967 		param->result.ru.info1501 = info1501;
968 		break;
969 
970 	default:
971 		status = ERROR_ACCESS_DENIED;
972 		break;
973 	}
974 
975 	if (status != ERROR_SUCCESS)
976 		bzero(param, sizeof (struct mlsm_NetShareGetInfo));
977 	else
978 		param->result.switch_value = param->level;
979 
980 	param->status = status;
981 	return (NDR_DRC_OK);
982 }
983 
984 static uint32_t
985 srvsvc_share_getsd(ndr_xa_t *mxa, smb_share_t *si, srvsvc_sd_t *sd)
986 {
987 	uint32_t status;
988 
989 	status = srvsvc_sd_get(si, NULL, &sd->sd_size);
990 	if (status != ERROR_SUCCESS) {
991 		if (status == ERROR_PATH_NOT_FOUND) {
992 			bzero(sd, sizeof (srvsvc_sd_t));
993 			status = ERROR_SUCCESS;
994 		}
995 
996 		return (status);
997 	}
998 
999 	if ((sd->sd_buf = NDR_MALLOC(mxa, sd->sd_size)) == NULL)
1000 		return (ERROR_NOT_ENOUGH_MEMORY);
1001 
1002 	status = srvsvc_sd_get(si, sd->sd_buf, NULL);
1003 	if (status == ERROR_PATH_NOT_FOUND) {
1004 		bzero(sd, sizeof (srvsvc_sd_t));
1005 		status = ERROR_SUCCESS;
1006 	}
1007 
1008 	return (status);
1009 }
1010 
1011 /*
1012  * srvsvc_s_NetShareSetInfo
1013  *
1014  * This call is made by SrvMgr to set share information.
1015  * Only power users groups can manage shares.
1016  *
1017  * To avoid misleading errors, we don't report an error
1018  * when a FS doesn't support ACLs on shares.
1019  *
1020  * Returns Win32 error codes.
1021  */
1022 static int
1023 srvsvc_s_NetShareSetInfo(void *arg, ndr_xa_t *mxa)
1024 {
1025 	struct mlsm_NetShareSetInfo *param = arg;
1026 	struct mslm_NetShareInfo_0 *info0;
1027 	struct mslm_NetShareInfo_1 *info1;
1028 	struct mslm_NetShareInfo_2 *info2;
1029 	struct mslm_NetShareInfo_501 *info501;
1030 	struct mslm_NetShareInfo_502 *info502;
1031 	struct mslm_NetShareInfo_503 *info503;
1032 	struct mslm_NetShareInfo_1004 *info1004;
1033 	struct mslm_NetShareInfo_1005 *info1005;
1034 	struct mslm_NetShareInfo_1501 *info1501;
1035 	static DWORD parm_err = 0;
1036 	srvsvc_netshare_setinfo_t info;
1037 	smb_share_t si;
1038 	uint8_t *sdbuf;
1039 	int32_t native_os;
1040 	DWORD status;
1041 
1042 	native_os = ndr_native_os(mxa);
1043 
1044 	if (!ndr_is_poweruser(mxa)) {
1045 		status = ERROR_ACCESS_DENIED;
1046 		goto netsharesetinfo_exit;
1047 	}
1048 
1049 	if (smb_shr_get((char *)param->netname, &si) != NERR_Success) {
1050 		status = ERROR_INVALID_NETNAME;
1051 		goto netsharesetinfo_exit;
1052 	}
1053 
1054 	if (param->result.ru.nullptr == NULL) {
1055 		status = ERROR_INVALID_PARAMETER;
1056 		goto netsharesetinfo_exit;
1057 	}
1058 
1059 	bzero(&info, sizeof (srvsvc_netshare_setinfo_t));
1060 
1061 	switch (param->level) {
1062 	case 0:
1063 		info0 = (struct mslm_NetShareInfo_0 *)param->result.ru.info0;
1064 		info.nss_netname = (char *)info0->shi0_netname;
1065 		status = srvsvc_modify_share(&si, &info);
1066 		break;
1067 
1068 	case 1:
1069 		info1 = (struct mslm_NetShareInfo_1 *)param->result.ru.info1;
1070 		info.nss_netname = (char *)info1->shi1_netname;
1071 		info.nss_comment = (char *)info1->shi1_comment;
1072 		info.nss_type = info1->shi1_type;
1073 		status = srvsvc_modify_share(&si, &info);
1074 		break;
1075 
1076 	case 2:
1077 		info2 = (struct mslm_NetShareInfo_2 *)param->result.ru.info2;
1078 		info.nss_netname = (char *)info2->shi2_netname;
1079 		info.nss_comment = (char *)info2->shi2_comment;
1080 		info.nss_path = (char *)info2->shi2_path;
1081 		info.nss_type = info2->shi2_type;
1082 		status = srvsvc_modify_share(&si, &info);
1083 		break;
1084 
1085 	case 501:
1086 		info501 = (struct mslm_NetShareInfo_501 *)
1087 		    param->result.ru.info501;
1088 		info.nss_netname = (char *)info501->shi501_netname;
1089 		info.nss_comment = (char *)info501->shi501_comment;
1090 		info.nss_type = info501->shi501_type;
1091 		status = srvsvc_modify_share(&si, &info);
1092 		if (status == ERROR_SUCCESS)
1093 			status = srvsvc_update_share_flags(&si,
1094 			    info501->shi501_flags);
1095 		break;
1096 
1097 	case 502:
1098 		info502 = (struct mslm_NetShareInfo_502 *)
1099 		    param->result.ru.info502;
1100 		info.nss_netname = (char *)info502->shi502_netname;
1101 		info.nss_comment = (char *)info502->shi502_comment;
1102 		info.nss_path = (char *)info502->shi502_path;
1103 		info.nss_type = info502->shi502_type;
1104 		info.nss_sd.sd_buf = info502->shi502_security_descriptor;
1105 		status = srvsvc_modify_share(&si, &info);
1106 		break;
1107 
1108 	case 503:
1109 		info503 = (struct mslm_NetShareInfo_503 *)
1110 		    param->result.ru.info503;
1111 		info.nss_netname = (char *)info503->shi503_netname;
1112 		info.nss_comment = (char *)info503->shi503_comment;
1113 		info.nss_path = (char *)info503->shi503_path;
1114 		info.nss_type = info503->shi503_type;
1115 		info.nss_sd.sd_buf = info503->shi503_security_descriptor;
1116 		status = srvsvc_modify_share(&si, &info);
1117 		break;
1118 
1119 	case 1004:
1120 		info1004 = (struct mslm_NetShareInfo_1004 *)
1121 		    param->result.ru.info1004;
1122 		info.nss_comment = (char *)info1004->shi1004_comment;
1123 		status = srvsvc_modify_share(&si, &info);
1124 		break;
1125 
1126 	case 1005:
1127 		info1005 = (struct mslm_NetShareInfo_1005 *)
1128 		    param->result.ru.info1005;
1129 		status = srvsvc_update_share_flags(&si,
1130 		    info1005->shi1005_flags);
1131 		break;
1132 
1133 	case 1006:
1134 		/*
1135 		 * We don't limit the maximum number of concurrent
1136 		 * connections to a share.
1137 		 */
1138 		status = ERROR_SUCCESS;
1139 		break;
1140 
1141 	case 1501:
1142 		info1501 = (struct mslm_NetShareInfo_1501 *)
1143 		    param->result.ru.info1501;
1144 		sdbuf = info1501->shi1501_security_descriptor;
1145 		status = ERROR_SUCCESS;
1146 
1147 		if (sdbuf != NULL) {
1148 			status = srvsvc_sd_set(&si, sdbuf);
1149 			if (status == ERROR_PATH_NOT_FOUND)
1150 				status = ERROR_SUCCESS;
1151 		}
1152 		break;
1153 
1154 	default:
1155 		status = ERROR_ACCESS_DENIED;
1156 		break;
1157 	}
1158 
1159 netsharesetinfo_exit:
1160 	if (status != ERROR_SUCCESS)
1161 		bzero(param, sizeof (struct mlsm_NetShareSetInfo));
1162 
1163 	param->parm_err = (native_os == NATIVE_OS_WIN95) ? 0 : &parm_err;
1164 	param->status = status;
1165 	return (NDR_DRC_OK);
1166 }
1167 
1168 static uint32_t
1169 srvsvc_modify_share(smb_share_t *si, srvsvc_netshare_setinfo_t *info)
1170 {
1171 	uint32_t nerr = NERR_Success;
1172 
1173 	if (si->shr_flags & SMB_SHRF_TRANS)
1174 		return (srvsvc_modify_transient_share(si, info));
1175 
1176 	if (info->nss_sd.sd_buf != NULL) {
1177 		nerr = srvsvc_sd_set(si, info->nss_sd.sd_buf);
1178 		if (nerr == ERROR_PATH_NOT_FOUND)
1179 			nerr = NERR_Success;
1180 	}
1181 
1182 	if ((nerr = srvsvc_sa_modify(si, info)) == NERR_Success)
1183 		nerr = smb_shr_modify(si);
1184 
1185 	return (nerr);
1186 }
1187 
1188 /*
1189  * Update transient shares.  This includes autohome shares.
1190  */
1191 static uint32_t
1192 srvsvc_modify_transient_share(smb_share_t *si, srvsvc_netshare_setinfo_t *info)
1193 {
1194 	uint32_t nerr;
1195 
1196 	if (info->nss_netname != NULL && info->nss_netname[0] != '\0' &&
1197 	    smb_strcasecmp(info->nss_netname, si->shr_name, 0) != 0) {
1198 		nerr = smb_shr_rename(si->shr_name, info->nss_netname);
1199 		if (nerr != NERR_Success)
1200 			return (nerr);
1201 
1202 		(void) strlcpy(si->shr_name, info->nss_netname, MAXNAMELEN);
1203 	}
1204 
1205 	if ((info->nss_comment != NULL) &&
1206 	    (strcmp(info->nss_comment, si->shr_cmnt) != 0)) {
1207 		(void) strlcpy(si->shr_cmnt, info->nss_comment,
1208 		    SMB_SHARE_CMNT_MAX);
1209 
1210 		if ((nerr = smb_shr_modify(si)) != NERR_Success)
1211 			return (nerr);
1212 	}
1213 
1214 	return (NERR_Success);
1215 }
1216 
1217 /*
1218  * srvsvc_update_share_flags
1219  *
1220  * This function updates flags for shares.
1221  * Flags for Persistent shares are updated in both libshare and the local cache.
1222  * Flags for Transient shares are updated only in the local cache.
1223  */
1224 static uint32_t
1225 srvsvc_update_share_flags(smb_share_t *si, uint32_t shi_flags)
1226 {
1227 	uint32_t nerr = NERR_Success;
1228 	uint32_t flag = 0;
1229 	char *csc_value;
1230 	char *abe_value = "false";
1231 	nvlist_t *nvl;
1232 	int err = 0;
1233 
1234 	if (shi_flags & SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM) {
1235 		flag = SMB_SHRF_ABE;
1236 		abe_value = "true";
1237 	}
1238 
1239 	si->shr_flags &= ~SMB_SHRF_ABE;
1240 	si->shr_flags |= flag;
1241 
1242 	switch ((shi_flags & CSC_MASK)) {
1243 	case CSC_CACHE_AUTO_REINT:
1244 		flag = SMB_SHRF_CSC_AUTO;
1245 		break;
1246 	case CSC_CACHE_VDO:
1247 		flag = SMB_SHRF_CSC_VDO;
1248 		break;
1249 	case CSC_CACHE_NONE:
1250 		flag = SMB_SHRF_CSC_DISABLED;
1251 		break;
1252 	case CSC_CACHE_MANUAL_REINT:
1253 		flag = SMB_SHRF_CSC_MANUAL;
1254 		break;
1255 	default:
1256 		return (NERR_InternalError);
1257 	}
1258 
1259 	si->shr_flags &= ~SMB_SHRF_CSC_MASK;
1260 	si->shr_flags |= flag;
1261 
1262 	if ((si->shr_flags & SMB_SHRF_TRANS) == 0) {
1263 		csc_value = smb_shr_sa_csc_name(si);
1264 
1265 		if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
1266 			return (NERR_InternalError);
1267 
1268 		err |= nvlist_add_string(nvl, SHOPT_CSC, csc_value);
1269 		err |= nvlist_add_string(nvl, SHOPT_ABE, abe_value);
1270 		if (err) {
1271 			nvlist_free(nvl);
1272 			return (NERR_InternalError);
1273 		}
1274 
1275 		nerr = srvsvc_sa_setprop(si, nvl);
1276 		nvlist_free(nvl);
1277 
1278 		if (nerr != NERR_Success)
1279 			return (nerr);
1280 	}
1281 
1282 	return (smb_shr_modify(si));
1283 }
1284 
1285 static uint32_t
1286 srvsvc_get_share_flags(smb_share_t *si)
1287 {
1288 	uint32_t flags = 0;
1289 
1290 	switch (si->shr_flags & SMB_SHRF_CSC_MASK) {
1291 	case SMB_SHRF_CSC_DISABLED:
1292 		flags |= CSC_CACHE_NONE;
1293 		break;
1294 	case SMB_SHRF_CSC_AUTO:
1295 		flags |= CSC_CACHE_AUTO_REINT;
1296 		break;
1297 	case SMB_SHRF_CSC_VDO:
1298 		flags |= CSC_CACHE_VDO;
1299 		break;
1300 	case SMB_SHRF_CSC_MANUAL:
1301 	default:
1302 		/*
1303 		 * Default to CSC_CACHE_MANUAL_REINT.
1304 		 */
1305 		break;
1306 	}
1307 
1308 	if (si->shr_flags & SMB_SHRF_ABE)
1309 		flags |= SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM;
1310 
1311 	return (flags);
1312 }
1313 
1314 /*
1315  * srvsvc_s_NetSessionEnum
1316  *
1317  * Level 1 request is made by (Server Manager (srvmgr) on NT Server when
1318  * the user info icon is selected.
1319  *
1320  * On success, the return value is NERR_Success.
1321  * On error, the return value can be one of the following error codes:
1322  *
1323  * ERROR_ACCESS_DENIED      The user does not have access to the requested
1324  *                          information.
1325  * ERROR_INVALID_LEVEL      The value specified for the level is invalid.
1326  * ERROR_INVALID_PARAMETER  The specified parameter is invalid.
1327  * ERROR_MORE_DATA          More entries are available. Specify a large
1328  *                          enough buffer to receive all entries.
1329  * ERROR_NOT_ENOUGH_MEMORY  Insufficient memory is available.
1330  * NERR_ClientNameNotFound  A session does not exist with the computer name.
1331  * NERR_InvalidComputer     The computer name is invalid.
1332  * NERR_UserNotFound        The user name could not be found.
1333  */
1334 static int
1335 srvsvc_s_NetSessionEnum(void *arg, ndr_xa_t *mxa)
1336 {
1337 	struct mslm_NetSessionEnum	*param = arg;
1338 	srvsvc_infonres_t		*info;
1339 	smb_netsvc_t			*ns;
1340 	smb_svcenum_t			se;
1341 	DWORD				status = ERROR_SUCCESS;
1342 
1343 	if (!ndr_is_admin(mxa)) {
1344 		status = ERROR_ACCESS_DENIED;
1345 		goto srvsvc_netsessionenum_error;
1346 	}
1347 
1348 	if ((info = NDR_NEW(mxa, srvsvc_infonres_t)) == NULL) {
1349 		status = ERROR_NOT_ENOUGH_MEMORY;
1350 		goto srvsvc_netsessionenum_error;
1351 	}
1352 
1353 	info->entriesread = 0;
1354 	info->entries = NULL;
1355 	param->result.level = param->level;
1356 	param->result.bufptr.p = info;
1357 
1358 	if ((param->total_entries = srvsvc_open_sessions()) == 0) {
1359 		param->resume_handle = NULL;
1360 		param->status = ERROR_SUCCESS;
1361 		return (NDR_DRC_OK);
1362 	}
1363 
1364 	bzero(&se, sizeof (smb_svcenum_t));
1365 	se.se_type = SMB_SVCENUM_TYPE_USER;
1366 	se.se_level = param->level;
1367 	se.se_ntotal = param->total_entries;
1368 	se.se_nlimit = se.se_ntotal;
1369 
1370 	if (param->resume_handle) {
1371 		se.se_resume = *param->resume_handle;
1372 		se.se_nskip = se.se_resume;
1373 		*param->resume_handle = 0;
1374 	}
1375 
1376 	switch (param->level) {
1377 	case 0:
1378 		info->entries = NDR_NEWN(mxa, struct mslm_SESSION_INFO_0,
1379 		    se.se_nlimit);
1380 		break;
1381 	case 1:
1382 		info->entries = NDR_NEWN(mxa, struct mslm_SESSION_INFO_1,
1383 		    se.se_nlimit);
1384 		break;
1385 	case 2:
1386 		info->entries = NDR_NEWN(mxa, struct mslm_SESSION_INFO_2,
1387 		    se.se_nlimit);
1388 		break;
1389 	case 10:
1390 		info->entries = NDR_NEWN(mxa, struct mslm_SESSION_INFO_10,
1391 		    se.se_nlimit);
1392 		break;
1393 	case 502:
1394 		info->entries = NDR_NEWN(mxa, struct mslm_SESSION_INFO_502,
1395 		    se.se_nlimit);
1396 		break;
1397 	default:
1398 		bzero(param, sizeof (struct mslm_NetSessionEnum));
1399 		param->status = ERROR_INVALID_LEVEL;
1400 		return (NDR_DRC_OK);
1401 	}
1402 
1403 	if (info->entries == NULL) {
1404 		status = ERROR_NOT_ENOUGH_MEMORY;
1405 		goto srvsvc_netsessionenum_error;
1406 	}
1407 
1408 	if ((ns = smb_kmod_enum_init(&se)) == NULL) {
1409 		status = ERROR_NOT_ENOUGH_MEMORY;
1410 		goto srvsvc_netsessionenum_error;
1411 	}
1412 
1413 	status = srvsvc_NetSessionEnumCommon(mxa, info, ns, &se);
1414 	smb_kmod_enum_fini(ns);
1415 
1416 	if (status != ERROR_SUCCESS)
1417 		goto srvsvc_netsessionenum_error;
1418 
1419 	if (param->resume_handle &&
1420 	    param->pref_max_len != SMB_SRVSVC_MAXPREFLEN) {
1421 		if (se.se_resume < param->total_entries) {
1422 			*param->resume_handle = se.se_resume;
1423 			status = ERROR_MORE_DATA;
1424 		}
1425 	}
1426 
1427 	param->total_entries = info->entriesread;
1428 	param->status = status;
1429 	return (NDR_DRC_OK);
1430 
1431 srvsvc_netsessionenum_error:
1432 	bzero(param, sizeof (struct mslm_NetSessionEnum));
1433 	param->status = status;
1434 	return (NDR_DRC_OK);
1435 }
1436 
1437 static uint32_t
1438 srvsvc_NetSessionEnumCommon(ndr_xa_t *mxa, srvsvc_infonres_t *info,
1439     smb_netsvc_t *ns, smb_svcenum_t *se)
1440 {
1441 	struct mslm_SESSION_INFO_0	*info0 = info->entries;
1442 	struct mslm_SESSION_INFO_1	*info1 = info->entries;
1443 	struct mslm_SESSION_INFO_2	*info2 = info->entries;
1444 	struct mslm_SESSION_INFO_10	*info10 = info->entries;
1445 	struct mslm_SESSION_INFO_502	*info502 = info->entries;
1446 	smb_netsvcitem_t		*item;
1447 	smb_netuserinfo_t		*user;
1448 	char				*workstation;
1449 	char				account[MAXNAMELEN];
1450 	char				ipaddr_buf[INET6_ADDRSTRLEN];
1451 	uint32_t			logon_time;
1452 	uint32_t			flags;
1453 	uint32_t			entries_read = 0;
1454 
1455 	if (smb_kmod_enum(ns) != 0)
1456 		return (ERROR_INTERNAL_ERROR);
1457 
1458 	item = list_head(&ns->ns_list);
1459 	while (item != NULL) {
1460 		user = &item->nsi_un.nsi_user;
1461 
1462 		workstation = user->ui_workstation;
1463 		if (workstation == NULL || *workstation == '\0') {
1464 			(void) smb_inet_ntop(&user->ui_ipaddr, ipaddr_buf,
1465 			    SMB_IPSTRLEN(user->ui_ipaddr.a_family));
1466 			workstation = ipaddr_buf;
1467 		}
1468 
1469 		(void) snprintf(account, MAXNAMELEN, "%s\\%s",
1470 		    user->ui_domain, user->ui_account);
1471 
1472 		logon_time = time(0) - user->ui_logon_time;
1473 		flags = (user->ui_flags & SMB_ATF_GUEST) ? SESS_GUEST : 0;
1474 
1475 		switch (se->se_level) {
1476 		case 0:
1477 			info0->sesi0_cname = NDR_STRDUP(mxa, workstation);
1478 			if (info0->sesi0_cname == NULL)
1479 				return (ERROR_NOT_ENOUGH_MEMORY);
1480 			++info0;
1481 			break;
1482 
1483 		case 1:
1484 			info1->sesi1_cname = NDR_STRDUP(mxa, workstation);
1485 			info1->sesi1_uname = NDR_STRDUP(mxa, account);
1486 
1487 			if (info1->sesi1_cname == NULL ||
1488 			    info1->sesi1_uname == NULL)
1489 				return (ERROR_NOT_ENOUGH_MEMORY);
1490 
1491 			info1->sesi1_nopens = user->ui_numopens;
1492 			info1->sesi1_time = logon_time;
1493 			info1->sesi1_itime = 0;
1494 			info1->sesi1_uflags = flags;
1495 			++info1;
1496 			break;
1497 
1498 		case 2:
1499 			info2->sesi2_cname = NDR_STRDUP(mxa, workstation);
1500 			info2->sesi2_uname = NDR_STRDUP(mxa, account);
1501 
1502 			if (info2->sesi2_cname == NULL ||
1503 			    info2->sesi2_uname == NULL)
1504 				return (ERROR_NOT_ENOUGH_MEMORY);
1505 
1506 			info2->sesi2_nopens = user->ui_numopens;
1507 			info2->sesi2_time = logon_time;
1508 			info2->sesi2_itime = 0;
1509 			info2->sesi2_uflags = flags;
1510 			info2->sesi2_cltype_name = (uint8_t *)"";
1511 			++info2;
1512 			break;
1513 
1514 		case 10:
1515 			info10->sesi10_cname = NDR_STRDUP(mxa, workstation);
1516 			info10->sesi10_uname = NDR_STRDUP(mxa, account);
1517 
1518 			if (info10->sesi10_cname == NULL ||
1519 			    info10->sesi10_uname == NULL)
1520 				return (ERROR_NOT_ENOUGH_MEMORY);
1521 
1522 			info10->sesi10_time = logon_time;
1523 			info10->sesi10_itime = 0;
1524 			++info10;
1525 			break;
1526 
1527 		case 502:
1528 			info502->sesi502_cname = NDR_STRDUP(mxa, workstation);
1529 			info502->sesi502_uname = NDR_STRDUP(mxa, account);
1530 
1531 			if (info502->sesi502_cname == NULL ||
1532 			    info502->sesi502_uname == NULL)
1533 				return (ERROR_NOT_ENOUGH_MEMORY);
1534 
1535 			info502->sesi502_nopens = user->ui_numopens;
1536 			info502->sesi502_time = logon_time;
1537 			info502->sesi502_itime = 0;
1538 			info502->sesi502_uflags = flags;
1539 			info502->sesi502_cltype_name = (uint8_t *)"";
1540 			info502->sesi502_transport = (uint8_t *)"";
1541 			++info502;
1542 			break;
1543 
1544 		default:
1545 			return (ERROR_INVALID_LEVEL);
1546 		}
1547 
1548 		++entries_read;
1549 		item = list_next(&ns->ns_list, item);
1550 	}
1551 
1552 	info->entriesread = entries_read;
1553 	return (ERROR_SUCCESS);
1554 }
1555 
1556 /*
1557  * srvsvc_s_NetSessionDel
1558  *
1559  * Ends a network session between a server and a workstation.
1560  * On NT only members of the Administrators or Account Operators
1561  * local groups are permitted to use NetSessionDel.
1562  *
1563  * If unc_clientname is NULL, all sessions associated with the
1564  * specified user will be disconnected.
1565  *
1566  * If username is NULL, all sessions from the specified client
1567  * will be disconnected.
1568  *
1569  * Return Values
1570  * On success, the return value is NERR_Success/ERROR_SUCCESS.
1571  * On failure, the return value can be one of the following errors:
1572  *
1573  * ERROR_ACCESS_DENIED 		The user does not have access to the
1574  * 				requested information.
1575  * ERROR_INVALID_PARAMETER	The specified parameter is invalid.
1576  * ERROR_NOT_ENOUGH_MEMORY	Insufficient memory is available.
1577  * NERR_ClientNameNotFound	A session does not exist with that
1578  *				computer name.
1579  */
1580 static int
1581 srvsvc_s_NetSessionDel(void *arg, ndr_xa_t *mxa)
1582 {
1583 	static struct {
1584 		int errnum;
1585 		int nerr;
1586 	} errmap[] = {
1587 		0,	ERROR_SUCCESS,
1588 		EACCES,	ERROR_ACCESS_DENIED,
1589 		EPERM,	ERROR_ACCESS_DENIED,
1590 		EINVAL,	ERROR_INVALID_PARAMETER,
1591 		ENOMEM,	ERROR_NOT_ENOUGH_MEMORY,
1592 		ENOENT,	NERR_ClientNameNotFound
1593 	};
1594 
1595 	struct mslm_NetSessionDel *param = arg;
1596 	int	i;
1597 	int	rc;
1598 
1599 	if (!ndr_is_admin(mxa)) {
1600 		param->status = ERROR_ACCESS_DENIED;
1601 		return (NDR_DRC_OK);
1602 	}
1603 
1604 	rc = smb_kmod_session_close((char *)param->unc_clientname,
1605 	    (char *)param->username);
1606 
1607 	for (i = 0; i < (sizeof (errmap) / sizeof (errmap[0])); ++i) {
1608 		if (rc == errmap[i].errnum) {
1609 			param->status = errmap[i].nerr;
1610 			return (NDR_DRC_OK);
1611 		}
1612 	}
1613 
1614 	param->status = ERROR_INTERNAL_ERROR;
1615 	return (NDR_DRC_OK);
1616 }
1617 
1618 /*
1619  * SRVSVC NetServerGetInfo
1620  *
1621  *	IN	LPTSTR servername,
1622  *	IN	DWORD level,
1623  *	OUT	union switch(level) {
1624  *		case 100:	mslm_SERVER_INFO_100 *p100;
1625  *		case 101:	mslm_SERVER_INFO_101 *p101;
1626  *		case 102:	mslm_SERVER_INFO_102 *p102;
1627  *		...
1628  *		default:	char *nullptr;
1629  *		} bufptr,
1630  *	OUT	DWORD status
1631  */
1632 static int
1633 srvsvc_s_NetServerGetInfo(void *arg, ndr_xa_t *mxa)
1634 {
1635 	struct mslm_NetServerGetInfo *param = arg;
1636 	struct mslm_SERVER_INFO_100 *info100;
1637 	struct mslm_SERVER_INFO_101 *info101;
1638 	struct mslm_SERVER_INFO_102 *info102;
1639 	struct mslm_SERVER_INFO_502 *info502;
1640 	struct mslm_SERVER_INFO_503 *info503;
1641 	char sys_comment[SMB_PI_MAX_COMMENT];
1642 	char hostname[NETBIOS_NAME_SZ];
1643 
1644 	if (smb_getnetbiosname(hostname, sizeof (hostname)) != 0) {
1645 netservergetinfo_no_memory:
1646 		bzero(param, sizeof (struct mslm_NetServerGetInfo));
1647 		return (ERROR_NOT_ENOUGH_MEMORY);
1648 	}
1649 
1650 	(void) smb_config_getstr(SMB_CI_SYS_CMNT, sys_comment,
1651 	    sizeof (sys_comment));
1652 	if (*sys_comment == '\0')
1653 		(void) strcpy(sys_comment, " ");
1654 
1655 	switch (param->level) {
1656 	case 100:
1657 		info100 = NDR_NEW(mxa, struct mslm_SERVER_INFO_100);
1658 		if (info100 == NULL)
1659 			goto netservergetinfo_no_memory;
1660 
1661 		bzero(info100, sizeof (struct mslm_SERVER_INFO_100));
1662 		info100->sv100_platform_id = SV_PLATFORM_ID_NT;
1663 		info100->sv100_name = (uint8_t *)NDR_STRDUP(mxa, hostname);
1664 		if (info100->sv100_name == NULL)
1665 			goto netservergetinfo_no_memory;
1666 
1667 		param->result.bufptr.bufptr100 = info100;
1668 		break;
1669 
1670 	case 101:
1671 		info101 = NDR_NEW(mxa, struct mslm_SERVER_INFO_101);
1672 		if (info101 == NULL)
1673 			goto netservergetinfo_no_memory;
1674 
1675 		bzero(info101, sizeof (struct mslm_SERVER_INFO_101));
1676 		info101->sv101_platform_id = SV_PLATFORM_ID_NT;
1677 		info101->sv101_version_major = 4;
1678 		info101->sv101_version_minor = 0;
1679 		info101->sv101_type = SV_TYPE_DEFAULT;
1680 		info101->sv101_name = (uint8_t *)NDR_STRDUP(mxa, hostname);
1681 		info101->sv101_comment
1682 		    = (uint8_t *)NDR_STRDUP(mxa, sys_comment);
1683 
1684 		if (info101->sv101_name == NULL ||
1685 		    info101->sv101_comment == NULL)
1686 			goto netservergetinfo_no_memory;
1687 
1688 		param->result.bufptr.bufptr101 = info101;
1689 		break;
1690 
1691 	case 102:
1692 		info102 = NDR_NEW(mxa, struct mslm_SERVER_INFO_102);
1693 		if (info102 == NULL)
1694 			goto netservergetinfo_no_memory;
1695 
1696 		bzero(info102, sizeof (struct mslm_SERVER_INFO_102));
1697 		info102->sv102_platform_id = SV_PLATFORM_ID_NT;
1698 		info102->sv102_version_major = 4;
1699 		info102->sv102_version_minor = 0;
1700 		info102->sv102_type = SV_TYPE_DEFAULT;
1701 		info102->sv102_name = (uint8_t *)NDR_STRDUP(mxa, hostname);
1702 		info102->sv102_comment
1703 		    = (uint8_t *)NDR_STRDUP(mxa, sys_comment);
1704 
1705 		/*
1706 		 * The following level 102 fields are defaulted to zero
1707 		 * by virtue of the call to bzero above.
1708 		 *
1709 		 * sv102_users
1710 		 * sv102_disc
1711 		 * sv102_hidden
1712 		 * sv102_announce
1713 		 * sv102_anndelta
1714 		 * sv102_licenses
1715 		 * sv102_userpath
1716 		 */
1717 		if (info102->sv102_name == NULL ||
1718 		    info102->sv102_comment == NULL)
1719 			goto netservergetinfo_no_memory;
1720 
1721 		param->result.bufptr.bufptr102 = info102;
1722 		break;
1723 
1724 	case 502:
1725 		info502 = NDR_NEW(mxa, struct mslm_SERVER_INFO_502);
1726 		if (info502 == NULL)
1727 			goto netservergetinfo_no_memory;
1728 
1729 		bzero(info502, sizeof (struct mslm_SERVER_INFO_502));
1730 		param->result.bufptr.bufptr502 = info502;
1731 #ifdef SRVSVC_SATISFY_SMBTORTURE
1732 		break;
1733 #else
1734 		param->result.level = param->level;
1735 		param->status = ERROR_ACCESS_DENIED;
1736 		return (NDR_DRC_OK);
1737 #endif /* SRVSVC_SATISFY_SMBTORTURE */
1738 
1739 	case 503:
1740 		info503 = NDR_NEW(mxa, struct mslm_SERVER_INFO_503);
1741 		if (info503 == NULL)
1742 			goto netservergetinfo_no_memory;
1743 
1744 		bzero(info503, sizeof (struct mslm_SERVER_INFO_503));
1745 		param->result.bufptr.bufptr503 = info503;
1746 #ifdef SRVSVC_SATISFY_SMBTORTURE
1747 		break;
1748 #else
1749 		param->result.level = param->level;
1750 		param->status = ERROR_ACCESS_DENIED;
1751 		return (NDR_DRC_OK);
1752 #endif /* SRVSVC_SATISFY_SMBTORTURE */
1753 
1754 	default:
1755 		bzero(&param->result,
1756 		    sizeof (struct mslm_NetServerGetInfo_result));
1757 		param->status = ERROR_ACCESS_DENIED;
1758 		return (NDR_DRC_OK);
1759 	}
1760 
1761 	param->result.level = param->level;
1762 	param->status = ERROR_SUCCESS;
1763 	return (NDR_DRC_OK);
1764 }
1765 
1766 /*
1767  * NetRemoteTOD
1768  *
1769  * Returns information about the time of day on this server.
1770  *
1771  * typedef struct _TIME_OF_DAY_INFO {
1772  *	DWORD tod_elapsedt;  // seconds since 00:00:00 January 1 1970 GMT
1773  *	DWORD tod_msecs;     // arbitrary milliseconds (since reset)
1774  *	DWORD tod_hours;     // current hour [0-23]
1775  *	DWORD tod_mins;      // current minute [0-59]
1776  *	DWORD tod_secs;      // current second [0-59]
1777  *	DWORD tod_hunds;     // current hundredth (0.01) second [0-99]
1778  *	LONG tod_timezone;   // time zone of the server
1779  *	DWORD tod_tinterval; // clock tick time interval
1780  *	DWORD tod_day;       // day of the month [1-31]
1781  *	DWORD tod_month;     // month of the year [1-12]
1782  *	DWORD tod_year;      // current year
1783  *	DWORD tod_weekday;   // day of the week since Sunday [0-6]
1784  * } TIME_OF_DAY_INFO;
1785  *
1786  * The time zone of the server is calculated in minutes from Greenwich
1787  * Mean Time (GMT). For time zones west of Greenwich, the value is
1788  * positive; for time zones east of Greenwich, the value is negative.
1789  * A value of -1 indicates that the time zone is undefined.
1790  *
1791  * Determine offset from GMT. If daylight saving time use altzone,
1792  * otherwise use timezone.
1793  *
1794  * The clock tick value represents a resolution of one ten-thousandth
1795  * (0.0001) second.
1796  */
1797 static int
1798 srvsvc_s_NetRemoteTOD(void *arg, ndr_xa_t *mxa)
1799 {
1800 	struct mslm_NetRemoteTOD *param = arg;
1801 	struct mslm_TIME_OF_DAY_INFO *tod;
1802 	struct timeval		time_val;
1803 	struct tm		tm;
1804 	time_t			gmtoff;
1805 
1806 
1807 	(void) gettimeofday(&time_val, 0);
1808 	(void) gmtime_r(&time_val.tv_sec, &tm);
1809 
1810 	tod = NDR_NEW(mxa, struct mslm_TIME_OF_DAY_INFO);
1811 	if (tod == NULL) {
1812 		bzero(param, sizeof (struct mslm_NetRemoteTOD));
1813 		return (ERROR_NOT_ENOUGH_MEMORY);
1814 	}
1815 
1816 	bzero(tod, sizeof (struct mslm_TIME_OF_DAY_INFO));
1817 
1818 	tod->tod_elapsedt = time_val.tv_sec;
1819 	tod->tod_msecs = time_val.tv_usec;
1820 	tod->tod_hours = tm.tm_hour;
1821 	tod->tod_mins = tm.tm_min;
1822 	tod->tod_secs = tm.tm_sec;
1823 	tod->tod_hunds = 0;
1824 	tod->tod_tinterval = 1000;
1825 	tod->tod_day = tm.tm_mday;
1826 	tod->tod_month = tm.tm_mon+1;
1827 	tod->tod_year = tm.tm_year+1900;
1828 	tod->tod_weekday = tm.tm_wday;
1829 
1830 	(void) localtime_r(&time_val.tv_sec, &tm);
1831 	gmtoff = (tm.tm_isdst) ? altzone : timezone;
1832 	tod->tod_timezone = gmtoff / SECSPERMIN;
1833 
1834 	param->bufptr = tod;
1835 	param->status = ERROR_SUCCESS;
1836 	return (NDR_DRC_OK);
1837 }
1838 
1839 /*
1840  * srvsvc_s_NetNameValidate
1841  *
1842  * Perform name validation.
1843  *
1844  * Returns Win32 error codes.
1845  */
1846 /*ARGSUSED*/
1847 static int
1848 srvsvc_s_NetNameValidate(void *arg, ndr_xa_t *mxa)
1849 {
1850 	struct mslm_NetNameValidate *param = arg;
1851 	char *name;
1852 	int maxlen;
1853 	int len;
1854 
1855 	if ((name = (char *)param->pathname) == NULL) {
1856 		param->status = ERROR_INVALID_PARAMETER;
1857 		return (NDR_DRC_OK);
1858 	}
1859 
1860 	switch (param->type) {
1861 	case NAMETYPE_SHARE:
1862 		len = strlen(name);
1863 		maxlen = (param->flags & NAMEFLAG_LM2) ?
1864 		    SMB_SHARE_OEMNAME_MAX : SMB_SHARE_NTNAME_MAX;
1865 
1866 		if (len > maxlen) {
1867 			param->status = ERROR_INVALID_NAME;
1868 			return (NDR_DRC_OK);
1869 		}
1870 
1871 		param->status = smb_name_validate_share(name);
1872 		break;
1873 
1874 	case NAMETYPE_USER:
1875 	case NAMETYPE_GROUP:
1876 		param->status = smb_name_validate_account(name);
1877 		break;
1878 
1879 	case NAMETYPE_DOMAIN:	/* NetBIOS domain name */
1880 		param->status = smb_name_validate_nbdomain(name);
1881 		break;
1882 
1883 	case NAMETYPE_WORKGROUP:
1884 		param->status = smb_name_validate_workgroup(name);
1885 		break;
1886 
1887 	case NAMETYPE_PASSWORD:
1888 	case NAMETYPE_COMPUTER:
1889 	case NAMETYPE_EVENT:
1890 	case NAMETYPE_SERVICE:
1891 	case NAMETYPE_NET:
1892 	case NAMETYPE_MESSAGE:
1893 	case NAMETYPE_MESSAGEDEST:
1894 	case NAMETYPE_SHAREPASSWORD:
1895 		param->status = ERROR_NOT_SUPPORTED;
1896 		break;
1897 
1898 	default:
1899 		param->status = ERROR_INVALID_PARAMETER;
1900 		break;
1901 	}
1902 
1903 	return (NDR_DRC_OK);
1904 }
1905 
1906 /*
1907  * srvsvc_s_NetShareAdd
1908  *
1909  * Add a new share. Only power users groups can manage shares.
1910  *
1911  * This interface is used by the rmtshare command from the NT resource
1912  * kit. Rmtshare allows a client to add or remove shares on a server
1913  * from the client's command line.
1914  *
1915  * Returns Win32 error codes.
1916  */
1917 static int
1918 srvsvc_s_NetShareAdd(void *arg, ndr_xa_t *mxa)
1919 {
1920 	static DWORD parm_err = 0;
1921 	DWORD parm_stat;
1922 	struct mslm_NetShareAdd *param = arg;
1923 	struct mslm_NetShareInfo_2 *info2;
1924 	struct mslm_NetShareInfo_502 *info502;
1925 	char realpath[MAXPATHLEN];
1926 	int32_t native_os;
1927 	uint8_t *sdbuf = NULL;
1928 	uint32_t status;
1929 	smb_share_t si;
1930 
1931 	native_os = ndr_native_os(mxa);
1932 
1933 	if (!ndr_is_poweruser(mxa)) {
1934 		bzero(param, sizeof (struct mslm_NetShareAdd));
1935 		param->status = ERROR_ACCESS_DENIED;
1936 		return (NDR_DRC_OK);
1937 	}
1938 
1939 	switch (param->level) {
1940 	case 2:
1941 		info2 = (struct mslm_NetShareInfo_2 *)param->info.un.info2;
1942 		break;
1943 
1944 	case 502:
1945 		info502 = (struct mslm_NetShareInfo_502 *)
1946 		    param->info.un.info502;
1947 		sdbuf = info502->shi502_security_descriptor;
1948 		info2 = (struct mslm_NetShareInfo_2 *)info502;
1949 		break;
1950 
1951 	default:
1952 		bzero(param, sizeof (struct mslm_NetShareAdd));
1953 		param->status = ERROR_ACCESS_DENIED;
1954 		return (NDR_DRC_OK);
1955 	}
1956 
1957 	if (info2->shi2_netname == NULL || info2->shi2_path == NULL) {
1958 		bzero(param, sizeof (struct mslm_NetShareAdd));
1959 		param->status = NERR_NetNameNotFound;
1960 		return (NDR_DRC_OK);
1961 	}
1962 
1963 	if (smb_shr_is_restricted((char *)info2->shi2_netname)) {
1964 		bzero(param, sizeof (struct mslm_NetShareAdd));
1965 		param->status = ERROR_ACCESS_DENIED;
1966 		return (NDR_DRC_OK);
1967 	}
1968 
1969 	if (info2->shi2_comment == NULL)
1970 		info2->shi2_comment = (uint8_t *)"";
1971 
1972 	/*
1973 	 * Derive the real path which will be stored in the
1974 	 * directory field of the smb_share_t structure
1975 	 * from the path field in this RPC request.
1976 	 */
1977 	parm_stat = smb_shr_get_realpath((const char *)info2->shi2_path,
1978 	    realpath, MAXPATHLEN);
1979 
1980 	if (parm_stat != NERR_Success) {
1981 		bzero(param, sizeof (struct mslm_NetShareAdd));
1982 		param->status = parm_stat;
1983 		param->parm_err
1984 		    = (native_os == NATIVE_OS_WIN95) ? 0 : &parm_err;
1985 		return (NDR_DRC_OK);
1986 	}
1987 
1988 	param->status = srvsvc_sa_add((char *)info2->shi2_netname, realpath,
1989 	    (char *)info2->shi2_comment);
1990 	if (param->status == NERR_Success) {
1991 		status = smb_shr_get((char *)info2->shi2_netname, &si);
1992 
1993 		if ((sdbuf != NULL) && (status == NERR_Success))
1994 			(void) srvsvc_sd_set(&si, sdbuf);
1995 	}
1996 	param->parm_err = (native_os == NATIVE_OS_WIN95) ? 0 : &parm_err;
1997 	return (NDR_DRC_OK);
1998 }
1999 
2000 /*
2001  * srvsvc_estimate_limit
2002  *
2003  * Estimate the number of objects that will fit in prefmaxlen.
2004  * nlimit is adjusted here.
2005  */
2006 static void
2007 srvsvc_estimate_limit(smb_svcenum_t *se, uint32_t obj_size)
2008 {
2009 	DWORD max_cnt;
2010 
2011 	if (obj_size == 0) {
2012 		se->se_nlimit = 0;
2013 		return;
2014 	}
2015 
2016 	if ((max_cnt = (se->se_prefmaxlen / obj_size)) == 0) {
2017 		se->se_nlimit = 0;
2018 		return;
2019 	}
2020 
2021 	if (se->se_ntotal > max_cnt)
2022 		se->se_nlimit = max_cnt;
2023 	else
2024 		se->se_nlimit = se->se_ntotal;
2025 }
2026 
2027 /*
2028  * srvsvc_s_NetShareEnum
2029  *
2030  * Enumerate all shares (see also NetShareEnumSticky).
2031  *
2032  * Request for various levels of information about our shares.
2033  * Level 0: share names.
2034  * Level 1: share name, share type and comment field.
2035  * Level 2: everything that we know about the shares.
2036  * Level 501: level 1 + flags.
2037  * Level 502: level 2 + security descriptor.
2038  */
2039 static int
2040 srvsvc_s_NetShareEnum(void *arg, ndr_xa_t *mxa)
2041 {
2042 	struct mslm_NetShareEnum *param = arg;
2043 	srvsvc_infonres_t *infonres;
2044 	smb_svcenum_t se;
2045 	DWORD status;
2046 
2047 	infonres = NDR_NEW(mxa, srvsvc_infonres_t);
2048 	if (infonres == NULL) {
2049 		bzero(param, sizeof (struct mslm_NetShareEnum));
2050 		param->status = ERROR_NOT_ENOUGH_MEMORY;
2051 		return (NDR_DRC_OK);
2052 	}
2053 
2054 	infonres->entriesread = 0;
2055 	infonres->entries = NULL;
2056 	param->result.level = param->level;
2057 	param->result.bufptr.p = infonres;
2058 
2059 	bzero(&se, sizeof (smb_svcenum_t));
2060 	se.se_type = SMB_SVCENUM_TYPE_SHARE;
2061 	se.se_level = param->level;
2062 	se.se_ntotal = smb_shr_count();
2063 	se.se_nlimit = se.se_ntotal;
2064 
2065 	if (param->prefmaxlen == SMB_SRVSVC_MAXPREFLEN ||
2066 	    param->prefmaxlen > SMB_SRVSVC_MAXBUFLEN)
2067 		se.se_prefmaxlen = SMB_SRVSVC_MAXBUFLEN;
2068 	else
2069 		se.se_prefmaxlen = param->prefmaxlen;
2070 
2071 	if (param->resume_handle) {
2072 		se.se_resume = *param->resume_handle;
2073 		se.se_nskip = se.se_resume;
2074 		*param->resume_handle = 0;
2075 	}
2076 
2077 	switch (param->level) {
2078 	case 0:
2079 		status = mlsvc_NetShareEnumLevel0(mxa, infonres, &se, 0);
2080 		break;
2081 
2082 	case 1:
2083 		status = mlsvc_NetShareEnumLevel1(mxa, infonres, &se, 0);
2084 		break;
2085 
2086 	case 2:
2087 		status = mlsvc_NetShareEnumLevel2(mxa, infonres, &se, 0);
2088 		break;
2089 
2090 	case 501:
2091 		status = mlsvc_NetShareEnumLevel501(mxa, infonres, &se, 0);
2092 		break;
2093 
2094 	case 502:
2095 		status = mlsvc_NetShareEnumLevel502(mxa, infonres, &se, 0);
2096 		break;
2097 
2098 	default:
2099 		status = ERROR_INVALID_LEVEL;
2100 		break;
2101 	}
2102 
2103 	if (status != 0) {
2104 		bzero(param, sizeof (struct mslm_NetShareEnum));
2105 		param->status = status;
2106 		return (NDR_DRC_OK);
2107 	}
2108 
2109 	if (se.se_nlimit == 0) {
2110 		param->status = ERROR_SUCCESS;
2111 		return (NDR_DRC_OK);
2112 	}
2113 
2114 	if (param->resume_handle &&
2115 	    param->prefmaxlen != SMB_SRVSVC_MAXPREFLEN) {
2116 		if (se.se_resume < se.se_ntotal) {
2117 			*param->resume_handle = se.se_resume;
2118 			status = ERROR_MORE_DATA;
2119 		}
2120 	}
2121 
2122 	param->totalentries = se.se_ntotal;
2123 	param->status = status;
2124 	return (NDR_DRC_OK);
2125 }
2126 
2127 /*
2128  * srvsvc_s_NetShareEnumSticky
2129  *
2130  * Enumerate sticky shares: all shares except those marked STYPE_SPECIAL.
2131  * Except for excluding STYPE_SPECIAL shares, NetShareEnumSticky is the
2132  * same as NetShareEnum.
2133  *
2134  * Request for various levels of information about our shares.
2135  * Level 0: share names.
2136  * Level 1: share name, share type and comment field.
2137  * Level 2: everything that we know about the shares.
2138  * Level 501: not valid for this request.
2139  * Level 502: level 2 + security descriptor.
2140  *
2141  * We set n_skip to resume_handle, which is used to find the appropriate
2142  * place to resume.  The resume_handle is similar to the readdir cookie.
2143  */
2144 static int
2145 srvsvc_s_NetShareEnumSticky(void *arg, ndr_xa_t *mxa)
2146 {
2147 	struct mslm_NetShareEnum *param = arg;
2148 	srvsvc_infonres_t *infonres;
2149 	smb_svcenum_t se;
2150 	DWORD status;
2151 
2152 	infonres = NDR_NEW(mxa, srvsvc_infonres_t);
2153 	if (infonres == NULL) {
2154 		bzero(param, sizeof (struct mslm_NetShareEnum));
2155 		param->status = ERROR_NOT_ENOUGH_MEMORY;
2156 		return (NDR_DRC_OK);
2157 	}
2158 
2159 	infonres->entriesread = 0;
2160 	infonres->entries = NULL;
2161 	param->result.level = param->level;
2162 	param->result.bufptr.p = infonres;
2163 
2164 	bzero(&se, sizeof (smb_svcenum_t));
2165 	se.se_type = SMB_SVCENUM_TYPE_SHARE;
2166 	se.se_level = param->level;
2167 	se.se_ntotal = smb_shr_count();
2168 	se.se_nlimit = se.se_ntotal;
2169 
2170 	if (param->prefmaxlen == SMB_SRVSVC_MAXPREFLEN ||
2171 	    param->prefmaxlen > SMB_SRVSVC_MAXBUFLEN)
2172 		se.se_prefmaxlen = SMB_SRVSVC_MAXBUFLEN;
2173 	else
2174 		se.se_prefmaxlen = param->prefmaxlen;
2175 
2176 	if (param->resume_handle) {
2177 		se.se_resume = *param->resume_handle;
2178 		se.se_nskip = se.se_resume;
2179 		*param->resume_handle = 0;
2180 	}
2181 
2182 	switch (param->level) {
2183 	case 0:
2184 		status = mlsvc_NetShareEnumLevel0(mxa, infonres, &se, 1);
2185 		break;
2186 
2187 	case 1:
2188 		status = mlsvc_NetShareEnumLevel1(mxa, infonres, &se, 1);
2189 		break;
2190 
2191 	case 2:
2192 		status = mlsvc_NetShareEnumLevel2(mxa, infonres, &se, 1);
2193 		break;
2194 
2195 	case 502:
2196 		status = mlsvc_NetShareEnumLevel502(mxa, infonres, &se, 1);
2197 		break;
2198 
2199 	case 501:
2200 	default:
2201 		status = ERROR_INVALID_LEVEL;
2202 		break;
2203 	}
2204 
2205 	if (status != ERROR_SUCCESS) {
2206 		bzero(param, sizeof (struct mslm_NetShareEnum));
2207 		param->status = status;
2208 		return (NDR_DRC_OK);
2209 	}
2210 
2211 	if (se.se_nlimit == 0) {
2212 		param->status = ERROR_SUCCESS;
2213 		return (NDR_DRC_OK);
2214 	}
2215 
2216 	if (param->resume_handle &&
2217 	    param->prefmaxlen != SMB_SRVSVC_MAXPREFLEN) {
2218 		if (se.se_resume < se.se_ntotal) {
2219 			*param->resume_handle = se.se_resume;
2220 			status = ERROR_MORE_DATA;
2221 		}
2222 	}
2223 
2224 	param->totalentries = se.se_ntotal;
2225 	param->status = status;
2226 	return (NDR_DRC_OK);
2227 }
2228 
2229 /*
2230  * NetShareEnum Level 0
2231  */
2232 static DWORD
2233 mlsvc_NetShareEnumLevel0(ndr_xa_t *mxa, srvsvc_infonres_t *infonres,
2234     smb_svcenum_t *se, int sticky)
2235 {
2236 	struct mslm_NetShareInfo_0 *info0;
2237 	smb_shriter_t iterator;
2238 	smb_share_t *si;
2239 	DWORD status;
2240 
2241 	srvsvc_estimate_limit(se,
2242 	    sizeof (struct mslm_NetShareInfo_0) + MAXNAMELEN);
2243 	if (se->se_nlimit == 0)
2244 		return (ERROR_SUCCESS);
2245 
2246 	info0 = NDR_NEWN(mxa, struct mslm_NetShareInfo_0, se->se_nlimit);
2247 	if (info0 == NULL)
2248 		return (ERROR_NOT_ENOUGH_MEMORY);
2249 
2250 	smb_shr_iterinit(&iterator);
2251 
2252 	se->se_nitems = 0;
2253 	while ((si = smb_shr_iterate(&iterator)) != NULL) {
2254 		if (se->se_nskip > 0) {
2255 			--se->se_nskip;
2256 			continue;
2257 		}
2258 
2259 		++se->se_resume;
2260 
2261 		if (sticky && (si->shr_flags & SMB_SHRF_TRANS))
2262 			continue;
2263 
2264 		if (si->shr_flags & SMB_SHRF_AUTOHOME)
2265 			continue;
2266 
2267 		if (se->se_nitems >= se->se_nlimit) {
2268 			se->se_nitems = se->se_nlimit;
2269 			break;
2270 		}
2271 
2272 		status = mlsvc_NetShareEnumCommon(mxa, se, si, (void *)info0);
2273 		if (status != ERROR_SUCCESS)
2274 			break;
2275 
2276 		++se->se_nitems;
2277 	}
2278 
2279 	if (se->se_nitems < se->se_nlimit) {
2280 		if (srvsvc_add_autohome(mxa, se, (void *)info0))
2281 			++se->se_nitems;
2282 	}
2283 
2284 	infonres->entriesread = se->se_nitems;
2285 	infonres->entries = info0;
2286 	return (ERROR_SUCCESS);
2287 }
2288 
2289 /*
2290  * NetShareEnum Level 1
2291  */
2292 static DWORD
2293 mlsvc_NetShareEnumLevel1(ndr_xa_t *mxa, srvsvc_infonres_t *infonres,
2294     smb_svcenum_t *se, int sticky)
2295 {
2296 	struct mslm_NetShareInfo_1 *info1;
2297 	smb_shriter_t iterator;
2298 	smb_share_t *si;
2299 	DWORD status;
2300 
2301 	srvsvc_estimate_limit(se,
2302 	    sizeof (struct mslm_NetShareInfo_1) + MAXNAMELEN);
2303 	if (se->se_nlimit == 0)
2304 		return (ERROR_SUCCESS);
2305 
2306 	info1 = NDR_NEWN(mxa, struct mslm_NetShareInfo_1, se->se_nlimit);
2307 	if (info1 == NULL)
2308 		return (ERROR_NOT_ENOUGH_MEMORY);
2309 
2310 	smb_shr_iterinit(&iterator);
2311 
2312 	se->se_nitems = 0;
2313 	while ((si = smb_shr_iterate(&iterator)) != 0) {
2314 		if (se->se_nskip > 0) {
2315 			--se->se_nskip;
2316 			continue;
2317 		}
2318 
2319 		++se->se_resume;
2320 
2321 		if (sticky && (si->shr_flags & SMB_SHRF_TRANS))
2322 			continue;
2323 
2324 		if (si->shr_flags & SMB_SHRF_AUTOHOME)
2325 			continue;
2326 
2327 		if (se->se_nitems >= se->se_nlimit) {
2328 			se->se_nitems = se->se_nlimit;
2329 			break;
2330 		}
2331 
2332 		status = mlsvc_NetShareEnumCommon(mxa, se, si, (void *)info1);
2333 		if (status != ERROR_SUCCESS)
2334 			break;
2335 
2336 		++se->se_nitems;
2337 	}
2338 
2339 	if (se->se_nitems < se->se_nlimit) {
2340 		if (srvsvc_add_autohome(mxa, se, (void *)info1))
2341 			++se->se_nitems;
2342 	}
2343 
2344 	infonres->entriesread = se->se_nitems;
2345 	infonres->entries = info1;
2346 	return (ERROR_SUCCESS);
2347 }
2348 
2349 /*
2350  * NetShareEnum Level 2
2351  */
2352 static DWORD
2353 mlsvc_NetShareEnumLevel2(ndr_xa_t *mxa, srvsvc_infonres_t *infonres,
2354     smb_svcenum_t *se, int sticky)
2355 {
2356 	struct mslm_NetShareInfo_2 *info2;
2357 	smb_shriter_t iterator;
2358 	smb_share_t *si;
2359 	DWORD status;
2360 
2361 	srvsvc_estimate_limit(se,
2362 	    sizeof (struct mslm_NetShareInfo_2) + MAXNAMELEN);
2363 	if (se->se_nlimit == 0)
2364 		return (ERROR_SUCCESS);
2365 
2366 	info2 = NDR_NEWN(mxa, struct mslm_NetShareInfo_2, se->se_nlimit);
2367 	if (info2 == NULL)
2368 		return (ERROR_NOT_ENOUGH_MEMORY);
2369 
2370 	smb_shr_iterinit(&iterator);
2371 
2372 	se->se_nitems = 0;
2373 	while ((si = smb_shr_iterate(&iterator)) != 0) {
2374 		if (se->se_nskip > 0) {
2375 			--se->se_nskip;
2376 			continue;
2377 		}
2378 
2379 		++se->se_resume;
2380 
2381 		if (sticky && (si->shr_flags & SMB_SHRF_TRANS))
2382 			continue;
2383 
2384 		if (si->shr_flags & SMB_SHRF_AUTOHOME)
2385 			continue;
2386 
2387 		if (se->se_nitems >= se->se_nlimit) {
2388 			se->se_nitems = se->se_nlimit;
2389 			break;
2390 		}
2391 
2392 		status = mlsvc_NetShareEnumCommon(mxa, se, si, (void *)info2);
2393 		if (status != ERROR_SUCCESS)
2394 			break;
2395 
2396 		++se->se_nitems;
2397 	}
2398 
2399 	if (se->se_nitems < se->se_nlimit) {
2400 		if (srvsvc_add_autohome(mxa, se, (void *)info2))
2401 			++se->se_nitems;
2402 	}
2403 
2404 	infonres->entriesread = se->se_nitems;
2405 	infonres->entries = info2;
2406 	return (ERROR_SUCCESS);
2407 }
2408 
2409 /*
2410  * NetShareEnum Level 501
2411  */
2412 static DWORD
2413 mlsvc_NetShareEnumLevel501(ndr_xa_t *mxa, srvsvc_infonres_t *infonres,
2414     smb_svcenum_t *se, int sticky)
2415 {
2416 	struct mslm_NetShareInfo_501 *info501;
2417 	smb_shriter_t iterator;
2418 	smb_share_t *si;
2419 	DWORD status;
2420 
2421 	srvsvc_estimate_limit(se,
2422 	    sizeof (struct mslm_NetShareInfo_501) + MAXNAMELEN);
2423 	if (se->se_nlimit == 0)
2424 		return (ERROR_SUCCESS);
2425 
2426 	info501 = NDR_NEWN(mxa, struct mslm_NetShareInfo_501,
2427 	    se->se_nlimit);
2428 	if (info501 == NULL)
2429 		return (ERROR_NOT_ENOUGH_MEMORY);
2430 
2431 	smb_shr_iterinit(&iterator);
2432 
2433 	se->se_nitems = 0;
2434 	while ((si = smb_shr_iterate(&iterator)) != 0) {
2435 		if (se->se_nskip > 0) {
2436 			--se->se_nskip;
2437 			continue;
2438 		}
2439 
2440 		++se->se_resume;
2441 
2442 		if (sticky && (si->shr_flags & SMB_SHRF_TRANS))
2443 			continue;
2444 
2445 		if (si->shr_flags & SMB_SHRF_AUTOHOME)
2446 			continue;
2447 
2448 		if (se->se_nitems >= se->se_nlimit) {
2449 			se->se_nitems = se->se_nlimit;
2450 			break;
2451 		}
2452 
2453 		status = mlsvc_NetShareEnumCommon(mxa, se, si, (void *)info501);
2454 		if (status != ERROR_SUCCESS)
2455 			break;
2456 
2457 		++se->se_nitems;
2458 	}
2459 
2460 	if (se->se_nitems < se->se_nlimit) {
2461 		if (srvsvc_add_autohome(mxa, se, (void *)info501))
2462 			++se->se_nitems;
2463 	}
2464 
2465 	infonres->entriesread = se->se_nitems;
2466 	infonres->entries = info501;
2467 	return (ERROR_SUCCESS);
2468 }
2469 
2470 /*
2471  * NetShareEnum Level 502
2472  */
2473 static DWORD
2474 mlsvc_NetShareEnumLevel502(ndr_xa_t *mxa, srvsvc_infonres_t *infonres,
2475     smb_svcenum_t *se, int sticky)
2476 {
2477 	struct mslm_NetShareInfo_502 *info502;
2478 	smb_shriter_t iterator;
2479 	smb_share_t *si;
2480 	DWORD status;
2481 
2482 	srvsvc_estimate_limit(se,
2483 	    sizeof (struct mslm_NetShareInfo_502) + MAXNAMELEN);
2484 	if (se->se_nlimit == 0)
2485 		return (ERROR_SUCCESS);
2486 
2487 	info502 = NDR_NEWN(mxa, struct mslm_NetShareInfo_502,
2488 	    se->se_nlimit);
2489 	if (info502 == NULL)
2490 		return (ERROR_NOT_ENOUGH_MEMORY);
2491 
2492 	smb_shr_iterinit(&iterator);
2493 
2494 	se->se_nitems = 0;
2495 	while ((si = smb_shr_iterate(&iterator)) != NULL) {
2496 		if (se->se_nskip > 0) {
2497 			--se->se_nskip;
2498 			continue;
2499 		}
2500 
2501 		++se->se_resume;
2502 
2503 		if (sticky && (si->shr_flags & SMB_SHRF_TRANS))
2504 			continue;
2505 
2506 		if (si->shr_flags & SMB_SHRF_AUTOHOME)
2507 			continue;
2508 
2509 		if (se->se_nitems >= se->se_nlimit) {
2510 			se->se_nitems = se->se_nlimit;
2511 			break;
2512 		}
2513 
2514 		status = mlsvc_NetShareEnumCommon(mxa, se, si, (void *)info502);
2515 		if (status != ERROR_SUCCESS)
2516 			break;
2517 
2518 		++se->se_nitems;
2519 	}
2520 
2521 	if (se->se_nitems < se->se_nlimit) {
2522 		if (srvsvc_add_autohome(mxa, se, (void *)info502))
2523 			++se->se_nitems;
2524 	}
2525 
2526 	infonres->entriesread = se->se_nitems;
2527 	infonres->entries = info502;
2528 	return (ERROR_SUCCESS);
2529 }
2530 
2531 /*
2532  * mlsvc_NetShareEnumCommon
2533  *
2534  * Build the levels 0, 1, 2, 501 and 502 share information. This function
2535  * is called by the various NetShareEnum levels for each share. If
2536  * we cannot build the share data for some reason, we return an error
2537  * but the actual value of the error is not important to the caller.
2538  * The caller just needs to know not to include this info in the RPC
2539  * response.
2540  *
2541  * Returns:
2542  *	ERROR_SUCCESS
2543  *	ERROR_NOT_ENOUGH_MEMORY
2544  *	ERROR_INVALID_LEVEL
2545  */
2546 static DWORD
2547 mlsvc_NetShareEnumCommon(ndr_xa_t *mxa, smb_svcenum_t *se,
2548     smb_share_t *si, void *infop)
2549 {
2550 	struct mslm_NetShareInfo_0 *info0;
2551 	struct mslm_NetShareInfo_1 *info1;
2552 	struct mslm_NetShareInfo_2 *info2;
2553 	struct mslm_NetShareInfo_501 *info501;
2554 	struct mslm_NetShareInfo_502 *info502;
2555 	srvsvc_sd_t sd;
2556 	uint8_t *netname;
2557 	uint8_t *comment;
2558 	uint8_t *passwd;
2559 	uint8_t *path;
2560 	int i = se->se_nitems;
2561 
2562 	netname = (uint8_t *)NDR_STRDUP(mxa, si->shr_name);
2563 	comment = (uint8_t *)NDR_STRDUP(mxa, si->shr_cmnt);
2564 	passwd = (uint8_t *)NDR_STRDUP(mxa, empty_string);
2565 	path = (uint8_t *)srvsvc_share_mkpath(mxa, si->shr_path);
2566 
2567 	if (!netname || !comment || !passwd || !path)
2568 		return (ERROR_NOT_ENOUGH_MEMORY);
2569 
2570 	switch (se->se_level) {
2571 	case 0:
2572 		info0 = (struct mslm_NetShareInfo_0 *)infop;
2573 		info0[i].shi0_netname = netname;
2574 		break;
2575 
2576 	case 1:
2577 		info1 = (struct mslm_NetShareInfo_1 *)infop;
2578 		info1[i].shi1_netname = netname;
2579 		info1[i].shi1_comment = comment;
2580 		info1[i].shi1_type = si->shr_type;
2581 		break;
2582 
2583 	case 2:
2584 		info2 = (struct mslm_NetShareInfo_2 *)infop;
2585 		info2[i].shi2_netname = netname;
2586 		info2[i].shi2_comment = comment;
2587 		info2[i].shi2_path = path;
2588 		info2[i].shi2_type = si->shr_type;
2589 		info2[i].shi2_permissions = 0;
2590 		info2[i].shi2_max_uses = SHI_USES_UNLIMITED;
2591 		info2[i].shi2_current_uses = 0;
2592 		info2[i].shi2_passwd = passwd;
2593 		break;
2594 
2595 	case 501:
2596 		info501 = (struct mslm_NetShareInfo_501 *)infop;
2597 		info501[i].shi501_netname = netname;
2598 		info501[i].shi501_comment = comment;
2599 		info501[i].shi501_type = si->shr_type;
2600 		info501[i].shi501_flags = srvsvc_get_share_flags(si);
2601 		break;
2602 
2603 	case 502:
2604 		info502 = (struct mslm_NetShareInfo_502 *)infop;
2605 		info502[i].shi502_netname = netname;
2606 		info502[i].shi502_comment = comment;
2607 		info502[i].shi502_path = path;
2608 		info502[i].shi502_type = si->shr_type;
2609 		info502[i].shi502_permissions = 0;
2610 		info502[i].shi502_max_uses = SHI_USES_UNLIMITED;
2611 		info502[i].shi502_current_uses = 0;
2612 		info502[i].shi502_passwd = passwd;
2613 
2614 		if (srvsvc_share_getsd(mxa, si, &sd) == ERROR_SUCCESS) {
2615 			info502[i].shi502_reserved = sd.sd_size;
2616 			info502[i].shi502_security_descriptor = sd.sd_buf;
2617 		} else {
2618 			info502[i].shi502_reserved = 0;
2619 			info502[i].shi502_security_descriptor = NULL;
2620 		}
2621 
2622 		break;
2623 
2624 	default:
2625 		return (ERROR_INVALID_LEVEL);
2626 	}
2627 
2628 	return (ERROR_SUCCESS);
2629 }
2630 
2631 /*
2632  * srvsvc_add_autohome
2633  *
2634  * Add the autohome share for the user. The share must not be a permanent
2635  * share to avoid duplicates.
2636  */
2637 static boolean_t
2638 srvsvc_add_autohome(ndr_xa_t *mxa, smb_svcenum_t *se, void *infop)
2639 {
2640 	smb_netuserinfo_t *user = &mxa->pipe->np_user;
2641 	char *username = user->ui_account;
2642 	smb_share_t si;
2643 	DWORD status;
2644 
2645 	if (smb_shr_get(username, &si) != NERR_Success)
2646 		return (B_FALSE);
2647 
2648 	if ((si.shr_flags & SMB_SHRF_AUTOHOME) == 0)
2649 		return (B_FALSE);
2650 
2651 	status = mlsvc_NetShareEnumCommon(mxa, se, &si, infop);
2652 	return (status == ERROR_SUCCESS);
2653 }
2654 
2655 /*
2656  * srvsvc_share_mkpath
2657  *
2658  * Create the share path required by the share enum calls. The path
2659  * is created in a heap buffer ready for use by the caller.
2660  *
2661  * Some Windows over-the-wire backup applications do not work unless a
2662  * drive letter is present in the share path.  We don't care about the
2663  * drive letter since the path is fully qualified with the volume name.
2664  *
2665  * Windows clients seem to be mostly okay with forward slashes in
2666  * share paths but they cannot handle one immediately after the drive
2667  * letter, i.e. B:/.  For consistency we convert all the slashes in
2668  * the path.
2669  *
2670  * Returns a pointer to a heap buffer containing the share path, which
2671  * could be a null pointer if the heap allocation fails.
2672  */
2673 static char *
2674 srvsvc_share_mkpath(ndr_xa_t *mxa, char *path)
2675 {
2676 	char tmpbuf[MAXPATHLEN];
2677 	char *p;
2678 
2679 	if (strlen(path) == 0)
2680 		return (NDR_STRDUP(mxa, path));
2681 
2682 	/*
2683 	 * Strip the volume name from the path (/vol1/home -> /home).
2684 	 */
2685 	p = path;
2686 	p += strspn(p, "/");
2687 	p += strcspn(p, "/");
2688 	p += strspn(p, "/");
2689 	(void) snprintf(tmpbuf, MAXPATHLEN, "%c:/%s", 'B', p);
2690 	(void) strsubst(tmpbuf, '/', '\\');
2691 
2692 	return (NDR_STRDUP(mxa, tmpbuf));
2693 }
2694 
2695 static int
2696 srvsvc_s_NetShareCheck(void *arg, ndr_xa_t *mxa)
2697 {
2698 	struct mslm_NetShareCheck *param = arg;
2699 	smb_shriter_t iterator;
2700 	smb_share_t *si;
2701 	char *path;
2702 
2703 	if (param->path == NULL) {
2704 		param->stype = STYPE_DISKTREE;
2705 		param->status = NERR_NetNameNotFound;
2706 		return (NDR_DRC_OK);
2707 	}
2708 
2709 	(void) strsubst((char *)param->path, '/', '\\');
2710 
2711 	smb_shr_iterinit(&iterator);
2712 
2713 	while ((si = smb_shr_iterate(&iterator)) != NULL) {
2714 		path = srvsvc_share_mkpath(mxa, si->shr_path);
2715 
2716 		if (smb_strcasecmp(path, (char *)param->path, 0) == 0) {
2717 			param->stype = (si->shr_type & STYPE_MASK);
2718 			param->status = NERR_Success;
2719 			return (NDR_DRC_OK);
2720 		}
2721 	}
2722 
2723 	param->stype = STYPE_DISKTREE;
2724 	param->status = NERR_NetNameNotFound;
2725 	return (NDR_DRC_OK);
2726 }
2727 
2728 /*
2729  * srvsvc_s_NetShareDel
2730  *
2731  * Delete a share.  Only members of the Administrators, Server Operators
2732  * or Power Users local groups are allowed to delete shares.
2733  *
2734  * This interface is used by the rmtshare command from the NT resource
2735  * kit. Rmtshare allows a client to add or remove shares on a server
2736  * from the client's command line.
2737  *
2738  * Returns Win32 error codes.
2739  */
2740 static int
2741 srvsvc_s_NetShareDel(void *arg, ndr_xa_t *mxa)
2742 {
2743 	struct mslm_NetShareDel *param = arg;
2744 
2745 	if (!ndr_is_poweruser(mxa) ||
2746 	    smb_shr_is_restricted((char *)param->netname)) {
2747 		param->status = ERROR_ACCESS_DENIED;
2748 		return (NDR_DRC_OK);
2749 	}
2750 
2751 	param->status = srvsvc_sa_delete((char *)param->netname);
2752 	return (NDR_DRC_OK);
2753 }
2754 
2755 /*
2756  * srvsvc_s_NetGetFileSecurity
2757  *
2758  * Get security descriptor of the requested file/folder
2759  *
2760  * Right now, just returns ERROR_ACCESS_DENIED, because we cannot
2761  * get the requested SD here in RPC code.
2762  */
2763 /*ARGSUSED*/
2764 static int
2765 srvsvc_s_NetGetFileSecurity(void *arg, ndr_xa_t *mxa)
2766 {
2767 	struct mslm_NetGetFileSecurity *param = arg;
2768 
2769 	param->length = 0;
2770 	param->status = ERROR_ACCESS_DENIED;
2771 	return (NDR_DRC_OK);
2772 }
2773 
2774 /*
2775  * srvsvc_s_NetSetFileSecurity
2776  *
2777  * Set the given security descriptor for the requested file/folder
2778  *
2779  * Right now, just returns ERROR_ACCESS_DENIED, because we cannot
2780  * set the requested SD here in RPC code.
2781  */
2782 /*ARGSUSED*/
2783 static int
2784 srvsvc_s_NetSetFileSecurity(void *arg, ndr_xa_t *mxa)
2785 {
2786 	struct mslm_NetSetFileSecurity *param = arg;
2787 
2788 	param->status = ERROR_ACCESS_DENIED;
2789 	return (NDR_DRC_OK);
2790 }
2791 
2792 /*
2793  * If the default "smb" share group exists then return the group
2794  * handle, otherwise create the group and return the handle.
2795  *
2796  * All shares created via the srvsvc will be added to the "smb"
2797  * group.
2798  */
2799 static sa_group_t
2800 srvsvc_sa_get_smbgrp(sa_handle_t handle)
2801 {
2802 	sa_group_t group = NULL;
2803 	int err;
2804 
2805 	group = sa_get_group(handle, SMB_DEFAULT_SHARE_GROUP);
2806 	if (group != NULL)
2807 		return (group);
2808 
2809 	group = sa_create_group(handle, SMB_DEFAULT_SHARE_GROUP, &err);
2810 	if (group == NULL)
2811 		return (NULL);
2812 
2813 	if (sa_create_optionset(group, SMB_DEFAULT_SHARE_GROUP) == NULL) {
2814 		(void) sa_remove_group(group);
2815 		group = NULL;
2816 	}
2817 
2818 	return (group);
2819 }
2820 
2821 /*
2822  * Stores the given share in sharemgr
2823  */
2824 static uint32_t
2825 srvsvc_sa_add(char *sharename, char *path, char *cmnt)
2826 {
2827 	sa_handle_t handle;
2828 	sa_share_t share;
2829 	sa_group_t group;
2830 	sa_resource_t resource;
2831 	boolean_t new_share = B_FALSE;
2832 	uint32_t status = NERR_Success;
2833 	int err;
2834 
2835 	if ((handle = smb_shr_sa_enter()) == NULL)
2836 		return (NERR_InternalError);
2837 
2838 	share = sa_find_share(handle, path);
2839 	if (share == NULL) {
2840 		group = srvsvc_sa_get_smbgrp(handle);
2841 		if (group == NULL) {
2842 			smb_shr_sa_exit();
2843 			return (NERR_InternalError);
2844 		}
2845 
2846 		share = sa_add_share(group, path, SA_SHARE_PERMANENT, &err);
2847 		if (share == NULL) {
2848 			smb_shr_sa_exit();
2849 			return (NERR_InternalError);
2850 		}
2851 		new_share = B_TRUE;
2852 	}
2853 
2854 	resource = sa_get_share_resource(share, sharename);
2855 	if (resource == NULL) {
2856 		resource = sa_add_resource(share, sharename,
2857 		    SA_SHARE_PERMANENT, &err);
2858 		if (resource == NULL) {
2859 			if (new_share)
2860 				(void) sa_remove_share(share);
2861 			smb_shr_sa_exit();
2862 			return (NERR_InternalError);
2863 		}
2864 	}
2865 
2866 	(void) sa_set_resource_description(resource, cmnt);
2867 
2868 	smb_shr_sa_exit();
2869 	return (status);
2870 }
2871 
2872 /*
2873  * Removes the share from sharemgr
2874  */
2875 static uint32_t
2876 srvsvc_sa_delete(char *sharename)
2877 {
2878 	sa_handle_t handle;
2879 	sa_resource_t resource;
2880 	uint32_t status;
2881 
2882 	if ((handle = smb_shr_sa_enter()) == NULL)
2883 		return (NERR_InternalError);
2884 
2885 	status = NERR_InternalError;
2886 	if ((resource = sa_find_resource(handle, sharename)) != NULL) {
2887 		if (sa_remove_resource(resource) == SA_OK)
2888 			status = NERR_Success;
2889 	}
2890 
2891 	smb_shr_sa_exit();
2892 	return (status);
2893 }
2894 
2895 /*
2896  * Update the share information.
2897  */
2898 static uint32_t
2899 srvsvc_sa_modify(smb_share_t *si, srvsvc_netshare_setinfo_t *info)
2900 {
2901 	sa_handle_t handle;
2902 	sa_share_t share;
2903 	sa_resource_t resource;
2904 	boolean_t renamed = B_FALSE;
2905 	uint32_t nerr = NERR_Success;
2906 
2907 	if ((handle = smb_shr_sa_enter()) == NULL)
2908 		return (NERR_InternalError);
2909 
2910 	if ((share = sa_find_share(handle, si->shr_path)) == NULL) {
2911 		smb_shr_sa_exit();
2912 		return (NERR_InternalError);
2913 	}
2914 
2915 	if ((resource = sa_get_share_resource(share, si->shr_name)) == NULL) {
2916 		smb_shr_sa_exit();
2917 		return (NERR_InternalError);
2918 	}
2919 
2920 	if (info->nss_netname != NULL && info->nss_netname[0] != '\0' &&
2921 	    smb_strcasecmp(info->nss_netname, si->shr_name, 0) != 0) {
2922 		(void) sa_set_resource_attr(resource, SHOPT_NAME,
2923 		    info->nss_netname);
2924 		renamed = B_TRUE;
2925 	}
2926 
2927 	if ((info->nss_comment != NULL) &&
2928 	    (strcmp(info->nss_comment, si->shr_cmnt) != 0)) {
2929 		(void) sa_set_resource_description(resource, info->nss_comment);
2930 		(void) strlcpy(si->shr_cmnt, info->nss_comment,
2931 		    SMB_SHARE_CMNT_MAX);
2932 	}
2933 
2934 	smb_shr_sa_exit();
2935 
2936 	if (renamed) {
2937 		nerr = smb_shr_rename(si->shr_name, info->nss_netname);
2938 		if (nerr != NERR_Success)
2939 			return (nerr);
2940 
2941 		(void) strlcpy(si->shr_name, info->nss_netname, MAXNAMELEN);
2942 	}
2943 
2944 	return (nerr);
2945 }
2946 
2947 /*
2948  * Update the share properties.
2949  *
2950  * Updates the optionset properties of the share resource.
2951  * The properties are given as a list of name-value pair.
2952  * The name argument should be the optionset property name and the value
2953  * should be a valid value for the specified property.
2954  */
2955 static uint32_t
2956 srvsvc_sa_setprop(smb_share_t *si, nvlist_t *nvl)
2957 {
2958 	sa_handle_t handle;
2959 	sa_share_t share;
2960 	sa_resource_t resource;
2961 	sa_property_t prop;
2962 	sa_optionset_t opts;
2963 	uint32_t nerr = NERR_Success;
2964 	nvpair_t *cur;
2965 	int err = 0;
2966 	char *name, *val;
2967 
2968 	if ((handle = smb_shr_sa_enter()) == NULL)
2969 		return (NERR_InternalError);
2970 
2971 	if ((share = sa_find_share(handle, si->shr_path)) == NULL) {
2972 		smb_shr_sa_exit();
2973 		return (NERR_InternalError);
2974 	}
2975 
2976 	if ((resource = sa_get_share_resource(share, si->shr_name)) == NULL) {
2977 		smb_shr_sa_exit();
2978 		return (NERR_InternalError);
2979 	}
2980 
2981 	if ((opts = sa_get_optionset(resource, SMB_PROTOCOL_NAME)) == NULL) {
2982 		opts = sa_create_optionset(resource, SMB_PROTOCOL_NAME);
2983 		if (opts == NULL) {
2984 			smb_shr_sa_exit();
2985 			return (NERR_InternalError);
2986 		}
2987 	}
2988 
2989 	cur = nvlist_next_nvpair(nvl, NULL);
2990 	while (cur != NULL) {
2991 		name = nvpair_name(cur);
2992 		err = nvpair_value_string(cur, &val);
2993 		if ((err != 0) || (name == NULL) || (val == NULL)) {
2994 			nerr = NERR_InternalError;
2995 			break;
2996 		}
2997 
2998 		prop = NULL;
2999 		if ((prop = sa_get_property(opts, name)) == NULL) {
3000 			prop = sa_create_property(name, val);
3001 			if (prop != NULL) {
3002 				nerr = sa_valid_property(handle, opts,
3003 				    SMB_PROTOCOL_NAME, prop);
3004 				if (nerr != NERR_Success) {
3005 					(void) sa_remove_property(prop);
3006 					break;
3007 				}
3008 			}
3009 			nerr = sa_add_property(opts, prop);
3010 			if (nerr != NERR_Success)
3011 				break;
3012 		} else {
3013 			nerr = sa_update_property(prop, val);
3014 			if (nerr != NERR_Success)
3015 				break;
3016 		}
3017 
3018 		cur = nvlist_next_nvpair(nvl, cur);
3019 	}
3020 
3021 	if (nerr == NERR_Success)
3022 		nerr = sa_commit_properties(opts, 0);
3023 
3024 	smb_shr_sa_exit();
3025 	return (nerr);
3026 }
3027 
3028 
3029 static ndr_stub_table_t srvsvc_stub_table[] = {
3030 	{ srvsvc_s_NetConnectEnum,	SRVSVC_OPNUM_NetConnectEnum },
3031 	{ srvsvc_s_NetFileEnum,		SRVSVC_OPNUM_NetFileEnum },
3032 	{ srvsvc_s_NetFileClose,	SRVSVC_OPNUM_NetFileClose },
3033 	{ srvsvc_s_NetShareGetInfo,	SRVSVC_OPNUM_NetShareGetInfo },
3034 	{ srvsvc_s_NetShareSetInfo,	SRVSVC_OPNUM_NetShareSetInfo },
3035 	{ srvsvc_s_NetSessionEnum,	SRVSVC_OPNUM_NetSessionEnum },
3036 	{ srvsvc_s_NetSessionDel,	SRVSVC_OPNUM_NetSessionDel },
3037 	{ srvsvc_s_NetServerGetInfo,	SRVSVC_OPNUM_NetServerGetInfo },
3038 	{ srvsvc_s_NetRemoteTOD,	SRVSVC_OPNUM_NetRemoteTOD },
3039 	{ srvsvc_s_NetNameValidate,	SRVSVC_OPNUM_NetNameValidate },
3040 	{ srvsvc_s_NetShareAdd,		SRVSVC_OPNUM_NetShareAdd },
3041 	{ srvsvc_s_NetShareDel,		SRVSVC_OPNUM_NetShareDel },
3042 	{ srvsvc_s_NetShareEnum,	SRVSVC_OPNUM_NetShareEnum },
3043 	{ srvsvc_s_NetShareEnumSticky,	SRVSVC_OPNUM_NetShareEnumSticky },
3044 	{ srvsvc_s_NetShareCheck,	SRVSVC_OPNUM_NetShareCheck },
3045 	{ srvsvc_s_NetGetFileSecurity,	SRVSVC_OPNUM_NetGetFileSecurity },
3046 	{ srvsvc_s_NetSetFileSecurity,	SRVSVC_OPNUM_NetSetFileSecurity },
3047 	{0}
3048 };
3049