s3-lanman: fix api_DosPrintQEnum.
[Samba/ekacnet.git] / source4 / smbd / service_named_pipe.c
blobbce663ba8ec1bc28545f0b27d8ccf4a46a94a6e5
1 /*
2 Unix SMB/CIFS implementation.
4 helper functions for NAMED PIPE servers
6 Copyright (C) Stefan (metze) Metzmacher 2008
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.
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.
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/>.
22 #include "includes.h"
23 #include <tevent.h>
24 #include "smbd/service.h"
25 #include "param/param.h"
26 #include "auth/auth.h"
27 #include "auth/session.h"
28 #include "auth/auth_sam_reply.h"
29 #include "lib/socket/socket.h"
30 #include "lib/tsocket/tsocket.h"
31 #include "libcli/util/tstream.h"
32 #include "librpc/gen_ndr/ndr_named_pipe_auth.h"
33 #include "system/passwd.h"
34 #include "system/network.h"
35 #include "libcli/raw/smb.h"
36 #include "auth/credentials/credentials.h"
37 #include "auth/credentials/credentials_krb5.h"
39 struct named_pipe_socket {
40 const char *pipe_name;
41 const char *pipe_path;
42 const struct stream_server_ops *ops;
43 void *private_data;
46 struct named_pipe_connection {
47 struct stream_connection *connection;
48 const struct named_pipe_socket *pipe_sock;
49 struct tstream_context *tstream;
52 static void named_pipe_terminate_connection(struct named_pipe_connection *pipe_conn, const char *reason)
54 stream_terminate_connection(pipe_conn->connection, reason);
57 static NTSTATUS named_pipe_full_request(void *private_data, DATA_BLOB blob, size_t *size)
59 if (blob.length < 8) {
60 return STATUS_MORE_ENTRIES;
63 if (memcmp(NAMED_PIPE_AUTH_MAGIC, &blob.data[4], 4) != 0) {
64 DEBUG(0,("named_pipe_full_request: wrong protocol\n"));
65 *size = blob.length;
66 /* the error will be handled in named_pipe_recv_auth_request */
67 return NT_STATUS_OK;
70 *size = 4 + RIVAL(blob.data, 0);
71 if (*size > blob.length) {
72 return STATUS_MORE_ENTRIES;
75 return NT_STATUS_OK;
78 static void named_pipe_auth_request(struct tevent_req *subreq);
80 static void named_pipe_accept(struct stream_connection *conn)
82 struct named_pipe_socket *pipe_sock = talloc_get_type(conn->private_data,
83 struct named_pipe_socket);
84 struct named_pipe_connection *pipe_conn;
85 struct tevent_req *subreq;
86 int rc, fd;
88 pipe_conn = talloc_zero(conn, struct named_pipe_connection);
89 if (pipe_conn == NULL) {
90 stream_terminate_connection(conn,
91 "named_pipe_accept: out of memory");
92 return;
95 TALLOC_FREE(conn->event.fde);
98 * We have to duplicate the fd, cause it gets closed when the tstream
99 * is freed and you shouldn't work a fd the tstream is based on.
101 fd = dup(socket_get_fd(conn->socket));
102 if (fd == -1) {
103 char *reason;
105 reason = talloc_asprintf(conn,
106 "named_pipe_accept: failed to duplicate the file descriptor - %s",
107 strerror(errno));
108 if (reason == NULL) {
109 reason = strerror(errno);
111 stream_terminate_connection(conn, reason);
113 rc = tstream_bsd_existing_socket(pipe_conn,
115 &pipe_conn->tstream);
116 if (rc < 0) {
117 stream_terminate_connection(conn,
118 "named_pipe_accept: out of memory");
119 return;
122 pipe_conn->connection = conn;
123 pipe_conn->pipe_sock = pipe_sock;
124 conn->private_data = pipe_conn;
127 * The named pipe pdu's have the length as 8 byte (initial_read_size),
128 * named_pipe_full_request provides the pdu length then.
130 subreq = tstream_read_pdu_blob_send(pipe_conn,
131 pipe_conn->connection->event.ctx,
132 pipe_conn->tstream,
133 8, /* initial_read_size */
134 named_pipe_full_request,
135 pipe_conn);
136 if (subreq == NULL) {
137 named_pipe_terminate_connection(pipe_conn,
138 "named_pipe_accept: "
139 "no memory for tstream_read_pdu_blob_send");
140 return;
142 tevent_req_set_callback(subreq, named_pipe_auth_request, pipe_conn);
145 struct named_pipe_call {
146 struct named_pipe_connection *pipe_conn;
147 DATA_BLOB in;
148 DATA_BLOB out;
149 struct iovec out_iov[1];
150 NTSTATUS status;
153 static void named_pipe_handover_connection(struct tevent_req *subreq);
155 static void named_pipe_auth_request(struct tevent_req *subreq)
157 struct named_pipe_connection *pipe_conn = tevent_req_callback_data(subreq,
158 struct named_pipe_connection);
159 struct stream_connection *conn = pipe_conn->connection;
160 struct named_pipe_call *call;
161 enum ndr_err_code ndr_err;
162 union netr_Validation val;
163 struct auth_serversupplied_info *server_info;
164 struct named_pipe_auth_req pipe_request;
165 struct named_pipe_auth_rep pipe_reply;
166 struct auth_context *auth_context;
167 NTSTATUS status;
168 int ret;
170 call = talloc(pipe_conn, struct named_pipe_call);
171 if (call == NULL) {
172 named_pipe_terminate_connection(pipe_conn,
173 "named_pipe_auth_request: "
174 "no memory for named_pipe_call");
175 return;
177 call->pipe_conn = pipe_conn;
179 status = tstream_read_pdu_blob_recv(subreq,
180 call,
181 &call->in);
182 TALLOC_FREE(subreq);
183 if (!NT_STATUS_IS_OK(status)) {
184 const char *reason;
186 reason = talloc_asprintf(call, "named_pipe_call_loop: "
187 "tstream_read_pdu_blob_recv() - %s",
188 nt_errstr(status));
189 if (reason == NULL) {
190 reason = nt_errstr(status);
193 named_pipe_terminate_connection(pipe_conn, reason);
194 return;
197 DEBUG(10,("Received named_pipe packet of length %lu from %s\n",
198 (long) call->in.length,
199 tsocket_address_string(pipe_conn->connection->remote_address, call)));
200 dump_data(11, call->in.data, call->in.length);
203 * TODO: check it's a root (uid == 0) pipe
206 ZERO_STRUCT(pipe_reply);
207 pipe_reply.level = 0;
208 pipe_reply.status = NT_STATUS_INTERNAL_ERROR;
210 /* parse the passed credentials */
211 ndr_err = ndr_pull_struct_blob_all(
212 &call->in,
213 pipe_conn,
214 lp_iconv_convenience(conn->lp_ctx),
215 &pipe_request,
216 (ndr_pull_flags_fn_t) ndr_pull_named_pipe_auth_req);
217 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
218 pipe_reply.status = ndr_map_error2ntstatus(ndr_err);
219 DEBUG(2, ("Could not unmarshall named_pipe_auth_req: %s\n",
220 nt_errstr(pipe_reply.status)));
221 goto reply;
224 if (DEBUGLVL(10)) {
225 NDR_PRINT_DEBUG(named_pipe_auth_req, &pipe_request);
228 if (strcmp(NAMED_PIPE_AUTH_MAGIC, pipe_request.magic) != 0) {
229 DEBUG(2, ("named_pipe_auth_req: invalid magic '%s' != %s\n",
230 pipe_request.magic, NAMED_PIPE_AUTH_MAGIC));
231 pipe_reply.status = NT_STATUS_INVALID_PARAMETER;
232 goto reply;
235 switch (pipe_request.level) {
236 case 0:
238 * anon connection, we don't create a session info
239 * and leave it NULL
241 pipe_reply.level = 0;
242 pipe_reply.status = NT_STATUS_OK;
243 break;
244 case 1:
245 val.sam3 = &pipe_request.info.info1;
247 pipe_reply.level = 1;
248 pipe_reply.status = make_server_info_netlogon_validation(pipe_conn,
249 "TODO",
250 3, &val,
251 &server_info);
252 if (!NT_STATUS_IS_OK(pipe_reply.status)) {
253 DEBUG(2, ("make_server_info_netlogon_validation returned "
254 "%s\n", nt_errstr(pipe_reply.status)));
255 goto reply;
258 pipe_reply.status = auth_context_create(conn,
259 conn->event.ctx, conn->msg_ctx,
260 conn->lp_ctx,
261 &auth_context);
262 if (!NT_STATUS_IS_OK(pipe_reply.status)) {
263 DEBUG(2, ("auth_context_create returned "
264 "%s\n", nt_errstr(pipe_reply.status)));
265 goto reply;
269 /* setup the session_info on the connection */
270 pipe_reply.status = auth_context->generate_session_info(conn,
271 auth_context,
272 server_info,
273 &conn->session_info);
274 talloc_free(auth_context);
275 if (!NT_STATUS_IS_OK(pipe_reply.status)) {
276 DEBUG(2, ("auth_generate_session_info failed: %s\n",
277 nt_errstr(pipe_reply.status)));
278 goto reply;
281 break;
282 case 2:
283 pipe_reply.level = 2;
284 pipe_reply.info.info2.file_type = FILE_TYPE_MESSAGE_MODE_PIPE;
285 pipe_reply.info.info2.device_state = 0xff | 0x0400 | 0x0100;
286 pipe_reply.info.info2.allocation_size = 4096;
288 if (pipe_request.info.info2.sam_info3 == NULL) {
290 * anon connection, we don't create a session info
291 * and leave it NULL
293 pipe_reply.status = NT_STATUS_OK;
294 break;
297 val.sam3 = pipe_request.info.info2.sam_info3;
299 pipe_reply.status = make_server_info_netlogon_validation(pipe_conn,
300 val.sam3->base.account_name.string,
301 3, &val, &server_info);
302 if (!NT_STATUS_IS_OK(pipe_reply.status)) {
303 DEBUG(2, ("make_server_info_netlogon_validation returned "
304 "%s\n", nt_errstr(pipe_reply.status)));
305 goto reply;
308 /* setup the session_info on the connection */
309 pipe_reply.status = auth_context_create(conn,
310 conn->event.ctx, conn->msg_ctx,
311 conn->lp_ctx,
312 &auth_context);
313 if (!NT_STATUS_IS_OK(pipe_reply.status)) {
314 DEBUG(2, ("auth_context_create returned "
315 "%s\n", nt_errstr(pipe_reply.status)));
316 goto reply;
319 pipe_reply.status = auth_context->generate_session_info(conn,
320 auth_context,
321 server_info,
322 &conn->session_info);
323 talloc_free(auth_context);
324 if (!NT_STATUS_IS_OK(pipe_reply.status)) {
325 DEBUG(2, ("auth_generate_session_info failed: %s\n",
326 nt_errstr(pipe_reply.status)));
327 goto reply;
330 conn->session_info->session_key = data_blob_const(pipe_request.info.info2.session_key,
331 pipe_request.info.info2.session_key_length);
332 talloc_steal(conn->session_info, pipe_request.info.info2.session_key);
334 break;
335 case 3:
336 pipe_reply.level = 3;
337 pipe_reply.info.info3.file_type = FILE_TYPE_MESSAGE_MODE_PIPE;
338 pipe_reply.info.info3.device_state = 0xff | 0x0400 | 0x0100;
339 pipe_reply.info.info3.allocation_size = 4096;
341 if (pipe_request.info.info3.server_addr == NULL) {
342 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
343 DEBUG(2, ("Missing server address\n"));
344 goto reply;
346 if (pipe_request.info.info3.client_addr == NULL) {
347 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
348 DEBUG(2, ("Missing client address\n"));
349 goto reply;
352 ret = tsocket_address_inet_from_strings(conn, "ip",
353 pipe_request.info.info3.server_addr,
354 pipe_request.info.info3.server_port,
355 &conn->local_address);
356 if (ret != 0) {
357 DEBUG(2, ("Invalid server address[%s] port[%u] - %s\n",
358 pipe_request.info.info3.server_addr,
359 pipe_request.info.info3.server_port,
360 strerror(errno)));
361 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
362 goto reply;
365 ret = tsocket_address_inet_from_strings(conn, "ip",
366 pipe_request.info.info3.client_addr,
367 pipe_request.info.info3.client_port,
368 &conn->remote_address);
369 if (ret != 0) {
370 DEBUG(2, ("Invalid client address[%s] port[%u] - %s\n",
371 pipe_request.info.info3.client_addr,
372 pipe_request.info.info3.client_port,
373 strerror(errno)));
374 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
375 goto reply;
378 if (pipe_request.info.info3.sam_info3 == NULL) {
380 * anon connection, we don't create a session info
381 * and leave it NULL
383 pipe_reply.status = NT_STATUS_OK;
384 break;
387 val.sam3 = pipe_request.info.info3.sam_info3;
389 pipe_reply.status = make_server_info_netlogon_validation(pipe_conn,
390 val.sam3->base.account_name.string,
391 3, &val, &server_info);
392 if (!NT_STATUS_IS_OK(pipe_reply.status)) {
393 DEBUG(2, ("make_server_info_netlogon_validation returned "
394 "%s\n", nt_errstr(pipe_reply.status)));
395 goto reply;
398 /* setup the session_info on the connection */
399 pipe_reply.status = auth_context_create(conn,
400 conn->event.ctx, conn->msg_ctx,
401 conn->lp_ctx,
402 &auth_context);
403 if (!NT_STATUS_IS_OK(pipe_reply.status)) {
404 DEBUG(2, ("auth_context_create returned "
405 "%s\n", nt_errstr(pipe_reply.status)));
406 goto reply;
409 /* setup the session_info on the connection */
410 pipe_reply.status = auth_context->generate_session_info(conn,
411 auth_context,
412 server_info,
413 &conn->session_info);
414 talloc_free(auth_context);
415 if (!NT_STATUS_IS_OK(pipe_reply.status)) {
416 DEBUG(2, ("auth_generate_session_info failed: %s\n",
417 nt_errstr(pipe_reply.status)));
418 goto reply;
421 if (pipe_request.info.info3.gssapi_delegated_creds_length) {
422 OM_uint32 minor_status;
423 gss_buffer_desc cred_token;
424 gss_cred_id_t cred_handle;
425 const char *error_string;
427 DEBUG(10, ("named_pipe_auth: delegated credentials supplied by client\n"));
429 cred_token.value = pipe_request.info.info3.gssapi_delegated_creds;
430 cred_token.length = pipe_request.info.info3.gssapi_delegated_creds_length;
432 ret = gss_import_cred(&minor_status,
433 &cred_token,
434 &cred_handle);
435 if (ret != GSS_S_COMPLETE) {
436 pipe_reply.status = NT_STATUS_INTERNAL_ERROR;
437 goto reply;
440 conn->session_info->credentials = cli_credentials_init(conn->session_info);
441 if (conn->session_info->credentials == NULL) {
442 pipe_reply.status = NT_STATUS_NO_MEMORY;
443 goto reply;
446 cli_credentials_set_conf(conn->session_info->credentials,
447 conn->lp_ctx);
448 /* Just so we don't segfault trying to get at a username */
449 cli_credentials_set_anonymous(conn->session_info->credentials);
451 ret = cli_credentials_set_client_gss_creds(conn->session_info->credentials,
452 conn->event.ctx,
453 conn->lp_ctx,
454 cred_handle,
455 CRED_SPECIFIED, &error_string);
456 if (ret) {
457 pipe_reply.status = NT_STATUS_INTERNAL_ERROR;
458 DEBUG(2, ("Failed to set pipe forwarded creds: %s\n", error_string));
459 goto reply;
462 /* This credential handle isn't useful for password authentication, so ensure nobody tries to do that */
463 cli_credentials_set_kerberos_state(conn->session_info->credentials,
464 CRED_MUST_USE_KERBEROS);
467 conn->session_info->session_key = data_blob_const(pipe_request.info.info3.session_key,
468 pipe_request.info.info3.session_key_length);
469 talloc_steal(conn->session_info, pipe_request.info.info3.session_key);
471 break;
472 default:
473 DEBUG(0, ("named_pipe_auth_req: unknown level %u\n",
474 pipe_request.level));
475 pipe_reply.level = 0;
476 pipe_reply.status = NT_STATUS_INVALID_LEVEL;
477 goto reply;
480 reply:
481 /* create the output */
482 ndr_err = ndr_push_struct_blob(&call->out, pipe_conn,
483 lp_iconv_convenience(conn->lp_ctx),
484 &pipe_reply,
485 (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_rep);
486 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
487 const char *reason;
488 status = ndr_map_error2ntstatus(ndr_err);
490 reason = talloc_asprintf(pipe_conn, "named_pipe_auth_request: could not marshall named_pipe_auth_rep: %s\n",
491 nt_errstr(status));
492 if (reason == NULL) {
493 reason = "named_pipe_auth_request: could not marshall named_pipe_auth_rep";
495 named_pipe_terminate_connection(pipe_conn, reason);
496 return;
499 DEBUG(10,("named_pipe_auth_request: named_pipe_auth reply[%u]\n",
500 (unsigned) call->out.length));
501 dump_data(11, call->out.data, call->out.length);
502 if (DEBUGLVL(10)) {
503 NDR_PRINT_DEBUG(named_pipe_auth_rep, &pipe_reply);
506 call->status = pipe_reply.status;
508 call->out_iov[0].iov_base = call->out.data;
509 call->out_iov[0].iov_len = call->out.length;
511 subreq = tstream_writev_send(call,
512 pipe_conn->connection->event.ctx,
513 pipe_conn->tstream,
514 call->out_iov, 1);
515 if (subreq == NULL) {
516 named_pipe_terminate_connection(pipe_conn, "named_pipe_auth_request: "
517 "no memory for tstream_writev_send");
518 return;
521 tevent_req_set_callback(subreq, named_pipe_handover_connection, call);
524 static void named_pipe_handover_connection(struct tevent_req *subreq)
526 struct named_pipe_call *call = tevent_req_callback_data(subreq,
527 struct named_pipe_call);
528 struct named_pipe_connection *pipe_conn = call->pipe_conn;
529 struct stream_connection *conn = pipe_conn->connection;
530 int sys_errno;
531 int rc;
533 rc = tstream_writev_recv(subreq, &sys_errno);
534 TALLOC_FREE(subreq);
535 if (rc == -1) {
536 const char *reason;
538 reason = talloc_asprintf(call, "named_pipe_handover_connection: "
539 "tstream_writev_recv() - %d:%s",
540 sys_errno, strerror(sys_errno));
541 if (reason == NULL) {
542 reason = "named_pipe_handover_connection: "
543 "tstream_writev_recv() failed";
546 named_pipe_terminate_connection(pipe_conn, reason);
547 return;
550 if (!NT_STATUS_IS_OK(call->status)) {
551 const char *reason;
553 reason = talloc_asprintf(call, "named_pipe_handover_connection: "
554 "reply status - %s", nt_errstr(call->status));
555 if (reason == NULL) {
556 reason = nt_errstr(call->status);
559 named_pipe_terminate_connection(pipe_conn, reason);
560 return;
564 * remove the named_pipe layer together with its packet layer
566 conn->ops = pipe_conn->pipe_sock->ops;
567 conn->private_data = pipe_conn->pipe_sock->private_data;
568 talloc_unlink(conn, pipe_conn);
570 conn->event.fde = tevent_add_fd(conn->event.ctx,
571 conn,
572 socket_get_fd(conn->socket),
573 TEVENT_FD_READ,
574 stream_io_handler_fde,
575 conn);
576 if (conn->event.fde == NULL) {
577 named_pipe_terminate_connection(pipe_conn, "named_pipe_handover_connection: "
578 "setting up the stream_io_handler_fde failed");
579 return;
583 * hand over to the real pipe implementation,
584 * now that we have setup the transport session_info
586 conn->ops->accept_connection(conn);
588 DEBUG(10,("named_pipe_handover_connection[%s]: succeeded\n",
589 conn->ops->name));
591 /* we don't have to free call here as the connection got closed */
595 called when a pipe socket becomes readable
597 static void named_pipe_recv(struct stream_connection *conn, uint16_t flags)
599 struct named_pipe_connection *pipe_conn = talloc_get_type(
600 conn->private_data, struct named_pipe_connection);
602 named_pipe_terminate_connection(pipe_conn,
603 "named_pipe_recv: called");
607 called when a pipe socket becomes writable
609 static void named_pipe_send(struct stream_connection *conn, uint16_t flags)
611 struct named_pipe_connection *pipe_conn = talloc_get_type(
612 conn->private_data, struct named_pipe_connection);
614 named_pipe_terminate_connection(pipe_conn,
615 "named_pipe_send: called");
618 static const struct stream_server_ops named_pipe_stream_ops = {
619 .name = "named_pipe",
620 .accept_connection = named_pipe_accept,
621 .recv_handler = named_pipe_recv,
622 .send_handler = named_pipe_send,
625 NTSTATUS stream_setup_named_pipe(struct tevent_context *event_context,
626 struct loadparm_context *lp_ctx,
627 const struct model_ops *model_ops,
628 const struct stream_server_ops *stream_ops,
629 const char *pipe_name,
630 void *private_data)
632 char *dirname;
633 struct named_pipe_socket *pipe_sock;
634 NTSTATUS status = NT_STATUS_NO_MEMORY;;
636 pipe_sock = talloc(event_context, struct named_pipe_socket);
637 if (pipe_sock == NULL) {
638 goto fail;
641 /* remember the details about the pipe */
642 pipe_sock->pipe_name = talloc_strdup(pipe_sock, pipe_name);
643 if (pipe_sock->pipe_name == NULL) {
644 goto fail;
647 dirname = talloc_asprintf(pipe_sock, "%s/np", lp_ncalrpc_dir(lp_ctx));
648 if (dirname == NULL) {
649 goto fail;
652 if (!directory_create_or_exist(dirname, geteuid(), 0700)) {
653 status = map_nt_error_from_unix(errno);
654 DEBUG(0,(__location__ ": Failed to create stream pipe directory %s - %s\n",
655 dirname, nt_errstr(status)));
656 goto fail;
659 if (strncmp(pipe_name, "\\pipe\\", 6) == 0) {
660 pipe_name += 6;
663 pipe_sock->pipe_path = talloc_asprintf(pipe_sock, "%s/%s", dirname,
664 pipe_name);
665 if (pipe_sock->pipe_path == NULL) {
666 goto fail;
669 talloc_free(dirname);
671 pipe_sock->ops = stream_ops;
672 pipe_sock->private_data = talloc_reference(pipe_sock, private_data);
674 status = stream_setup_socket(event_context,
675 lp_ctx,
676 model_ops,
677 &named_pipe_stream_ops,
678 "unix",
679 pipe_sock->pipe_path,
680 NULL,
681 NULL,
682 pipe_sock);
683 if (!NT_STATUS_IS_OK(status)) {
684 goto fail;
686 return NT_STATUS_OK;
688 fail:
689 talloc_free(pipe_sock);
690 return status;