417b05cf063c4dd6dae3ab594058b620e34ea603
[obnox/samba/samba-obnox.git] / auth / gensec / gensec.c
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-2006
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "system/network.h"
25 #include <tevent.h>
26 #include "lib/tsocket/tsocket.h"
27 #include "lib/util/tevent_ntstatus.h"
28 #include "auth/gensec/gensec.h"
29
30 /*
31   wrappers for the gensec function pointers
32 */
33 _PUBLIC_ NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
34                               uint8_t *data, size_t length,
35                               const uint8_t *whole_pdu, size_t pdu_length,
36                               const DATA_BLOB *sig)
37 {
38         if (!gensec_security->ops->unseal_packet) {
39                 return NT_STATUS_NOT_IMPLEMENTED;
40         }
41         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
42                 return NT_STATUS_INVALID_PARAMETER;
43         }
44
45         return gensec_security->ops->unseal_packet(gensec_security,
46                                                    data, length,
47                                                    whole_pdu, pdu_length,
48                                                    sig);
49 }
50
51 _PUBLIC_ NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
52                              const uint8_t *data, size_t length,
53                              const uint8_t *whole_pdu, size_t pdu_length,
54                              const DATA_BLOB *sig)
55 {
56         if (!gensec_security->ops->check_packet) {
57                 return NT_STATUS_NOT_IMPLEMENTED;
58         }
59         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
60                 return NT_STATUS_INVALID_PARAMETER;
61         }
62
63         return gensec_security->ops->check_packet(gensec_security, data, length, whole_pdu, pdu_length, sig);
64 }
65
66 _PUBLIC_ NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
67                             TALLOC_CTX *mem_ctx,
68                             uint8_t *data, size_t length,
69                             const uint8_t *whole_pdu, size_t pdu_length,
70                             DATA_BLOB *sig)
71 {
72         if (!gensec_security->ops->seal_packet) {
73                 return NT_STATUS_NOT_IMPLEMENTED;
74         }
75         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
76                 return NT_STATUS_INVALID_PARAMETER;
77         }
78
79         return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
80 }
81
82 _PUBLIC_ NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
83                             TALLOC_CTX *mem_ctx,
84                             const uint8_t *data, size_t length,
85                             const uint8_t *whole_pdu, size_t pdu_length,
86                             DATA_BLOB *sig)
87 {
88         if (!gensec_security->ops->sign_packet) {
89                 return NT_STATUS_NOT_IMPLEMENTED;
90         }
91         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
92                 return NT_STATUS_INVALID_PARAMETER;
93         }
94
95         return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
96 }
97
98 _PUBLIC_ size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size)
99 {
100         if (!gensec_security->ops->sig_size) {
101                 return 0;
102         }
103         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
104                 return 0;
105         }
106
107         return gensec_security->ops->sig_size(gensec_security, data_size);
108 }
109
110 size_t gensec_max_wrapped_size(struct gensec_security *gensec_security)
111 {
112         if (!gensec_security->ops->max_wrapped_size) {
113                 return (1 << 17);
114         }
115
116         return gensec_security->ops->max_wrapped_size(gensec_security);
117 }
118
119 size_t gensec_max_input_size(struct gensec_security *gensec_security)
120 {
121         if (!gensec_security->ops->max_input_size) {
122                 return (1 << 17) - gensec_sig_size(gensec_security, 1 << 17);
123         }
124
125         return gensec_security->ops->max_input_size(gensec_security);
126 }
127
128 _PUBLIC_ NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
129                      TALLOC_CTX *mem_ctx,
130                      const DATA_BLOB *in,
131                      DATA_BLOB *out)
132 {
133         if (!gensec_security->ops->wrap) {
134                 return NT_STATUS_NOT_IMPLEMENTED;
135         }
136         return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
137 }
138
139 _PUBLIC_ NTSTATUS gensec_unwrap(struct gensec_security *gensec_security,
140                        TALLOC_CTX *mem_ctx,
141                        const DATA_BLOB *in,
142                        DATA_BLOB *out)
143 {
144         if (!gensec_security->ops->unwrap) {
145                 return NT_STATUS_NOT_IMPLEMENTED;
146         }
147         return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
148 }
149
150 _PUBLIC_ NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
151                                      TALLOC_CTX *mem_ctx,
152                                      DATA_BLOB *session_key)
153 {
154         if (!gensec_security->ops->session_key) {
155                 return NT_STATUS_NOT_IMPLEMENTED;
156         }
157         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SESSION_KEY)) {
158                 return NT_STATUS_NO_USER_SESSION_KEY;
159         }
160
161         return gensec_security->ops->session_key(gensec_security, mem_ctx, session_key);
162 }
163
164 /**
165  * Return the credentials of a logged on user, including session keys
166  * etc.
167  *
168  * Only valid after a successful authentication
169  *
170  * May only be called once per authentication.
171  *
172  */
173
174 _PUBLIC_ NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
175                                       TALLOC_CTX *mem_ctx,
176                                       struct auth_session_info **session_info)
177 {
178         if (!gensec_security->ops->session_info) {
179                 return NT_STATUS_NOT_IMPLEMENTED;
180         }
181         return gensec_security->ops->session_info(gensec_security, mem_ctx, session_info);
182 }
183
184 /**
185  * Next state function for the GENSEC state machine
186  *
187  * @param gensec_security GENSEC State
188  * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
189  * @param in The request, as a DATA_BLOB
190  * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
191  * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
192  *                or NT_STATUS_OK if the user is authenticated.
193  */
194
195 _PUBLIC_ NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
196                        const DATA_BLOB in, DATA_BLOB *out)
197 {
198         return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
199 }
200
201 struct gensec_update_state {
202         struct tevent_immediate *im;
203         struct gensec_security *gensec_security;
204         DATA_BLOB in;
205         DATA_BLOB out;
206 };
207
208 static void gensec_update_async_trigger(struct tevent_context *ctx,
209                                         struct tevent_immediate *im,
210                                         void *private_data);
211 /**
212  * Next state function for the GENSEC state machine async version
213  *
214  * @param mem_ctx The memory context for the request
215  * @param ev The event context for the request
216  * @param gensec_security GENSEC State
217  * @param in The request, as a DATA_BLOB
218  *
219  * @return The request handle or NULL on no memory failure
220  */
221
222 _PUBLIC_ struct tevent_req *gensec_update_send(TALLOC_CTX *mem_ctx,
223                                                struct tevent_context *ev,
224                                                struct gensec_security *gensec_security,
225                                                const DATA_BLOB in)
226 {
227         struct tevent_req *req;
228         struct gensec_update_state *state = NULL;
229
230         req = tevent_req_create(mem_ctx, &state,
231                                 struct gensec_update_state);
232         if (req == NULL) {
233                 return NULL;
234         }
235
236         state->gensec_security          = gensec_security;
237         state->in                       = in;
238         state->out                      = data_blob(NULL, 0);
239         state->im                       = tevent_create_immediate(state);
240         if (tevent_req_nomem(state->im, req)) {
241                 return tevent_req_post(req, ev);
242         }
243
244         tevent_schedule_immediate(state->im, ev,
245                                   gensec_update_async_trigger,
246                                   req);
247
248         return req;
249 }
250
251 static void gensec_update_async_trigger(struct tevent_context *ctx,
252                                         struct tevent_immediate *im,
253                                         void *private_data)
254 {
255         struct tevent_req *req =
256                 talloc_get_type_abort(private_data, struct tevent_req);
257         struct gensec_update_state *state =
258                 tevent_req_data(req, struct gensec_update_state);
259         NTSTATUS status;
260
261         status = gensec_update(state->gensec_security, state,
262                                state->in, &state->out);
263         if (tevent_req_nterror(req, status)) {
264                 return;
265         }
266
267         tevent_req_done(req);
268 }
269
270 /**
271  * Next state function for the GENSEC state machine
272  *
273  * @param req request state
274  * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
275  * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
276  * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
277  *                or NT_STATUS_OK if the user is authenticated.
278  */
279 _PUBLIC_ NTSTATUS gensec_update_recv(struct tevent_req *req,
280                                      TALLOC_CTX *out_mem_ctx,
281                                      DATA_BLOB *out)
282 {
283         struct gensec_update_state *state =
284                 tevent_req_data(req, struct gensec_update_state);
285         NTSTATUS status;
286
287         if (tevent_req_is_nterror(req, &status)) {
288                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
289                         tevent_req_received(req);
290                         return status;
291                 }
292         } else {
293                 status = NT_STATUS_OK;
294         }
295
296         *out = state->out;
297         talloc_steal(out_mem_ctx, out->data);
298
299         tevent_req_received(req);
300         return status;
301 }
302
303 /**
304  * Set the requirement for a certain feature on the connection
305  *
306  */
307
308 _PUBLIC_ void gensec_want_feature(struct gensec_security *gensec_security,
309                          uint32_t feature)
310 {
311         if (!gensec_security->ops || !gensec_security->ops->want_feature) {
312                 gensec_security->want_features |= feature;
313                 return;
314         }
315         gensec_security->ops->want_feature(gensec_security, feature);
316 }
317
318 /**
319  * Check the requirement for a certain feature on the connection
320  *
321  */
322
323 _PUBLIC_ bool gensec_have_feature(struct gensec_security *gensec_security,
324                          uint32_t feature)
325 {
326         if (!gensec_security->ops->have_feature) {
327                 return false;
328         }
329
330         /* We might 'have' features that we don't 'want', because the
331          * other end demanded them, or we can't neotiate them off */
332         return gensec_security->ops->have_feature(gensec_security, feature);
333 }
334
335 /**
336  * Return the credentials structure associated with a GENSEC context
337  *
338  */
339
340 _PUBLIC_ struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security)
341 {
342         if (!gensec_security) {
343                 return NULL;
344         }
345         return gensec_security->credentials;
346 }
347
348 /**
349  * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
350  *
351  */
352
353 _PUBLIC_ NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
354 {
355         gensec_security->target.service = talloc_strdup(gensec_security, service);
356         if (!gensec_security->target.service) {
357                 return NT_STATUS_NO_MEMORY;
358         }
359         return NT_STATUS_OK;
360 }
361
362 _PUBLIC_ const char *gensec_get_target_service(struct gensec_security *gensec_security)
363 {
364         if (gensec_security->target.service) {
365                 return gensec_security->target.service;
366         }
367
368         return "host";
369 }
370
371 /**
372  * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
373  *
374  */
375
376 _PUBLIC_ NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
377 {
378         gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
379         if (hostname && !gensec_security->target.hostname) {
380                 return NT_STATUS_NO_MEMORY;
381         }
382         return NT_STATUS_OK;
383 }
384
385 _PUBLIC_ const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
386 {
387         /* We allow the target hostname to be overriden for testing purposes */
388         if (gensec_security->settings->target_hostname) {
389                 return gensec_security->settings->target_hostname;
390         }
391
392         if (gensec_security->target.hostname) {
393                 return gensec_security->target.hostname;
394         }
395
396         /* We could add use the 'set sockaddr' call, and do a reverse
397          * lookup, but this would be both insecure (compromising the
398          * way kerberos works) and add DNS timeouts */
399         return NULL;
400 }
401
402 /**
403  * Set (and talloc_reference) local and peer socket addresses onto a socket
404  * context on the GENSEC context.
405  *
406  * This is so that kerberos can include these addresses in
407  * cryptographic tokens, to avoid certain attacks.
408  */
409
410 /**
411  * @brief Set the local gensec address.
412  *
413  * @param  gensec_security   The gensec security context to use.
414  *
415  * @param  remote       The local address to set.
416  *
417  * @return              On success NT_STATUS_OK is returned or an NT_STATUS
418  *                      error.
419  */
420 _PUBLIC_ NTSTATUS gensec_set_local_address(struct gensec_security *gensec_security,
421                 const struct tsocket_address *local)
422 {
423         TALLOC_FREE(gensec_security->local_addr);
424
425         if (local == NULL) {
426                 return NT_STATUS_OK;
427         }
428
429         gensec_security->local_addr = tsocket_address_copy(local, gensec_security);
430         if (gensec_security->local_addr == NULL) {
431                 return NT_STATUS_NO_MEMORY;
432         }
433
434         return NT_STATUS_OK;
435 }
436
437 /**
438  * @brief Set the remote gensec address.
439  *
440  * @param  gensec_security   The gensec security context to use.
441  *
442  * @param  remote       The remote address to set.
443  *
444  * @return              On success NT_STATUS_OK is returned or an NT_STATUS
445  *                      error.
446  */
447 _PUBLIC_ NTSTATUS gensec_set_remote_address(struct gensec_security *gensec_security,
448                 const struct tsocket_address *remote)
449 {
450         TALLOC_FREE(gensec_security->remote_addr);
451
452         if (remote == NULL) {
453                 return NT_STATUS_OK;
454         }
455
456         gensec_security->remote_addr = tsocket_address_copy(remote, gensec_security);
457         if (gensec_security->remote_addr == NULL) {
458                 return NT_STATUS_NO_MEMORY;
459         }
460
461         return NT_STATUS_OK;
462 }
463
464 /**
465  * @brief Get the local address from a gensec security context.
466  *
467  * @param  gensec_security   The security context to get the address from.
468  *
469  * @return              The address as tsocket_address which could be NULL if
470  *                      no address is set.
471  */
472 _PUBLIC_ const struct tsocket_address *gensec_get_local_address(struct gensec_security *gensec_security)
473 {
474         if (gensec_security == NULL) {
475                 return NULL;
476         }
477         return gensec_security->local_addr;
478 }
479
480 /**
481  * @brief Get the remote address from a gensec security context.
482  *
483  * @param  gensec_security   The security context to get the address from.
484  *
485  * @return              The address as tsocket_address which could be NULL if
486  *                      no address is set.
487  */
488 _PUBLIC_ const struct tsocket_address *gensec_get_remote_address(struct gensec_security *gensec_security)
489 {
490         if (gensec_security == NULL) {
491                 return NULL;
492         }
493         return gensec_security->remote_addr;
494 }
495
496 /**
497  * Set the target principal (assuming it it known, say from the SPNEGO reply)
498  *  - ensures it is talloc()ed
499  *
500  */
501
502 _PUBLIC_ NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
503 {
504         gensec_security->target.principal = talloc_strdup(gensec_security, principal);
505         if (!gensec_security->target.principal) {
506                 return NT_STATUS_NO_MEMORY;
507         }
508         return NT_STATUS_OK;
509 }
510
511 const char *gensec_get_target_principal(struct gensec_security *gensec_security)
512 {
513         if (gensec_security->target.principal) {
514                 return gensec_security->target.principal;
515         }
516
517         return NULL;
518 }