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 * This module provides the high level interface to the LSA RPC functions. 28 */ 29 30 #include <strings.h> 31 #include <unistd.h> 32 33 #include <smbsrv/libsmb.h> 34 #include <smbsrv/libmlsvc.h> 35 #include <smbsrv/ntstatus.h> 36 #include <smbsrv/smbinfo.h> 37 #include <smbsrv/smb_token.h> 38 39 #include <lsalib.h> 40 41 static uint32_t lsa_lookup_name_builtin(char *, char *, smb_account_t *); 42 static uint32_t lsa_lookup_name_domain(char *, smb_account_t *); 43 44 static uint32_t lsa_lookup_sid_builtin(smb_sid_t *, smb_account_t *); 45 static uint32_t lsa_lookup_sid_domain(smb_sid_t *, smb_account_t *); 46 47 static int lsa_list_accounts(mlsvc_handle_t *); 48 49 /* 50 * Lookup the given account and returns the account information 51 * in the passed smb_account_t structure. 52 * 53 * The lookup is performed in the following order: 54 * well known accounts 55 * local accounts 56 * domain accounts 57 * 58 * If it's established the given account is well know or local 59 * but the lookup fails for some reason, the next step(s) won't be 60 * performed. 61 * 62 * If the name is a domain account, it may refer to a user, group or 63 * alias. If it is a local account, its type should be specified 64 * in the sid_type parameter. In case the account type is unknown 65 * sid_type should be set to SidTypeUnknown. 66 * 67 * account argument could be either [domain\]name or [domain/]name. 68 * 69 * Return status: 70 * 71 * NT_STATUS_SUCCESS Account is successfully translated 72 * NT_STATUS_NONE_MAPPED Couldn't translate the account 73 */ 74 uint32_t 75 lsa_lookup_name(char *account, uint16_t type, smb_account_t *info) 76 { 77 char nambuf[SMB_USERNAME_MAXLEN]; 78 char dombuf[SMB_PI_MAX_DOMAIN]; 79 char *name, *domain; 80 uint32_t status; 81 char *slash; 82 83 (void) strsubst(account, '/', '\\'); 84 (void) strcanon(account, "\\"); 85 /* \john -> john */ 86 account += strspn(account, "\\"); 87 88 if ((slash = strchr(account, '\\')) != NULL) { 89 *slash = '\0'; 90 (void) strlcpy(dombuf, account, sizeof (dombuf)); 91 (void) strlcpy(nambuf, slash + 1, sizeof (nambuf)); 92 *slash = '\\'; 93 name = nambuf; 94 domain = dombuf; 95 } else { 96 name = account; 97 domain = NULL; 98 } 99 100 status = lsa_lookup_name_builtin(domain, name, info); 101 if (status == NT_STATUS_NOT_FOUND) { 102 status = smb_sam_lookup_name(domain, name, type, info); 103 if (status == NT_STATUS_SUCCESS) 104 return (status); 105 106 if ((domain == NULL) || (status == NT_STATUS_NOT_FOUND)) 107 status = lsa_lookup_name_domain(account, info); 108 } 109 110 return ((status == NT_STATUS_SUCCESS) ? status : NT_STATUS_NONE_MAPPED); 111 } 112 113 uint32_t 114 lsa_lookup_sid(smb_sid_t *sid, smb_account_t *info) 115 { 116 uint32_t status; 117 118 if (!smb_sid_isvalid(sid)) 119 return (NT_STATUS_INVALID_SID); 120 121 status = lsa_lookup_sid_builtin(sid, info); 122 if (status == NT_STATUS_NOT_FOUND) { 123 status = smb_sam_lookup_sid(sid, info); 124 if (status == NT_STATUS_NOT_FOUND) 125 status = lsa_lookup_sid_domain(sid, info); 126 } 127 128 return ((status == NT_STATUS_SUCCESS) ? status : NT_STATUS_NONE_MAPPED); 129 } 130 131 /* 132 * Obtains the primary domain SID and name from the specified server 133 * (domain controller). 134 * 135 * The requested information will be returned via 'info' argument. 136 * 137 * Returns NT status codes. 138 */ 139 DWORD 140 lsa_query_primary_domain_info(char *server, char *domain, 141 smb_domain_t *info) 142 { 143 mlsvc_handle_t domain_handle; 144 DWORD status; 145 char user[SMB_USERNAME_MAXLEN]; 146 147 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN); 148 149 if ((lsar_open(server, domain, user, &domain_handle)) != 0) 150 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); 151 152 status = lsar_query_info_policy(&domain_handle, 153 MSLSA_POLICY_PRIMARY_DOMAIN_INFO, info); 154 155 (void) lsar_close(&domain_handle); 156 return (status); 157 } 158 159 /* 160 * Obtains the account domain SID and name from the current server 161 * (domain controller). 162 * 163 * The requested information will be returned via 'info' argument. 164 * 165 * Returns NT status codes. 166 */ 167 DWORD 168 lsa_query_account_domain_info(char *server, char *domain, 169 smb_domain_t *info) 170 { 171 mlsvc_handle_t domain_handle; 172 DWORD status; 173 char user[SMB_USERNAME_MAXLEN]; 174 175 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN); 176 177 if ((lsar_open(server, domain, user, &domain_handle)) != 0) 178 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); 179 180 status = lsar_query_info_policy(&domain_handle, 181 MSLSA_POLICY_ACCOUNT_DOMAIN_INFO, info); 182 183 (void) lsar_close(&domain_handle); 184 return (status); 185 } 186 187 /* 188 * lsa_query_dns_domain_info 189 * 190 * Obtains the DNS domain info from the specified server 191 * (domain controller). 192 * 193 * The requested information will be returned via 'info' argument. 194 * 195 * Returns NT status codes. 196 */ 197 DWORD 198 lsa_query_dns_domain_info(char *server, char *domain, smb_domain_t *info) 199 { 200 mlsvc_handle_t domain_handle; 201 DWORD status; 202 char user[SMB_USERNAME_MAXLEN]; 203 204 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN); 205 206 if ((lsar_open(server, domain, user, &domain_handle)) != 0) 207 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); 208 209 status = lsar_query_info_policy(&domain_handle, 210 MSLSA_POLICY_DNS_DOMAIN_INFO, info); 211 212 (void) lsar_close(&domain_handle); 213 return (status); 214 } 215 216 /* 217 * Enumerate the trusted domains of primary domain. 218 * This is the basic enumaration call which only returns the 219 * NetBIOS name of the domain and its SID. 220 * 221 * The requested information will be returned via 'info' argument. 222 * 223 * Returns NT status codes. 224 */ 225 DWORD 226 lsa_enum_trusted_domains(char *server, char *domain, 227 smb_trusted_domains_t *info) 228 { 229 mlsvc_handle_t domain_handle; 230 DWORD enum_context; 231 DWORD status; 232 char user[SMB_USERNAME_MAXLEN]; 233 234 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN); 235 236 if ((lsar_open(server, domain, user, &domain_handle)) != 0) 237 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); 238 239 enum_context = 0; 240 241 status = lsar_enum_trusted_domains(&domain_handle, &enum_context, info); 242 if (status == NT_STATUS_NO_MORE_DATA) { 243 /* 244 * NT_STATUS_NO_MORE_DATA indicates that we 245 * have all of the available information. 246 */ 247 status = NT_STATUS_SUCCESS; 248 } 249 250 (void) lsar_close(&domain_handle); 251 return (status); 252 } 253 254 /* 255 * Enumerate the trusted domains of the primary domain. 256 * This is the extended enumaration call which besides 257 * NetBIOS name of the domain and its SID, it will return 258 * the FQDN plus some trust information which is not used. 259 * 260 * The requested information will be returned via 'info' argument. 261 * 262 * Returns NT status codes. 263 */ 264 DWORD 265 lsa_enum_trusted_domains_ex(char *server, char *domain, 266 smb_trusted_domains_t *info) 267 { 268 mlsvc_handle_t domain_handle; 269 DWORD enum_context; 270 DWORD status; 271 char user[SMB_USERNAME_MAXLEN]; 272 273 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN); 274 275 if ((lsar_open(server, domain, user, &domain_handle)) != 0) 276 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); 277 278 enum_context = 0; 279 280 status = lsar_enum_trusted_domains_ex(&domain_handle, &enum_context, 281 info); 282 if (status == NT_STATUS_NO_MORE_DATA) { 283 /* 284 * NT_STATUS_NO_MORE_DATA indicates that we 285 * have all of the available information. 286 */ 287 status = NT_STATUS_SUCCESS; 288 } 289 290 (void) lsar_close(&domain_handle); 291 return (status); 292 } 293 294 /* 295 * Lookup well known accounts table 296 * 297 * Return status: 298 * 299 * NT_STATUS_SUCCESS Account is translated successfully 300 * NT_STATUS_NOT_FOUND This is not a well known account 301 * NT_STATUS_NONE_MAPPED Account is found but domains don't match 302 * NT_STATUS_NO_MEMORY Memory shortage 303 * NT_STATUS_INTERNAL_ERROR Internal error/unexpected failure 304 */ 305 static uint32_t 306 lsa_lookup_name_builtin(char *domain, char *name, smb_account_t *info) 307 { 308 smb_wka_t *wka; 309 char *wkadom; 310 311 bzero(info, sizeof (smb_account_t)); 312 313 if ((wka = smb_wka_lookup_name(name)) == NULL) 314 return (NT_STATUS_NOT_FOUND); 315 316 if ((wkadom = smb_wka_get_domain(wka->wka_domidx)) == NULL) 317 return (NT_STATUS_INTERNAL_ERROR); 318 319 if ((domain != NULL) && (smb_strcasecmp(domain, wkadom, 0) != 0)) 320 return (NT_STATUS_NONE_MAPPED); 321 322 info->a_name = strdup(name); 323 info->a_sid = smb_sid_dup(wka->wka_binsid); 324 info->a_domain = strdup(wkadom); 325 info->a_domsid = smb_sid_split(wka->wka_binsid, &info->a_rid); 326 info->a_type = wka->wka_type; 327 328 if (!smb_account_validate(info)) { 329 smb_account_free(info); 330 return (NT_STATUS_NO_MEMORY); 331 } 332 333 return (NT_STATUS_SUCCESS); 334 } 335 336 /* 337 * Lookup the given account in domain. 338 * 339 * The information is returned in the user_info structure. 340 * The caller is responsible for allocating and releasing 341 * this structure. 342 */ 343 static uint32_t 344 lsa_lookup_name_domain(char *account_name, smb_account_t *info) 345 { 346 mlsvc_handle_t domain_handle; 347 smb_domainex_t dinfo; 348 uint32_t status; 349 char user[SMB_USERNAME_MAXLEN]; 350 351 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN); 352 353 if (!smb_domain_getinfo(&dinfo)) 354 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); 355 356 if (lsar_open(dinfo.d_dc, dinfo.d_primary.di_nbname, user, 357 &domain_handle) != 0) 358 return (NT_STATUS_INVALID_PARAMETER); 359 360 status = lsar_lookup_names(&domain_handle, account_name, info); 361 362 (void) lsar_close(&domain_handle); 363 return (status); 364 } 365 366 /* 367 * lsa_lookup_privs 368 * 369 * Request the privileges associated with the specified account. In 370 * order to get the privileges, we first have to lookup the name on 371 * the specified domain controller and obtain the appropriate SID. 372 * The SID can then be used to open the account and obtain the 373 * account privileges. The results from both the name lookup and the 374 * privileges are returned in the user_info structure. The caller is 375 * responsible for allocating and releasing this structure. 376 * 377 * On success 0 is returned. Otherwise a -ve error code. 378 */ 379 /*ARGSUSED*/ 380 int 381 lsa_lookup_privs(char *account_name, char *target_name, smb_account_t *ainfo) 382 { 383 mlsvc_handle_t domain_handle; 384 int rc; 385 smb_domainex_t dinfo; 386 char user[SMB_USERNAME_MAXLEN]; 387 388 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN); 389 390 if (!smb_domain_getinfo(&dinfo)) 391 return (-1); 392 393 if ((lsar_open(dinfo.d_dc, dinfo.d_primary.di_nbname, user, 394 &domain_handle)) != 0) 395 return (-1); 396 397 rc = lsa_list_accounts(&domain_handle); 398 (void) lsar_close(&domain_handle); 399 return (rc); 400 } 401 402 /* 403 * lsa_list_privs 404 * 405 * List the privileges supported by the specified server. 406 * This function is only intended for diagnostics. 407 * 408 * Returns NT status codes. 409 */ 410 DWORD 411 lsa_list_privs(char *server, char *domain) 412 { 413 static char name[128]; 414 static struct ms_luid luid; 415 mlsvc_handle_t domain_handle; 416 int rc; 417 int i; 418 char user[SMB_USERNAME_MAXLEN]; 419 420 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN); 421 422 rc = lsar_open(server, domain, user, &domain_handle); 423 if (rc != 0) 424 return (NT_STATUS_INVALID_PARAMETER); 425 426 for (i = 0; i < 30; ++i) { 427 luid.low_part = i; 428 rc = lsar_lookup_priv_name(&domain_handle, &luid, name, 128); 429 if (rc != 0) 430 continue; 431 432 (void) lsar_lookup_priv_value(&domain_handle, name, &luid); 433 (void) lsar_lookup_priv_display_name(&domain_handle, name, 434 name, 128); 435 } 436 437 (void) lsar_close(&domain_handle); 438 return (NT_STATUS_SUCCESS); 439 } 440 441 /* 442 * lsa_list_accounts 443 * 444 * This function can be used to list the accounts in the specified 445 * domain. For now the SIDs are just listed in the system log. 446 * 447 * On success 0 is returned. Otherwise a -ve error code. 448 */ 449 static int 450 lsa_list_accounts(mlsvc_handle_t *domain_handle) 451 { 452 mlsvc_handle_t account_handle; 453 struct mslsa_EnumAccountBuf accounts; 454 struct mslsa_sid *sid; 455 smb_account_t ainfo; 456 DWORD enum_context = 0; 457 int rc; 458 int i; 459 460 bzero(&accounts, sizeof (struct mslsa_EnumAccountBuf)); 461 462 do { 463 rc = lsar_enum_accounts(domain_handle, &enum_context, 464 &accounts); 465 if (rc != 0) 466 return (rc); 467 468 for (i = 0; i < accounts.entries_read; ++i) { 469 sid = accounts.info[i].sid; 470 471 if (lsar_open_account(domain_handle, sid, 472 &account_handle) == 0) { 473 (void) lsar_enum_privs_account(&account_handle, 474 &ainfo); 475 (void) lsar_close(&account_handle); 476 } 477 478 free(accounts.info[i].sid); 479 } 480 481 if (accounts.info) 482 free(accounts.info); 483 } while (rc == 0 && accounts.entries_read != 0); 484 485 return (0); 486 } 487 488 /* 489 * Lookup well known accounts table for the given SID 490 * 491 * Return status: 492 * 493 * NT_STATUS_SUCCESS Account is translated successfully 494 * NT_STATUS_NOT_FOUND This is not a well known account 495 * NT_STATUS_NO_MEMORY Memory shortage 496 * NT_STATUS_INTERNAL_ERROR Internal error/unexpected failure 497 */ 498 static uint32_t 499 lsa_lookup_sid_builtin(smb_sid_t *sid, smb_account_t *ainfo) 500 { 501 smb_wka_t *wka; 502 char *wkadom; 503 504 bzero(ainfo, sizeof (smb_account_t)); 505 506 if ((wka = smb_wka_lookup_sid(sid)) == NULL) 507 return (NT_STATUS_NOT_FOUND); 508 509 if ((wkadom = smb_wka_get_domain(wka->wka_domidx)) == NULL) 510 return (NT_STATUS_INTERNAL_ERROR); 511 512 ainfo->a_name = strdup(wka->wka_name); 513 ainfo->a_sid = smb_sid_dup(wka->wka_binsid); 514 ainfo->a_domain = strdup(wkadom); 515 ainfo->a_domsid = smb_sid_split(ainfo->a_sid, &ainfo->a_rid); 516 ainfo->a_type = wka->wka_type; 517 518 if (!smb_account_validate(ainfo)) { 519 smb_account_free(ainfo); 520 return (NT_STATUS_NO_MEMORY); 521 } 522 523 return (NT_STATUS_SUCCESS); 524 } 525 526 static uint32_t 527 lsa_lookup_sid_domain(smb_sid_t *sid, smb_account_t *ainfo) 528 { 529 mlsvc_handle_t domain_handle; 530 uint32_t status; 531 smb_domainex_t dinfo; 532 char user[SMB_USERNAME_MAXLEN]; 533 534 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN); 535 536 if (!smb_domain_getinfo(&dinfo)) 537 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); 538 539 if (lsar_open(dinfo.d_dc, dinfo.d_primary.di_nbname, user, 540 &domain_handle) != 0) 541 return (NT_STATUS_INVALID_PARAMETER); 542 543 status = lsar_lookup_sids(&domain_handle, sid, ainfo); 544 545 (void) lsar_close(&domain_handle); 546 return (status); 547 } 548