Line data Source code
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 "samba/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 7813 : static void named_pipe_accept(struct stream_connection *conn)
50 : {
51 628 : struct tstream_context *plain_tstream;
52 628 : int fd;
53 628 : struct tevent_req *subreq;
54 628 : int ret;
55 :
56 : /* Let tstream take over fd operations */
57 :
58 7813 : fd = socket_get_fd(conn->socket);
59 7813 : socket_set_flags(conn->socket, SOCKET_FLAG_NOCLOSE);
60 7813 : TALLOC_FREE(conn->event.fde);
61 7813 : TALLOC_FREE(conn->socket);
62 :
63 7813 : ret = tstream_bsd_existing_socket(conn, fd, &plain_tstream);
64 7813 : if (ret != 0) {
65 0 : stream_terminate_connection(conn,
66 : "named_pipe_accept: out of memory");
67 0 : return;
68 : }
69 : /* as server we want to fail early */
70 7813 : tstream_bsd_fail_readv_first_error(plain_tstream, true);
71 :
72 7813 : subreq = tstream_npa_accept_existing_send(conn, conn->event.ctx,
73 : plain_tstream,
74 : FILE_TYPE_MESSAGE_MODE_PIPE,
75 : 0xff | 0x0400 | 0x0100,
76 : 4096);
77 7813 : if (subreq == NULL) {
78 0 : stream_terminate_connection(conn,
79 : "named_pipe_accept: "
80 : "no memory for tstream_npa_accept_existing_send");
81 0 : return;
82 : }
83 7813 : tevent_req_set_callback(subreq, named_pipe_accept_done, conn);
84 : }
85 :
86 7813 : static void named_pipe_accept_done(struct tevent_req *subreq)
87 : {
88 7813 : struct stream_connection *conn = tevent_req_callback_data(subreq,
89 : struct stream_connection);
90 628 : struct named_pipe_socket *pipe_sock =
91 7813 : talloc_get_type(conn->private_data,
92 : struct named_pipe_socket);
93 628 : enum dcerpc_transport_t transport;
94 628 : struct tsocket_address *remote_client_addr;
95 628 : char *remote_client_name;
96 628 : struct tsocket_address *local_server_addr;
97 628 : char *local_server_name;
98 628 : struct auth_session_info_transport *session_info_transport;
99 7813 : const char *reason = NULL;
100 628 : TALLOC_CTX *tmp_ctx;
101 628 : int error;
102 628 : int ret;
103 :
104 7813 : tmp_ctx = talloc_new(conn);
105 7813 : if (!tmp_ctx) {
106 0 : reason = "Out of memory!\n";
107 0 : goto out;
108 : }
109 :
110 7813 : ret = tstream_npa_accept_existing_recv(subreq, &error, tmp_ctx,
111 : &conn->tstream,
112 : NULL,
113 : &transport,
114 : &remote_client_addr,
115 : &remote_client_name,
116 : &local_server_addr,
117 : &local_server_name,
118 : &session_info_transport);
119 7813 : TALLOC_FREE(subreq);
120 7813 : if (ret != 0) {
121 0 : reason = talloc_asprintf(conn,
122 : "tstream_npa_accept_existing_recv()"
123 : " failed: %s", strerror(error));
124 0 : goto out;
125 : }
126 :
127 7813 : conn->local_address = talloc_move(conn, &local_server_addr);
128 7813 : conn->remote_address = talloc_move(conn, &remote_client_addr);
129 :
130 7813 : DBG_DEBUG("Accepted npa connection from %s. "
131 : "Client: %s (%s). Server: %s (%s)\n",
132 : tsocket_address_string(conn->remote_address, tmp_ctx),
133 : local_server_name,
134 : tsocket_address_string(local_server_addr, tmp_ctx),
135 : remote_client_name,
136 : tsocket_address_string(remote_client_addr, tmp_ctx));
137 :
138 7813 : conn->session_info = auth_session_info_from_transport(conn, session_info_transport,
139 : conn->lp_ctx,
140 : &reason);
141 7813 : if (!conn->session_info) {
142 0 : goto out;
143 : }
144 :
145 7813 : if (transport == NCACN_NP) {
146 7104 : if (security_token_is_system(conn->session_info->security_token)) {
147 0 : reason = talloc_asprintf(
148 : conn,
149 : "System token not allowed on transport %d\n",
150 : transport);
151 0 : goto out;
152 : }
153 709 : } else if (transport == NCALRPC) {
154 : /*
155 : * TODO:
156 : * we should somehow remember the given transport on
157 : * the connection, but that's a task for another day
158 : * as it's not trivial to do...
159 : */
160 : } else {
161 0 : reason = talloc_asprintf(
162 : conn,
163 : "Only allow NCACN_NP or NCALRPC transport on named pipes, "
164 : "got %d\n",
165 : (int)transport);
166 0 : goto out;
167 : }
168 :
169 : /*
170 : * hand over to the real pipe implementation,
171 : * now that we have setup the transport session_info
172 : */
173 7813 : conn->ops = pipe_sock->ops;
174 7813 : conn->private_data = pipe_sock->private_data;
175 7813 : conn->ops->accept_connection(conn);
176 :
177 7813 : DBG_DEBUG("named pipe connection [%s] established\n", conn->ops->name);
178 :
179 7813 : talloc_free(tmp_ctx);
180 7813 : return;
181 :
182 0 : out:
183 0 : talloc_free(tmp_ctx);
184 0 : if (!reason) {
185 0 : reason = "Internal error";
186 : }
187 0 : stream_terminate_connection(conn, reason);
188 : }
189 :
190 : /*
191 : called when a pipe socket becomes readable
192 : */
193 0 : static void named_pipe_recv(struct stream_connection *conn, uint16_t flags)
194 : {
195 0 : stream_terminate_connection(conn, "named_pipe_recv: called");
196 0 : }
197 :
198 : /*
199 : called when a pipe socket becomes writable
200 : */
201 0 : static void named_pipe_send(struct stream_connection *conn, uint16_t flags)
202 : {
203 0 : stream_terminate_connection(conn, "named_pipe_send: called");
204 0 : }
205 :
206 : static const struct stream_server_ops named_pipe_stream_ops = {
207 : .name = "named_pipe",
208 : .accept_connection = named_pipe_accept,
209 : .recv_handler = named_pipe_recv,
210 : .send_handler = named_pipe_send,
211 : };
212 :
213 802 : NTSTATUS tstream_setup_named_pipe(TALLOC_CTX *mem_ctx,
214 : struct tevent_context *event_context,
215 : struct loadparm_context *lp_ctx,
216 : const struct model_ops *model_ops,
217 : const struct stream_server_ops *stream_ops,
218 : const char *pipe_name,
219 : void *private_data,
220 : void *process_context)
221 : {
222 22 : char *dirname;
223 22 : struct named_pipe_socket *pipe_sock;
224 802 : NTSTATUS status = NT_STATUS_NO_MEMORY;;
225 :
226 802 : pipe_sock = talloc(mem_ctx, struct named_pipe_socket);
227 802 : if (pipe_sock == NULL) {
228 0 : goto fail;
229 : }
230 :
231 : /* remember the details about the pipe */
232 802 : pipe_sock->pipe_name = strlower_talloc(pipe_sock, pipe_name);
233 802 : if (pipe_sock->pipe_name == NULL) {
234 0 : goto fail;
235 : }
236 :
237 802 : if (!directory_create_or_exist(lpcfg_ncalrpc_dir(lp_ctx), 0755)) {
238 0 : status = map_nt_error_from_unix_common(errno);
239 0 : DBG_ERR("Failed to create ncalrpc pipe directory '%s' - %s\n",
240 : lpcfg_ncalrpc_dir(lp_ctx), nt_errstr(status));
241 0 : goto fail;
242 : }
243 :
244 802 : dirname = talloc_asprintf(pipe_sock, "%s/np", lpcfg_ncalrpc_dir(lp_ctx));
245 802 : if (dirname == NULL) {
246 0 : goto fail;
247 : }
248 :
249 802 : if (!directory_create_or_exist_strict(dirname, geteuid(), 0700)) {
250 0 : status = map_nt_error_from_unix_common(errno);
251 0 : DBG_ERR("Failed to create stream pipe directory '%s' - %s\n",
252 : dirname, nt_errstr(status));
253 0 : goto fail;
254 : }
255 :
256 802 : if (strncmp(pipe_name, "\\pipe\\", 6) == 0) {
257 802 : pipe_name += 6;
258 : }
259 :
260 802 : pipe_sock->pipe_path = talloc_asprintf(pipe_sock, "%s/%s", dirname,
261 : pipe_name);
262 802 : if (pipe_sock->pipe_path == NULL) {
263 0 : goto fail;
264 : }
265 :
266 802 : talloc_free(dirname);
267 :
268 802 : pipe_sock->ops = stream_ops;
269 802 : pipe_sock->private_data = private_data;
270 :
271 802 : status = stream_setup_socket(pipe_sock,
272 : event_context,
273 : lp_ctx,
274 : model_ops,
275 : &named_pipe_stream_ops,
276 : "unix",
277 : pipe_sock->pipe_path,
278 : NULL,
279 : NULL,
280 : pipe_sock,
281 : process_context);
282 802 : if (!NT_STATUS_IS_OK(status)) {
283 0 : goto fail;
284 : }
285 802 : return NT_STATUS_OK;
286 :
287 0 : fail:
288 0 : talloc_free(pipe_sock);
289 0 : return status;
290 : }
|