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