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