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