c7e31bc47186f5ba272c77bc2d5bf0da5fd6abaf
[bbaumbach/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/session.h"
37 #include "libcli/security/security.h"
38 #include "libcli/named_pipe_auth/npa_tstream.h"
39
40 struct named_pipe_socket {
41         const char *pipe_name;
42         const char *pipe_path;
43         const struct stream_server_ops *ops;
44         void *private_data;
45 };
46
47 static void named_pipe_accept_done(struct tevent_req *subreq);
48
49 static void named_pipe_accept(struct stream_connection *conn)
50 {
51         struct tstream_context *plain_tstream;
52         int fd;
53         struct tevent_req *subreq;
54         int ret;
55
56         /* Let tstream take over fd operations */
57
58         fd = socket_get_fd(conn->socket);
59         socket_set_flags(conn->socket, SOCKET_FLAG_NOCLOSE);
60         TALLOC_FREE(conn->event.fde);
61         TALLOC_FREE(conn->socket);
62
63         ret = tstream_bsd_existing_socket(conn, fd, &plain_tstream);
64         if (ret != 0) {
65                 stream_terminate_connection(conn,
66                                 "named_pipe_accept: out of memory");
67                 return;
68         }
69
70         subreq = tstream_npa_accept_existing_send(conn, conn->event.ctx,
71                                                   plain_tstream,
72                                                   FILE_TYPE_MESSAGE_MODE_PIPE,
73                                                   0xff | 0x0400 | 0x0100,
74                                                   4096);
75         if (subreq == NULL) {
76                 stream_terminate_connection(conn,
77                         "named_pipe_accept: "
78                         "no memory for tstream_npa_accept_existing_send");
79                 return;
80         }
81         tevent_req_set_callback(subreq, named_pipe_accept_done, conn);
82 }
83
84 static void named_pipe_accept_done(struct tevent_req *subreq)
85 {
86         struct stream_connection *conn = tevent_req_callback_data(subreq,
87                                                 struct stream_connection);
88         struct named_pipe_socket *pipe_sock =
89                                 talloc_get_type(conn->private_data,
90                                                 struct named_pipe_socket);
91         struct tsocket_address *remote_client_addr;
92         char *remote_client_name;
93         struct tsocket_address *local_server_addr;
94         char *local_server_name;
95         struct auth_session_info_transport *session_info_transport;
96         const char *reason = NULL;
97         TALLOC_CTX *tmp_ctx;
98         int error;
99         int ret;
100
101         tmp_ctx = talloc_new(conn);
102         if (!tmp_ctx) {
103                 reason = "Out of memory!\n";
104                 goto out;
105         }
106
107         ret = tstream_npa_accept_existing_recv(subreq, &error, tmp_ctx,
108                                                &conn->tstream,
109                                                &remote_client_addr,
110                                                &remote_client_name,
111                                                &local_server_addr,
112                                                &local_server_name,
113                                                &session_info_transport);
114         TALLOC_FREE(subreq);
115         if (ret != 0) {
116                 reason = talloc_asprintf(conn,
117                                          "tstream_npa_accept_existing_recv()"
118                                          " failed: %s", strerror(error));
119                 goto out;
120         }
121
122         conn->local_address = talloc_move(conn, &local_server_addr);
123         conn->remote_address = talloc_move(conn, &remote_client_addr);
124
125         DEBUG(10, ("Accepted npa connection from %s. "
126                    "Client: %s (%s). Server: %s (%s)\n",
127                    tsocket_address_string(conn->remote_address, tmp_ctx),
128                    local_server_name,
129                    tsocket_address_string(local_server_addr, tmp_ctx),
130                    remote_client_name,
131                    tsocket_address_string(remote_client_addr, tmp_ctx)));
132
133         conn->session_info = auth_session_info_from_transport(conn, session_info_transport,
134                                                               conn->lp_ctx,
135                                                               &reason);
136         if (!conn->session_info) {
137                 goto out;
138         }
139
140         /*
141          * hand over to the real pipe implementation,
142          * now that we have setup the transport session_info
143          */
144         conn->ops = pipe_sock->ops;
145         conn->private_data = pipe_sock->private_data;
146         conn->ops->accept_connection(conn);
147
148         DEBUG(10, ("named pipe connection [%s] established\n",
149                    conn->ops->name));
150
151         talloc_free(tmp_ctx);
152         return;
153
154 out:
155         talloc_free(tmp_ctx);
156         if (!reason) {
157                 reason = "Internal error";
158         }
159         stream_terminate_connection(conn, reason);
160 }
161
162 /*
163   called when a pipe socket becomes readable
164 */
165 static void named_pipe_recv(struct stream_connection *conn, uint16_t flags)
166 {
167         stream_terminate_connection(conn, "named_pipe_recv: called");
168 }
169
170 /*
171   called when a pipe socket becomes writable
172 */
173 static void named_pipe_send(struct stream_connection *conn, uint16_t flags)
174 {
175         stream_terminate_connection(conn, "named_pipe_send: called");
176 }
177
178 static const struct stream_server_ops named_pipe_stream_ops = {
179         .name                   = "named_pipe",
180         .accept_connection      = named_pipe_accept,
181         .recv_handler           = named_pipe_recv,
182         .send_handler           = named_pipe_send,
183 };
184
185 NTSTATUS tstream_setup_named_pipe(TALLOC_CTX *mem_ctx,
186                                   struct tevent_context *event_context,
187                                   struct loadparm_context *lp_ctx,
188                                   const struct model_ops *model_ops,
189                                   const struct stream_server_ops *stream_ops,
190                                   const char *pipe_name,
191                                   void *private_data)
192 {
193         char *dirname;
194         struct named_pipe_socket *pipe_sock;
195         NTSTATUS status = NT_STATUS_NO_MEMORY;;
196
197         pipe_sock = talloc(mem_ctx, struct named_pipe_socket);
198         if (pipe_sock == NULL) {
199                 goto fail;
200         }
201
202         /* remember the details about the pipe */
203         pipe_sock->pipe_name    = strlower_talloc(pipe_sock, pipe_name);
204         if (pipe_sock->pipe_name == NULL) {
205                 goto fail;
206         }
207
208         if (!directory_create_or_exist(lpcfg_ncalrpc_dir(lp_ctx), 0755)) {
209                 status = map_nt_error_from_unix_common(errno);
210                 DEBUG(0,(__location__ ": Failed to create ncalrpc pipe directory '%s' - %s\n",
211                          lpcfg_ncalrpc_dir(lp_ctx), nt_errstr(status)));
212                 goto fail;
213         }
214
215         dirname = talloc_asprintf(pipe_sock, "%s/np", lpcfg_ncalrpc_dir(lp_ctx));
216         if (dirname == NULL) {
217                 goto fail;
218         }
219
220         if (!directory_create_or_exist_strict(dirname, geteuid(), 0700)) {
221                 status = map_nt_error_from_unix_common(errno);
222                 DEBUG(0,(__location__ ": Failed to create stream pipe directory '%s' - %s\n",
223                          dirname, nt_errstr(status)));
224                 goto fail;
225         }
226
227         if (strncmp(pipe_name, "\\pipe\\", 6) == 0) {
228                 pipe_name += 6;
229         }
230
231         pipe_sock->pipe_path = talloc_asprintf(pipe_sock, "%s/%s", dirname,
232                                                pipe_name);
233         if (pipe_sock->pipe_path == NULL) {
234                 goto fail;
235         }
236
237         talloc_free(dirname);
238
239         pipe_sock->ops = stream_ops;
240         pipe_sock->private_data = private_data;
241
242         status = stream_setup_socket(pipe_sock,
243                                      event_context,
244                                      lp_ctx,
245                                      model_ops,
246                                      &named_pipe_stream_ops,
247                                      "unix",
248                                      pipe_sock->pipe_path,
249                                      NULL,
250                                      NULL,
251                                      pipe_sock);
252         if (!NT_STATUS_IS_OK(status)) {
253                 goto fail;
254         }
255         return NT_STATUS_OK;
256
257  fail:
258         talloc_free(pipe_sock);
259         return status;
260 }