s3:rpcclient: we also need some ndr_pull functions
[Samba/ita.git] / source4 / smbd / service_named_pipe.c
blob84b490ac2d25cc683811adb0d0dc70d3a574880f
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"
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;
45 void *private_data;
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;
53 int fd;
54 struct tevent_req *subreq;
55 int ret;
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);
65 if (ret != 0) {
66 stream_terminate_connection(conn,
67 "named_pipe_accept: out of memory");
68 return;
71 subreq = tstream_npa_accept_existing_send(conn, conn->event.ctx,
72 plain_tstream,
73 FILE_TYPE_MESSAGE_MODE_PIPE,
74 0xff | 0x0400 | 0x0100,
75 4096);
76 if (subreq == NULL) {
77 stream_terminate_connection(conn,
78 "named_pipe_accept: "
79 "no memory for tstream_npa_accept_existing_send");
80 return;
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;
93 char *client_name;
94 struct tsocket_address *server;
95 char *server_name;
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;
106 TALLOC_CTX *tmp_ctx;
107 NTSTATUS status;
108 int error;
109 int ret;
111 tmp_ctx = talloc_new(conn);
112 if (!tmp_ctx) {
113 reason = "Out of memory!\n";
114 goto out;
117 ret = tstream_npa_accept_existing_recv(subreq, &error, tmp_ctx,
118 &conn->tstream,
119 &client,
120 &client_name,
121 &server,
122 &server_name,
123 &info3,
124 &session_key,
125 &delegated_creds);
126 TALLOC_FREE(subreq);
127 if (ret != 0) {
128 reason = talloc_asprintf(conn,
129 "tstream_npa_accept_existing_recv()"
130 " failed: %s", strerror(error));
131 goto out;
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)));
140 if (info3) {
141 val.sam3 = info3;
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));
150 goto out;
153 status = auth_context_create(conn, conn->event.ctx,
154 conn->msg_ctx, conn->lp_ctx,
155 &auth_context);
156 if (!NT_STATUS_IS_OK(status)) {
157 reason = talloc_asprintf(conn,
158 "auth_context_create returned: %s",
159 nt_errstr(status));
160 goto out;
163 anonymous_sid = dom_sid_parse_talloc(auth_context,
164 SID_NT_ANONYMOUS);
165 if (anonymous_sid == NULL) {
166 talloc_free(auth_context);
167 reason = "Failed to parse Anonymous SID ";
168 goto out;
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,
179 auth_context,
180 server_info,
181 session_flags,
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));
188 goto out;
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,
210 &cred_token,
211 &cred_handle);
212 if (ret != GSS_S_COMPLETE) {
213 reason = "Internal error in gss_import_cred()";
214 goto out;
217 creds = cli_credentials_init(conn->session_info);
218 if (!creds) {
219 reason = "Out of memory in cli_credentials_init()";
220 goto out;
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,
229 conn->event.ctx,
230 conn->lp_ctx,
231 cred_handle,
232 CRED_SPECIFIED,
233 &error_string);
234 if (ret) {
235 reason = talloc_asprintf(conn,
236 "Failed to set pipe forwarded"
237 "creds: %s\n", error_string);
238 goto out;
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",
257 conn->ops->name));
259 talloc_free(tmp_ctx);
260 return;
262 out:
263 talloc_free(tmp_ctx);
264 if (!reason) {
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,
298 void *private_data)
300 char *dirname;
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) {
306 goto fail;
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) {
312 goto fail;
315 dirname = talloc_asprintf(pipe_sock, "%s/np", lpcfg_ncalrpc_dir(lp_ctx));
316 if (dirname == NULL) {
317 goto fail;
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)));
324 goto fail;
327 if (strncmp(pipe_name, "\\pipe\\", 6) == 0) {
328 pipe_name += 6;
331 pipe_sock->pipe_path = talloc_asprintf(pipe_sock, "%s/%s", dirname,
332 pipe_name);
333 if (pipe_sock->pipe_path == NULL) {
334 goto fail;
337 talloc_free(dirname);
339 pipe_sock->ops = stream_ops;
340 pipe_sock->private_data = private_data;
342 status = stream_setup_socket(event_context,
343 lp_ctx,
344 model_ops,
345 &named_pipe_stream_ops,
346 "unix",
347 pipe_sock->pipe_path,
348 NULL,
349 NULL,
350 pipe_sock);
351 if (!NT_STATUS_IS_OK(status)) {
352 goto fail;
354 return NT_STATUS_OK;
356 fail:
357 talloc_free(pipe_sock);
358 return status;