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/>.
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"
38 #include "libcli/security/dom_sid.h"
39 #include "libcli/named_pipe_auth/npa_tstream.h"
41 struct named_pipe_socket
{
42 const char *pipe_name
;
43 const char *pipe_path
;
44 const struct stream_server_ops
*ops
;
48 static void named_pipe_accept_done(struct tevent_req
*subreq
);
50 static void named_pipe_accept(struct stream_connection
*conn
)
52 struct tstream_context
*plain_tstream
;
54 struct tevent_req
*subreq
;
57 /* Let tstream take over fd operations */
59 fd
= socket_get_fd(conn
->socket
);
60 socket_set_flags(conn
->socket
, SOCKET_FLAG_NOCLOSE
);
61 TALLOC_FREE(conn
->event
.fde
);
62 TALLOC_FREE(conn
->socket
);
64 ret
= tstream_bsd_existing_socket(conn
, fd
, &plain_tstream
);
66 stream_terminate_connection(conn
,
67 "named_pipe_accept: out of memory");
71 subreq
= tstream_npa_accept_existing_send(conn
, conn
->event
.ctx
,
73 FILE_TYPE_MESSAGE_MODE_PIPE
,
74 0xff | 0x0400 | 0x0100,
77 stream_terminate_connection(conn
,
79 "no memory for tstream_npa_accept_existing_send");
82 tevent_req_set_callback(subreq
, named_pipe_accept_done
, conn
);
85 static void named_pipe_accept_done(struct tevent_req
*subreq
)
87 struct stream_connection
*conn
= tevent_req_callback_data(subreq
,
88 struct stream_connection
);
89 struct named_pipe_socket
*pipe_sock
=
90 talloc_get_type(conn
->private_data
,
91 struct named_pipe_socket
);
92 struct tsocket_address
*client
;
94 struct tsocket_address
*server
;
96 struct netr_SamInfo3
*info3
;
97 DATA_BLOB session_key
;
98 DATA_BLOB delegated_creds
;
100 union netr_Validation val
;
101 struct auth_serversupplied_info
*server_info
;
102 struct auth_context
*auth_context
;
103 uint32_t session_flags
= 0;
104 struct dom_sid
*anonymous_sid
;
105 const char *reason
= NULL
;
111 tmp_ctx
= talloc_new(conn
);
113 reason
= "Out of memory!\n";
117 ret
= tstream_npa_accept_existing_recv(subreq
, &error
, tmp_ctx
,
128 reason
= talloc_asprintf(conn
,
129 "tstream_npa_accept_existing_recv()"
130 " failed: %s", strerror(error
));
134 DEBUG(10, ("Accepted npa connection from %s. "
135 "Client: %s (%s). Server: %s (%s)\n",
136 tsocket_address_string(conn
->remote_address
, tmp_ctx
),
137 client_name
, tsocket_address_string(client
, tmp_ctx
),
138 server_name
, tsocket_address_string(server
, tmp_ctx
)));
143 status
= make_server_info_netlogon_validation(conn
,
144 val
.sam3
->base
.account_name
.string
,
145 3, &val
, &server_info
);
146 if (!NT_STATUS_IS_OK(status
)) {
147 reason
= talloc_asprintf(conn
,
148 "make_server_info_netlogon_validation "
149 "returned: %s", nt_errstr(status
));
153 status
= auth_context_create(conn
, conn
->event
.ctx
,
154 conn
->msg_ctx
, conn
->lp_ctx
,
156 if (!NT_STATUS_IS_OK(status
)) {
157 reason
= talloc_asprintf(conn
,
158 "auth_context_create returned: %s",
163 anonymous_sid
= dom_sid_parse_talloc(auth_context
,
165 if (anonymous_sid
== NULL
) {
166 talloc_free(auth_context
);
167 reason
= "Failed to parse Anonymous SID ";
171 session_flags
= AUTH_SESSION_INFO_DEFAULT_GROUPS
;
172 if (!dom_sid_equal(anonymous_sid
, server_info
->account_sid
)) {
173 session_flags
|= AUTH_SESSION_INFO_AUTHENTICATED
;
177 /* setup the session_info on the connection */
178 status
= auth_context
->generate_session_info(conn
,
182 &conn
->session_info
);
183 talloc_free(auth_context
);
184 if (!NT_STATUS_IS_OK(status
)) {
185 reason
= talloc_asprintf(conn
,
186 "auth_generate_session_info "
187 "returned: %s", nt_errstr(status
));
192 if (session_key
.length
) {
193 conn
->session_info
->session_key
= session_key
;
194 talloc_steal(conn
->session_info
, session_key
.data
);
197 if (delegated_creds
.length
) {
198 struct cli_credentials
*creds
;
199 OM_uint32 minor_status
;
200 gss_buffer_desc cred_token
;
201 gss_cred_id_t cred_handle
;
202 const char *error_string
;
204 DEBUG(10, ("Delegated credentials supplied by client\n"));
206 cred_token
.value
= delegated_creds
.data
;
207 cred_token
.length
= delegated_creds
.length
;
209 ret
= gss_import_cred(&minor_status
,
212 if (ret
!= GSS_S_COMPLETE
) {
213 reason
= "Internal error in gss_import_cred()";
217 creds
= cli_credentials_init(conn
->session_info
);
219 reason
= "Out of memory in cli_credentials_init()";
222 conn
->session_info
->credentials
= creds
;
224 cli_credentials_set_conf(creds
, conn
->lp_ctx
);
225 /* Just so we don't segfault trying to get at a username */
226 cli_credentials_set_anonymous(creds
);
228 ret
= cli_credentials_set_client_gss_creds(creds
,
235 reason
= talloc_asprintf(conn
,
236 "Failed to set pipe forwarded"
237 "creds: %s\n", error_string
);
241 /* This credential handle isn't useful for password
242 * authentication, so ensure nobody tries to do that */
243 cli_credentials_set_kerberos_state(creds
,
244 CRED_MUST_USE_KERBEROS
);
249 * hand over to the real pipe implementation,
250 * now that we have setup the transport session_info
252 conn
->ops
= pipe_sock
->ops
;
253 conn
->private_data
= pipe_sock
->private_data
;
254 conn
->ops
->accept_connection(conn
);
256 DEBUG(10, ("named pipe connection [%s] established\n",
259 talloc_free(tmp_ctx
);
263 talloc_free(tmp_ctx
);
265 reason
= "Internal error";
267 stream_terminate_connection(conn
, reason
);
271 called when a pipe socket becomes readable
273 static void named_pipe_recv(struct stream_connection
*conn
, uint16_t flags
)
275 stream_terminate_connection(conn
, "named_pipe_recv: called");
279 called when a pipe socket becomes writable
281 static void named_pipe_send(struct stream_connection
*conn
, uint16_t flags
)
283 stream_terminate_connection(conn
, "named_pipe_send: called");
286 static const struct stream_server_ops named_pipe_stream_ops
= {
287 .name
= "named_pipe",
288 .accept_connection
= named_pipe_accept
,
289 .recv_handler
= named_pipe_recv
,
290 .send_handler
= named_pipe_send
,
293 NTSTATUS
tstream_setup_named_pipe(struct tevent_context
*event_context
,
294 struct loadparm_context
*lp_ctx
,
295 const struct model_ops
*model_ops
,
296 const struct stream_server_ops
*stream_ops
,
297 const char *pipe_name
,
301 struct named_pipe_socket
*pipe_sock
;
302 NTSTATUS status
= NT_STATUS_NO_MEMORY
;;
304 pipe_sock
= talloc(event_context
, struct named_pipe_socket
);
305 if (pipe_sock
== NULL
) {
309 /* remember the details about the pipe */
310 pipe_sock
->pipe_name
= talloc_strdup(pipe_sock
, pipe_name
);
311 if (pipe_sock
->pipe_name
== NULL
) {
315 dirname
= talloc_asprintf(pipe_sock
, "%s/np", lpcfg_ncalrpc_dir(lp_ctx
));
316 if (dirname
== NULL
) {
320 if (!directory_create_or_exist(dirname
, geteuid(), 0700)) {
321 status
= map_nt_error_from_unix(errno
);
322 DEBUG(0,(__location__
": Failed to create stream pipe directory %s - %s\n",
323 dirname
, nt_errstr(status
)));
327 if (strncmp(pipe_name
, "\\pipe\\", 6) == 0) {
331 pipe_sock
->pipe_path
= talloc_asprintf(pipe_sock
, "%s/%s", dirname
,
333 if (pipe_sock
->pipe_path
== NULL
) {
337 talloc_free(dirname
);
339 pipe_sock
->ops
= stream_ops
;
340 pipe_sock
->private_data
= private_data
;
342 status
= stream_setup_socket(event_context
,
345 &named_pipe_stream_ops
,
347 pipe_sock
->pipe_path
,
351 if (!NT_STATUS_IS_OK(status
)) {
357 talloc_free(pipe_sock
);