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