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