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