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