1 /*
2    Unix SMB/CIFS implementation.
3 
4    Generic Authentication Interface
5 
6    Copyright (C) Andrew Tridgell 2003
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
8    Copyright (C) Stefan Metzmacher 2004
9 
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24 
25 #include "includes.h"
26 #include "libcli/composite/composite.h"
27 #include "auth/gensec/gensec.h"
28 #include "librpc/rpc/dcerpc.h"
29 
30 /*
31   return the rpc syntax and transfer syntax given the pipe uuid and version
32 */
dcerpc_init_syntaxes(const struct dcerpc_interface_table * table,struct dcerpc_syntax_id * syntax,struct dcerpc_syntax_id * transfer_syntax)33 static NTSTATUS dcerpc_init_syntaxes(const struct dcerpc_interface_table *table,
34 			      struct dcerpc_syntax_id *syntax,
35 			      struct dcerpc_syntax_id *transfer_syntax)
36 {
37 	syntax->uuid = table->syntax_id.uuid;
38 	syntax->if_version = table->syntax_id.if_version;
39 
40 	*transfer_syntax = ndr_transfer_syntax;
41 
42 	return NT_STATUS_OK;
43 }
44 
45 
46 /*
47   Send request to do a non-authenticated dcerpc bind
48 */
dcerpc_bind_auth_none_send(TALLOC_CTX * mem_ctx,struct dcerpc_pipe * p,const struct dcerpc_interface_table * table)49 struct composite_context *dcerpc_bind_auth_none_send(TALLOC_CTX *mem_ctx,
50 						     struct dcerpc_pipe *p,
51 						     const struct dcerpc_interface_table *table)
52 {
53 	struct dcerpc_syntax_id syntax;
54 	struct dcerpc_syntax_id transfer_syntax;
55 
56 	struct composite_context *c;
57 
58 	c = composite_create(mem_ctx, p->conn->event_ctx);
59 	if (c == NULL) return NULL;
60 
61 	c->status = dcerpc_init_syntaxes(table,
62 					 &syntax, &transfer_syntax);
63 	if (!NT_STATUS_IS_OK(c->status)) {
64 		DEBUG(2,("Invalid uuid string in "
65 			 "dcerpc_bind_auth_none_send\n"));
66 		composite_error(c, c->status);
67 		return c;
68 	}
69 
70 	/* c was only allocated as a container for a possible error */
71 	talloc_free(c);
72 
73 	return dcerpc_bind_send(p, mem_ctx, &syntax, &transfer_syntax);
74 }
75 
76 
77 /*
78   Receive result of a non-authenticated dcerpc bind
79 */
dcerpc_bind_auth_none_recv(struct composite_context * ctx)80 NTSTATUS dcerpc_bind_auth_none_recv(struct composite_context *ctx)
81 {
82 	return dcerpc_bind_recv(ctx);
83 }
84 
85 
86 /*
87   Perform sync non-authenticated dcerpc bind
88 */
dcerpc_bind_auth_none(struct dcerpc_pipe * p,const struct dcerpc_interface_table * table)89 NTSTATUS dcerpc_bind_auth_none(struct dcerpc_pipe *p,
90 			       const struct dcerpc_interface_table *table)
91 {
92 	struct composite_context *ctx;
93 
94 	ctx = dcerpc_bind_auth_none_send(p, p, table);
95 	return dcerpc_bind_auth_none_recv(ctx);
96 }
97 
98 
99 struct bind_auth_state {
100 	struct dcerpc_pipe *pipe;
101 	DATA_BLOB credentials;
102 	BOOL more_processing;	/* Is there anything more to do after the
103 				 * first bind itself received? */
104 };
105 
106 static void bind_auth_recv_alter(struct composite_context *creq);
107 
bind_auth_next_step(struct composite_context * c)108 static void bind_auth_next_step(struct composite_context *c)
109 {
110 	struct bind_auth_state *state;
111 	struct dcerpc_security *sec;
112 	struct composite_context *creq;
113 	BOOL more_processing = False;
114 
115 	state = talloc_get_type(c->private_data, struct bind_auth_state);
116 	sec = &state->pipe->conn->security_state;
117 
118 	/* The status value here, from GENSEC is vital to the security
119 	 * of the system.  Even if the other end accepts, if GENSEC
120 	 * claims 'MORE_PROCESSING_REQUIRED' then you must keep
121 	 * feeding it blobs, or else the remote host/attacker might
122 	 * avoid mutal authentication requirements.
123 	 *
124 	 * Likewise, you must not feed GENSEC too much (after the OK),
125 	 * it doesn't like that either
126 	 */
127 
128 	c->status = gensec_update(sec->generic_state, state,
129 				  sec->auth_info->credentials,
130 				  &state->credentials);
131 
132 	if (NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
133 		more_processing = True;
134 		c->status = NT_STATUS_OK;
135 	}
136 
137 	if (!composite_is_ok(c)) return;
138 
139 	if (state->credentials.length == 0) {
140 		composite_done(c);
141 		return;
142 	}
143 
144 	sec->auth_info->credentials = state->credentials;
145 
146 	if (!more_processing) {
147 		/* NO reply expected, so just send it */
148 		c->status = dcerpc_auth3(state->pipe->conn, state);
149 		if (!composite_is_ok(c)) return;
150 
151 		composite_done(c);
152 		return;
153 	}
154 
155 	/* We are demanding a reply, so use a request that will get us one */
156 
157 	creq = dcerpc_alter_context_send(state->pipe, state,
158 					 &state->pipe->syntax,
159 					 &state->pipe->transfer_syntax);
160 	if (composite_nomem(creq, c)) return;
161 
162 	composite_continue(c, creq, bind_auth_recv_alter, c);
163 }
164 
165 
bind_auth_recv_alter(struct composite_context * creq)166 static void bind_auth_recv_alter(struct composite_context *creq)
167 {
168 	struct composite_context *c = talloc_get_type(creq->async.private_data,
169 						      struct composite_context);
170 
171 	c->status = dcerpc_alter_context_recv(creq);
172 	if (!composite_is_ok(c)) return;
173 
174 	bind_auth_next_step(c);
175 }
176 
177 
bind_auth_recv_bindreply(struct composite_context * creq)178 static void bind_auth_recv_bindreply(struct composite_context *creq)
179 {
180 	struct composite_context *c = talloc_get_type(creq->async.private_data,
181 						      struct composite_context);
182 	struct bind_auth_state *state =	talloc_get_type(c->private_data,
183 							struct bind_auth_state);
184 
185 	c->status = dcerpc_bind_recv(creq);
186 	if (!composite_is_ok(c)) return;
187 
188 	if (!state->more_processing) {
189 		/* The first gensec_update has not requested a second run, so
190 		 * we're done here. */
191 		composite_done(c);
192 		return;
193 	}
194 
195 	bind_auth_next_step(c);
196 }
197 
198 
199 /**
200    Bind to a DCE/RPC pipe, send async request
201    @param mem_ctx TALLOC_CTX for the allocation of the composite_context
202    @param p The dcerpc_pipe to bind (must already be connected)
203    @param table The interface table to use (the DCE/RPC bind both selects and interface and authenticates)
204    @param credentials The credentials of the account to connect with
205    @param auth_type Select the authentication scheme to use
206    @param auth_level Chooses between unprotected (connect), signed or sealed
207    @param service The service (used by Kerberos to select the service principal to contact)
208    @retval A composite context describing the partial state of the bind
209 */
210 
dcerpc_bind_auth_send(TALLOC_CTX * mem_ctx,struct dcerpc_pipe * p,const struct dcerpc_interface_table * table,struct cli_credentials * credentials,uint8_t auth_type,uint8_t auth_level,const char * service)211 struct composite_context *dcerpc_bind_auth_send(TALLOC_CTX *mem_ctx,
212 						struct dcerpc_pipe *p,
213 						const struct dcerpc_interface_table *table,
214 						struct cli_credentials *credentials,
215 						uint8_t auth_type, uint8_t auth_level,
216 						const char *service)
217 {
218 	struct composite_context *c, *creq;
219 	struct bind_auth_state *state;
220 	struct dcerpc_security *sec;
221 
222 	struct dcerpc_syntax_id syntax, transfer_syntax;
223 
224 	/* composite context allocation and setup */
225 	c = composite_create(mem_ctx, p->conn->event_ctx);
226 	if (c == NULL) return NULL;
227 
228 	state = talloc(c, struct bind_auth_state);
229 	if (composite_nomem(state, c)) return c;
230 	c->private_data = state;
231 
232 	state->pipe = p;
233 
234 	c->status = dcerpc_init_syntaxes(table,
235 					 &syntax,
236 					 &transfer_syntax);
237 	if (!composite_is_ok(c)) return c;
238 
239 	sec = &p->conn->security_state;
240 
241 	c->status = gensec_client_start(p, &sec->generic_state,
242 					p->conn->event_ctx);
243 	if (!NT_STATUS_IS_OK(c->status)) {
244 		DEBUG(1, ("Failed to start GENSEC client mode: %s\n",
245 			  nt_errstr(c->status)));
246 		composite_error(c, c->status);
247 		return c;
248 	}
249 
250 	c->status = gensec_set_credentials(sec->generic_state, credentials);
251 	if (!NT_STATUS_IS_OK(c->status)) {
252 		DEBUG(1, ("Failed to set GENSEC client credentails: %s\n",
253 			  nt_errstr(c->status)));
254 		composite_error(c, c->status);
255 		return c;
256 	}
257 
258 	c->status = gensec_set_target_hostname(sec->generic_state,
259 					       p->conn->transport.target_hostname(p->conn));
260 	if (!NT_STATUS_IS_OK(c->status)) {
261 		DEBUG(1, ("Failed to set GENSEC target hostname: %s\n",
262 			  nt_errstr(c->status)));
263 		composite_error(c, c->status);
264 		return c;
265 	}
266 
267 	if (service != NULL) {
268 		c->status = gensec_set_target_service(sec->generic_state,
269 						      service);
270 		if (!NT_STATUS_IS_OK(c->status)) {
271 			DEBUG(1, ("Failed to set GENSEC target service: %s\n",
272 				  nt_errstr(c->status)));
273 			composite_error(c, c->status);
274 			return c;
275 		}
276 	}
277 
278 	c->status = gensec_start_mech_by_authtype(sec->generic_state,
279 						  auth_type, auth_level);
280 	if (!NT_STATUS_IS_OK(c->status)) {
281 		DEBUG(1, ("Failed to start GENSEC client mechanism %s: %s\n",
282 			  gensec_get_name_by_authtype(auth_type),
283 			  nt_errstr(c->status)));
284 		composite_error(c, c->status);
285 		return c;
286 	}
287 
288 	sec->auth_info = talloc(p, struct dcerpc_auth);
289 	if (composite_nomem(sec->auth_info, c)) return c;
290 
291 	sec->auth_info->auth_type = auth_type;
292 	sec->auth_info->auth_level = auth_level,
293 	sec->auth_info->auth_pad_length = 0;
294 	sec->auth_info->auth_reserved = 0;
295 	sec->auth_info->auth_context_id = random();
296 	sec->auth_info->credentials = data_blob(NULL, 0);
297 
298 	/* The status value here, from GENSEC is vital to the security
299 	 * of the system.  Even if the other end accepts, if GENSEC
300 	 * claims 'MORE_PROCESSING_REQUIRED' then you must keep
301 	 * feeding it blobs, or else the remote host/attacker might
302 	 * avoid mutal authentication requirements.
303 	 *
304 	 * Likewise, you must not feed GENSEC too much (after the OK),
305 	 * it doesn't like that either
306 	 */
307 
308 	c->status = gensec_update(sec->generic_state, state,
309 				  sec->auth_info->credentials,
310 				  &state->credentials);
311 	if (!NT_STATUS_IS_OK(c->status) &&
312 	    !NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
313 		composite_error(c, c->status);
314 		return c;
315 	}
316 
317 	state->more_processing = NT_STATUS_EQUAL(c->status,
318 						 NT_STATUS_MORE_PROCESSING_REQUIRED);
319 
320 	if (state->credentials.length == 0) {
321 		composite_done(c);
322 		return c;
323 	}
324 
325 	sec->auth_info->credentials = state->credentials;
326 
327 	/* The first request always is a dcerpc_bind. The subsequent ones
328 	 * depend on gensec results */
329 	creq = dcerpc_bind_send(p, state, &syntax, &transfer_syntax);
330 	if (composite_nomem(creq, c)) return c;
331 
332 	composite_continue(c, creq, bind_auth_recv_bindreply, c);
333 	return c;
334 }
335 
336 
337 /**
338    Bind to a DCE/RPC pipe, receive result
339    @param creq A composite context describing state of async call
340    @retval NTSTATUS code
341 */
342 
dcerpc_bind_auth_recv(struct composite_context * creq)343 NTSTATUS dcerpc_bind_auth_recv(struct composite_context *creq)
344 {
345 	NTSTATUS result = composite_wait(creq);
346 	struct bind_auth_state *state = talloc_get_type(creq->private_data,
347 							struct bind_auth_state);
348 
349 	if (NT_STATUS_IS_OK(result)) {
350 		/*
351 		  after a successful authenticated bind the session
352 		  key reverts to the generic session key
353 		*/
354 		state->pipe->conn->security_state.session_key = dcerpc_generic_session_key;
355 	}
356 
357 	talloc_free(creq);
358 	return result;
359 }
360 
361 
362 /**
363    Perform a GENSEC authenticated bind to a DCE/RPC pipe, sync
364    @param p The dcerpc_pipe to bind (must already be connected)
365    @param table The interface table to use (the DCE/RPC bind both selects and interface and authenticates)
366    @param credentials The credentials of the account to connect with
367    @param auth_type Select the authentication scheme to use
368    @param auth_level Chooses between unprotected (connect), signed or sealed
369    @param service The service (used by Kerberos to select the service principal to contact)
370    @retval NTSTATUS status code
371 */
372 
dcerpc_bind_auth(struct dcerpc_pipe * p,const struct dcerpc_interface_table * table,struct cli_credentials * credentials,uint8_t auth_type,uint8_t auth_level,const char * service)373 NTSTATUS dcerpc_bind_auth(struct dcerpc_pipe *p,
374 			  const struct dcerpc_interface_table *table,
375 			  struct cli_credentials *credentials,
376 			  uint8_t auth_type, uint8_t auth_level,
377 			  const char *service)
378 {
379 	struct composite_context *creq;
380 	creq = dcerpc_bind_auth_send(p, p, table, credentials,
381 				     auth_type, auth_level, service);
382 	return dcerpc_bind_auth_recv(creq);
383 }
384