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 <tzfile.h>
40 #include <time.h>
41 #include <thread.h>
42 #include <ctype.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <sys/types.h>
46 #include <sys/socket.h>
47 #include <netinet/in.h>
48 #include <arpa/inet.h>
49 #include <libshare.h>
50 
51 #include <smbsrv/libsmb.h>
52 #include <smbsrv/libmlsvc.h>
53 #include <smbsrv/lmerr.h>
54 #include <smbsrv/nterror.h>
55 #include <smbsrv/nmpipes.h>
56 #include <smbsrv/cifs.h>
57 #include <smbsrv/netrauth.h>
58 #include <smbsrv/ndl/srvsvc.ndl>
59 #include <smbsrv/smb_common_door.h>
60 
61 #define	SV_TYPE_SENT_BY_ME (SV_TYPE_WORKSTATION | SV_TYPE_SERVER | SV_TYPE_NT)
62 
63 /*
64  * Qualifier types for NetConnectEnum.
65  */
66 #define	SRVSVC_CONNECT_ENUM_NULL	0
67 #define	SRVSVC_CONNECT_ENUM_SHARE	1
68 #define	SRVSVC_CONNECT_ENUM_WKSTN	2
69 
70 #define	SMB_SRVSVC_MAXBUFLEN	(8 * 1024 * 1024)
71 #define	SMB_SRVSVC_MAXPREFLEN	((uint32_t)(-1))
72 
73 /*
74  * prefmaxlen:    Client specified response buffer limit.
75  * resume_handle: Cookie used to track enumeration across multiple calls.
76  * n_total:       Total number of entries.
77  * n_enum:        Number of entries to enumerate (derived from prefmaxlen).
78  * n_skip:        Number of entries to skip (from incoming resume handle).
79  * n_read:        Number of objects returned for current enumeration request.
80  */
81 typedef struct srvsvc_enum {
82 	uint32_t se_level;
83 	uint32_t se_prefmaxlen;
84 	uint32_t se_resume_handle;
85 	uint32_t se_n_total;
86 	uint32_t se_n_enum;
87 	uint32_t se_n_skip;
88 	uint32_t se_n_read;
89 } srvsvc_enum_t;
90 
91 static DWORD srvsvc_s_NetConnectEnumLevel0(ndr_xa_t *,
92     srvsvc_NetConnectInfo0_t *);
93 static DWORD srvsvc_s_NetConnectEnumLevel1(ndr_xa_t *,
94     srvsvc_NetConnectInfo1_t *);
95 
96 static DWORD srvsvc_NetFileEnum2(ndr_xa_t *,
97     struct mslm_NetFileEnum *);
98 static DWORD srvsvc_NetFileEnum3(ndr_xa_t *,
99     struct mslm_NetFileEnum *);
100 
101 static DWORD mlsvc_NetSessionEnumLevel0(struct mslm_infonres *, DWORD,
102     ndr_xa_t *);
103 static DWORD mlsvc_NetSessionEnumLevel1(struct mslm_infonres *, DWORD,
104     ndr_xa_t *);
105 
106 static DWORD mlsvc_NetShareEnumLevel0(ndr_xa_t *,
107     struct mslm_infonres *, srvsvc_enum_t *, int);
108 static DWORD mlsvc_NetShareEnumLevel1(ndr_xa_t *,
109     struct mslm_infonres *, srvsvc_enum_t *, int);
110 static DWORD mlsvc_NetShareEnumLevel2(ndr_xa_t *,
111     struct mslm_infonres *, srvsvc_enum_t *, int);
112 static DWORD mlsvc_NetShareEnumLevel501(ndr_xa_t *,
113     struct mslm_infonres *, srvsvc_enum_t *, int);
114 static DWORD mlsvc_NetShareEnumLevel502(ndr_xa_t *,
115     struct mslm_infonres *, srvsvc_enum_t *, int);
116 static DWORD mlsvc_NetShareEnumCommon(ndr_xa_t *,
117     srvsvc_enum_t *, smb_share_t *, void *);
118 static boolean_t srvsvc_add_autohome(ndr_xa_t *, srvsvc_enum_t *,
119     void *);
120 static char *srvsvc_share_mkpath(ndr_xa_t *, char *);
121 
122 static int srvsvc_netconnect_qualifier(const char *);
123 static uint32_t srvsvc_estimate_objcnt(uint32_t, uint32_t, uint32_t);
124 
125 static uint32_t srvsvc_sa_add(char *, char *, char *);
126 static uint32_t srvsvc_sa_delete(char *);
127 
128 static char empty_string[1];
129 
130 static ndr_stub_table_t srvsvc_stub_table[];
131 
132 static ndr_service_t srvsvc_service = {
133 	"SRVSVC",			/* name */
134 	"Server services",		/* desc */
135 	"\\srvsvc",			/* endpoint */
136 	PIPE_NTSVCS,			/* sec_addr_port */
137 	"4b324fc8-1670-01d3-1278-5a47bf6ee188", 3,	/* abstract */
138 	NDR_TRANSFER_SYNTAX_UUID,		2,	/* transfer */
139 	0,				/* no bind_instance_size */
140 	0,				/* no bind_req() */
141 	0,				/* no unbind_and_close() */
142 	0,				/* use generic_call_stub() */
143 	&TYPEINFO(srvsvc_interface),	/* interface ti */
144 	srvsvc_stub_table		/* stub_table */
145 };
146 
147 /*
148  * srvsvc_initialize
149  *
150  * This function registers the SRVSVC RPC interface with the RPC runtime
151  * library. It must be called in order to use either the client side
152  * or the server side functions.
153  */
154 void
155 srvsvc_initialize(void)
156 {
157 	(void) ndr_svc_register(&srvsvc_service);
158 }
159 
160 /*
161  * srvsvc_s_NetConnectEnum
162  *
163  * List tree connections made to a share on this server or all tree
164  * connections established from a specific client.  Administrator,
165  * Server Operator, Print Operator or Power User group membership
166  * is required to use this interface.
167  *
168  * There are three information levels:  0, 1, and 50.  We don't support
169  * level 50, which is only used by Windows 9x clients.
170  *
171  * It seems Server Manger (srvmgr) only sends workstation as the qualifier
172  * and the Computer Management Interface on Windows 2000 doesn't request
173  * a list of connections.
174  *
175  * Return Values:
176  * ERROR_SUCCESS            Success
177  * ERROR_ACCESS_DENIED      Caller does not have access to this call.
178  * ERROR_INVALID_PARAMETER  One of the parameters is invalid.
179  * ERROR_INVALID_LEVEL      Unknown information level specified.
180  * ERROR_MORE_DATA          Partial date returned, more entries available.
181  * ERROR_NOT_ENOUGH_MEMORY  Insufficient memory is available.
182  * NERR_NetNameNotFound     The share qualifier cannot be found.
183  * NERR_BufTooSmall         The supplied buffer is too small.
184  */
185 static int
186 srvsvc_s_NetConnectEnum(void *arg, ndr_xa_t *mxa)
187 {
188 	struct mslm_NetConnectEnum *param = arg;
189 	srvsvc_NetConnectInfo0_t *info0;
190 	srvsvc_NetConnectInfo1_t *info1;
191 	char *qualifier;
192 	int qualtype;
193 	DWORD status = ERROR_SUCCESS;
194 
195 	if (!ndr_is_poweruser(mxa)) {
196 		bzero(param, sizeof (struct mslm_NetConnectEnum));
197 		param->status = ERROR_ACCESS_DENIED;
198 		return (NDR_DRC_OK);
199 	}
200 
201 	qualifier = (char *)param->qualifier;
202 	qualtype = srvsvc_netconnect_qualifier(qualifier);
203 
204 	if (qualtype == SRVSVC_CONNECT_ENUM_NULL) {
205 		bzero(param, sizeof (struct mslm_NetConnectEnum));
206 		param->status = NERR_NetNameNotFound;
207 		return (NDR_DRC_OK);
208 	}
209 
210 	switch (param->info.level) {
211 	case 0:
212 		info0 = NDR_NEW(mxa, srvsvc_NetConnectInfo0_t);
213 		if (info0 == NULL) {
214 			status = ERROR_NOT_ENOUGH_MEMORY;
215 			break;
216 		}
217 
218 		bzero(info0, sizeof (srvsvc_NetConnectInfo0_t));
219 		param->info.ru.info0 = info0;
220 
221 		status = srvsvc_s_NetConnectEnumLevel0(mxa, info0);
222 
223 		param->total_entries = info0->entries_read;
224 		param->resume_handle = NULL;
225 		break;
226 
227 	case 1:
228 		info1 = NDR_NEW(mxa, srvsvc_NetConnectInfo1_t);
229 		if (info1 == NULL) {
230 			status = ERROR_NOT_ENOUGH_MEMORY;
231 			break;
232 		}
233 
234 		bzero(info1, sizeof (srvsvc_NetConnectInfo1_t));
235 		param->info.ru.info1 = info1;
236 
237 		status = srvsvc_s_NetConnectEnumLevel1(mxa, info1);
238 
239 		param->total_entries = info1->entries_read;
240 		param->resume_handle = NULL;
241 		break;
242 
243 	case 50:
244 		status = ERROR_NOT_SUPPORTED;
245 		break;
246 
247 	default:
248 		status = ERROR_INVALID_LEVEL;
249 		break;
250 	}
251 
252 	if (status != ERROR_SUCCESS)
253 		bzero(param, sizeof (struct mslm_NetConnectEnum));
254 
255 	param->status = status;
256 	return (NDR_DRC_OK);
257 }
258 
259 static DWORD
260 srvsvc_s_NetConnectEnumLevel0(ndr_xa_t *mxa, srvsvc_NetConnectInfo0_t *info0)
261 {
262 	srvsvc_NetConnectInfoBuf0_t *ci0;
263 
264 	ci0 = NDR_NEW(mxa, srvsvc_NetConnectInfoBuf0_t);
265 	if (ci0 == NULL)
266 		return (ERROR_NOT_ENOUGH_MEMORY);
267 
268 	ci0->coni0_id = 0x17;
269 
270 	info0->ci0 = ci0;
271 	info0->entries_read = 1;
272 	return (ERROR_SUCCESS);
273 }
274 
275 static DWORD
276 srvsvc_s_NetConnectEnumLevel1(ndr_xa_t *mxa, srvsvc_NetConnectInfo1_t *info1)
277 {
278 	srvsvc_NetConnectInfoBuf1_t *ci1;
279 
280 	ci1 = NDR_NEW(mxa, srvsvc_NetConnectInfoBuf1_t);
281 	if (ci1 == NULL)
282 		return (ERROR_NOT_ENOUGH_MEMORY);
283 
284 	ci1->coni1_id = 0x17;
285 	ci1->coni1_type = STYPE_IPC;
286 	ci1->coni1_num_opens = 1;
287 	ci1->coni1_num_users = 1;
288 	ci1->coni1_time = 16;
289 	ci1->coni1_username = (uint8_t *)NDR_STRDUP(mxa, "Administrator");
290 	ci1->coni1_netname = (uint8_t *)NDR_STRDUP(mxa, "IPC$");
291 
292 	info1->ci1 = ci1;
293 	info1->entries_read = 1;
294 	return (ERROR_SUCCESS);
295 }
296 
297 /*
298  * srvsvc_netconnect_qualifier
299  *
300  * The qualifier is a string that specifies a share name or computer name
301  * for the connections of interest.  If it is a share name then all the
302  * connections made to that share name are listed.  If it is a computer
303  * name (it starts with two backslash characters), then NetConnectEnum
304  * lists all connections made from that computer to the specified server.
305  */
306 static int
307 srvsvc_netconnect_qualifier(const char *qualifier)
308 {
309 	if (qualifier == NULL || *qualifier == '\0')
310 		return (SRVSVC_CONNECT_ENUM_NULL);
311 
312 	if (strlen(qualifier) > MAXHOSTNAMELEN)
313 		return (SRVSVC_CONNECT_ENUM_NULL);
314 
315 	if (qualifier[0] == '\\' && qualifier[1] == '\\') {
316 		return (SRVSVC_CONNECT_ENUM_WKSTN);
317 	} else {
318 		if (!smb_shr_exists((char *)qualifier))
319 			return (SRVSVC_CONNECT_ENUM_NULL);
320 
321 		return (SRVSVC_CONNECT_ENUM_SHARE);
322 	}
323 }
324 
325 /*
326  * srvsvc_s_NetFileEnum
327  *
328  * Return information on open files or named pipes. Only members of the
329  * Administrators or Server Operators local groups are allowed to make
330  * this call. Currently, we only support Administrators.
331  *
332  * If basepath is null, all open resources are enumerated. If basepath
333  * is non-null, only resources that have basepath as a prefix should
334  * be returned.
335  *
336  * If username is specified (non-null), only files opened by username
337  * should be returned.
338  *
339  * Notes:
340  * 1. We don't validate the servername because we would have to check
341  * all primary IPs and the ROI seems unlikely to be worth it.
342  * 2. Both basepath and username are currently ignored because both
343  * Server Manger (NT 4.0) and CMI (Windows 2000) always set them to null.
344  *
345  * The level of information requested may be one of:
346  *
347  *  2   Return the file identification number.
348  *      This level is not supported on Windows Me/98/95.
349  *
350  *  3   Return information about the file.
351  *      This level is not supported on Windows Me/98/95.
352  *
353  *  50  Windows Me/98/95:  Return information about the file.
354  *
355  * Note:
356  * If pref_max_len is unlimited and resume_handle is null, the client
357  * expects to receive all data in a single call.
358  * If we are unable to do fit all data in a single response, we would
359  * normally return ERROR_MORE_DATA with a partial list.
360  *
361  * Unfortunately, when both of these conditions occur, Server Manager
362  * pops up an error box with the message "more data available" and
363  * doesn't display any of the returned data. In this case, it is
364  * probably better to return ERROR_SUCCESS with the partial list.
365  * Windows 2000 doesn't have this problem because it always sends a
366  * non-null resume_handle.
367  *
368  * Return Values:
369  * ERROR_SUCCESS            Success
370  * ERROR_ACCESS_DENIED      Caller does not have access to this call.
371  * ERROR_INVALID_PARAMETER  One of the parameters is invalid.
372  * ERROR_INVALID_LEVEL      Unknown information level specified.
373  * ERROR_MORE_DATA          Partial date returned, more entries available.
374  * ERROR_NOT_ENOUGH_MEMORY  Insufficient memory is available.
375  * NERR_BufTooSmall         The supplied buffer is too small.
376  */
377 static int
378 srvsvc_s_NetFileEnum(void *arg, ndr_xa_t *mxa)
379 {
380 	struct mslm_NetFileEnum *param = arg;
381 	DWORD status;
382 
383 	if (!ndr_is_admin(mxa)) {
384 		bzero(param, sizeof (struct mslm_NetFileEnum));
385 		param->status = ERROR_ACCESS_DENIED;
386 		return (NDR_DRC_OK);
387 	}
388 
389 	switch (param->info.switch_value) {
390 	case 2:
391 		status = srvsvc_NetFileEnum2(mxa, param);
392 		break;
393 
394 	case 3:
395 		status = srvsvc_NetFileEnum3(mxa, param);
396 		break;
397 
398 	case 50:
399 		status = ERROR_NOT_SUPPORTED;
400 		break;
401 
402 	default:
403 		status = ERROR_INVALID_LEVEL;
404 		break;
405 	}
406 
407 	if (status != ERROR_SUCCESS) {
408 		bzero(param, sizeof (struct mslm_NetFileEnum));
409 		param->status = status;
410 		return (NDR_DRC_OK);
411 	}
412 
413 	if (param->resume_handle)
414 		*param->resume_handle = 0;
415 
416 	param->status = ERROR_SUCCESS;
417 	return (NDR_DRC_OK);
418 }
419 
420 /*
421  * Build level 2 file information.
422  *
423  * On success, the caller expects that the info2, fi2 and entries_read
424  * fields have been set up.
425  */
426 static DWORD
427 srvsvc_NetFileEnum2(ndr_xa_t *mxa, struct mslm_NetFileEnum *param)
428 {
429 	struct mslm_NetFileInfoBuf2 *fi2;
430 	ndr_pipe_info_t pi;
431 	uint32_t entries_read = 0;
432 	int i;
433 
434 	param->info.ru.info2 = NDR_NEW(mxa, struct mslm_NetFileInfo2);
435 	if (param->info.ru.info3 == NULL)
436 		return (ERROR_NOT_ENOUGH_MEMORY);
437 
438 	fi2 = NDR_NEWN(mxa, struct mslm_NetFileInfoBuf2, 128);
439 	if (fi2 == NULL)
440 		return (ERROR_NOT_ENOUGH_MEMORY);
441 
442 	param->info.ru.info2->fi2 = fi2;
443 
444 	for (i = 0; i < 128; ++i) {
445 		if (ndr_pipe_getinfo(i, &pi) == -1)
446 			continue;
447 
448 		fi2->fi2_id = pi.npi_fid;
449 
450 		++entries_read;
451 		++fi2;
452 	}
453 
454 	param->info.ru.info2->entries_read = entries_read;
455 	param->total_entries = entries_read;
456 	return (ERROR_SUCCESS);
457 }
458 
459 /*
460  * Build level 3 file information.
461  *
462  * On success, the caller expects that the info3, fi3 and entries_read
463  * fields have been set up.
464  */
465 static DWORD
466 srvsvc_NetFileEnum3(ndr_xa_t *mxa, struct mslm_NetFileEnum *param)
467 {
468 	struct mslm_NetFileInfoBuf3 *fi3;
469 	ndr_pipe_info_t pi;
470 	uint32_t entries_read = 0;
471 	int i;
472 
473 	param->info.ru.info3 = NDR_NEW(mxa, struct mslm_NetFileInfo3);
474 	if (param->info.ru.info3 == NULL)
475 		return (ERROR_NOT_ENOUGH_MEMORY);
476 
477 	fi3 = NDR_NEWN(mxa, struct mslm_NetFileInfoBuf3, 128);
478 	if (fi3 == NULL)
479 		return (ERROR_NOT_ENOUGH_MEMORY);
480 
481 	param->info.ru.info3->fi3 = fi3;
482 
483 	for (i = 0; i < 128; ++i) {
484 		if (ndr_pipe_getinfo(i, &pi) == -1)
485 			continue;
486 
487 		fi3->fi3_id = pi.npi_fid;
488 		fi3->fi3_permissions = pi.npi_permissions;
489 		fi3->fi3_num_locks = pi.npi_num_locks;
490 		fi3->fi3_pathname = (uint8_t *)
491 		    NDR_STRDUP(mxa, pi.npi_pathname);
492 		fi3->fi3_username = (uint8_t *)
493 		    NDR_STRDUP(mxa, pi.npi_username);
494 
495 		++entries_read;
496 		++fi3;
497 	}
498 
499 	param->info.ru.info3->entries_read = entries_read;
500 	param->total_entries = entries_read;
501 	return (ERROR_SUCCESS);
502 }
503 
504 /*
505  * srvsvc_s_NetFileClose
506  *
507  * NetFileClose forces a file to close. This function can be used when
508  * an error prevents closure by any other means.  Use NetFileClose with
509  * caution because it does not flush data, cached on a client, to the
510  * file before closing the file.
511  *
512  * Return Values
513  * ERROR_SUCCESS            Operation succeeded.
514  * ERROR_ACCESS_DENIED      Operation denied.
515  * NERR_FileIdNotFound      No open file with the specified id.
516  *
517  * Note: MSDN suggests that the error code should be ERROR_FILE_NOT_FOUND
518  * but network captures using NT show NERR_FileIdNotFound.
519  * The NetFileClose2 MSDN page has the right error code.
520  */
521 static int
522 srvsvc_s_NetFileClose(void *arg, ndr_xa_t *mxa)
523 {
524 	struct mslm_NetFileClose *param = arg;
525 
526 	if (!ndr_is_admin(mxa)) {
527 		bzero(param, sizeof (struct mslm_NetFileClose));
528 		param->status = ERROR_ACCESS_DENIED;
529 		return (NDR_DRC_OK);
530 	}
531 
532 	bzero(param, sizeof (struct mslm_NetFileClose));
533 	param->status = ERROR_SUCCESS;
534 	return (NDR_DRC_OK);
535 }
536 
537 
538 /*
539  * srvsvc_s_NetShareGetInfo
540  *
541  * Returns Win32 error codes.
542  */
543 static int
544 srvsvc_s_NetShareGetInfo(void *arg, ndr_xa_t *mxa)
545 {
546 	struct mlsm_NetShareGetInfo *param = arg;
547 	struct mslm_NetShareGetInfo0 *info0;
548 	struct mslm_NetShareGetInfo1 *info1;
549 	struct mslm_NetShareGetInfo2 *info2;
550 	struct mslm_NetShareGetInfo501 *info501;
551 	struct mslm_NetShareGetInfo502 *info502;
552 	struct mslm_NetShareGetInfo1004 *info1004;
553 	struct mslm_NetShareGetInfo1005 *info1005;
554 	struct mslm_NetShareGetInfo1006 *info1006;
555 	smb_share_t si;
556 	DWORD status;
557 
558 	status = smb_shr_get((char *)param->netname, &si);
559 	if (status != NERR_Success) {
560 		bzero(param, sizeof (struct mlsm_NetShareGetInfo));
561 		param->status = status;
562 		return (NDR_DRC_OK);
563 	}
564 
565 	switch (param->level) {
566 	case 0:
567 		info0 = NDR_NEW(mxa, struct mslm_NetShareGetInfo0);
568 		if (info0 == NULL) {
569 			status = ERROR_NOT_ENOUGH_MEMORY;
570 			break;
571 		}
572 
573 		info0->shi0_netname
574 		    = (uint8_t *)NDR_STRDUP(mxa, si.shr_name);
575 		if (info0->shi0_netname == NULL) {
576 			status = ERROR_NOT_ENOUGH_MEMORY;
577 			break;
578 		}
579 
580 		param->result.ru.info0 = info0;
581 		break;
582 
583 	case 1:
584 		info1 = NDR_NEW(mxa, struct mslm_NetShareGetInfo1);
585 		if (info1 == NULL) {
586 			status = ERROR_NOT_ENOUGH_MEMORY;
587 			break;
588 		}
589 
590 		info1->shi1_netname = (uint8_t *)NDR_STRDUP(mxa, si.shr_name);
591 		info1->shi1_comment = (uint8_t *)NDR_STRDUP(mxa, si.shr_cmnt);
592 		if (info1->shi1_netname == NULL ||
593 		    info1->shi1_comment == NULL) {
594 			status = ERROR_NOT_ENOUGH_MEMORY;
595 			break;
596 		}
597 
598 		info1->shi1_type = si.shr_type;
599 		param->result.ru.info1 = info1;
600 		break;
601 
602 	case 2:
603 		info2 = NDR_NEW(mxa, struct mslm_NetShareGetInfo2);
604 		if (info2 == NULL) {
605 			status = ERROR_NOT_ENOUGH_MEMORY;
606 			break;
607 		}
608 
609 		info2->shi2_netname = (uint8_t *)NDR_STRDUP(mxa, si.shr_name);
610 		info2->shi2_comment = (uint8_t *)NDR_STRDUP(mxa, si.shr_cmnt);
611 		if (info2->shi2_netname == NULL ||
612 		    info2->shi2_comment == NULL) {
613 			status = ERROR_NOT_ENOUGH_MEMORY;
614 			break;
615 		}
616 
617 		info2->shi2_path =
618 		    (uint8_t *)srvsvc_share_mkpath(mxa, si.shr_path);
619 		info2->shi2_passwd = 0;
620 		info2->shi2_type = si.shr_type;
621 		info2->shi2_permissions = 0;
622 		info2->shi2_max_uses = SHI_USES_UNLIMITED;
623 		info2->shi2_current_uses = 0;
624 		param->result.ru.info2 = info2;
625 		break;
626 
627 	case 1004:
628 		info1004 = NDR_NEW(mxa, struct mslm_NetShareGetInfo1004);
629 		if (info1004 == NULL) {
630 			status = ERROR_NOT_ENOUGH_MEMORY;
631 			break;
632 		}
633 
634 		info1004->shi1004_comment =
635 		    (uint8_t *)NDR_STRDUP(mxa, si.shr_cmnt);
636 		if (info1004->shi1004_comment == NULL)
637 			status = ERROR_NOT_ENOUGH_MEMORY;
638 		break;
639 
640 	case 1005:
641 		info1005 = NDR_NEW(mxa, struct mslm_NetShareGetInfo1005);
642 		if (info1005 == NULL) {
643 			status = ERROR_NOT_ENOUGH_MEMORY;
644 			break;
645 		}
646 
647 		info1005->shi1005_flags = 0;
648 
649 		switch (si.shr_flags & SMB_SHRF_CSC_MASK) {
650 		case SMB_SHRF_CSC_DISABLED:
651 			info1005->shi1005_flags |= CSC_CACHE_NONE;
652 			break;
653 		case SMB_SHRF_CSC_AUTO:
654 			info1005->shi1005_flags |= CSC_CACHE_AUTO_REINT;
655 			break;
656 		case SMB_SHRF_CSC_VDO:
657 			info1005->shi1005_flags |= CSC_CACHE_VDO;
658 			break;
659 		case SMB_SHRF_CSC_MANUAL:
660 		default:
661 			/*
662 			 * Default to CSC_CACHE_MANUAL_REINT.
663 			 */
664 			break;
665 		}
666 
667 		param->result.ru.info1005 = info1005;
668 		break;
669 
670 	case 1006:
671 		info1006 = NDR_NEW(mxa, struct mslm_NetShareGetInfo1006);
672 		if (info1006 == NULL) {
673 			status = ERROR_NOT_ENOUGH_MEMORY;
674 			break;
675 		}
676 		info1006->shi1006_max_uses = SHI_USES_UNLIMITED;
677 		param->result.ru.info1006 = info1006;
678 		break;
679 
680 	case 501:
681 		/*
682 		 * Level 501 provides level 1 information.
683 		 */
684 		info501 = NDR_NEW(mxa, struct mslm_NetShareGetInfo501);
685 		if (info501 == NULL) {
686 			status = ERROR_NOT_ENOUGH_MEMORY;
687 			break;
688 		}
689 
690 		info501->shi501_netname =
691 		    (uint8_t *)NDR_STRDUP(mxa, si.shr_name);
692 		info501->shi501_comment =
693 		    (uint8_t *)NDR_STRDUP(mxa, si.shr_cmnt);
694 		if (info501->shi501_netname == NULL ||
695 		    info501->shi501_comment == NULL) {
696 			status = ERROR_NOT_ENOUGH_MEMORY;
697 			break;
698 		}
699 
700 		info501->shi501_type = si.shr_type;
701 		info501->shi501_reserved = 0;
702 		param->result.ru.info501 = info501;
703 		break;
704 
705 	case 502:
706 		/*
707 		 * Level 502 provides level 2 information plus a
708 		 * security descriptor. We don't support security
709 		 * descriptors on shares yet.
710 		 */
711 		info502 = NDR_NEW(mxa, struct mslm_NetShareGetInfo502);
712 		if (info502 == NULL) {
713 			status = ERROR_NOT_ENOUGH_MEMORY;
714 			break;
715 		}
716 
717 		info502->shi502_netname =
718 		    (uint8_t *)NDR_STRDUP(mxa, si.shr_name);
719 		info502->shi502_comment =
720 		    (uint8_t *)NDR_STRDUP(mxa, si.shr_cmnt);
721 		if (info502->shi502_netname == NULL ||
722 		    info502->shi502_comment == NULL) {
723 			status = ERROR_NOT_ENOUGH_MEMORY;
724 			break;
725 		}
726 
727 		info502->shi502_path =
728 		    (uint8_t *)srvsvc_share_mkpath(mxa, si.shr_path);
729 		info502->shi502_passwd = 0;
730 		info502->shi502_type = si.shr_type;
731 		info502->shi502_permissions = 0;
732 		info502->shi502_max_uses = SHI_USES_UNLIMITED;
733 		info502->shi502_current_uses = 0;
734 		info502->shi502_reserved = 0;
735 		info502->shi502_security_descriptor = 0;
736 		param->result.ru.info502 = info502;
737 		break;
738 
739 	default:
740 		status = ERROR_ACCESS_DENIED;
741 		break;
742 	}
743 
744 	if (status != ERROR_SUCCESS)
745 		bzero(param, sizeof (struct mlsm_NetShareGetInfo));
746 	else
747 		param->result.switch_value = param->level;
748 
749 	param->status = status;
750 	return (NDR_DRC_OK);
751 }
752 
753 
754 /*
755  * srvsvc_s_NetShareSetInfo
756  *
757  * This call is made by SrvMgr to set share information.
758  * Always returns ERROR_ACCESS_DENIED for now.
759  *
760  * Returns Win32 error codes.
761  */
762 static int
763 srvsvc_s_NetShareSetInfo(void *arg, ndr_xa_t *mxa)
764 {
765 	struct mlsm_NetShareSetInfo *param = arg;
766 
767 	(void) memset(param, 0, sizeof (struct mlsm_NetShareSetInfo));
768 	param->parm_err_ptr = (DWORD)(uintptr_t)NDR_MALLOC(mxa,
769 	    sizeof (DWORD));
770 	param->parm_err = 0;
771 
772 	if (!smb_config_getbool(SMB_CI_SRVSVC_SHRSET_ENABLE))
773 		param->status = ERROR_SUCCESS;
774 	else
775 		param->status = ERROR_ACCESS_DENIED;
776 
777 	return (NDR_DRC_OK);
778 }
779 
780 /*
781  * srvsvc_s_NetSessionEnum
782  *
783  * Level 1 request is made by (Server Manager (srvmgr) on NT Server when
784  * the user info icon is selected.
785  *
786  * On success, the return value is NERR_Success.
787  * On error, the return value can be one of the following error codes:
788  *
789  * ERROR_ACCESS_DENIED      The user does not have access to the requested
790  *                          information.
791  * ERROR_INVALID_LEVEL      The value specified for the level is invalid.
792  * ERROR_INVALID_PARAMETER  The specified parameter is invalid.
793  * ERROR_MORE_DATA          More entries are available. Specify a large
794  *                          enough buffer to receive all entries.
795  * ERROR_NOT_ENOUGH_MEMORY  Insufficient memory is available.
796  * NERR_ClientNameNotFound  A session does not exist with the computer name.
797  * NERR_InvalidComputer     The computer name is invalid.
798  * NERR_UserNotFound        The user name could not be found.
799  */
800 static int
801 srvsvc_s_NetSessionEnum(void *arg, ndr_xa_t *mxa)
802 {
803 	struct mslm_NetSessionEnum *param = arg;
804 	struct mslm_infonres *infonres;
805 	DWORD status;
806 	DWORD n_sessions;
807 
808 	infonres = NDR_NEW(mxa, struct mslm_infonres);
809 	if (infonres == NULL) {
810 		bzero(param, sizeof (struct mslm_NetSessionEnum));
811 		param->status = ERROR_NOT_ENOUGH_MEMORY;
812 		return (NDR_DRC_OK);
813 	}
814 
815 	infonres->entriesread = 0;
816 	infonres->entries = NULL;
817 	param->result.level = param->level;
818 	param->result.bufptr.p = infonres;
819 	param->total_entries = 0;
820 	param->resume_handle = NULL;
821 	param->status = ERROR_SUCCESS;
822 
823 	if ((n_sessions = (DWORD) mlsvc_get_num_users()) == 0)
824 		return (NDR_DRC_OK);
825 
826 	switch (param->level) {
827 	case 0:
828 		status = mlsvc_NetSessionEnumLevel0(infonres, n_sessions, mxa);
829 		break;
830 
831 	case 1:
832 		status = mlsvc_NetSessionEnumLevel1(infonres, n_sessions, mxa);
833 		break;
834 
835 	default:
836 		status = ERROR_INVALID_LEVEL;
837 		break;
838 	}
839 
840 	if (status != 0) {
841 		bzero(param, sizeof (struct mslm_NetSessionEnum));
842 		param->status = status;
843 		return (NDR_DRC_OK);
844 	}
845 
846 	param->total_entries = infonres->entriesread;
847 	param->status = status;
848 	return (NDR_DRC_OK);
849 }
850 
851 /*
852  * mlsvc_NetSessionEnumLevel0
853  *
854  * Build the level 0 session information.
855  */
856 static DWORD
857 mlsvc_NetSessionEnumLevel0(struct mslm_infonres *infonres, DWORD n_sessions,
858     ndr_xa_t *mxa)
859 {
860 	struct mslm_SESSION_INFO_0 *info0;
861 	smb_dr_ulist_t *ulist;
862 	smb_opipe_context_t *user;
863 	char *workstation;
864 	char ipaddr_buf[INET_ADDRSTRLEN];
865 	int n_users;
866 	int offset = 0;
867 	int i;
868 
869 	if ((ulist = malloc(sizeof (smb_dr_ulist_t))) == NULL)
870 		return (ERROR_NOT_ENOUGH_MEMORY);
871 
872 	if ((n_users = mlsvc_get_user_list(offset, ulist)) == 0) {
873 		smb_dr_ulist_free(ulist);
874 		return (ERROR_NOT_ENOUGH_MEMORY);
875 	}
876 
877 	if (n_users < n_sessions)
878 		n_sessions = n_users;
879 
880 	info0 = NDR_NEWN(mxa, struct mslm_SESSION_INFO_0, n_sessions);
881 	if (info0 == NULL) {
882 		smb_dr_ulist_free(ulist);
883 		return (ERROR_NOT_ENOUGH_MEMORY);
884 	}
885 
886 	for (i = 0; i < n_sessions; ++i) {
887 		user = &ulist->dul_users[i];
888 
889 		workstation = user->oc_workstation;
890 		if (workstation == NULL || *workstation == '\0') {
891 			(void) inet_ntop(AF_INET, (char *)&user->oc_ipaddr,
892 			    ipaddr_buf, sizeof (ipaddr_buf));
893 			workstation = ipaddr_buf;
894 		}
895 
896 		info0[i].sesi0_cname = NDR_STRDUP(mxa, workstation);
897 		if (info0[i].sesi0_cname == NULL) {
898 			smb_dr_ulist_free(ulist);
899 			return (ERROR_NOT_ENOUGH_MEMORY);
900 		}
901 	}
902 
903 	smb_dr_ulist_free(ulist);
904 	infonres->entriesread = n_sessions;
905 	infonres->entries = info0;
906 	return (ERROR_SUCCESS);
907 }
908 
909 /*
910  * mlsvc_NetSessionEnumLevel1
911  *
912  * Build the level 1 session information.
913  */
914 static DWORD
915 mlsvc_NetSessionEnumLevel1(struct mslm_infonres *infonres, DWORD n_sessions,
916     ndr_xa_t *mxa)
917 {
918 	struct mslm_SESSION_INFO_1 *info1;
919 	smb_dr_ulist_t *ulist;
920 	smb_opipe_context_t *user;
921 	char *workstation;
922 	char account[MAXNAMELEN];
923 	char ipaddr_buf[INET_ADDRSTRLEN];
924 	int n_users;
925 	int offset = 0;
926 	int i;
927 
928 	if ((ulist = malloc(sizeof (smb_dr_ulist_t))) == NULL)
929 		return (ERROR_NOT_ENOUGH_MEMORY);
930 
931 	if ((n_users = mlsvc_get_user_list(offset, ulist)) == 0) {
932 		smb_dr_ulist_free(ulist);
933 		return (ERROR_NOT_ENOUGH_MEMORY);
934 	}
935 
936 	if (n_users < n_sessions)
937 		n_sessions = n_users;
938 
939 	info1 = NDR_NEWN(mxa, struct mslm_SESSION_INFO_1, n_sessions);
940 	if (info1 == NULL) {
941 		smb_dr_ulist_free(ulist);
942 		return (ERROR_NOT_ENOUGH_MEMORY);
943 	}
944 
945 	for (i = 0; i < n_sessions; ++i) {
946 		user = &ulist->dul_users[i];
947 
948 		workstation = user->oc_workstation;
949 		if (workstation == NULL || *workstation == '\0') {
950 			(void) inet_ntop(AF_INET, (char *)&user->oc_ipaddr,
951 			    ipaddr_buf, sizeof (ipaddr_buf));
952 			workstation = ipaddr_buf;
953 		}
954 
955 		(void) snprintf(account, MAXNAMELEN, "%s\\%s",
956 		    user->oc_domain, user->oc_account);
957 
958 		info1[i].sesi1_cname = NDR_STRDUP(mxa, workstation);
959 		info1[i].sesi1_uname = NDR_STRDUP(mxa, account);
960 
961 		if (info1[i].sesi1_cname == NULL ||
962 		    info1[i].sesi1_uname == NULL) {
963 			smb_dr_ulist_free(ulist);
964 			return (ERROR_NOT_ENOUGH_MEMORY);
965 		}
966 
967 		info1[i].sesi1_nopens = 1;
968 		info1[i].sesi1_time = time(0) - user->oc_logon_time;
969 		info1[i].sesi1_itime = 0;
970 		info1[i].sesi1_uflags =
971 		    (user->oc_flags & SMB_ATF_GUEST) ? SESS_GUEST : 0;
972 	}
973 
974 	smb_dr_ulist_free(ulist);
975 	infonres->entriesread = n_sessions;
976 	infonres->entries = info1;
977 	return (ERROR_SUCCESS);
978 }
979 
980 /*
981  * srvsvc_s_NetSessionDel
982  *
983  * Ends a network session between a server and a workstation.
984  * On NT only members of the Administrators or Account Operators
985  * local groups are permitted to use NetSessionDel.
986  *
987  * Return Values
988  * If the function succeeds, the return value is NERR_Success/
989  * ERROR_SUCCESS. If the function fails, the return value can be
990  * one of the following error codes:
991  *
992  * ERROR_ACCESS_DENIED 		The user does not have access to the
993  * 							requested information.
994  * ERROR_INVALID_PARAMETER	The specified parameter is invalid.
995  * ERROR_NOT_ENOUGH_MEMORY	Insufficient memory is available.
996  * NERR_ClientNameNotFound	A session does not exist with that
997  *                          computer name.
998  */
999 static int
1000 srvsvc_s_NetSessionDel(void *arg, ndr_xa_t *mxa)
1001 {
1002 	struct mslm_NetSessionDel *param = arg;
1003 
1004 	if (!ndr_is_poweruser(mxa)) {
1005 		param->status = ERROR_ACCESS_DENIED;
1006 		return (NDR_DRC_OK);
1007 	}
1008 
1009 	param->status = ERROR_ACCESS_DENIED;
1010 	return (NDR_DRC_OK);
1011 }
1012 
1013 /*
1014  * SRVSVC NetServerGetInfo
1015  *
1016  *	IN	LPTSTR servername,
1017  *	IN	DWORD level,
1018  *	OUT	union switch(level) {
1019  *		case 100:	mslm_SERVER_INFO_100 *p100;
1020  *		case 101:	mslm_SERVER_INFO_101 *p101;
1021  *		case 102:	mslm_SERVER_INFO_102 *p102;
1022  *		default:	char *nullptr;
1023  *		} bufptr,
1024  *	OUT	DWORD status
1025  */
1026 static int
1027 srvsvc_s_NetServerGetInfo(void *arg, ndr_xa_t *mxa)
1028 {
1029 	struct mslm_NetServerGetInfo *param = arg;
1030 	struct mslm_SERVER_INFO_100 *info100;
1031 	struct mslm_SERVER_INFO_101 *info101;
1032 	struct mslm_SERVER_INFO_102 *info102;
1033 	char sys_comment[SMB_PI_MAX_COMMENT];
1034 	char hostname[NETBIOS_NAME_SZ];
1035 
1036 	if (smb_getnetbiosname(hostname, sizeof (hostname)) != 0) {
1037 netservergetinfo_no_memory:
1038 		bzero(param, sizeof (struct mslm_NetServerGetInfo));
1039 		return (ERROR_NOT_ENOUGH_MEMORY);
1040 	}
1041 
1042 	(void) smb_config_getstr(SMB_CI_SYS_CMNT, sys_comment,
1043 	    sizeof (sys_comment));
1044 	if (*sys_comment == '\0')
1045 		(void) strcpy(sys_comment, " ");
1046 
1047 	switch (param->level) {
1048 	case 100:
1049 		info100 = NDR_NEW(mxa, struct mslm_SERVER_INFO_100);
1050 		if (info100 == NULL)
1051 			goto netservergetinfo_no_memory;
1052 
1053 		bzero(info100, sizeof (struct mslm_SERVER_INFO_100));
1054 		info100->sv100_platform_id = SV_PLATFORM_ID_NT;
1055 		info100->sv100_name = (uint8_t *)NDR_STRDUP(mxa, hostname);
1056 		if (info100->sv100_name == NULL)
1057 			goto netservergetinfo_no_memory;
1058 
1059 		param->result.bufptr.bufptr100 = info100;
1060 		break;
1061 
1062 	case 101:
1063 		info101 = NDR_NEW(mxa, struct mslm_SERVER_INFO_101);
1064 		if (info101 == NULL)
1065 			goto netservergetinfo_no_memory;
1066 
1067 		bzero(info101, sizeof (struct mslm_SERVER_INFO_101));
1068 		info101->sv101_platform_id = SV_PLATFORM_ID_NT;
1069 		info101->sv101_version_major = 4;
1070 		info101->sv101_version_minor = 0;
1071 		info101->sv101_type = SV_TYPE_SENT_BY_ME;
1072 		info101->sv101_name = (uint8_t *)NDR_STRDUP(mxa, hostname);
1073 		info101->sv101_comment
1074 		    = (uint8_t *)NDR_STRDUP(mxa, sys_comment);
1075 
1076 		if (info101->sv101_name == NULL ||
1077 		    info101->sv101_comment == NULL)
1078 			goto netservergetinfo_no_memory;
1079 
1080 		param->result.bufptr.bufptr101 = info101;
1081 		break;
1082 
1083 	case 102:
1084 		info102 = NDR_NEW(mxa, struct mslm_SERVER_INFO_102);
1085 		if (info102 == NULL)
1086 			goto netservergetinfo_no_memory;
1087 
1088 		bzero(info102, sizeof (struct mslm_SERVER_INFO_102));
1089 		info102->sv102_platform_id = SV_PLATFORM_ID_NT;
1090 		info102->sv102_version_major = 4;
1091 		info102->sv102_version_minor = 0;
1092 		info102->sv102_type = SV_TYPE_SENT_BY_ME;
1093 		info102->sv102_name = (uint8_t *)NDR_STRDUP(mxa, hostname);
1094 		info102->sv102_comment
1095 		    = (uint8_t *)NDR_STRDUP(mxa, sys_comment);
1096 
1097 		/*
1098 		 * The following level 102 fields are defaulted to zero
1099 		 * by virtue of the call to bzero above.
1100 		 *
1101 		 * sv102_users
1102 		 * sv102_disc
1103 		 * sv102_hidden
1104 		 * sv102_announce
1105 		 * sv102_anndelta
1106 		 * sv102_licenses
1107 		 * sv102_userpath
1108 		 */
1109 		if (info102->sv102_name == NULL ||
1110 		    info102->sv102_comment == NULL)
1111 			goto netservergetinfo_no_memory;
1112 
1113 		param->result.bufptr.bufptr102 = info102;
1114 		break;
1115 
1116 	default:
1117 		bzero(&param->result,
1118 		    sizeof (struct mslm_NetServerGetInfo_result));
1119 		param->status = ERROR_ACCESS_DENIED;
1120 		return (NDR_DRC_OK);
1121 	}
1122 
1123 	param->result.level = param->level;
1124 	param->status = (ERROR_SUCCESS);
1125 	return (NDR_DRC_OK);
1126 }
1127 
1128 /*
1129  * NetRemoteTOD
1130  *
1131  * Returns information about the time of day on this server.
1132  *
1133  * typedef struct _TIME_OF_DAY_INFO {
1134  *	DWORD tod_elapsedt;  // seconds since 00:00:00 January 1 1970 GMT
1135  *	DWORD tod_msecs;     // arbitrary milliseconds (since reset)
1136  *	DWORD tod_hours;     // current hour [0-23]
1137  *	DWORD tod_mins;      // current minute [0-59]
1138  *	DWORD tod_secs;      // current second [0-59]
1139  *	DWORD tod_hunds;     // current hundredth (0.01) second [0-99]
1140  *	LONG tod_timezone;   // time zone of the server
1141  *	DWORD tod_tinterval; // clock tick time interval
1142  *	DWORD tod_day;       // day of the month [1-31]
1143  *	DWORD tod_month;     // month of the year [1-12]
1144  *	DWORD tod_year;      // current year
1145  *	DWORD tod_weekday;   // day of the week since Sunday [0-6]
1146  * } TIME_OF_DAY_INFO;
1147  *
1148  * The time zone of the server is calculated in minutes from Greenwich
1149  * Mean Time (GMT). For time zones west of Greenwich, the value is
1150  * positive; for time zones east of Greenwich, the value is negative.
1151  * A value of -1 indicates that the time zone is undefined.
1152  *
1153  * The clock tick value represents a resolution of one ten-thousandth
1154  * (0.0001) second.
1155  */
1156 static int
1157 srvsvc_s_NetRemoteTOD(void *arg, ndr_xa_t *mxa)
1158 {
1159 	struct mslm_NetRemoteTOD *param = arg;
1160 	struct mslm_TIME_OF_DAY_INFO *tod;
1161 	struct timeval		time_val;
1162 	struct tm		tm;
1163 
1164 	(void) gettimeofday(&time_val, 0);
1165 	(void) gmtime_r(&time_val.tv_sec, &tm);
1166 
1167 	tod = NDR_NEW(mxa, struct mslm_TIME_OF_DAY_INFO);
1168 	if (tod == NULL) {
1169 		bzero(param, sizeof (struct mslm_NetRemoteTOD));
1170 		return (ERROR_NOT_ENOUGH_MEMORY);
1171 	}
1172 
1173 	tod->tod_elapsedt = time_val.tv_sec;
1174 	tod->tod_msecs = time_val.tv_usec;
1175 	tod->tod_hours = tm.tm_hour;
1176 	tod->tod_mins = tm.tm_min;
1177 	tod->tod_secs = tm.tm_sec;
1178 	tod->tod_hunds = 0;
1179 	tod->tod_tinterval = 1000;
1180 	tod->tod_day = tm.tm_mday;
1181 	tod->tod_month = tm.tm_mon+1;
1182 	tod->tod_year = tm.tm_year+1900;
1183 	tod->tod_weekday = tm.tm_wday;
1184 
1185 	(void) localtime_r(&time_val.tv_sec, &tm);
1186 
1187 	param->bufptr = tod;
1188 	param->status = ERROR_SUCCESS;
1189 	return (NDR_DRC_OK);
1190 }
1191 
1192 /*
1193  * srvsvc_s_NetNameValidate
1194  *
1195  * Perform name validation.
1196  *
1197  * The share name is considered invalid if it contains any of the
1198  * following character (MSDN 236388).
1199  *
1200  * " / \ [ ] : | < > + ; , ? * =
1201  *
1202  * Returns Win32 error codes.
1203  */
1204 /*ARGSUSED*/
1205 static int
1206 srvsvc_s_NetNameValidate(void *arg, ndr_xa_t *mxa)
1207 {
1208 	struct mslm_NetNameValidate *param = arg;
1209 	char *name;
1210 	int len;
1211 
1212 	if ((name = (char *)param->pathname) == NULL) {
1213 		param->status = ERROR_INVALID_PARAMETER;
1214 		return (NDR_DRC_OK);
1215 	}
1216 
1217 	len = strlen(name);
1218 
1219 	if ((param->flags == 0 && len > 81) ||
1220 	    (param->flags == 0x80000000 && len > 13)) {
1221 		param->status = ERROR_INVALID_NAME;
1222 		return (NDR_DRC_OK);
1223 	}
1224 
1225 	switch (param->type) {
1226 	case NAMETYPE_SHARE:
1227 		if (smb_shr_chkname(name))
1228 			param->status = ERROR_SUCCESS;
1229 		else
1230 			param->status = ERROR_INVALID_NAME;
1231 		break;
1232 
1233 	case NAMETYPE_USER:
1234 	case NAMETYPE_PASSWORD:
1235 	case NAMETYPE_GROUP:
1236 	case NAMETYPE_COMPUTER:
1237 	case NAMETYPE_EVENT:
1238 	case NAMETYPE_DOMAIN:
1239 	case NAMETYPE_SERVICE:
1240 	case NAMETYPE_NET:
1241 	case NAMETYPE_MESSAGE:
1242 	case NAMETYPE_MESSAGEDEST:
1243 	case NAMETYPE_SHAREPASSWORD:
1244 	case NAMETYPE_WORKGROUP:
1245 		param->status = ERROR_NOT_SUPPORTED;
1246 		break;
1247 
1248 	default:
1249 		param->status = ERROR_INVALID_PARAMETER;
1250 		break;
1251 	}
1252 
1253 	return (NDR_DRC_OK);
1254 }
1255 
1256 /*
1257  * srvsvc_s_NetShareAdd
1258  *
1259  * Add a new share. We support info levels 2 and 502 but ignore the
1260  * security descriptor in level 502 requests. Only the administrator,
1261  * or a member of the domain administrators group, is allowed to add
1262  * shares.
1263  *
1264  * This interface is used by the rmtshare command from the NT resource
1265  * kit. Rmtshare allows a client to add or remove shares on a server
1266  * from the client's command line.
1267  *
1268  * Note that we don't support security descriptors on a share. If the
1269  * /grant is used, the share will be created but the subsequent attempt
1270  * to manipulate the security descriptor (NetShareGetInfo) will fail.
1271  * Similarly for the /remove option.
1272  *
1273  * Returns Win32 error codes.
1274  */
1275 static int
1276 srvsvc_s_NetShareAdd(void *arg, ndr_xa_t *mxa)
1277 {
1278 	static DWORD parm_err = 0;
1279 	DWORD parm_stat;
1280 	struct mslm_NetShareAdd *param = arg;
1281 	struct mslm_SHARE_INFO_2 *info2;
1282 	char realpath[MAXPATHLEN];
1283 	int32_t native_os;
1284 
1285 	native_os = ndr_native_os(mxa);
1286 
1287 	if (!ndr_is_poweruser(mxa)) {
1288 		bzero(param, sizeof (struct mslm_NetShareAdd));
1289 		param->status = ERROR_ACCESS_DENIED;
1290 		return (NDR_DRC_OK);
1291 	}
1292 
1293 	switch (param->level) {
1294 	case 2:
1295 		info2 = param->info.un.info2;
1296 		break;
1297 
1298 	case 502:
1299 		info2 = (struct mslm_SHARE_INFO_2 *)param->info.un.info502;
1300 		break;
1301 
1302 	default:
1303 		bzero(param, sizeof (struct mslm_NetShareAdd));
1304 		param->status = ERROR_ACCESS_DENIED;
1305 		return (NDR_DRC_OK);
1306 	}
1307 
1308 	if (info2->shi2_netname == NULL || info2->shi2_path == NULL) {
1309 		bzero(param, sizeof (struct mslm_NetShareAdd));
1310 		param->status = NERR_NetNameNotFound;
1311 		return (NDR_DRC_OK);
1312 	}
1313 
1314 	if (smb_shr_is_restricted((char *)info2->shi2_netname)) {
1315 		bzero(param, sizeof (struct mslm_NetShareAdd));
1316 		param->status = ERROR_ACCESS_DENIED;
1317 		return (NDR_DRC_OK);
1318 	}
1319 
1320 	if (info2->shi2_remark == NULL)
1321 		info2->shi2_remark = (uint8_t *)"";
1322 
1323 	/*
1324 	 * Derive the real path which will be stored in the
1325 	 * directory field of the smb_share_t structure
1326 	 * from the path field in this RPC request.
1327 	 */
1328 	parm_stat = smb_shr_get_realpath((const char *)info2->shi2_path,
1329 	    realpath, MAXPATHLEN);
1330 
1331 	if (parm_stat != NERR_Success) {
1332 		bzero(param, sizeof (struct mslm_NetShareAdd));
1333 		param->status = parm_stat;
1334 		param->parm_err
1335 		    = (native_os == NATIVE_OS_WIN95) ? 0 : &parm_err;
1336 		return (NDR_DRC_OK);
1337 	}
1338 
1339 	param->status = srvsvc_sa_add((char *)info2->shi2_netname, realpath,
1340 	    (char *)info2->shi2_remark);
1341 	if (param->status == NERR_Success) {
1342 		smb_share_t si;
1343 		/*
1344 		 * Lookup the share, which will bring it into the cache.
1345 		 */
1346 		(void) smb_shr_get((char *)info2->shi2_netname, &si);
1347 	}
1348 	param->parm_err = (native_os == NATIVE_OS_WIN95) ? 0 : &parm_err;
1349 	return (NDR_DRC_OK);
1350 }
1351 
1352 /*
1353  * srvsvc_estimate_objcnt
1354  *
1355  * Estimate the number of objects that will fit in prefmaxlen.
1356  */
1357 static uint32_t
1358 srvsvc_estimate_objcnt(uint32_t prefmaxlen, uint32_t n_obj, uint32_t obj_size)
1359 {
1360 	DWORD max_cnt;
1361 
1362 	if (obj_size == 0)
1363 		return (0);
1364 
1365 	if ((max_cnt = (prefmaxlen / obj_size)) == 0)
1366 		return (0);
1367 
1368 	if (n_obj > max_cnt)
1369 		n_obj = max_cnt;
1370 
1371 	return (n_obj);
1372 }
1373 
1374 /*
1375  * srvsvc_s_NetShareEnum
1376  *
1377  * Enumerate all shares (see also NetShareEnumSticky).
1378  *
1379  * Request for various levels of information about our shares.
1380  * Level 0: share names.
1381  * Level 1: share name, share type and comment field.
1382  * Level 2: everything that we know about the shares.
1383  * Level 501: level 1 + flags (flags must be zero).
1384  * Level 502: level 2 + security descriptor.
1385  */
1386 static int
1387 srvsvc_s_NetShareEnum(void *arg, ndr_xa_t *mxa)
1388 {
1389 	struct mslm_NetShareEnum *param = arg;
1390 	struct mslm_infonres *infonres;
1391 	srvsvc_enum_t se;
1392 	DWORD status;
1393 
1394 	infonres = NDR_NEW(mxa, struct mslm_infonres);
1395 	if (infonres == NULL) {
1396 		bzero(param, sizeof (struct mslm_NetShareEnum));
1397 		param->status = ERROR_NOT_ENOUGH_MEMORY;
1398 		return (NDR_DRC_OK);
1399 	}
1400 
1401 	infonres->entriesread = 0;
1402 	infonres->entries = NULL;
1403 	param->result.level = param->level;
1404 	param->result.bufptr.p = infonres;
1405 
1406 	bzero(&se, sizeof (srvsvc_enum_t));
1407 	se.se_level = param->level;
1408 	se.se_n_total = smb_shr_count();
1409 
1410 	if (param->prefmaxlen == SMB_SRVSVC_MAXPREFLEN ||
1411 	    param->prefmaxlen > SMB_SRVSVC_MAXBUFLEN)
1412 		se.se_prefmaxlen = SMB_SRVSVC_MAXBUFLEN;
1413 	else
1414 		se.se_prefmaxlen = param->prefmaxlen;
1415 
1416 	if (param->resume_handle) {
1417 		se.se_resume_handle = *param->resume_handle;
1418 		se.se_n_skip = se.se_resume_handle;
1419 	}
1420 
1421 	switch (param->level) {
1422 	case 0:
1423 		status = mlsvc_NetShareEnumLevel0(mxa, infonres, &se, 0);
1424 		break;
1425 
1426 	case 1:
1427 		status = mlsvc_NetShareEnumLevel1(mxa, infonres, &se, 0);
1428 		break;
1429 
1430 	case 2:
1431 		status = mlsvc_NetShareEnumLevel2(mxa, infonres, &se, 0);
1432 		break;
1433 
1434 	case 501:
1435 		status = mlsvc_NetShareEnumLevel501(mxa, infonres, &se, 0);
1436 		break;
1437 
1438 	case 502:
1439 		status = mlsvc_NetShareEnumLevel502(mxa, infonres, &se, 0);
1440 		break;
1441 
1442 	default:
1443 		status = ERROR_INVALID_PARAMETER;
1444 		break;
1445 	}
1446 
1447 	if (status != 0) {
1448 		bzero(param, sizeof (struct mslm_NetShareEnum));
1449 		param->status = status;
1450 		return (NDR_DRC_OK);
1451 	}
1452 
1453 	if (se.se_n_enum == 0) {
1454 		if (param->resume_handle)
1455 			*param->resume_handle = 0;
1456 		param->status = ERROR_SUCCESS;
1457 		return (NDR_DRC_OK);
1458 	}
1459 
1460 	if (param->resume_handle &&
1461 	    param->prefmaxlen != SMB_SRVSVC_MAXPREFLEN) {
1462 		if (se.se_resume_handle < se.se_n_total) {
1463 			*param->resume_handle = se.se_resume_handle;
1464 			status = ERROR_MORE_DATA;
1465 		} else {
1466 			*param->resume_handle = 0;
1467 		}
1468 	}
1469 
1470 	param->totalentries = se.se_n_total;
1471 	param->status = status;
1472 	return (NDR_DRC_OK);
1473 }
1474 
1475 /*
1476  * srvsvc_s_NetShareEnumSticky
1477  *
1478  * Enumerate sticky shares: all shares except those marked STYPE_SPECIAL.
1479  * Except for excluding STYPE_SPECIAL shares, NetShareEnumSticky is the
1480  * same as NetShareEnum.
1481  *
1482  * Request for various levels of information about our shares.
1483  * Level 0: share names.
1484  * Level 1: share name, share type and comment field.
1485  * Level 2: everything that we know about the shares.
1486  * Level 501: not valid for this request.
1487  * Level 502: level 2 + security descriptor.
1488  *
1489  * We set n_skip to resume_handle, which is used to find the appropriate
1490  * place to resume.  The resume_handle is similar to the readdir cookie.
1491  */
1492 static int
1493 srvsvc_s_NetShareEnumSticky(void *arg, ndr_xa_t *mxa)
1494 {
1495 	struct mslm_NetShareEnum *param = arg;
1496 	struct mslm_infonres *infonres;
1497 	srvsvc_enum_t se;
1498 	DWORD status;
1499 
1500 	infonres = NDR_NEW(mxa, struct mslm_infonres);
1501 	if (infonres == NULL) {
1502 		bzero(param, sizeof (struct mslm_NetShareEnum));
1503 		param->status = ERROR_NOT_ENOUGH_MEMORY;
1504 		return (NDR_DRC_OK);
1505 	}
1506 
1507 	infonres->entriesread = 0;
1508 	infonres->entries = NULL;
1509 	param->result.level = param->level;
1510 	param->result.bufptr.p = infonres;
1511 
1512 	bzero(&se, sizeof (srvsvc_enum_t));
1513 	se.se_level = param->level;
1514 	se.se_n_total = smb_shr_count();
1515 
1516 	if (param->prefmaxlen == SMB_SRVSVC_MAXPREFLEN ||
1517 	    param->prefmaxlen > SMB_SRVSVC_MAXBUFLEN)
1518 		se.se_prefmaxlen = SMB_SRVSVC_MAXBUFLEN;
1519 	else
1520 		se.se_prefmaxlen = param->prefmaxlen;
1521 
1522 	if (param->resume_handle) {
1523 		se.se_resume_handle = *param->resume_handle;
1524 		se.se_n_skip = se.se_resume_handle;
1525 	}
1526 
1527 	switch (param->level) {
1528 	case 0:
1529 		status = mlsvc_NetShareEnumLevel0(mxa, infonres, &se, 1);
1530 		break;
1531 
1532 	case 1:
1533 		status = mlsvc_NetShareEnumLevel1(mxa, infonres, &se, 1);
1534 		break;
1535 
1536 	case 2:
1537 		status = mlsvc_NetShareEnumLevel2(mxa, infonres, &se, 1);
1538 		break;
1539 
1540 	case 502:
1541 		status = mlsvc_NetShareEnumLevel502(mxa, infonres, &se, 1);
1542 		break;
1543 
1544 	default:
1545 		status = ERROR_INVALID_LEVEL;
1546 		break;
1547 	}
1548 
1549 	if (status != ERROR_SUCCESS) {
1550 		bzero(param, sizeof (struct mslm_NetShareEnum));
1551 		param->status = status;
1552 		return (NDR_DRC_OK);
1553 	}
1554 
1555 	if (se.se_n_enum == 0) {
1556 		if (param->resume_handle)
1557 			*param->resume_handle = 0;
1558 		param->status = ERROR_SUCCESS;
1559 		return (NDR_DRC_OK);
1560 	}
1561 
1562 	if (param->resume_handle &&
1563 	    param->prefmaxlen != SMB_SRVSVC_MAXPREFLEN) {
1564 		if (se.se_resume_handle < se.se_n_total) {
1565 			*param->resume_handle = se.se_resume_handle;
1566 			status = ERROR_MORE_DATA;
1567 		} else {
1568 			*param->resume_handle = 0;
1569 		}
1570 	}
1571 
1572 	param->totalentries = se.se_n_total;
1573 	param->status = status;
1574 	return (NDR_DRC_OK);
1575 }
1576 
1577 /*
1578  * NetShareEnum Level 0
1579  */
1580 static DWORD
1581 mlsvc_NetShareEnumLevel0(ndr_xa_t *mxa,
1582     struct mslm_infonres *infonres, srvsvc_enum_t *se, int sticky)
1583 {
1584 	struct mslm_SHARE_INFO_0 *info0;
1585 	smb_shriter_t iterator;
1586 	smb_share_t *si;
1587 	DWORD status;
1588 
1589 	se->se_n_enum = srvsvc_estimate_objcnt(se->se_prefmaxlen,
1590 	    se->se_n_total, sizeof (struct mslm_SHARE_INFO_0) + MAXNAMELEN);
1591 	if (se->se_n_enum == 0)
1592 		return (ERROR_SUCCESS);
1593 
1594 	info0 = NDR_NEWN(mxa, struct mslm_SHARE_INFO_0, se->se_n_enum);
1595 	if (info0 == NULL)
1596 		return (ERROR_NOT_ENOUGH_MEMORY);
1597 
1598 	smb_shr_iterinit(&iterator);
1599 
1600 	se->se_n_read = 0;
1601 	while ((si = smb_shr_iterate(&iterator)) != NULL) {
1602 		if (se->se_n_skip > 0) {
1603 			--se->se_n_skip;
1604 			continue;
1605 		}
1606 
1607 		++se->se_resume_handle;
1608 
1609 		if (sticky && (si->shr_flags & SMB_SHRF_TRANS))
1610 			continue;
1611 
1612 		if (si->shr_flags & SMB_SHRF_AUTOHOME)
1613 			continue;
1614 
1615 		if (se->se_n_read >= se->se_n_enum) {
1616 			se->se_n_read = se->se_n_enum;
1617 			break;
1618 		}
1619 
1620 		status = mlsvc_NetShareEnumCommon(mxa, se, si, (void *)info0);
1621 		if (status != ERROR_SUCCESS)
1622 			break;
1623 
1624 		++se->se_n_read;
1625 	}
1626 
1627 	if (se->se_n_read < se->se_n_enum) {
1628 		if (srvsvc_add_autohome(mxa, se, (void *)info0))
1629 			++se->se_n_read;
1630 	}
1631 
1632 	infonres->entriesread = se->se_n_read;
1633 	infonres->entries = info0;
1634 	return (ERROR_SUCCESS);
1635 }
1636 
1637 /*
1638  * NetShareEnum Level 1
1639  */
1640 static DWORD
1641 mlsvc_NetShareEnumLevel1(ndr_xa_t *mxa,
1642     struct mslm_infonres *infonres, srvsvc_enum_t *se, int sticky)
1643 {
1644 	struct mslm_SHARE_INFO_1 *info1;
1645 	smb_shriter_t iterator;
1646 	smb_share_t *si;
1647 	DWORD status;
1648 
1649 	se->se_n_enum = srvsvc_estimate_objcnt(se->se_prefmaxlen,
1650 	    se->se_n_total, sizeof (struct mslm_SHARE_INFO_1) + MAXNAMELEN);
1651 	if (se->se_n_enum == 0)
1652 		return (ERROR_SUCCESS);
1653 
1654 	info1 = NDR_NEWN(mxa, struct mslm_SHARE_INFO_1, se->se_n_enum);
1655 	if (info1 == NULL)
1656 		return (ERROR_NOT_ENOUGH_MEMORY);
1657 
1658 	smb_shr_iterinit(&iterator);
1659 
1660 	se->se_n_read = 0;
1661 	while ((si = smb_shr_iterate(&iterator)) != 0) {
1662 		if (se->se_n_skip > 0) {
1663 			--se->se_n_skip;
1664 			continue;
1665 		}
1666 
1667 		++se->se_resume_handle;
1668 
1669 		if (sticky && (si->shr_flags & SMB_SHRF_TRANS))
1670 			continue;
1671 
1672 		if (si->shr_flags & SMB_SHRF_AUTOHOME)
1673 			continue;
1674 
1675 		if (se->se_n_read >= se->se_n_enum) {
1676 			se->se_n_read = se->se_n_enum;
1677 			break;
1678 		}
1679 
1680 		status = mlsvc_NetShareEnumCommon(mxa, se, si, (void *)info1);
1681 		if (status != ERROR_SUCCESS)
1682 			break;
1683 
1684 		++se->se_n_read;
1685 	}
1686 
1687 	if (se->se_n_read < se->se_n_enum) {
1688 		if (srvsvc_add_autohome(mxa, se, (void *)info1))
1689 			++se->se_n_read;
1690 	}
1691 
1692 	infonres->entriesread = se->se_n_read;
1693 	infonres->entries = info1;
1694 	return (ERROR_SUCCESS);
1695 }
1696 
1697 /*
1698  * NetShareEnum Level 2
1699  */
1700 static DWORD
1701 mlsvc_NetShareEnumLevel2(ndr_xa_t *mxa,
1702     struct mslm_infonres *infonres, srvsvc_enum_t *se, int sticky)
1703 {
1704 	struct mslm_SHARE_INFO_2 *info2;
1705 	smb_shriter_t iterator;
1706 	smb_share_t *si;
1707 	DWORD status;
1708 
1709 	se->se_n_enum = srvsvc_estimate_objcnt(se->se_prefmaxlen,
1710 	    se->se_n_total, sizeof (struct mslm_SHARE_INFO_2) + MAXNAMELEN);
1711 	if (se->se_n_enum == 0)
1712 		return (ERROR_SUCCESS);
1713 
1714 	info2 = NDR_NEWN(mxa, struct mslm_SHARE_INFO_2, se->se_n_enum);
1715 	if (info2 == NULL)
1716 		return (ERROR_NOT_ENOUGH_MEMORY);
1717 
1718 	smb_shr_iterinit(&iterator);
1719 
1720 	se->se_n_read = 0;
1721 	while ((si = smb_shr_iterate(&iterator)) != 0) {
1722 		if (se->se_n_skip > 0) {
1723 			--se->se_n_skip;
1724 			continue;
1725 		}
1726 
1727 		++se->se_resume_handle;
1728 
1729 		if (sticky && (si->shr_flags & SMB_SHRF_TRANS))
1730 			continue;
1731 
1732 		if (si->shr_flags & SMB_SHRF_AUTOHOME)
1733 			continue;
1734 
1735 		if (se->se_n_read >= se->se_n_enum) {
1736 			se->se_n_read = se->se_n_enum;
1737 			break;
1738 		}
1739 
1740 		status = mlsvc_NetShareEnumCommon(mxa, se, si, (void *)info2);
1741 		if (status != ERROR_SUCCESS)
1742 			break;
1743 
1744 		++se->se_n_read;
1745 	}
1746 
1747 	if (se->se_n_read < se->se_n_enum) {
1748 		if (srvsvc_add_autohome(mxa, se, (void *)info2))
1749 			++se->se_n_read;
1750 	}
1751 
1752 	infonres->entriesread = se->se_n_read;
1753 	infonres->entries = info2;
1754 	return (ERROR_SUCCESS);
1755 }
1756 
1757 /*
1758  * NetShareEnum Level 501
1759  */
1760 static DWORD
1761 mlsvc_NetShareEnumLevel501(ndr_xa_t *mxa,
1762     struct mslm_infonres *infonres, srvsvc_enum_t *se, int sticky)
1763 {
1764 	struct mslm_SHARE_INFO_501 *info501;
1765 	smb_shriter_t iterator;
1766 	smb_share_t *si;
1767 	DWORD status;
1768 
1769 	se->se_n_enum = srvsvc_estimate_objcnt(se->se_prefmaxlen,
1770 	    se->se_n_total, sizeof (struct mslm_SHARE_INFO_501) + MAXNAMELEN);
1771 	if (se->se_n_enum == 0)
1772 		return (ERROR_SUCCESS);
1773 
1774 	info501 = NDR_NEWN(mxa, struct mslm_SHARE_INFO_501,
1775 	    se->se_n_enum);
1776 	if (info501 == NULL)
1777 		return (ERROR_NOT_ENOUGH_MEMORY);
1778 
1779 	smb_shr_iterinit(&iterator);
1780 
1781 	se->se_n_read = 0;
1782 	while ((si = smb_shr_iterate(&iterator)) != 0) {
1783 		if (se->se_n_skip > 0) {
1784 			--se->se_n_skip;
1785 			continue;
1786 		}
1787 
1788 		++se->se_resume_handle;
1789 
1790 		if (sticky && (si->shr_flags & SMB_SHRF_TRANS))
1791 			continue;
1792 
1793 		if (si->shr_flags & SMB_SHRF_AUTOHOME)
1794 			continue;
1795 
1796 		if (se->se_n_read >= se->se_n_enum) {
1797 			se->se_n_read = se->se_n_enum;
1798 			break;
1799 		}
1800 
1801 		status = mlsvc_NetShareEnumCommon(mxa, se, si, (void *)info501);
1802 		if (status != ERROR_SUCCESS)
1803 			break;
1804 
1805 		++se->se_n_read;
1806 	}
1807 
1808 	if (se->se_n_read < se->se_n_enum) {
1809 		if (srvsvc_add_autohome(mxa, se, (void *)info501))
1810 			++se->se_n_read;
1811 	}
1812 
1813 	infonres->entriesread = se->se_n_read;
1814 	infonres->entries = info501;
1815 	return (ERROR_SUCCESS);
1816 }
1817 
1818 /*
1819  * NetShareEnum Level 502
1820  */
1821 static DWORD
1822 mlsvc_NetShareEnumLevel502(ndr_xa_t *mxa,
1823     struct mslm_infonres *infonres, srvsvc_enum_t *se, int sticky)
1824 {
1825 	struct mslm_SHARE_INFO_502 *info502;
1826 	smb_shriter_t iterator;
1827 	smb_share_t *si;
1828 	DWORD status;
1829 
1830 	se->se_n_enum = srvsvc_estimate_objcnt(se->se_prefmaxlen,
1831 	    se->se_n_total, sizeof (struct mslm_SHARE_INFO_502) + MAXNAMELEN);
1832 	if (se->se_n_enum == 0)
1833 		return (ERROR_SUCCESS);
1834 
1835 	info502 = NDR_NEWN(mxa, struct mslm_SHARE_INFO_502,
1836 	    se->se_n_enum);
1837 	if (info502 == NULL)
1838 		return (ERROR_NOT_ENOUGH_MEMORY);
1839 
1840 	smb_shr_iterinit(&iterator);
1841 
1842 	se->se_n_read = 0;
1843 	while ((si = smb_shr_iterate(&iterator)) != NULL) {
1844 		if (se->se_n_skip > 0) {
1845 			--se->se_n_skip;
1846 			continue;
1847 		}
1848 
1849 		++se->se_resume_handle;
1850 
1851 		if (sticky && (si->shr_flags & SMB_SHRF_TRANS))
1852 			continue;
1853 
1854 		if (si->shr_flags & SMB_SHRF_AUTOHOME)
1855 			continue;
1856 
1857 		if (se->se_n_read >= se->se_n_enum) {
1858 			se->se_n_read = se->se_n_enum;
1859 			break;
1860 		}
1861 
1862 		status = mlsvc_NetShareEnumCommon(mxa, se, si, (void *)info502);
1863 		if (status != ERROR_SUCCESS)
1864 			break;
1865 
1866 		++se->se_n_read;
1867 	}
1868 
1869 	if (se->se_n_read < se->se_n_enum) {
1870 		if (srvsvc_add_autohome(mxa, se, (void *)info502))
1871 			++se->se_n_read;
1872 	}
1873 
1874 	infonres->entriesread = se->se_n_read;
1875 	infonres->entries = info502;
1876 	return (ERROR_SUCCESS);
1877 }
1878 
1879 /*
1880  * mlsvc_NetShareEnumCommon
1881  *
1882  * Build the levels 0, 1, 2, 501 and 502 share information. This function
1883  * is called by the various NetShareEnum levels for each share. If
1884  * we cannot build the share data for some reason, we return an error
1885  * but the actual value of the error is not important to the caller.
1886  * The caller just needs to know not to include this info in the RPC
1887  * response.
1888  *
1889  * Returns:
1890  *	ERROR_SUCCESS
1891  *	ERROR_NOT_ENOUGH_MEMORY
1892  *	ERROR_INVALID_LEVEL
1893  */
1894 static DWORD
1895 mlsvc_NetShareEnumCommon(ndr_xa_t *mxa, srvsvc_enum_t *se,
1896     smb_share_t *si, void *infop)
1897 {
1898 	struct mslm_SHARE_INFO_0 *info0;
1899 	struct mslm_SHARE_INFO_1 *info1;
1900 	struct mslm_SHARE_INFO_2 *info2;
1901 	struct mslm_SHARE_INFO_501 *info501;
1902 	struct mslm_SHARE_INFO_502 *info502;
1903 	int i = se->se_n_read;
1904 
1905 	switch (se->se_level) {
1906 	case 0:
1907 		info0 = (struct mslm_SHARE_INFO_0 *)infop;
1908 		info0[i].shi0_netname
1909 		    = (uint8_t *)NDR_STRDUP(mxa, si->shr_name);
1910 
1911 		if (info0[i].shi0_netname == NULL)
1912 			return (ERROR_NOT_ENOUGH_MEMORY);
1913 		break;
1914 
1915 	case 1:
1916 		info1 = (struct mslm_SHARE_INFO_1 *)infop;
1917 		info1[i].shi1_netname
1918 		    = (uint8_t *)NDR_STRDUP(mxa, si->shr_name);
1919 		info1[i].shi1_remark
1920 		    = (uint8_t *)NDR_STRDUP(mxa, si->shr_cmnt);
1921 
1922 		info1[i].shi1_type = si->shr_type;
1923 
1924 		if (!info1[i].shi1_netname || !info1[i].shi1_remark)
1925 			return (ERROR_NOT_ENOUGH_MEMORY);
1926 		break;
1927 
1928 	case 2:
1929 		info2 = (struct mslm_SHARE_INFO_2 *)infop;
1930 		info2[i].shi2_netname
1931 		    = (uint8_t *)NDR_STRDUP(mxa, si->shr_name);
1932 		info2[i].shi2_remark
1933 		    = (uint8_t *)NDR_STRDUP(mxa, si->shr_cmnt);
1934 
1935 		info2[i].shi2_path
1936 		    = (uint8_t *)srvsvc_share_mkpath(mxa, si->shr_path);
1937 
1938 		info2[i].shi2_type = si->shr_type;
1939 		info2[i].shi2_permissions = 0;
1940 		info2[i].shi2_max_uses = SHI_USES_UNLIMITED;
1941 		info2[i].shi2_current_uses = 0;
1942 		info2[i].shi2_passwd
1943 		    = (uint8_t *)NDR_STRDUP(mxa, empty_string);
1944 
1945 		if (!info2[i].shi2_netname || !info2[i].shi2_remark ||
1946 		    !info2[i].shi2_passwd || !info2[i].shi2_path)
1947 			return (ERROR_NOT_ENOUGH_MEMORY);
1948 
1949 		break;
1950 
1951 	case 501:
1952 		info501 = (struct mslm_SHARE_INFO_501 *)infop;
1953 		info501[i].shi501_netname
1954 		    = (uint8_t *)NDR_STRDUP(mxa, si->shr_name);
1955 		info501[i].shi501_remark
1956 		    = (uint8_t *)NDR_STRDUP(mxa, si->shr_cmnt);
1957 
1958 		info501[i].shi501_type = si->shr_type;
1959 		info501[i].shi501_flags = 0;
1960 
1961 		if (!info501[i].shi501_netname || !info501[i].shi501_remark)
1962 			return (ERROR_NOT_ENOUGH_MEMORY);
1963 		break;
1964 
1965 	case 502:
1966 		info502 = (struct mslm_SHARE_INFO_502 *)infop;
1967 		info502[i].shi502_netname
1968 		    = (uint8_t *)NDR_STRDUP(mxa, si->shr_name);
1969 		info502[i].shi502_remark
1970 		    = (uint8_t *)NDR_STRDUP(mxa, si->shr_cmnt);
1971 
1972 		info502[i].shi502_path
1973 		    = (uint8_t *)srvsvc_share_mkpath(mxa, si->shr_path);
1974 
1975 		info502[i].shi502_type = si->shr_type;
1976 		info502[i].shi502_permissions = 0;
1977 		info502[i].shi502_max_uses = SHI_USES_UNLIMITED;
1978 		info502[i].shi502_current_uses = 0;
1979 		info502[i].shi502_passwd
1980 		    = (uint8_t *)NDR_STRDUP(mxa, empty_string);
1981 
1982 		info502[i].shi502_reserved = 0;
1983 		info502[i].shi502_security_descriptor = 0;
1984 
1985 		if (!info502[i].shi502_netname || !info502[i].shi502_remark ||
1986 		    !info502[i].shi502_passwd || !info502[i].shi502_path)
1987 			return (ERROR_NOT_ENOUGH_MEMORY);
1988 		break;
1989 
1990 	default:
1991 		return (ERROR_INVALID_LEVEL);
1992 	}
1993 
1994 	return (ERROR_SUCCESS);
1995 }
1996 
1997 /*
1998  * srvsvc_add_autohome
1999  *
2000  * Add the autohome share for the user. The share must not be a permanent
2001  * share to avoid duplicates.
2002  */
2003 static boolean_t
2004 srvsvc_add_autohome(ndr_xa_t *mxa, srvsvc_enum_t *se, void *infop)
2005 {
2006 	smb_opipe_context_t *ctx = &mxa->pipe->np_ctx;
2007 	char *username = ctx->oc_account;
2008 	smb_share_t si;
2009 	DWORD status;
2010 
2011 	if (smb_shr_get(username, &si) != NERR_Success)
2012 		return (B_FALSE);
2013 
2014 	if ((si.shr_flags & SMB_SHRF_AUTOHOME) == 0)
2015 		return (B_FALSE);
2016 
2017 	status = mlsvc_NetShareEnumCommon(mxa, se, &si, infop);
2018 	return (status == ERROR_SUCCESS);
2019 }
2020 
2021 /*
2022  * srvsvc_share_mkpath
2023  *
2024  * Create the share path required by the share enum calls. The path
2025  * is created in a heap buffer ready for use by the caller.
2026  *
2027  * Some Windows over-the-wire backup applications do not work unless a
2028  * drive letter is present in the share path.  We don't care about the
2029  * drive letter since the path is fully qualified with the volume name.
2030  *
2031  * Windows clients seem to be mostly okay with forward slashes in
2032  * share paths but they cannot handle one immediately after the drive
2033  * letter, i.e. B:/.  For consistency we convert all the slashes in
2034  * the path.
2035  *
2036  * Returns a pointer to a heap buffer containing the share path, which
2037  * could be a null pointer if the heap allocation fails.
2038  */
2039 static char *
2040 srvsvc_share_mkpath(ndr_xa_t *mxa, char *path)
2041 {
2042 	char tmpbuf[MAXPATHLEN];
2043 	char *p;
2044 
2045 	if (strlen(path) == 0)
2046 		return (NDR_STRDUP(mxa, path));
2047 
2048 	/*
2049 	 * Strip the volume name from the path (/vol1/home -> /home).
2050 	 */
2051 	p = path;
2052 	p += strspn(p, "/");
2053 	p += strcspn(p, "/");
2054 	p += strspn(p, "/");
2055 	(void) snprintf(tmpbuf, MAXPATHLEN, "%c:/%s", 'B', p);
2056 	(void) strsubst(tmpbuf, '/', '\\');
2057 
2058 	return (NDR_STRDUP(mxa, tmpbuf));
2059 }
2060 
2061 /*
2062  * srvsvc_s_NetShareDel
2063  *
2064  * Delete a share. Only the administrator, or a member of the domain
2065  * administrators group, is allowed to delete shares.
2066  *
2067  * This interface is used by the rmtshare command from the NT resource
2068  * kit. Rmtshare allows a client to add or remove shares on a server
2069  * from the client's command line.
2070  *
2071  * Returns Win32 error codes.
2072  */
2073 static int
2074 srvsvc_s_NetShareDel(void *arg, ndr_xa_t *mxa)
2075 {
2076 	struct mslm_NetShareDel *param = arg;
2077 
2078 	if (!ndr_is_poweruser(mxa) ||
2079 	    smb_shr_is_restricted((char *)param->netname)) {
2080 		param->status = ERROR_ACCESS_DENIED;
2081 		return (NDR_DRC_OK);
2082 	}
2083 
2084 	param->status = srvsvc_sa_delete((char *)param->netname);
2085 	return (NDR_DRC_OK);
2086 }
2087 
2088 /*
2089  * srvsvc_s_NetGetFileSecurity
2090  *
2091  * Get security descriptor of the requested file/folder
2092  *
2093  * Right now, just returns ERROR_ACCESS_DENIED, because we cannot
2094  * get the requested SD here in RPC code.
2095  */
2096 /*ARGSUSED*/
2097 static int
2098 srvsvc_s_NetGetFileSecurity(void *arg, ndr_xa_t *mxa)
2099 {
2100 	struct mslm_NetGetFileSecurity *param = arg;
2101 
2102 	param->length = 0;
2103 	param->status = ERROR_ACCESS_DENIED;
2104 	return (NDR_DRC_OK);
2105 }
2106 
2107 /*
2108  * srvsvc_s_NetSetFileSecurity
2109  *
2110  * Set the given security descriptor for the requested file/folder
2111  *
2112  * Right now, just returns ERROR_ACCESS_DENIED, because we cannot
2113  * set the requested SD here in RPC code.
2114  */
2115 /*ARGSUSED*/
2116 static int
2117 srvsvc_s_NetSetFileSecurity(void *arg, ndr_xa_t *mxa)
2118 {
2119 	struct mslm_NetSetFileSecurity *param = arg;
2120 
2121 	param->status = ERROR_ACCESS_DENIED;
2122 	return (NDR_DRC_OK);
2123 }
2124 
2125 /*
2126  * If the default "smb" share group exists then return the group
2127  * handle, otherwise create the group and return the handle.
2128  *
2129  * All shares created via the srvsvc will be added to the "smb"
2130  * group.
2131  */
2132 static sa_group_t
2133 srvsvc_sa_get_smbgrp(sa_handle_t handle)
2134 {
2135 	sa_group_t group = NULL;
2136 	int err;
2137 
2138 	group = sa_get_group(handle, SMB_DEFAULT_SHARE_GROUP);
2139 	if (group != NULL)
2140 		return (group);
2141 
2142 	group = sa_create_group(handle, SMB_DEFAULT_SHARE_GROUP, &err);
2143 	if (group == NULL)
2144 		return (NULL);
2145 
2146 	if (sa_create_optionset(group, SMB_DEFAULT_SHARE_GROUP) == NULL) {
2147 		(void) sa_remove_group(group);
2148 		group = NULL;
2149 	}
2150 
2151 	return (group);
2152 }
2153 
2154 /*
2155  * Stores the given share in sharemgr
2156  */
2157 static uint32_t
2158 srvsvc_sa_add(char *sharename, char *path, char *cmnt)
2159 {
2160 	sa_handle_t handle;
2161 	sa_share_t share;
2162 	sa_group_t group;
2163 	sa_resource_t resource;
2164 	boolean_t new_share = B_FALSE;
2165 	uint32_t status = NERR_Success;
2166 	int err;
2167 
2168 	if ((handle = smb_shr_sa_enter()) == NULL)
2169 		return (NERR_InternalError);
2170 
2171 	share = sa_find_share(handle, path);
2172 	if (share == NULL) {
2173 		group = srvsvc_sa_get_smbgrp(handle);
2174 		if (group == NULL) {
2175 			smb_shr_sa_exit();
2176 			return (NERR_InternalError);
2177 		}
2178 
2179 		share = sa_add_share(group, path, SA_SHARE_PERMANENT, &err);
2180 		if (share == NULL) {
2181 			smb_shr_sa_exit();
2182 			return (NERR_InternalError);
2183 		}
2184 		new_share = B_TRUE;
2185 	}
2186 
2187 	resource = sa_get_share_resource(share, sharename);
2188 	if (resource == NULL) {
2189 		resource = sa_add_resource(share, sharename,
2190 		    SA_SHARE_PERMANENT, &err);
2191 		if (resource == NULL) {
2192 			if (new_share)
2193 				(void) sa_remove_share(share);
2194 			smb_shr_sa_exit();
2195 			return (NERR_InternalError);
2196 		}
2197 	}
2198 
2199 	(void) sa_set_resource_description(resource, cmnt);
2200 
2201 	smb_shr_sa_exit();
2202 	return (status);
2203 }
2204 
2205 /*
2206  * Removes the share from sharemgr
2207  */
2208 static uint32_t
2209 srvsvc_sa_delete(char *sharename)
2210 {
2211 	sa_handle_t handle;
2212 	sa_resource_t resource;
2213 	uint32_t status;
2214 
2215 	if ((handle = smb_shr_sa_enter()) == NULL)
2216 		return (NERR_InternalError);
2217 
2218 	status = NERR_InternalError;
2219 	if ((resource = sa_find_resource(handle, sharename)) != NULL) {
2220 		if (sa_remove_resource(resource) == SA_OK)
2221 			status = NERR_Success;
2222 	}
2223 
2224 	smb_shr_sa_exit();
2225 	return (status);
2226 }
2227 
2228 static ndr_stub_table_t srvsvc_stub_table[] = {
2229 	{ srvsvc_s_NetConnectEnum,	SRVSVC_OPNUM_NetConnectEnum },
2230 	{ srvsvc_s_NetFileEnum,		SRVSVC_OPNUM_NetFileEnum },
2231 	{ srvsvc_s_NetFileClose,	SRVSVC_OPNUM_NetFileClose },
2232 	{ srvsvc_s_NetShareGetInfo,	SRVSVC_OPNUM_NetShareGetInfo },
2233 	{ srvsvc_s_NetShareSetInfo,	SRVSVC_OPNUM_NetShareSetInfo },
2234 	{ srvsvc_s_NetSessionEnum,	SRVSVC_OPNUM_NetSessionEnum },
2235 	{ srvsvc_s_NetSessionDel,	SRVSVC_OPNUM_NetSessionDel },
2236 	{ srvsvc_s_NetServerGetInfo,	SRVSVC_OPNUM_NetServerGetInfo },
2237 	{ srvsvc_s_NetRemoteTOD,	SRVSVC_OPNUM_NetRemoteTOD },
2238 	{ srvsvc_s_NetNameValidate,	SRVSVC_OPNUM_NetNameValidate },
2239 	{ srvsvc_s_NetShareAdd,		SRVSVC_OPNUM_NetShareAdd },
2240 	{ srvsvc_s_NetShareDel,		SRVSVC_OPNUM_NetShareDel },
2241 	{ srvsvc_s_NetShareEnum,	SRVSVC_OPNUM_NetShareEnum },
2242 	{ srvsvc_s_NetShareEnumSticky,	SRVSVC_OPNUM_NetShareEnumSticky },
2243 	{ srvsvc_s_NetGetFileSecurity,	SRVSVC_OPNUM_NetGetFileSecurity },
2244 	{ srvsvc_s_NetSetFileSecurity,	SRVSVC_OPNUM_NetSetFileSecurity },
2245 	{0}
2246 };
2247