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