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