s4-smb: Migrate named_pipe_server to tsocket.
[Samba/ekacnet.git] / source4 / smbd / service_named_pipe.c
blob18ae823dd277148b81a1a118b8805dda7d4cafbf
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;
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);
96 rc = tstream_bsd_existing_socket(pipe_conn->tstream,
97 socket_get_fd(conn->socket),
98 &pipe_conn->tstream);
99 if (rc < 0) {
100 stream_terminate_connection(conn,
101 "named_pipe_accept: out of memory");
102 return;
105 pipe_conn->connection = conn;
106 pipe_conn->pipe_sock = pipe_sock;
107 conn->private_data = pipe_conn;
110 * The named pipe pdu's have the length as 8 byte (initial_read_size),
111 * named_pipe_full_request provides the pdu length then.
113 subreq = tstream_read_pdu_blob_send(pipe_conn,
114 pipe_conn->connection->event.ctx,
115 pipe_conn->tstream,
116 8, /* initial_read_size */
117 named_pipe_full_request,
118 pipe_conn);
119 if (subreq == NULL) {
120 named_pipe_terminate_connection(pipe_conn,
121 "named_pipe_accept: "
122 "no memory for tstream_read_pdu_blob_send");
123 return;
125 tevent_req_set_callback(subreq, named_pipe_auth_request, pipe_conn);
128 struct named_pipe_call {
129 struct named_pipe_connection *pipe_conn;
130 DATA_BLOB in;
131 DATA_BLOB out;
132 struct iovec out_iov[1];
133 NTSTATUS status;
136 static void named_pipe_handover_connection(struct tevent_req *subreq);
138 static void named_pipe_auth_request(struct tevent_req *subreq)
140 struct named_pipe_connection *pipe_conn = tevent_req_callback_data(subreq,
141 struct named_pipe_connection);
142 struct stream_connection *conn = pipe_conn->connection;
143 struct named_pipe_call *call;
144 enum ndr_err_code ndr_err;
145 union netr_Validation val;
146 struct auth_serversupplied_info *server_info;
147 struct named_pipe_auth_req pipe_request;
148 struct named_pipe_auth_rep pipe_reply;
149 NTSTATUS status;
151 call = talloc(pipe_conn, struct named_pipe_call);
152 if (call == NULL) {
153 named_pipe_terminate_connection(pipe_conn,
154 "named_pipe_auth_request: "
155 "no memory for named_pipe_call");
156 return;
158 call->pipe_conn = pipe_conn;
160 status = tstream_read_pdu_blob_recv(subreq,
161 call,
162 &call->in);
163 TALLOC_FREE(subreq);
164 if (!NT_STATUS_IS_OK(status)) {
165 const char *reason;
167 reason = talloc_asprintf(call, "named_pipe_call_loop: "
168 "tstream_read_pdu_blob_recv() - %s",
169 nt_errstr(status));
170 if (reason == NULL) {
171 reason = nt_errstr(status);
174 named_pipe_terminate_connection(pipe_conn, reason);
175 return;
178 DEBUG(10,("Received named_pipe packet of length %lu from %s\n",
179 (long) call->in.length,
180 tsocket_address_string(pipe_conn->connection->remote_address, call)));
181 dump_data(11, call->in.data, call->in.length);
184 * TODO: check it's a root (uid == 0) pipe
187 ZERO_STRUCT(pipe_reply);
188 pipe_reply.level = 0;
189 pipe_reply.status = NT_STATUS_INTERNAL_ERROR;
191 /* parse the passed credentials */
192 ndr_err = ndr_pull_struct_blob_all(
193 &call->in,
194 pipe_conn,
195 lp_iconv_convenience(conn->lp_ctx),
196 &pipe_request,
197 (ndr_pull_flags_fn_t) ndr_pull_named_pipe_auth_req);
198 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
199 pipe_reply.status = ndr_map_error2ntstatus(ndr_err);
200 DEBUG(2, ("Could not unmarshall named_pipe_auth_req: %s\n",
201 nt_errstr(pipe_reply.status)));
202 goto reply;
205 if (DEBUGLVL(10)) {
206 NDR_PRINT_DEBUG(named_pipe_auth_req, &pipe_request);
209 if (strcmp(NAMED_PIPE_AUTH_MAGIC, pipe_request.magic) != 0) {
210 DEBUG(2, ("named_pipe_auth_req: invalid magic '%s' != %s\n",
211 pipe_request.magic, NAMED_PIPE_AUTH_MAGIC));
212 pipe_reply.status = NT_STATUS_INVALID_PARAMETER;
213 goto reply;
216 switch (pipe_request.level) {
217 case 0:
219 * anon connection, we don't create a session info
220 * and leave it NULL
222 pipe_reply.level = 0;
223 pipe_reply.status = NT_STATUS_OK;
224 break;
225 case 1:
226 val.sam3 = &pipe_request.info.info1;
228 pipe_reply.level = 1;
229 pipe_reply.status = make_server_info_netlogon_validation(pipe_conn,
230 "TODO",
231 3, &val,
232 &server_info);
233 if (!NT_STATUS_IS_OK(pipe_reply.status)) {
234 DEBUG(2, ("make_server_info_netlogon_validation returned "
235 "%s\n", nt_errstr(pipe_reply.status)));
236 goto reply;
239 /* setup the session_info on the connection */
240 pipe_reply.status = auth_generate_session_info(conn,
241 conn->event.ctx,
242 conn->lp_ctx,
243 server_info,
244 &conn->session_info);
245 if (!NT_STATUS_IS_OK(pipe_reply.status)) {
246 DEBUG(2, ("auth_generate_session_info failed: %s\n",
247 nt_errstr(pipe_reply.status)));
248 goto reply;
251 break;
252 case 2:
253 pipe_reply.level = 2;
254 pipe_reply.info.info2.file_type = FILE_TYPE_MESSAGE_MODE_PIPE;
255 pipe_reply.info.info2.device_state = 0xff | 0x0400 | 0x0100;
256 pipe_reply.info.info2.allocation_size = 4096;
258 if (pipe_request.info.info2.sam_info3 == NULL) {
260 * anon connection, we don't create a session info
261 * and leave it NULL
263 pipe_reply.status = NT_STATUS_OK;
264 break;
267 val.sam3 = pipe_request.info.info2.sam_info3;
269 pipe_reply.status = make_server_info_netlogon_validation(pipe_conn,
270 val.sam3->base.account_name.string,
271 3, &val, &server_info);
272 if (!NT_STATUS_IS_OK(pipe_reply.status)) {
273 DEBUG(2, ("make_server_info_netlogon_validation returned "
274 "%s\n", nt_errstr(pipe_reply.status)));
275 goto reply;
278 /* setup the session_info on the connection */
279 pipe_reply.status = auth_generate_session_info(conn,
280 conn->event.ctx,
281 conn->lp_ctx,
282 server_info,
283 &conn->session_info);
284 if (!NT_STATUS_IS_OK(pipe_reply.status)) {
285 DEBUG(2, ("auth_generate_session_info failed: %s\n",
286 nt_errstr(pipe_reply.status)));
287 goto reply;
290 conn->session_info->session_key = data_blob_const(pipe_request.info.info2.session_key,
291 pipe_request.info.info2.session_key_length);
292 talloc_steal(conn->session_info, pipe_request.info.info2.session_key);
294 break;
295 case 3:
296 pipe_reply.level = 3;
297 pipe_reply.info.info3.file_type = FILE_TYPE_MESSAGE_MODE_PIPE;
298 pipe_reply.info.info3.device_state = 0xff | 0x0400 | 0x0100;
299 pipe_reply.info.info3.allocation_size = 4096;
301 if (pipe_request.info.info3.sam_info3 == NULL) {
303 * anon connection, we don't create a session info
304 * and leave it NULL
306 pipe_reply.status = NT_STATUS_OK;
307 break;
310 val.sam3 = pipe_request.info.info3.sam_info3;
312 pipe_reply.status = make_server_info_netlogon_validation(pipe_conn,
313 val.sam3->base.account_name.string,
314 3, &val, &server_info);
315 if (!NT_STATUS_IS_OK(pipe_reply.status)) {
316 DEBUG(2, ("make_server_info_netlogon_validation returned "
317 "%s\n", nt_errstr(pipe_reply.status)));
318 goto reply;
321 /* setup the session_info on the connection */
322 pipe_reply.status = auth_generate_session_info(conn,
323 conn->event.ctx,
324 conn->lp_ctx,
325 server_info,
326 &conn->session_info);
327 if (!NT_STATUS_IS_OK(pipe_reply.status)) {
328 DEBUG(2, ("auth_generate_session_info failed: %s\n",
329 nt_errstr(pipe_reply.status)));
330 goto reply;
333 if (pipe_request.info.info3.gssapi_delegated_creds_length) {
334 OM_uint32 minor_status;
335 gss_buffer_desc cred_token;
336 gss_cred_id_t cred_handle;
337 int ret;
339 DEBUG(10, ("named_pipe_auth: delegated credentials supplied by client\n"));
341 cred_token.value = pipe_request.info.info3.gssapi_delegated_creds;
342 cred_token.length = pipe_request.info.info3.gssapi_delegated_creds_length;
344 ret = gss_import_cred(&minor_status,
345 &cred_token,
346 &cred_handle);
347 if (ret != GSS_S_COMPLETE) {
348 pipe_reply.status = NT_STATUS_INTERNAL_ERROR;
349 goto reply;
352 conn->session_info->credentials = cli_credentials_init(conn->session_info);
353 if (conn->session_info->credentials == NULL) {
354 pipe_reply.status = NT_STATUS_NO_MEMORY;
355 goto reply;
358 cli_credentials_set_conf(conn->session_info->credentials,
359 conn->lp_ctx);
360 /* Just so we don't segfault trying to get at a username */
361 cli_credentials_set_anonymous(conn->session_info->credentials);
363 ret = cli_credentials_set_client_gss_creds(conn->session_info->credentials,
364 conn->event.ctx,
365 conn->lp_ctx,
366 cred_handle,
367 CRED_SPECIFIED);
368 if (ret) {
369 pipe_reply.status = NT_STATUS_INTERNAL_ERROR;
370 goto reply;
373 /* This credential handle isn't useful for password authentication, so ensure nobody tries to do that */
374 cli_credentials_set_kerberos_state(conn->session_info->credentials,
375 CRED_MUST_USE_KERBEROS);
378 conn->session_info->session_key = data_blob_const(pipe_request.info.info3.session_key,
379 pipe_request.info.info3.session_key_length);
380 talloc_steal(conn->session_info, pipe_request.info.info3.session_key);
382 break;
383 default:
384 DEBUG(0, ("named_pipe_auth_req: unknown level %u\n",
385 pipe_request.level));
386 pipe_reply.level = 0;
387 pipe_reply.status = NT_STATUS_INVALID_LEVEL;
388 goto reply;
391 reply:
392 /* create the output */
393 ndr_err = ndr_push_struct_blob(&call->out, pipe_conn,
394 lp_iconv_convenience(conn->lp_ctx),
395 &pipe_reply,
396 (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_rep);
397 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
398 const char *reason;
399 status = ndr_map_error2ntstatus(ndr_err);
401 reason = talloc_asprintf(pipe_conn, "named_pipe_auth_request: could not marshall named_pipe_auth_rep: %s\n",
402 nt_errstr(status));
403 if (reason == NULL) {
404 reason = "named_pipe_auth_request: could not marshall named_pipe_auth_rep";
406 named_pipe_terminate_connection(pipe_conn, reason);
407 return;
410 DEBUG(10,("named_pipe_auth_request: named_pipe_auth reply[%u]\n",
411 (unsigned) call->out.length));
412 dump_data(11, call->out.data, call->out.length);
413 if (DEBUGLVL(10)) {
414 NDR_PRINT_DEBUG(named_pipe_auth_rep, &pipe_reply);
417 call->status = pipe_reply.status;
419 call->out_iov[0].iov_base = call->out.data;
420 call->out_iov[0].iov_len = call->out.length;
422 subreq = tstream_writev_send(call,
423 pipe_conn->connection->event.ctx,
424 pipe_conn->tstream,
425 call->out_iov, 1);
426 if (subreq == NULL) {
427 named_pipe_terminate_connection(pipe_conn, "named_pipe_auth_request: "
428 "no memory for tstream_writev_send");
429 return;
432 tevent_req_set_callback(subreq, named_pipe_handover_connection, call);
435 static void named_pipe_handover_connection(struct tevent_req *subreq)
437 struct named_pipe_call *call = tevent_req_callback_data(subreq,
438 struct named_pipe_call);
439 struct named_pipe_connection *pipe_conn = call->pipe_conn;
440 struct stream_connection *conn = pipe_conn->connection;
441 int sys_errno;
442 int rc;
444 rc = tstream_writev_recv(subreq, &sys_errno);
445 TALLOC_FREE(subreq);
446 if (rc == -1) {
447 const char *reason;
449 reason = talloc_asprintf(call, "named_pipe_handover_connection: "
450 "tstream_writev_recv() - %d:%s",
451 sys_errno, strerror(sys_errno));
452 if (reason == NULL) {
453 reason = "named_pipe_handover_connection: "
454 "tstream_writev_recv() failed";
457 named_pipe_terminate_connection(pipe_conn, reason);
458 return;
461 if (!NT_STATUS_IS_OK(call->status)) {
462 named_pipe_terminate_connection(pipe_conn,
463 nt_errstr(call->status));
464 return;
468 * remove the named_pipe layer together with its packet layer
470 conn->ops = pipe_conn->pipe_sock->ops;
471 conn->private_data = pipe_conn->pipe_sock->private_data;
472 talloc_unlink(conn, pipe_conn);
475 * hand over to the real pipe implementation,
476 * now that we have setup the transport session_info
478 conn->ops->accept_connection(conn);
480 DEBUG(10,("named_pipe_handover_connection[%s]: succeeded\n",
481 conn->ops->name));
483 /* we don't have to free call here as the connection got closed */
487 called when a pipe socket becomes readable
489 static void named_pipe_recv(struct stream_connection *conn, uint16_t flags)
491 struct named_pipe_connection *pipe_conn = talloc_get_type(
492 conn->private_data, struct named_pipe_connection);
494 named_pipe_terminate_connection(pipe_conn,
495 "named_pipe_recv: called");
499 called when a pipe socket becomes writable
501 static void named_pipe_send(struct stream_connection *conn, uint16_t flags)
503 struct named_pipe_connection *pipe_conn = talloc_get_type(
504 conn->private_data, struct named_pipe_connection);
506 named_pipe_terminate_connection(pipe_conn,
507 "named_pipe_send: called");
510 static const struct stream_server_ops named_pipe_stream_ops = {
511 .name = "named_pipe",
512 .accept_connection = named_pipe_accept,
513 .recv_handler = named_pipe_recv,
514 .send_handler = named_pipe_send,
517 NTSTATUS stream_setup_named_pipe(struct tevent_context *event_context,
518 struct loadparm_context *lp_ctx,
519 const struct model_ops *model_ops,
520 const struct stream_server_ops *stream_ops,
521 const char *pipe_name,
522 void *private_data)
524 char *dirname;
525 struct named_pipe_socket *pipe_sock;
526 NTSTATUS status = NT_STATUS_NO_MEMORY;;
528 pipe_sock = talloc(event_context, struct named_pipe_socket);
529 if (pipe_sock == NULL) {
530 goto fail;
533 /* remember the details about the pipe */
534 pipe_sock->pipe_name = talloc_strdup(pipe_sock, pipe_name);
535 if (pipe_sock->pipe_name == NULL) {
536 goto fail;
539 dirname = talloc_asprintf(pipe_sock, "%s/np", lp_ncalrpc_dir(lp_ctx));
540 if (dirname == NULL) {
541 goto fail;
544 if (!directory_create_or_exist(dirname, geteuid(), 0700)) {
545 status = map_nt_error_from_unix(errno);
546 DEBUG(0,(__location__ ": Failed to create stream pipe directory %s - %s\n",
547 dirname, nt_errstr(status)));
548 goto fail;
551 if (strncmp(pipe_name, "\\pipe\\", 6) == 0) {
552 pipe_name += 6;
555 pipe_sock->pipe_path = talloc_asprintf(pipe_sock, "%s/%s", dirname,
556 pipe_name);
557 if (pipe_sock->pipe_path == NULL) {
558 goto fail;
561 talloc_free(dirname);
563 pipe_sock->ops = stream_ops;
564 pipe_sock->private_data = talloc_reference(pipe_sock, private_data);
566 status = stream_setup_socket(event_context,
567 lp_ctx,
568 model_ops,
569 &named_pipe_stream_ops,
570 "unix",
571 pipe_sock->pipe_path,
572 NULL,
573 NULL,
574 pipe_sock);
575 if (!NT_STATUS_IS_OK(status)) {
576 goto fail;
578 return NT_STATUS_OK;
580 fail:
581 talloc_free(pipe_sock);
582 return status;