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