1/* 2 Unix SMB/CIFS implementation. 3 4 server side dcerpc authentication code 5 6 Copyright (C) Andrew Tridgell 2003 7 Copyright (C) Stefan (metze) Metzmacher 2004 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 "rpc_server/dcerpc_server.h" 25#include "rpc_server/dcerpc_server_proto.h" 26#include "librpc/rpc/dcerpc_proto.h" 27#include "librpc/gen_ndr/ndr_dcerpc.h" 28#include "auth/credentials/credentials.h" 29#include "auth/gensec/gensec.h" 30#include "auth/auth.h" 31#include "param/param.h" 32 33/* 34 parse any auth information from a dcerpc bind request 35 return false if we can't handle the auth request for some 36 reason (in which case we send a bind_nak) 37*/ 38bool dcesrv_auth_bind(struct dcesrv_call_state *call) 39{ 40 struct cli_credentials *server_credentials; 41 struct ncacn_packet *pkt = &call->pkt; 42 struct dcesrv_connection *dce_conn = call->conn; 43 struct dcesrv_auth *auth = &dce_conn->auth_state; 44 NTSTATUS status; 45 enum ndr_err_code ndr_err; 46 47 if (pkt->u.bind.auth_info.length == 0) { 48 dce_conn->auth_state.auth_info = NULL; 49 return true; 50 } 51 52 dce_conn->auth_state.auth_info = talloc(dce_conn, struct dcerpc_auth); 53 if (!dce_conn->auth_state.auth_info) { 54 return false; 55 } 56 57 ndr_err = ndr_pull_struct_blob(&pkt->u.bind.auth_info, 58 call, NULL, 59 dce_conn->auth_state.auth_info, 60 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth); 61 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 62 return false; 63 } 64 65 server_credentials 66 = cli_credentials_init(call); 67 if (!server_credentials) { 68 DEBUG(1, ("Failed to init server credentials\n")); 69 return false; 70 } 71 72 cli_credentials_set_conf(server_credentials, call->conn->dce_ctx->lp_ctx); 73 status = cli_credentials_set_machine_account(server_credentials, call->conn->dce_ctx->lp_ctx); 74 if (!NT_STATUS_IS_OK(status)) { 75 DEBUG(10, ("Failed to obtain server credentials, perhaps a standalone server?: %s\n", nt_errstr(status))); 76 talloc_free(server_credentials); 77 server_credentials = NULL; 78 } 79 80 status = samba_server_gensec_start(dce_conn, call->event_ctx, 81 call->msg_ctx, 82 call->conn->dce_ctx->lp_ctx, 83 server_credentials, 84 NULL, 85 &auth->gensec_security); 86 87 status = gensec_start_mech_by_authtype(auth->gensec_security, auth->auth_info->auth_type, 88 auth->auth_info->auth_level); 89 90 if (!NT_STATUS_IS_OK(status)) { 91 DEBUG(1, ("Failed to start GENSEC mechanism for DCERPC server: auth_type=%d, auth_level=%d: %s\n", 92 (int)auth->auth_info->auth_type, 93 (int)auth->auth_info->auth_level, 94 nt_errstr(status))); 95 return false; 96 } 97 98 if (call->conn->state_flags & DCESRV_CALL_STATE_FLAG_HEADER_SIGNING) { 99 gensec_want_feature(auth->gensec_security, GENSEC_FEATURE_SIGN_PKT_HEADER); 100 } 101 102 return true; 103} 104 105/* 106 add any auth information needed in a bind ack, and process the authentication 107 information found in the bind. 108*/ 109NTSTATUS dcesrv_auth_bind_ack(struct dcesrv_call_state *call, struct ncacn_packet *pkt) 110{ 111 struct dcesrv_connection *dce_conn = call->conn; 112 NTSTATUS status; 113 114 if (!call->conn->auth_state.gensec_security) { 115 return NT_STATUS_OK; 116 } 117 118 status = gensec_update(dce_conn->auth_state.gensec_security, 119 call, 120 dce_conn->auth_state.auth_info->credentials, 121 &dce_conn->auth_state.auth_info->credentials); 122 123 if (NT_STATUS_IS_OK(status)) { 124 status = gensec_session_info(dce_conn->auth_state.gensec_security, 125 &dce_conn->auth_state.session_info); 126 if (!NT_STATUS_IS_OK(status)) { 127 DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status))); 128 return status; 129 } 130 131 if (dce_conn->state_flags & DCESRV_CALL_STATE_FLAG_HEADER_SIGNING) { 132 gensec_want_feature(dce_conn->auth_state.gensec_security, 133 GENSEC_FEATURE_SIGN_PKT_HEADER); 134 } 135 136 /* Now that we are authenticated, go back to the generic session key... */ 137 dce_conn->auth_state.session_key = dcesrv_generic_session_key; 138 return NT_STATUS_OK; 139 } else if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { 140 dce_conn->auth_state.auth_info->auth_pad_length = 0; 141 dce_conn->auth_state.auth_info->auth_reserved = 0; 142 return NT_STATUS_OK; 143 } else { 144 DEBUG(2, ("Failed to start dcesrv auth negotiate: %s\n", nt_errstr(status))); 145 return status; 146 } 147} 148 149 150/* 151 process the final stage of a auth request 152*/ 153bool dcesrv_auth_auth3(struct dcesrv_call_state *call) 154{ 155 struct ncacn_packet *pkt = &call->pkt; 156 struct dcesrv_connection *dce_conn = call->conn; 157 NTSTATUS status; 158 enum ndr_err_code ndr_err; 159 160 /* We can't work without an existing gensec state, and an new blob to feed it */ 161 if (!dce_conn->auth_state.auth_info || 162 !dce_conn->auth_state.gensec_security || 163 pkt->u.auth3.auth_info.length == 0) { 164 return false; 165 } 166 167 ndr_err = ndr_pull_struct_blob(&pkt->u.auth3.auth_info, 168 call, NULL, 169 dce_conn->auth_state.auth_info, 170 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth); 171 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 172 return false; 173 } 174 175 /* Pass the extra data we got from the client down to gensec for processing */ 176 status = gensec_update(dce_conn->auth_state.gensec_security, 177 call, 178 dce_conn->auth_state.auth_info->credentials, 179 &dce_conn->auth_state.auth_info->credentials); 180 if (NT_STATUS_IS_OK(status)) { 181 status = gensec_session_info(dce_conn->auth_state.gensec_security, 182 &dce_conn->auth_state.session_info); 183 if (!NT_STATUS_IS_OK(status)) { 184 DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status))); 185 return false; 186 } 187 /* Now that we are authenticated, go back to the generic session key... */ 188 dce_conn->auth_state.session_key = dcesrv_generic_session_key; 189 return true; 190 } else { 191 DEBUG(4, ("dcesrv_auth_auth3: failed to authenticate: %s\n", 192 nt_errstr(status))); 193 return false; 194 } 195 196 return true; 197} 198 199/* 200 parse any auth information from a dcerpc alter request 201 return false if we can't handle the auth request for some 202 reason (in which case we send a bind_nak (is this true for here?)) 203*/ 204bool dcesrv_auth_alter(struct dcesrv_call_state *call) 205{ 206 struct ncacn_packet *pkt = &call->pkt; 207 struct dcesrv_connection *dce_conn = call->conn; 208 enum ndr_err_code ndr_err; 209 210 /* on a pure interface change there is no auth blob */ 211 if (pkt->u.alter.auth_info.length == 0) { 212 return true; 213 } 214 215 /* We can't work without an existing gensec state */ 216 if (!dce_conn->auth_state.gensec_security) { 217 return false; 218 } 219 220 dce_conn->auth_state.auth_info = talloc(dce_conn, struct dcerpc_auth); 221 if (!dce_conn->auth_state.auth_info) { 222 return false; 223 } 224 225 ndr_err = ndr_pull_struct_blob(&pkt->u.alter.auth_info, 226 call, NULL, 227 dce_conn->auth_state.auth_info, 228 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth); 229 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 230 return false; 231 } 232 233 return true; 234} 235 236/* 237 add any auth information needed in a alter ack, and process the authentication 238 information found in the alter. 239*/ 240NTSTATUS dcesrv_auth_alter_ack(struct dcesrv_call_state *call, struct ncacn_packet *pkt) 241{ 242 struct dcesrv_connection *dce_conn = call->conn; 243 NTSTATUS status; 244 245 /* on a pure interface change there is no auth_info structure 246 setup */ 247 if (!call->conn->auth_state.auth_info || 248 dce_conn->auth_state.auth_info->credentials.length == 0) { 249 return NT_STATUS_OK; 250 } 251 252 if (!call->conn->auth_state.gensec_security) { 253 return NT_STATUS_INVALID_PARAMETER; 254 } 255 256 status = gensec_update(dce_conn->auth_state.gensec_security, 257 call, 258 dce_conn->auth_state.auth_info->credentials, 259 &dce_conn->auth_state.auth_info->credentials); 260 261 if (NT_STATUS_IS_OK(status)) { 262 status = gensec_session_info(dce_conn->auth_state.gensec_security, 263 &dce_conn->auth_state.session_info); 264 if (!NT_STATUS_IS_OK(status)) { 265 DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status))); 266 return status; 267 } 268 269 /* Now that we are authenticated, got back to the generic session key... */ 270 dce_conn->auth_state.session_key = dcesrv_generic_session_key; 271 return NT_STATUS_OK; 272 } else if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { 273 dce_conn->auth_state.auth_info->auth_pad_length = 0; 274 dce_conn->auth_state.auth_info->auth_reserved = 0; 275 return NT_STATUS_OK; 276 } 277 278 DEBUG(2, ("Failed to finish dcesrv auth alter_ack: %s\n", nt_errstr(status))); 279 return status; 280} 281 282/* 283 check credentials on a request 284*/ 285bool dcesrv_auth_request(struct dcesrv_call_state *call, DATA_BLOB *full_packet) 286{ 287 struct ncacn_packet *pkt = &call->pkt; 288 struct dcesrv_connection *dce_conn = call->conn; 289 DATA_BLOB auth_blob; 290 struct dcerpc_auth auth; 291 struct ndr_pull *ndr; 292 NTSTATUS status; 293 enum ndr_err_code ndr_err; 294 size_t hdr_size = DCERPC_REQUEST_LENGTH; 295 296 if (!dce_conn->auth_state.auth_info || 297 !dce_conn->auth_state.gensec_security) { 298 return true; 299 } 300 301 switch (dce_conn->auth_state.auth_info->auth_level) { 302 case DCERPC_AUTH_LEVEL_PRIVACY: 303 case DCERPC_AUTH_LEVEL_INTEGRITY: 304 break; 305 306 case DCERPC_AUTH_LEVEL_CONNECT: 307 if (pkt->auth_length != 0) { 308 break; 309 } 310 return true; 311 case DCERPC_AUTH_LEVEL_NONE: 312 if (pkt->auth_length != 0) { 313 return false; 314 } 315 return true; 316 317 default: 318 return false; 319 } 320 321 auth_blob.length = 8 + pkt->auth_length; 322 323 /* check for a valid length */ 324 if (pkt->u.request.stub_and_verifier.length < auth_blob.length) { 325 return false; 326 } 327 328 auth_blob.data = 329 pkt->u.request.stub_and_verifier.data + 330 pkt->u.request.stub_and_verifier.length - auth_blob.length; 331 pkt->u.request.stub_and_verifier.length -= auth_blob.length; 332 333 /* pull the auth structure */ 334 ndr = ndr_pull_init_blob(&auth_blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx)); 335 if (!ndr) { 336 return false; 337 } 338 339 if (!(pkt->drep[0] & DCERPC_DREP_LE)) { 340 ndr->flags |= LIBNDR_FLAG_BIGENDIAN; 341 } 342 343 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) { 344 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT; 345 hdr_size += 16; 346 } 347 348 ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth); 349 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 350 talloc_free(ndr); 351 return false; 352 } 353 354 /* check signature or unseal the packet */ 355 switch (dce_conn->auth_state.auth_info->auth_level) { 356 case DCERPC_AUTH_LEVEL_PRIVACY: 357 status = gensec_unseal_packet(dce_conn->auth_state.gensec_security, 358 call, 359 full_packet->data + hdr_size, 360 pkt->u.request.stub_and_verifier.length, 361 full_packet->data, 362 full_packet->length-auth.credentials.length, 363 &auth.credentials); 364 memcpy(pkt->u.request.stub_and_verifier.data, 365 full_packet->data + hdr_size, 366 pkt->u.request.stub_and_verifier.length); 367 break; 368 369 case DCERPC_AUTH_LEVEL_INTEGRITY: 370 status = gensec_check_packet(dce_conn->auth_state.gensec_security, 371 call, 372 pkt->u.request.stub_and_verifier.data, 373 pkt->u.request.stub_and_verifier.length, 374 full_packet->data, 375 full_packet->length-auth.credentials.length, 376 &auth.credentials); 377 break; 378 379 case DCERPC_AUTH_LEVEL_CONNECT: 380 /* for now we ignore possible signatures here */ 381 status = NT_STATUS_OK; 382 break; 383 384 default: 385 status = NT_STATUS_INVALID_LEVEL; 386 break; 387 } 388 389 /* remove the indicated amount of padding */ 390 if (pkt->u.request.stub_and_verifier.length < auth.auth_pad_length) { 391 talloc_free(ndr); 392 return false; 393 } 394 pkt->u.request.stub_and_verifier.length -= auth.auth_pad_length; 395 talloc_free(ndr); 396 397 return NT_STATUS_IS_OK(status); 398} 399 400 401/* 402 push a signed or sealed dcerpc request packet into a blob 403*/ 404bool dcesrv_auth_response(struct dcesrv_call_state *call, 405 DATA_BLOB *blob, size_t sig_size, 406 struct ncacn_packet *pkt) 407{ 408 struct dcesrv_connection *dce_conn = call->conn; 409 NTSTATUS status; 410 enum ndr_err_code ndr_err; 411 struct ndr_push *ndr; 412 uint32_t payload_length; 413 DATA_BLOB creds2; 414 415 /* non-signed packets are simple */ 416 if (sig_size == 0) { 417 status = ncacn_push_auth(blob, call, lp_iconv_convenience(dce_conn->dce_ctx->lp_ctx), pkt, NULL); 418 return NT_STATUS_IS_OK(status); 419 } 420 421 switch (dce_conn->auth_state.auth_info->auth_level) { 422 case DCERPC_AUTH_LEVEL_PRIVACY: 423 case DCERPC_AUTH_LEVEL_INTEGRITY: 424 break; 425 426 case DCERPC_AUTH_LEVEL_CONNECT: 427 /* 428 * TODO: let the gensec mech decide if it wants to generate a signature 429 * that might be needed for schannel... 430 */ 431 status = ncacn_push_auth(blob, call, lp_iconv_convenience(dce_conn->dce_ctx->lp_ctx), pkt, NULL); 432 return NT_STATUS_IS_OK(status); 433 434 case DCERPC_AUTH_LEVEL_NONE: 435 status = ncacn_push_auth(blob, call, lp_iconv_convenience(dce_conn->dce_ctx->lp_ctx), pkt, NULL); 436 return NT_STATUS_IS_OK(status); 437 438 default: 439 return false; 440 } 441 442 ndr = ndr_push_init_ctx(call, lp_iconv_convenience(dce_conn->dce_ctx->lp_ctx)); 443 if (!ndr) { 444 return false; 445 } 446 447 if (!(pkt->drep[0] & DCERPC_DREP_LE)) { 448 ndr->flags |= LIBNDR_FLAG_BIGENDIAN; 449 } 450 451 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt); 452 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 453 return false; 454 } 455 456 /* pad to 16 byte multiple, match win2k3 */ 457 dce_conn->auth_state.auth_info->auth_pad_length = 458 (16 - (pkt->u.response.stub_and_verifier.length & 15)) & 15; 459 ndr_err = ndr_push_zero(ndr, dce_conn->auth_state.auth_info->auth_pad_length); 460 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 461 return false; 462 } 463 464 payload_length = pkt->u.response.stub_and_verifier.length + 465 dce_conn->auth_state.auth_info->auth_pad_length; 466 467 /* we start without signature, it will appended later */ 468 dce_conn->auth_state.auth_info->credentials = data_blob(NULL, 0); 469 470 /* add the auth verifier */ 471 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, 472 dce_conn->auth_state.auth_info); 473 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 474 return false; 475 } 476 477 /* extract the whole packet as a blob */ 478 *blob = ndr_push_blob(ndr); 479 480 /* 481 * Setup the frag and auth length in the packet buffer. 482 * This is needed if the GENSEC mech does AEAD signing 483 * of the packet headers. The signature itself will be 484 * appended later. 485 */ 486 dcerpc_set_frag_length(blob, blob->length + sig_size); 487 dcerpc_set_auth_length(blob, sig_size); 488 489 /* sign or seal the packet */ 490 switch (dce_conn->auth_state.auth_info->auth_level) { 491 case DCERPC_AUTH_LEVEL_PRIVACY: 492 status = gensec_seal_packet(dce_conn->auth_state.gensec_security, 493 call, 494 ndr->data + DCERPC_REQUEST_LENGTH, 495 payload_length, 496 blob->data, 497 blob->length, 498 &creds2); 499 break; 500 501 case DCERPC_AUTH_LEVEL_INTEGRITY: 502 status = gensec_sign_packet(dce_conn->auth_state.gensec_security, 503 call, 504 ndr->data + DCERPC_REQUEST_LENGTH, 505 payload_length, 506 blob->data, 507 blob->length, 508 &creds2); 509 break; 510 511 default: 512 status = NT_STATUS_INVALID_LEVEL; 513 break; 514 } 515 516 if (NT_STATUS_IS_OK(status)) { 517 if (creds2.length != sig_size) { 518 DEBUG(0,("dcesrv_auth_response: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n", 519 (unsigned)creds2.length, (uint32_t)sig_size, 520 (unsigned)dce_conn->auth_state.auth_info->auth_pad_length, 521 (unsigned)pkt->u.response.stub_and_verifier.length)); 522 data_blob_free(&creds2); 523 status = NT_STATUS_INTERNAL_ERROR; 524 } 525 } 526 527 if (NT_STATUS_IS_OK(status)) { 528 if (!data_blob_append(call, blob, creds2.data, creds2.length)) { 529 status = NT_STATUS_NO_MEMORY; 530 } 531 data_blob_free(&creds2); 532 } 533 534 if (!NT_STATUS_IS_OK(status)) { 535 return false; 536 } 537 538 return true; 539} 540