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