1/* 2 Unix SMB/CIFS implementation. 3 4 kpasswd Server implementation 5 6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005 7 Copyright (C) Andrew Tridgell 2005 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 3 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program. If not, see <http://www.gnu.org/licenses/>. 21*/ 22 23#include "includes.h" 24#include "smbd/service_task.h" 25#include "lib/events/events.h" 26#include "lib/socket/socket.h" 27#include "system/network.h" 28#include "../lib/util/dlinklist.h" 29#include "lib/ldb/include/ldb.h" 30#include "auth/gensec/gensec.h" 31#include "auth/credentials/credentials.h" 32#include "auth/credentials/credentials_krb5.h" 33#include "auth/auth.h" 34#include "dsdb/samdb/samdb.h" 35#include "rpc_server/dcerpc_server.h" 36#include "rpc_server/samr/proto.h" 37#include "libcli/security/security.h" 38#include "param/param.h" 39#include "kdc/kdc.h" 40 41/* TODO: remove all SAMBA4_INTERNAL_HEIMDAL stuff from this file */ 42#ifdef SAMBA4_INTERNAL_HEIMDAL 43#include "heimdal_build/kpasswdd-glue.h" 44#endif 45 46/* hold information about one kdc socket */ 47struct kpasswd_socket { 48 struct socket_context *sock; 49 struct kdc_server *kdc; 50 struct tevent_fd *fde; 51 52 /* a queue of outgoing replies that have been deferred */ 53 struct kdc_reply *send_queue; 54}; 55 56/* Return true if there is a valid error packet formed in the error_blob */ 57static bool kpasswdd_make_error_reply(struct kdc_server *kdc, 58 TALLOC_CTX *mem_ctx, 59 uint16_t result_code, 60 const char *error_string, 61 DATA_BLOB *error_blob) 62{ 63 char *error_string_utf8; 64 size_t len; 65 66 DEBUG(result_code ? 3 : 10, ("kpasswdd: %s\n", error_string)); 67 68 if (!push_utf8_talloc(mem_ctx, &error_string_utf8, error_string, &len)) { 69 return false; 70 } 71 72 *error_blob = data_blob_talloc(mem_ctx, NULL, 2 + len + 1); 73 if (!error_blob->data) { 74 return false; 75 } 76 RSSVAL(error_blob->data, 0, result_code); 77 memcpy(error_blob->data + 2, error_string_utf8, len + 1); 78 return true; 79} 80 81/* Return true if there is a valid error packet formed in the error_blob */ 82static bool kpasswdd_make_unauth_error_reply(struct kdc_server *kdc, 83 TALLOC_CTX *mem_ctx, 84 uint16_t result_code, 85 const char *error_string, 86 DATA_BLOB *error_blob) 87{ 88 bool ret; 89 int kret; 90 DATA_BLOB error_bytes; 91 krb5_data k5_error_bytes, k5_error_blob; 92 ret = kpasswdd_make_error_reply(kdc, mem_ctx, result_code, error_string, 93 &error_bytes); 94 if (!ret) { 95 return false; 96 } 97 k5_error_bytes.data = error_bytes.data; 98 k5_error_bytes.length = error_bytes.length; 99 kret = krb5_mk_error(kdc->smb_krb5_context->krb5_context, 100 result_code, NULL, &k5_error_bytes, 101 NULL, NULL, NULL, NULL, &k5_error_blob); 102 if (kret) { 103 return false; 104 } 105 *error_blob = data_blob_talloc(mem_ctx, k5_error_blob.data, k5_error_blob.length); 106 krb5_data_free(&k5_error_blob); 107 if (!error_blob->data) { 108 return false; 109 } 110 return true; 111} 112 113static bool kpasswd_make_pwchange_reply(struct kdc_server *kdc, 114 TALLOC_CTX *mem_ctx, 115 NTSTATUS status, 116 enum samr_RejectReason reject_reason, 117 struct samr_DomInfo1 *dominfo, 118 DATA_BLOB *error_blob) 119{ 120 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) { 121 return kpasswdd_make_error_reply(kdc, mem_ctx, 122 KRB5_KPASSWD_ACCESSDENIED, 123 "No such user when changing password", 124 error_blob); 125 } 126 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) { 127 return kpasswdd_make_error_reply(kdc, mem_ctx, 128 KRB5_KPASSWD_ACCESSDENIED, 129 "Not permitted to change password", 130 error_blob); 131 } 132 if (dominfo && NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION)) { 133 const char *reject_string; 134 switch (reject_reason) { 135 case SAMR_REJECT_TOO_SHORT: 136 reject_string = talloc_asprintf(mem_ctx, "Password too short, password must be at least %d characters long", 137 dominfo->min_password_length); 138 break; 139 case SAMR_REJECT_COMPLEXITY: 140 reject_string = "Password does not meet complexity requirements"; 141 break; 142 case SAMR_REJECT_IN_HISTORY: 143 reject_string = "Password is already in password history"; 144 break; 145 case SAMR_REJECT_OTHER: 146 default: 147 reject_string = talloc_asprintf(mem_ctx, "Password must be at least %d characters long, and cannot match any of your %d previous passwords", 148 dominfo->min_password_length, dominfo->password_history_length); 149 break; 150 } 151 return kpasswdd_make_error_reply(kdc, mem_ctx, 152 KRB5_KPASSWD_SOFTERROR, 153 reject_string, 154 error_blob); 155 } 156 if (!NT_STATUS_IS_OK(status)) { 157 return kpasswdd_make_error_reply(kdc, mem_ctx, 158 KRB5_KPASSWD_HARDERROR, 159 talloc_asprintf(mem_ctx, "failed to set password: %s", nt_errstr(status)), 160 error_blob); 161 162 } 163 return kpasswdd_make_error_reply(kdc, mem_ctx, KRB5_KPASSWD_SUCCESS, 164 "Password changed", 165 error_blob); 166} 167 168/* 169 A user password change 170 171 Return true if there is a valid error packet (or sucess) formed in 172 the error_blob 173*/ 174static bool kpasswdd_change_password(struct kdc_server *kdc, 175 TALLOC_CTX *mem_ctx, 176 struct auth_session_info *session_info, 177 const DATA_BLOB *password, 178 DATA_BLOB *reply) 179{ 180 NTSTATUS status; 181 enum samr_RejectReason reject_reason; 182 struct samr_DomInfo1 *dominfo; 183 struct ldb_context *samdb; 184 185 samdb = samdb_connect(mem_ctx, kdc->task->event_ctx, kdc->task->lp_ctx, system_session(mem_ctx, kdc->task->lp_ctx)); 186 if (!samdb) { 187 return kpasswdd_make_error_reply(kdc, mem_ctx, 188 KRB5_KPASSWD_HARDERROR, 189 "Failed to open samdb", 190 reply); 191 } 192 193 DEBUG(3, ("Changing password of %s\\%s (%s)\n", 194 session_info->server_info->domain_name, 195 session_info->server_info->account_name, 196 dom_sid_string(mem_ctx, session_info->security_token->user_sid))); 197 198 /* User password change */ 199 status = samdb_set_password_sid(samdb, mem_ctx, 200 session_info->security_token->user_sid, 201 password, NULL, NULL, 202 true, /* this is a user password change */ 203 &reject_reason, 204 &dominfo); 205 return kpasswd_make_pwchange_reply(kdc, mem_ctx, 206 status, 207 reject_reason, 208 dominfo, 209 reply); 210 211} 212 213static bool kpasswd_process_request(struct kdc_server *kdc, 214 TALLOC_CTX *mem_ctx, 215 struct gensec_security *gensec_security, 216 uint16_t version, 217 DATA_BLOB *input, 218 DATA_BLOB *reply) 219{ 220 struct auth_session_info *session_info; 221 size_t pw_len; 222 223 if (!NT_STATUS_IS_OK(gensec_session_info(gensec_security, 224 &session_info))) { 225 return kpasswdd_make_error_reply(kdc, mem_ctx, 226 KRB5_KPASSWD_HARDERROR, 227 "gensec_session_info failed!", 228 reply); 229 } 230 231 switch (version) { 232 case KRB5_KPASSWD_VERS_CHANGEPW: 233 { 234 DATA_BLOB password; 235 if (!convert_string_talloc_convenience(mem_ctx, lp_iconv_convenience(kdc->task->lp_ctx), 236 CH_UTF8, CH_UTF16, 237 (const char *)input->data, 238 input->length, 239 (void **)&password.data, &pw_len, false)) { 240 return false; 241 } 242 password.length = pw_len; 243 244 return kpasswdd_change_password(kdc, mem_ctx, session_info, 245 &password, reply); 246 break; 247 } 248 case KRB5_KPASSWD_VERS_SETPW: 249 { 250 NTSTATUS status; 251 enum samr_RejectReason reject_reason = SAMR_REJECT_OTHER; 252 struct samr_DomInfo1 *dominfo = NULL; 253 struct ldb_context *samdb; 254 struct ldb_message *msg; 255 krb5_context context = kdc->smb_krb5_context->krb5_context; 256 257 ChangePasswdDataMS chpw; 258 DATA_BLOB password; 259 260 krb5_principal principal; 261 char *set_password_on_princ; 262 struct ldb_dn *set_password_on_dn; 263 264 size_t len; 265 int ret; 266 267 msg = ldb_msg_new(mem_ctx); 268 if (!msg) { 269 return false; 270 } 271 272 ret = decode_ChangePasswdDataMS(input->data, input->length, 273 &chpw, &len); 274 if (ret) { 275 return kpasswdd_make_error_reply(kdc, mem_ctx, 276 KRB5_KPASSWD_MALFORMED, 277 "failed to decode password change structure", 278 reply); 279 } 280 281 if (!convert_string_talloc_convenience(mem_ctx, lp_iconv_convenience(kdc->task->lp_ctx), 282 CH_UTF8, CH_UTF16, 283 (const char *)chpw.newpasswd.data, 284 chpw.newpasswd.length, 285 (void **)&password.data, &pw_len, false)) { 286 free_ChangePasswdDataMS(&chpw); 287 return false; 288 } 289 290 password.length = pw_len; 291 292 if ((chpw.targname && !chpw.targrealm) 293 || (!chpw.targname && chpw.targrealm)) { 294 return kpasswdd_make_error_reply(kdc, mem_ctx, 295 KRB5_KPASSWD_MALFORMED, 296 "Realm and principal must be both present, or neither present", 297 reply); 298 } 299 if (chpw.targname && chpw.targrealm) { 300#ifdef SAMBA4_INTERNAL_HEIMDAL 301 if (_krb5_principalname2krb5_principal(kdc->smb_krb5_context->krb5_context, 302 &principal, *chpw.targname, 303 *chpw.targrealm) != 0) { 304 free_ChangePasswdDataMS(&chpw); 305 return kpasswdd_make_error_reply(kdc, mem_ctx, 306 KRB5_KPASSWD_MALFORMED, 307 "failed to extract principal to set", 308 reply); 309 310 } 311#else /* SAMBA4_INTERNAL_HEIMDAL */ 312 return kpasswdd_make_error_reply(kdc, mem_ctx, 313 KRB5_KPASSWD_BAD_VERSION, 314 "Operation Not Implemented", 315 reply); 316#endif /* SAMBA4_INTERNAL_HEIMDAL */ 317 } else { 318 free_ChangePasswdDataMS(&chpw); 319 return kpasswdd_change_password(kdc, mem_ctx, session_info, 320 &password, reply); 321 } 322 free_ChangePasswdDataMS(&chpw); 323 324 if (krb5_unparse_name(context, principal, &set_password_on_princ) != 0) { 325 krb5_free_principal(context, principal); 326 return kpasswdd_make_error_reply(kdc, mem_ctx, 327 KRB5_KPASSWD_MALFORMED, 328 "krb5_unparse_name failed!", 329 reply); 330 } 331 332 krb5_free_principal(context, principal); 333 334 samdb = samdb_connect(mem_ctx, kdc->task->event_ctx, kdc->task->lp_ctx, session_info); 335 if (!samdb) { 336 return kpasswdd_make_error_reply(kdc, mem_ctx, 337 KRB5_KPASSWD_HARDERROR, 338 "Unable to open database!", 339 reply); 340 } 341 342 DEBUG(3, ("%s\\%s (%s) is changing password of %s\n", 343 session_info->server_info->domain_name, 344 session_info->server_info->account_name, 345 dom_sid_string(mem_ctx, session_info->security_token->user_sid), 346 set_password_on_princ)); 347 ret = ldb_transaction_start(samdb); 348 if (ret) { 349 status = NT_STATUS_TRANSACTION_ABORTED; 350 return kpasswd_make_pwchange_reply(kdc, mem_ctx, 351 status, 352 SAMR_REJECT_OTHER, 353 NULL, 354 reply); 355 } 356 357 status = crack_user_principal_name(samdb, mem_ctx, 358 set_password_on_princ, 359 &set_password_on_dn, NULL); 360 free(set_password_on_princ); 361 if (!NT_STATUS_IS_OK(status)) { 362 ldb_transaction_cancel(samdb); 363 return kpasswd_make_pwchange_reply(kdc, mem_ctx, 364 status, 365 SAMR_REJECT_OTHER, 366 NULL, 367 reply); 368 } 369 370 msg = ldb_msg_new(mem_ctx); 371 if (msg == NULL) { 372 ldb_transaction_cancel(samdb); 373 status = NT_STATUS_NO_MEMORY; 374 } else { 375 msg->dn = ldb_dn_copy(msg, set_password_on_dn); 376 if (!msg->dn) { 377 status = NT_STATUS_NO_MEMORY; 378 } 379 } 380 381 if (NT_STATUS_IS_OK(status)) { 382 /* Admin password set */ 383 status = samdb_set_password(samdb, mem_ctx, 384 set_password_on_dn, NULL, 385 msg, &password, NULL, NULL, 386 false, /* this is not a user password change */ 387 &reject_reason, &dominfo); 388 } 389 390 if (NT_STATUS_IS_OK(status)) { 391 /* modify the samdb record */ 392 ret = samdb_replace(samdb, mem_ctx, msg); 393 if (ret != 0) { 394 DEBUG(2,("Failed to modify record to set password on %s: %s\n", 395 ldb_dn_get_linearized(msg->dn), 396 ldb_errstring(samdb))); 397 status = NT_STATUS_ACCESS_DENIED; 398 } 399 } 400 if (NT_STATUS_IS_OK(status)) { 401 ret = ldb_transaction_commit(samdb); 402 if (ret != 0) { 403 DEBUG(1,("Failed to commit transaction to set password on %s: %s\n", 404 ldb_dn_get_linearized(msg->dn), 405 ldb_errstring(samdb))); 406 status = NT_STATUS_TRANSACTION_ABORTED; 407 } 408 } else { 409 ldb_transaction_cancel(samdb); 410 } 411 return kpasswd_make_pwchange_reply(kdc, mem_ctx, 412 status, 413 reject_reason, 414 dominfo, 415 reply); 416 } 417 default: 418 return kpasswdd_make_error_reply(kdc, mem_ctx, 419 KRB5_KPASSWD_BAD_VERSION, 420 talloc_asprintf(mem_ctx, 421 "Protocol version %u not supported", 422 version), 423 reply); 424 } 425 return true; 426} 427 428bool kpasswdd_process(struct kdc_server *kdc, 429 TALLOC_CTX *mem_ctx, 430 DATA_BLOB *input, 431 DATA_BLOB *reply, 432 struct socket_address *peer_addr, 433 struct socket_address *my_addr, 434 int datagram_reply) 435{ 436 bool ret; 437 const uint16_t header_len = 6; 438 uint16_t len; 439 uint16_t ap_req_len; 440 uint16_t krb_priv_len; 441 uint16_t version; 442 NTSTATUS nt_status; 443 DATA_BLOB ap_req, krb_priv_req; 444 DATA_BLOB krb_priv_rep = data_blob(NULL, 0); 445 DATA_BLOB ap_rep = data_blob(NULL, 0); 446 DATA_BLOB kpasswd_req, kpasswd_rep; 447 struct cli_credentials *server_credentials; 448 struct gensec_security *gensec_security; 449 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); 450 451 char *keytab_name; 452 453 if (!tmp_ctx) { 454 return false; 455 } 456 457 /* Be parinoid. We need to ensure we don't just let the 458 * caller lead us into a buffer overflow */ 459 if (input->length <= header_len) { 460 talloc_free(tmp_ctx); 461 return false; 462 } 463 464 len = RSVAL(input->data, 0); 465 if (input->length != len) { 466 talloc_free(tmp_ctx); 467 return false; 468 } 469 470 /* There are two different versions of this protocol so far, 471 * plus others in the standards pipe. Fortunetly they all 472 * take a very similar framing */ 473 version = RSVAL(input->data, 2); 474 ap_req_len = RSVAL(input->data, 4); 475 if ((ap_req_len >= len) || (ap_req_len + header_len) >= len) { 476 talloc_free(tmp_ctx); 477 return false; 478 } 479 480 krb_priv_len = len - ap_req_len; 481 ap_req = data_blob_const(&input->data[header_len], ap_req_len); 482 krb_priv_req = data_blob_const(&input->data[header_len + ap_req_len], krb_priv_len); 483 484 server_credentials = cli_credentials_init(tmp_ctx); 485 if (!server_credentials) { 486 DEBUG(1, ("Failed to init server credentials\n")); 487 return false; 488 } 489 490 /* We want the credentials subsystem to use the krb5 context 491 * we already have, rather than a new context */ 492 cli_credentials_set_krb5_context(server_credentials, kdc->smb_krb5_context); 493 cli_credentials_set_conf(server_credentials, kdc->task->lp_ctx); 494 495 keytab_name = talloc_asprintf(server_credentials, "HDB:samba4&%p", kdc->hdb_samba4_context); 496 497 cli_credentials_set_username(server_credentials, "kadmin/changepw", CRED_SPECIFIED); 498 ret = cli_credentials_set_keytab_name(server_credentials, kdc->task->event_ctx, kdc->task->lp_ctx, keytab_name, CRED_SPECIFIED); 499 if (ret != 0) { 500 ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx, 501 KRB5_KPASSWD_HARDERROR, 502 talloc_asprintf(mem_ctx, 503 "Failed to obtain server credentials for kadmin/changepw: %s\n", 504 nt_errstr(nt_status)), 505 &krb_priv_rep); 506 ap_rep.length = 0; 507 if (ret) { 508 goto reply; 509 } 510 talloc_free(tmp_ctx); 511 return ret; 512 } 513 514 /* We don't strictly need to call this wrapper, and could call 515 * gensec_server_start directly, as we have no need for NTLM 516 * and we have a PAC, but this ensures that the wrapper can be 517 * safely extended for other helpful things in future */ 518 nt_status = samba_server_gensec_start(tmp_ctx, kdc->task->event_ctx, 519 kdc->task->msg_ctx, 520 kdc->task->lp_ctx, 521 server_credentials, 522 "kpasswd", 523 &gensec_security); 524 if (!NT_STATUS_IS_OK(nt_status)) { 525 talloc_free(tmp_ctx); 526 return false; 527 } 528 529 /* The kerberos PRIV packets include these addresses. MIT 530 * clients check that they are present */ 531#if 0 532 /* Skip this part for now, it breaks with a NetAPP filer and 533 * in any case where the client address is behind NAT. If 534 * older MIT clients need this, we might have to insert more 535 * complex code */ 536 537 nt_status = gensec_set_peer_addr(gensec_security, peer_addr); 538 if (!NT_STATUS_IS_OK(nt_status)) { 539 talloc_free(tmp_ctx); 540 return false; 541 } 542#endif 543 544 nt_status = gensec_set_my_addr(gensec_security, my_addr); 545 if (!NT_STATUS_IS_OK(nt_status)) { 546 talloc_free(tmp_ctx); 547 return false; 548 } 549 550 /* We want the GENSEC wrap calls to generate PRIV tokens */ 551 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL); 552 553 nt_status = gensec_start_mech_by_name(gensec_security, "krb5"); 554 if (!NT_STATUS_IS_OK(nt_status)) { 555 talloc_free(tmp_ctx); 556 return false; 557 } 558 559 /* Accept the AP-REQ and generate teh AP-REP we need for the reply */ 560 nt_status = gensec_update(gensec_security, tmp_ctx, ap_req, &ap_rep); 561 if (!NT_STATUS_IS_OK(nt_status) && !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { 562 563 ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx, 564 KRB5_KPASSWD_HARDERROR, 565 talloc_asprintf(mem_ctx, 566 "gensec_update failed: %s", 567 nt_errstr(nt_status)), 568 &krb_priv_rep); 569 ap_rep.length = 0; 570 if (ret) { 571 goto reply; 572 } 573 talloc_free(tmp_ctx); 574 return ret; 575 } 576 577 /* Extract the data from the KRB-PRIV half of the message */ 578 nt_status = gensec_unwrap(gensec_security, tmp_ctx, &krb_priv_req, &kpasswd_req); 579 if (!NT_STATUS_IS_OK(nt_status)) { 580 ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx, 581 KRB5_KPASSWD_HARDERROR, 582 talloc_asprintf(mem_ctx, 583 "gensec_unwrap failed: %s", 584 nt_errstr(nt_status)), 585 &krb_priv_rep); 586 ap_rep.length = 0; 587 if (ret) { 588 goto reply; 589 } 590 talloc_free(tmp_ctx); 591 return ret; 592 } 593 594 /* Figure out something to do with it (probably changing a password...) */ 595 ret = kpasswd_process_request(kdc, tmp_ctx, 596 gensec_security, 597 version, 598 &kpasswd_req, &kpasswd_rep); 599 if (!ret) { 600 /* Argh! */ 601 return false; 602 } 603 604 /* And wrap up the reply: This ensures that the error message 605 * or success can be verified by the client */ 606 nt_status = gensec_wrap(gensec_security, tmp_ctx, 607 &kpasswd_rep, &krb_priv_rep); 608 if (!NT_STATUS_IS_OK(nt_status)) { 609 ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx, 610 KRB5_KPASSWD_HARDERROR, 611 talloc_asprintf(mem_ctx, 612 "gensec_wrap failed: %s", 613 nt_errstr(nt_status)), 614 &krb_priv_rep); 615 ap_rep.length = 0; 616 if (ret) { 617 goto reply; 618 } 619 talloc_free(tmp_ctx); 620 return ret; 621 } 622 623reply: 624 *reply = data_blob_talloc(mem_ctx, NULL, krb_priv_rep.length + ap_rep.length + header_len); 625 if (!reply->data) { 626 return false; 627 } 628 629 RSSVAL(reply->data, 0, reply->length); 630 RSSVAL(reply->data, 2, 1); /* This is a version 1 reply, MS change/set or otherwise */ 631 RSSVAL(reply->data, 4, ap_rep.length); 632 memcpy(reply->data + header_len, 633 ap_rep.data, 634 ap_rep.length); 635 memcpy(reply->data + header_len + ap_rep.length, 636 krb_priv_rep.data, 637 krb_priv_rep.length); 638 639 talloc_free(tmp_ctx); 640 return ret; 641} 642 643