1/* 2 Unix SMB/CIFS implementation. 3 4 helper functions for NAMED PIPE servers 5 6 Copyright (C) Stefan (metze) Metzmacher 2008 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program. If not, see <http://www.gnu.org/licenses/>. 20*/ 21 22#include "includes.h" 23#include <tevent.h> 24#include "smbd/service.h" 25#include "param/param.h" 26#include "auth/session.h" 27#include "auth/auth_sam_reply.h" 28#include "lib/stream/packet.h" 29#include "librpc/gen_ndr/ndr_named_pipe_auth.h" 30#include "system/passwd.h" 31#include "libcli/raw/smb.h" 32#include "auth/credentials/credentials.h" 33#include "auth/credentials/credentials_krb5.h" 34 35struct named_pipe_socket { 36 const char *pipe_name; 37 const char *pipe_path; 38 const struct stream_server_ops *ops; 39 void *private_data; 40}; 41 42struct named_pipe_connection { 43 struct stream_connection *connection; 44 struct packet_context *packet; 45 const struct named_pipe_socket *pipe_sock; 46 NTSTATUS status; 47}; 48 49static void named_pipe_handover_connection(void *private_data) 50{ 51 struct named_pipe_connection *pipe_conn = talloc_get_type( 52 private_data, struct named_pipe_connection); 53 struct stream_connection *conn = pipe_conn->connection; 54 55 TEVENT_FD_NOT_WRITEABLE(conn->event.fde); 56 57 packet_set_socket(pipe_conn->packet, NULL); 58 packet_set_event_context(pipe_conn->packet, NULL); 59 packet_set_fde(pipe_conn->packet, NULL); 60 TALLOC_FREE(pipe_conn->packet); 61 62 if (!NT_STATUS_IS_OK(pipe_conn->status)) { 63 stream_terminate_connection(conn, nt_errstr(pipe_conn->status)); 64 return; 65 } 66 67 /* 68 * remove the named_pipe layer together with its packet layer 69 */ 70 conn->ops = pipe_conn->pipe_sock->ops; 71 conn->private_data = pipe_conn->pipe_sock->private_data; 72 talloc_unlink(conn, pipe_conn); 73 74 /* we're now ready to start receiving events on this stream */ 75 TEVENT_FD_READABLE(conn->event.fde); 76 77 /* 78 * hand over to the real pipe implementation, 79 * now that we have setup the transport session_info 80 */ 81 conn->ops->accept_connection(conn); 82 83 DEBUG(10,("named_pipe_handover_connection[%s]: succeeded\n", 84 conn->ops->name)); 85} 86 87static NTSTATUS named_pipe_recv_auth_request(void *private_data, 88 DATA_BLOB req_blob) 89{ 90 struct named_pipe_connection *pipe_conn = talloc_get_type( 91 private_data, struct named_pipe_connection); 92 struct stream_connection *conn = pipe_conn->connection; 93 enum ndr_err_code ndr_err; 94 struct named_pipe_auth_req req; 95 union netr_Validation val; 96 struct auth_serversupplied_info *server_info; 97 struct named_pipe_auth_rep rep; 98 DATA_BLOB rep_blob; 99 NTSTATUS status; 100 101 /* 102 * make sure nothing happens on the socket untill the 103 * real implemenation takes over 104 */ 105 packet_recv_disable(pipe_conn->packet); 106 107 /* 108 * TODO: check it's a root (uid == 0) pipe 109 */ 110 111 ZERO_STRUCT(rep); 112 rep.level = 0; 113 rep.status = NT_STATUS_INTERNAL_ERROR; 114 115 DEBUG(10,("named_pipe_auth: req_blob.length[%u]\n", 116 (unsigned int)req_blob.length)); 117 dump_data(11, req_blob.data, req_blob.length); 118 119 /* parse the passed credentials */ 120 ndr_err = ndr_pull_struct_blob_all( 121 &req_blob, 122 pipe_conn, 123 lp_iconv_convenience(conn->lp_ctx), 124 &req, 125 (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_req); 126 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 127 rep.status = ndr_map_error2ntstatus(ndr_err); 128 DEBUG(2, ("Could not unmarshall named_pipe_auth_req: %s\n", 129 nt_errstr(rep.status))); 130 goto reply; 131 } 132 133 if (DEBUGLVL(10)) { 134 NDR_PRINT_DEBUG(named_pipe_auth_req, &req); 135 } 136 137 if (strcmp(NAMED_PIPE_AUTH_MAGIC, req.magic) != 0) { 138 DEBUG(2, ("named_pipe_auth_req: invalid magic '%s' != %s\n", 139 req.magic, NAMED_PIPE_AUTH_MAGIC)); 140 rep.status = NT_STATUS_INVALID_PARAMETER; 141 goto reply; 142 } 143 144 switch (req.level) { 145 case 0: 146 /* 147 * anon connection, we don't create a session info 148 * and leave it NULL 149 */ 150 rep.level = 0; 151 rep.status = NT_STATUS_OK; 152 break; 153 case 1: 154 val.sam3 = &req.info.info1; 155 156 rep.level = 1; 157 rep.status = make_server_info_netlogon_validation(pipe_conn, 158 "TODO", 159 3, &val, 160 &server_info); 161 if (!NT_STATUS_IS_OK(rep.status)) { 162 DEBUG(2, ("make_server_info_netlogon_validation returned " 163 "%s\n", nt_errstr(rep.status))); 164 goto reply; 165 } 166 167 /* setup the session_info on the connection */ 168 rep.status = auth_generate_session_info(conn, 169 conn->event.ctx, 170 conn->lp_ctx, 171 server_info, 172 &conn->session_info); 173 if (!NT_STATUS_IS_OK(rep.status)) { 174 DEBUG(2, ("auth_generate_session_info failed: %s\n", 175 nt_errstr(rep.status))); 176 goto reply; 177 } 178 179 break; 180 case 2: 181 rep.level = 2; 182 rep.info.info2.file_type = FILE_TYPE_MESSAGE_MODE_PIPE; 183 rep.info.info2.device_state = 0xff | 0x0400 | 0x0100; 184 rep.info.info2.allocation_size = 4096; 185 186 if (!req.info.info2.sam_info3) { 187 /* 188 * anon connection, we don't create a session info 189 * and leave it NULL 190 */ 191 rep.status = NT_STATUS_OK; 192 break; 193 } 194 195 val.sam3 = req.info.info2.sam_info3; 196 197 rep.status = make_server_info_netlogon_validation(pipe_conn, 198 val.sam3->base.account_name.string, 199 3, &val, &server_info); 200 if (!NT_STATUS_IS_OK(rep.status)) { 201 DEBUG(2, ("make_server_info_netlogon_validation returned " 202 "%s\n", nt_errstr(rep.status))); 203 goto reply; 204 } 205 206 /* setup the session_info on the connection */ 207 rep.status = auth_generate_session_info(conn, 208 conn->event.ctx, 209 conn->lp_ctx, 210 server_info, 211 &conn->session_info); 212 if (!NT_STATUS_IS_OK(rep.status)) { 213 DEBUG(2, ("auth_generate_session_info failed: %s\n", 214 nt_errstr(rep.status))); 215 goto reply; 216 } 217 218 conn->session_info->session_key = data_blob_const(req.info.info2.session_key, 219 req.info.info2.session_key_length); 220 talloc_steal(conn->session_info, req.info.info2.session_key); 221 222 break; 223 case 3: 224 rep.level = 3; 225 rep.info.info3.file_type = FILE_TYPE_MESSAGE_MODE_PIPE; 226 rep.info.info3.device_state = 0xff | 0x0400 | 0x0100; 227 rep.info.info3.allocation_size = 4096; 228 229 if (!req.info.info3.sam_info3) { 230 /* 231 * anon connection, we don't create a session info 232 * and leave it NULL 233 */ 234 rep.status = NT_STATUS_OK; 235 break; 236 } 237 238 val.sam3 = req.info.info3.sam_info3; 239 240 rep.status = make_server_info_netlogon_validation(pipe_conn, 241 val.sam3->base.account_name.string, 242 3, &val, &server_info); 243 if (!NT_STATUS_IS_OK(rep.status)) { 244 DEBUG(2, ("make_server_info_netlogon_validation returned " 245 "%s\n", nt_errstr(rep.status))); 246 goto reply; 247 } 248 249 /* setup the session_info on the connection */ 250 rep.status = auth_generate_session_info(conn, 251 conn->event.ctx, 252 conn->lp_ctx, 253 server_info, 254 &conn->session_info); 255 if (!NT_STATUS_IS_OK(rep.status)) { 256 DEBUG(2, ("auth_generate_session_info failed: %s\n", 257 nt_errstr(rep.status))); 258 goto reply; 259 } 260 261 if (req.info.info3.gssapi_delegated_creds_length) { 262 OM_uint32 minor_status; 263 gss_buffer_desc cred_token; 264 gss_cred_id_t cred_handle; 265 int ret; 266 267 DEBUG(10, ("named_pipe_auth: delegated credentials supplied by client\n")); 268 269 cred_token.value = req.info.info3.gssapi_delegated_creds; 270 cred_token.length = req.info.info3.gssapi_delegated_creds_length; 271 272 ret = gss_import_cred(&minor_status, 273 &cred_token, 274 &cred_handle); 275 if (ret != GSS_S_COMPLETE) { 276 rep.status = NT_STATUS_INTERNAL_ERROR; 277 goto reply; 278 } 279 280 conn->session_info->credentials = cli_credentials_init(conn->session_info); 281 if (!conn->session_info->credentials) { 282 rep.status = NT_STATUS_NO_MEMORY; 283 goto reply; 284 } 285 286 cli_credentials_set_conf(conn->session_info->credentials, 287 conn->lp_ctx); 288 /* Just so we don't segfault trying to get at a username */ 289 cli_credentials_set_anonymous(conn->session_info->credentials); 290 291 ret = cli_credentials_set_client_gss_creds(conn->session_info->credentials, 292 conn->event.ctx, 293 conn->lp_ctx, 294 cred_handle, 295 CRED_SPECIFIED); 296 if (ret) { 297 rep.status = NT_STATUS_INTERNAL_ERROR; 298 goto reply; 299 } 300 301 /* This credential handle isn't useful for password authentication, so ensure nobody tries to do that */ 302 cli_credentials_set_kerberos_state(conn->session_info->credentials, 303 CRED_MUST_USE_KERBEROS); 304 } 305 306 conn->session_info->session_key = data_blob_const(req.info.info3.session_key, 307 req.info.info3.session_key_length); 308 talloc_steal(conn->session_info, req.info.info3.session_key); 309 310 break; 311 default: 312 DEBUG(2, ("named_pipe_auth_req: unknown level %u\n", 313 req.level)); 314 rep.level = 0; 315 rep.status = NT_STATUS_INVALID_LEVEL; 316 goto reply; 317 } 318 319reply: 320 /* create the output */ 321 ndr_err = ndr_push_struct_blob(&rep_blob, pipe_conn, 322 lp_iconv_convenience(conn->lp_ctx), 323 &rep, 324 (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_rep); 325 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 326 status = ndr_map_error2ntstatus(ndr_err); 327 DEBUG(2, ("Could not marshall named_pipe_auth_rep: %s\n", 328 nt_errstr(status))); 329 return status; 330 } 331 332 DEBUG(10,("named_pipe_auth reply[%u]\n", (unsigned)rep_blob.length)); 333 dump_data(11, rep_blob.data, rep_blob.length); 334 if (DEBUGLVL(10)) { 335 NDR_PRINT_DEBUG(named_pipe_auth_rep, &rep); 336 } 337 338 pipe_conn->status = rep.status; 339 status = packet_send_callback(pipe_conn->packet, rep_blob, 340 named_pipe_handover_connection, 341 pipe_conn); 342 if (!NT_STATUS_IS_OK(status)) { 343 DEBUG(0, ("packet_send_callback returned %s\n", 344 nt_errstr(status))); 345 return status; 346 } 347 348 return NT_STATUS_OK; 349} 350 351/* 352 called when a pipe socket becomes readable 353*/ 354static void named_pipe_recv(struct stream_connection *conn, uint16_t flags) 355{ 356 struct named_pipe_connection *pipe_conn = talloc_get_type( 357 conn->private_data, struct named_pipe_connection); 358 359 DEBUG(10,("named_pipe_recv\n")); 360 361 packet_recv(pipe_conn->packet); 362} 363 364/* 365 called when a pipe socket becomes writable 366*/ 367static void named_pipe_send(struct stream_connection *conn, uint16_t flags) 368{ 369 struct named_pipe_connection *pipe_conn = talloc_get_type( 370 conn->private_data, struct named_pipe_connection); 371 372 packet_queue_run(pipe_conn->packet); 373} 374 375/* 376 handle socket recv errors 377*/ 378static void named_pipe_recv_error(void *private_data, NTSTATUS status) 379{ 380 struct named_pipe_connection *pipe_conn = talloc_get_type( 381 private_data, struct named_pipe_connection); 382 383 stream_terminate_connection(pipe_conn->connection, nt_errstr(status)); 384} 385 386static NTSTATUS named_pipe_full_request(void *private_data, DATA_BLOB blob, size_t *size) 387{ 388 if (blob.length < 8) { 389 return STATUS_MORE_ENTRIES; 390 } 391 392 if (memcmp(NAMED_PIPE_AUTH_MAGIC, &blob.data[4], 4) != 0) { 393 DEBUG(0,("named_pipe_full_request: wrong protocol\n")); 394 *size = blob.length; 395 /* the error will be handled in named_pipe_recv_auth_request */ 396 return NT_STATUS_OK; 397 } 398 399 *size = 4 + RIVAL(blob.data, 0); 400 if (*size > blob.length) { 401 return STATUS_MORE_ENTRIES; 402 } 403 404 return NT_STATUS_OK; 405} 406 407static void named_pipe_accept(struct stream_connection *conn) 408{ 409 struct named_pipe_socket *pipe_sock = talloc_get_type( 410 conn->private_data, struct named_pipe_socket); 411 struct named_pipe_connection *pipe_conn; 412 413 DEBUG(5,("named_pipe_accept\n")); 414 415 pipe_conn = talloc_zero(conn, struct named_pipe_connection); 416 if (!pipe_conn) { 417 stream_terminate_connection(conn, "out of memory"); 418 return; 419 } 420 421 pipe_conn->packet = packet_init(pipe_conn); 422 if (!pipe_conn->packet) { 423 stream_terminate_connection(conn, "out of memory"); 424 return; 425 } 426 packet_set_private(pipe_conn->packet, pipe_conn); 427 packet_set_socket(pipe_conn->packet, conn->socket); 428 packet_set_callback(pipe_conn->packet, named_pipe_recv_auth_request); 429 packet_set_full_request(pipe_conn->packet, named_pipe_full_request); 430 packet_set_error_handler(pipe_conn->packet, named_pipe_recv_error); 431 packet_set_event_context(pipe_conn->packet, conn->event.ctx); 432 packet_set_fde(pipe_conn->packet, conn->event.fde); 433 packet_set_serialise(pipe_conn->packet); 434 packet_set_initial_read(pipe_conn->packet, 8); 435 436 pipe_conn->pipe_sock = pipe_sock; 437 438 pipe_conn->connection = conn; 439 conn->private_data = pipe_conn; 440} 441 442static const struct stream_server_ops named_pipe_stream_ops = { 443 .name = "named_pipe", 444 .accept_connection = named_pipe_accept, 445 .recv_handler = named_pipe_recv, 446 .send_handler = named_pipe_send, 447}; 448 449NTSTATUS stream_setup_named_pipe(struct tevent_context *event_context, 450 struct loadparm_context *lp_ctx, 451 const struct model_ops *model_ops, 452 const struct stream_server_ops *stream_ops, 453 const char *pipe_name, 454 void *private_data) 455{ 456 char *dirname; 457 struct named_pipe_socket *pipe_sock; 458 NTSTATUS status = NT_STATUS_NO_MEMORY;; 459 460 pipe_sock = talloc(event_context, struct named_pipe_socket); 461 if (pipe_sock == NULL) { 462 goto fail; 463 } 464 465 /* remember the details about the pipe */ 466 pipe_sock->pipe_name = talloc_strdup(pipe_sock, pipe_name); 467 if (pipe_sock->pipe_name == NULL) { 468 goto fail; 469 } 470 471 dirname = talloc_asprintf(pipe_sock, "%s/np", lp_ncalrpc_dir(lp_ctx)); 472 if (dirname == NULL) { 473 goto fail; 474 } 475 476 if (!directory_create_or_exist(dirname, geteuid(), 0700)) { 477 status = map_nt_error_from_unix(errno); 478 DEBUG(0,(__location__ ": Failed to create stream pipe directory %s - %s\n", 479 dirname, nt_errstr(status))); 480 goto fail; 481 } 482 483 if (strncmp(pipe_name, "\\pipe\\", 6) == 0) { 484 pipe_name += 6; 485 } 486 487 pipe_sock->pipe_path = talloc_asprintf(pipe_sock, "%s/%s", dirname, 488 pipe_name); 489 if (pipe_sock->pipe_path == NULL) { 490 goto fail; 491 } 492 493 talloc_free(dirname); 494 495 pipe_sock->ops = stream_ops; 496 pipe_sock->private_data = talloc_reference(pipe_sock, private_data); 497 498 status = stream_setup_socket(event_context, 499 lp_ctx, 500 model_ops, 501 &named_pipe_stream_ops, 502 "unix", 503 pipe_sock->pipe_path, 504 NULL, 505 NULL, 506 pipe_sock); 507 if (!NT_STATUS_IS_OK(status)) { 508 goto fail; 509 } 510 return NT_STATUS_OK; 511 512 fail: 513 talloc_free(pipe_sock); 514 return status; 515} 516