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