s3-passdb: Fix typo in debug message.
[Samba.git] / source4 / smbd / service_named_pipe.c
blobec833d0c5a9c0534e8a1a502eb86e6be9644afa5
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/session.h"
27 #include "auth/auth_sam_reply.h"
28 #include "lib/socket/socket.h"
29 #include "lib/tsocket/tsocket.h"
30 #include "libcli/util/tstream.h"
31 #include "librpc/gen_ndr/ndr_named_pipe_auth.h"
32 #include "system/passwd.h"
33 #include "system/network.h"
34 #include "libcli/raw/smb.h"
35 #include "auth/credentials/credentials.h"
36 #include "auth/credentials/credentials_krb5.h"
38 struct named_pipe_socket {
39 const char *pipe_name;
40 const char *pipe_path;
41 const struct stream_server_ops *ops;
42 void *private_data;
45 struct named_pipe_connection {
46 struct stream_connection *connection;
47 const struct named_pipe_socket *pipe_sock;
48 struct tstream_context *tstream;
51 static void named_pipe_terminate_connection(struct named_pipe_connection *pipe_conn, const char *reason)
53 stream_terminate_connection(pipe_conn->connection, reason);
56 static NTSTATUS named_pipe_full_request(void *private_data, DATA_BLOB blob, size_t *size)
58 if (blob.length < 8) {
59 return STATUS_MORE_ENTRIES;
62 if (memcmp(NAMED_PIPE_AUTH_MAGIC, &blob.data[4], 4) != 0) {
63 DEBUG(0,("named_pipe_full_request: wrong protocol\n"));
64 *size = blob.length;
65 /* the error will be handled in named_pipe_recv_auth_request */
66 return NT_STATUS_OK;
69 *size = 4 + RIVAL(blob.data, 0);
70 if (*size > blob.length) {
71 return STATUS_MORE_ENTRIES;
74 return NT_STATUS_OK;
77 static void named_pipe_auth_request(struct tevent_req *subreq);
79 static void named_pipe_accept(struct stream_connection *conn)
81 struct named_pipe_socket *pipe_sock = talloc_get_type(conn->private_data,
82 struct named_pipe_socket);
83 struct named_pipe_connection *pipe_conn;
84 struct tevent_req *subreq;
85 int rc, fd;
87 pipe_conn = talloc_zero(conn, struct named_pipe_connection);
88 if (pipe_conn == NULL) {
89 stream_terminate_connection(conn,
90 "named_pipe_accept: out of memory");
91 return;
94 TALLOC_FREE(conn->event.fde);
97 * We have to duplicate the fd, cause it gets closed when the tstream
98 * is freed and you shouldn't work a fd the tstream is based on.
100 fd = dup(socket_get_fd(conn->socket));
101 if (fd == -1) {
102 char *reason;
104 reason = talloc_asprintf(conn,
105 "named_pipe_accept: failed to duplicate the file descriptor - %s",
106 strerror(errno));
107 if (reason == NULL) {
108 reason = strerror(errno);
110 stream_terminate_connection(conn, reason);
112 rc = tstream_bsd_existing_socket(pipe_conn,
114 &pipe_conn->tstream);
115 if (rc < 0) {
116 stream_terminate_connection(conn,
117 "named_pipe_accept: out of memory");
118 return;
121 pipe_conn->connection = conn;
122 pipe_conn->pipe_sock = pipe_sock;
123 conn->private_data = pipe_conn;
126 * The named pipe pdu's have the length as 8 byte (initial_read_size),
127 * named_pipe_full_request provides the pdu length then.
129 subreq = tstream_read_pdu_blob_send(pipe_conn,
130 pipe_conn->connection->event.ctx,
131 pipe_conn->tstream,
132 8, /* initial_read_size */
133 named_pipe_full_request,
134 pipe_conn);
135 if (subreq == NULL) {
136 named_pipe_terminate_connection(pipe_conn,
137 "named_pipe_accept: "
138 "no memory for tstream_read_pdu_blob_send");
139 return;
141 tevent_req_set_callback(subreq, named_pipe_auth_request, pipe_conn);
144 struct named_pipe_call {
145 struct named_pipe_connection *pipe_conn;
146 DATA_BLOB in;
147 DATA_BLOB out;
148 struct iovec out_iov[1];
149 NTSTATUS status;
152 static void named_pipe_handover_connection(struct tevent_req *subreq);
154 static void named_pipe_auth_request(struct tevent_req *subreq)
156 struct named_pipe_connection *pipe_conn = tevent_req_callback_data(subreq,
157 struct named_pipe_connection);
158 struct stream_connection *conn = pipe_conn->connection;
159 struct named_pipe_call *call;
160 enum ndr_err_code ndr_err;
161 union netr_Validation val;
162 struct auth_serversupplied_info *server_info;
163 struct named_pipe_auth_req pipe_request;
164 struct named_pipe_auth_rep pipe_reply;
165 NTSTATUS status;
167 call = talloc(pipe_conn, struct named_pipe_call);
168 if (call == NULL) {
169 named_pipe_terminate_connection(pipe_conn,
170 "named_pipe_auth_request: "
171 "no memory for named_pipe_call");
172 return;
174 call->pipe_conn = pipe_conn;
176 status = tstream_read_pdu_blob_recv(subreq,
177 call,
178 &call->in);
179 TALLOC_FREE(subreq);
180 if (!NT_STATUS_IS_OK(status)) {
181 const char *reason;
183 reason = talloc_asprintf(call, "named_pipe_call_loop: "
184 "tstream_read_pdu_blob_recv() - %s",
185 nt_errstr(status));
186 if (reason == NULL) {
187 reason = nt_errstr(status);
190 named_pipe_terminate_connection(pipe_conn, reason);
191 return;
194 DEBUG(10,("Received named_pipe packet of length %lu from %s\n",
195 (long) call->in.length,
196 tsocket_address_string(pipe_conn->connection->remote_address, call)));
197 dump_data(11, call->in.data, call->in.length);
200 * TODO: check it's a root (uid == 0) pipe
203 ZERO_STRUCT(pipe_reply);
204 pipe_reply.level = 0;
205 pipe_reply.status = NT_STATUS_INTERNAL_ERROR;
207 /* parse the passed credentials */
208 ndr_err = ndr_pull_struct_blob_all(
209 &call->in,
210 pipe_conn,
211 lp_iconv_convenience(conn->lp_ctx),
212 &pipe_request,
213 (ndr_pull_flags_fn_t) ndr_pull_named_pipe_auth_req);
214 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
215 pipe_reply.status = ndr_map_error2ntstatus(ndr_err);
216 DEBUG(2, ("Could not unmarshall named_pipe_auth_req: %s\n",
217 nt_errstr(pipe_reply.status)));
218 goto reply;
221 if (DEBUGLVL(10)) {
222 NDR_PRINT_DEBUG(named_pipe_auth_req, &pipe_request);
225 if (strcmp(NAMED_PIPE_AUTH_MAGIC, pipe_request.magic) != 0) {
226 DEBUG(2, ("named_pipe_auth_req: invalid magic '%s' != %s\n",
227 pipe_request.magic, NAMED_PIPE_AUTH_MAGIC));
228 pipe_reply.status = NT_STATUS_INVALID_PARAMETER;
229 goto reply;
232 switch (pipe_request.level) {
233 case 0:
235 * anon connection, we don't create a session info
236 * and leave it NULL
238 pipe_reply.level = 0;
239 pipe_reply.status = NT_STATUS_OK;
240 break;
241 case 1:
242 val.sam3 = &pipe_request.info.info1;
244 pipe_reply.level = 1;
245 pipe_reply.status = make_server_info_netlogon_validation(pipe_conn,
246 "TODO",
247 3, &val,
248 &server_info);
249 if (!NT_STATUS_IS_OK(pipe_reply.status)) {
250 DEBUG(2, ("make_server_info_netlogon_validation returned "
251 "%s\n", nt_errstr(pipe_reply.status)));
252 goto reply;
255 /* setup the session_info on the connection */
256 pipe_reply.status = auth_generate_session_info(conn,
257 conn->event.ctx,
258 conn->lp_ctx,
259 server_info,
260 &conn->session_info);
261 if (!NT_STATUS_IS_OK(pipe_reply.status)) {
262 DEBUG(2, ("auth_generate_session_info failed: %s\n",
263 nt_errstr(pipe_reply.status)));
264 goto reply;
267 break;
268 case 2:
269 pipe_reply.level = 2;
270 pipe_reply.info.info2.file_type = FILE_TYPE_MESSAGE_MODE_PIPE;
271 pipe_reply.info.info2.device_state = 0xff | 0x0400 | 0x0100;
272 pipe_reply.info.info2.allocation_size = 4096;
274 if (pipe_request.info.info2.sam_info3 == NULL) {
276 * anon connection, we don't create a session info
277 * and leave it NULL
279 pipe_reply.status = NT_STATUS_OK;
280 break;
283 val.sam3 = pipe_request.info.info2.sam_info3;
285 pipe_reply.status = make_server_info_netlogon_validation(pipe_conn,
286 val.sam3->base.account_name.string,
287 3, &val, &server_info);
288 if (!NT_STATUS_IS_OK(pipe_reply.status)) {
289 DEBUG(2, ("make_server_info_netlogon_validation returned "
290 "%s\n", nt_errstr(pipe_reply.status)));
291 goto reply;
294 /* setup the session_info on the connection */
295 pipe_reply.status = auth_generate_session_info(conn,
296 conn->event.ctx,
297 conn->lp_ctx,
298 server_info,
299 &conn->session_info);
300 if (!NT_STATUS_IS_OK(pipe_reply.status)) {
301 DEBUG(2, ("auth_generate_session_info failed: %s\n",
302 nt_errstr(pipe_reply.status)));
303 goto reply;
306 conn->session_info->session_key = data_blob_const(pipe_request.info.info2.session_key,
307 pipe_request.info.info2.session_key_length);
308 talloc_steal(conn->session_info, pipe_request.info.info2.session_key);
310 break;
311 case 3:
312 pipe_reply.level = 3;
313 pipe_reply.info.info3.file_type = FILE_TYPE_MESSAGE_MODE_PIPE;
314 pipe_reply.info.info3.device_state = 0xff | 0x0400 | 0x0100;
315 pipe_reply.info.info3.allocation_size = 4096;
317 if (pipe_request.info.info3.sam_info3 == NULL) {
319 * anon connection, we don't create a session info
320 * and leave it NULL
322 pipe_reply.status = NT_STATUS_OK;
323 break;
326 val.sam3 = pipe_request.info.info3.sam_info3;
328 pipe_reply.status = make_server_info_netlogon_validation(pipe_conn,
329 val.sam3->base.account_name.string,
330 3, &val, &server_info);
331 if (!NT_STATUS_IS_OK(pipe_reply.status)) {
332 DEBUG(2, ("make_server_info_netlogon_validation returned "
333 "%s\n", nt_errstr(pipe_reply.status)));
334 goto reply;
337 /* setup the session_info on the connection */
338 pipe_reply.status = auth_generate_session_info(conn,
339 conn->event.ctx,
340 conn->lp_ctx,
341 server_info,
342 &conn->session_info);
343 if (!NT_STATUS_IS_OK(pipe_reply.status)) {
344 DEBUG(2, ("auth_generate_session_info failed: %s\n",
345 nt_errstr(pipe_reply.status)));
346 goto reply;
349 if (pipe_request.info.info3.gssapi_delegated_creds_length) {
350 OM_uint32 minor_status;
351 gss_buffer_desc cred_token;
352 gss_cred_id_t cred_handle;
353 int ret;
354 const char *error_string;
356 DEBUG(10, ("named_pipe_auth: delegated credentials supplied by client\n"));
358 cred_token.value = pipe_request.info.info3.gssapi_delegated_creds;
359 cred_token.length = pipe_request.info.info3.gssapi_delegated_creds_length;
361 ret = gss_import_cred(&minor_status,
362 &cred_token,
363 &cred_handle);
364 if (ret != GSS_S_COMPLETE) {
365 pipe_reply.status = NT_STATUS_INTERNAL_ERROR;
366 goto reply;
369 conn->session_info->credentials = cli_credentials_init(conn->session_info);
370 if (conn->session_info->credentials == NULL) {
371 pipe_reply.status = NT_STATUS_NO_MEMORY;
372 goto reply;
375 cli_credentials_set_conf(conn->session_info->credentials,
376 conn->lp_ctx);
377 /* Just so we don't segfault trying to get at a username */
378 cli_credentials_set_anonymous(conn->session_info->credentials);
380 ret = cli_credentials_set_client_gss_creds(conn->session_info->credentials,
381 conn->event.ctx,
382 conn->lp_ctx,
383 cred_handle,
384 CRED_SPECIFIED, &error_string);
385 if (ret) {
386 pipe_reply.status = NT_STATUS_INTERNAL_ERROR;
387 DEBUG(2, ("Failed to set pipe forwarded creds: %s\n", error_string));
388 goto reply;
391 /* This credential handle isn't useful for password authentication, so ensure nobody tries to do that */
392 cli_credentials_set_kerberos_state(conn->session_info->credentials,
393 CRED_MUST_USE_KERBEROS);
396 conn->session_info->session_key = data_blob_const(pipe_request.info.info3.session_key,
397 pipe_request.info.info3.session_key_length);
398 talloc_steal(conn->session_info, pipe_request.info.info3.session_key);
400 break;
401 default:
402 DEBUG(0, ("named_pipe_auth_req: unknown level %u\n",
403 pipe_request.level));
404 pipe_reply.level = 0;
405 pipe_reply.status = NT_STATUS_INVALID_LEVEL;
406 goto reply;
409 reply:
410 /* create the output */
411 ndr_err = ndr_push_struct_blob(&call->out, pipe_conn,
412 lp_iconv_convenience(conn->lp_ctx),
413 &pipe_reply,
414 (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_rep);
415 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
416 const char *reason;
417 status = ndr_map_error2ntstatus(ndr_err);
419 reason = talloc_asprintf(pipe_conn, "named_pipe_auth_request: could not marshall named_pipe_auth_rep: %s\n",
420 nt_errstr(status));
421 if (reason == NULL) {
422 reason = "named_pipe_auth_request: could not marshall named_pipe_auth_rep";
424 named_pipe_terminate_connection(pipe_conn, reason);
425 return;
428 DEBUG(10,("named_pipe_auth_request: named_pipe_auth reply[%u]\n",
429 (unsigned) call->out.length));
430 dump_data(11, call->out.data, call->out.length);
431 if (DEBUGLVL(10)) {
432 NDR_PRINT_DEBUG(named_pipe_auth_rep, &pipe_reply);
435 call->status = pipe_reply.status;
437 call->out_iov[0].iov_base = call->out.data;
438 call->out_iov[0].iov_len = call->out.length;
440 subreq = tstream_writev_send(call,
441 pipe_conn->connection->event.ctx,
442 pipe_conn->tstream,
443 call->out_iov, 1);
444 if (subreq == NULL) {
445 named_pipe_terminate_connection(pipe_conn, "named_pipe_auth_request: "
446 "no memory for tstream_writev_send");
447 return;
450 tevent_req_set_callback(subreq, named_pipe_handover_connection, call);
453 static void named_pipe_handover_connection(struct tevent_req *subreq)
455 struct named_pipe_call *call = tevent_req_callback_data(subreq,
456 struct named_pipe_call);
457 struct named_pipe_connection *pipe_conn = call->pipe_conn;
458 struct stream_connection *conn = pipe_conn->connection;
459 int sys_errno;
460 int rc;
462 rc = tstream_writev_recv(subreq, &sys_errno);
463 TALLOC_FREE(subreq);
464 if (rc == -1) {
465 const char *reason;
467 reason = talloc_asprintf(call, "named_pipe_handover_connection: "
468 "tstream_writev_recv() - %d:%s",
469 sys_errno, strerror(sys_errno));
470 if (reason == NULL) {
471 reason = "named_pipe_handover_connection: "
472 "tstream_writev_recv() failed";
475 named_pipe_terminate_connection(pipe_conn, reason);
476 return;
479 if (!NT_STATUS_IS_OK(call->status)) {
480 const char *reason;
482 reason = talloc_asprintf(call, "named_pipe_handover_connection: "
483 "reply status - %s", nt_errstr(call->status));
484 if (reason == NULL) {
485 reason = nt_errstr(call->status);
488 named_pipe_terminate_connection(pipe_conn, reason);
489 return;
493 * remove the named_pipe layer together with its packet layer
495 conn->ops = pipe_conn->pipe_sock->ops;
496 conn->private_data = pipe_conn->pipe_sock->private_data;
497 talloc_unlink(conn, pipe_conn);
499 conn->event.fde = tevent_add_fd(conn->event.ctx,
500 conn,
501 socket_get_fd(conn->socket),
502 TEVENT_FD_READ,
503 stream_io_handler_fde,
504 conn);
505 if (conn->event.fde == NULL) {
506 named_pipe_terminate_connection(pipe_conn, "named_pipe_handover_connection: "
507 "setting up the stream_io_handler_fde failed");
508 return;
512 * hand over to the real pipe implementation,
513 * now that we have setup the transport session_info
515 conn->ops->accept_connection(conn);
517 DEBUG(10,("named_pipe_handover_connection[%s]: succeeded\n",
518 conn->ops->name));
520 /* we don't have to free call here as the connection got closed */
524 called when a pipe socket becomes readable
526 static void named_pipe_recv(struct stream_connection *conn, uint16_t flags)
528 struct named_pipe_connection *pipe_conn = talloc_get_type(
529 conn->private_data, struct named_pipe_connection);
531 named_pipe_terminate_connection(pipe_conn,
532 "named_pipe_recv: called");
536 called when a pipe socket becomes writable
538 static void named_pipe_send(struct stream_connection *conn, uint16_t flags)
540 struct named_pipe_connection *pipe_conn = talloc_get_type(
541 conn->private_data, struct named_pipe_connection);
543 named_pipe_terminate_connection(pipe_conn,
544 "named_pipe_send: called");
547 static const struct stream_server_ops named_pipe_stream_ops = {
548 .name = "named_pipe",
549 .accept_connection = named_pipe_accept,
550 .recv_handler = named_pipe_recv,
551 .send_handler = named_pipe_send,
554 NTSTATUS stream_setup_named_pipe(struct tevent_context *event_context,
555 struct loadparm_context *lp_ctx,
556 const struct model_ops *model_ops,
557 const struct stream_server_ops *stream_ops,
558 const char *pipe_name,
559 void *private_data)
561 char *dirname;
562 struct named_pipe_socket *pipe_sock;
563 NTSTATUS status = NT_STATUS_NO_MEMORY;;
565 pipe_sock = talloc(event_context, struct named_pipe_socket);
566 if (pipe_sock == NULL) {
567 goto fail;
570 /* remember the details about the pipe */
571 pipe_sock->pipe_name = talloc_strdup(pipe_sock, pipe_name);
572 if (pipe_sock->pipe_name == NULL) {
573 goto fail;
576 dirname = talloc_asprintf(pipe_sock, "%s/np", lp_ncalrpc_dir(lp_ctx));
577 if (dirname == NULL) {
578 goto fail;
581 if (!directory_create_or_exist(dirname, geteuid(), 0700)) {
582 status = map_nt_error_from_unix(errno);
583 DEBUG(0,(__location__ ": Failed to create stream pipe directory %s - %s\n",
584 dirname, nt_errstr(status)));
585 goto fail;
588 if (strncmp(pipe_name, "\\pipe\\", 6) == 0) {
589 pipe_name += 6;
592 pipe_sock->pipe_path = talloc_asprintf(pipe_sock, "%s/%s", dirname,
593 pipe_name);
594 if (pipe_sock->pipe_path == NULL) {
595 goto fail;
598 talloc_free(dirname);
600 pipe_sock->ops = stream_ops;
601 pipe_sock->private_data = talloc_reference(pipe_sock, private_data);
603 status = stream_setup_socket(event_context,
604 lp_ctx,
605 model_ops,
606 &named_pipe_stream_ops,
607 "unix",
608 pipe_sock->pipe_path,
609 NULL,
610 NULL,
611 pipe_sock);
612 if (!NT_STATUS_IS_OK(status)) {
613 goto fail;
615 return NT_STATUS_OK;
617 fail:
618 talloc_free(pipe_sock);
619 return status;