s4-loadparm: 2nd half of lp_ to lpcfg_ conversion
[gd/samba-autobuild/.git] / source4 / smbd / service_named_pipe.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    helper functions for NAMED PIPE servers
5
6    Copyright (C) Stefan (metze) Metzmacher      2008
7
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.
12
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.
17
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/>.
20 */
21
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"
40
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;
46 };
47
48 static void named_pipe_accept_done(struct tevent_req *subreq);
49
50 static void named_pipe_accept(struct stream_connection *conn)
51 {
52         struct tstream_context *plain_tstream;
53         int fd;
54         struct tevent_req *subreq;
55         int ret;
56
57         /* Let tstream take over fd operations */
58
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);
63
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;
69         }
70
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;
81         }
82         tevent_req_set_callback(subreq, named_pipe_accept_done, conn);
83 }
84
85 static void named_pipe_accept_done(struct tevent_req *subreq)
86 {
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;
99
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;
110
111         tmp_ctx = talloc_new(conn);
112         if (!tmp_ctx) {
113                 reason = "Out of memory!\n";
114                 goto out;
115         }
116
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;
132         }
133
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)));
139
140         if (info3) {
141                 val.sam3 = info3;
142
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;
151                 }
152
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;
161                 }
162
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;
169                 }
170
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;
174                 }
175
176
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;
189                 }
190         }
191
192         if (session_key.length) {
193                 conn->session_info->session_key = session_key;
194                 talloc_steal(conn->session_info, session_key.data);
195         }
196
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;
203
204                 DEBUG(10, ("Delegated credentials supplied by client\n"));
205
206                 cred_token.value = delegated_creds.data;
207                 cred_token.length = delegated_creds.length;
208
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;
215                 }
216
217                 creds = cli_credentials_init(conn->session_info);
218                 if (!creds) {
219                         reason = "Out of memory in cli_credentials_init()";
220                         goto out;
221                 }
222                 conn->session_info->credentials = creds;
223
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);
227
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;
239                 }
240
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);
245
246         }
247
248         /*
249          * hand over to the real pipe implementation,
250          * now that we have setup the transport session_info
251          */
252         conn->ops = pipe_sock->ops;
253         conn->private_data = pipe_sock->private_data;
254         conn->ops->accept_connection(conn);
255
256         DEBUG(10, ("named pipe connection [%s] established\n",
257                    conn->ops->name));
258
259         talloc_free(tmp_ctx);
260         return;
261
262 out:
263         talloc_free(tmp_ctx);
264         if (!reason) {
265                 reason = "Internal error";
266         }
267         stream_terminate_connection(conn, reason);
268 }
269
270 /*
271   called when a pipe socket becomes readable
272 */
273 static void named_pipe_recv(struct stream_connection *conn, uint16_t flags)
274 {
275         stream_terminate_connection(conn, "named_pipe_recv: called");
276 }
277
278 /*
279   called when a pipe socket becomes writable
280 */
281 static void named_pipe_send(struct stream_connection *conn, uint16_t flags)
282 {
283         stream_terminate_connection(conn, "named_pipe_send: called");
284 }
285
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,
291 };
292
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)
299 {
300         char *dirname;
301         struct named_pipe_socket *pipe_sock;
302         NTSTATUS status = NT_STATUS_NO_MEMORY;;
303
304         pipe_sock = talloc(event_context, struct named_pipe_socket);
305         if (pipe_sock == NULL) {
306                 goto fail;
307         }
308
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;
313         }
314
315         dirname = talloc_asprintf(pipe_sock, "%s/np", lpcfg_ncalrpc_dir(lp_ctx));
316         if (dirname == NULL) {
317                 goto fail;
318         }
319
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;
325         }
326
327         if (strncmp(pipe_name, "\\pipe\\", 6) == 0) {
328                 pipe_name += 6;
329         }
330
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;
335         }
336
337         talloc_free(dirname);
338
339         pipe_sock->ops = stream_ops;
340         pipe_sock->private_data = private_data;
341
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;
353         }
354         return NT_STATUS_OK;
355
356  fail:
357         talloc_free(pipe_sock);
358         return status;
359 }