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