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