auth/gensec: introduce gensec_internal.h
[nivanova/samba-autobuild/.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 #include "auth/gensec/gensec_internal.h"
30 #include "librpc/rpc/dcerpc.h"
31
32 /*
33   wrappers for the gensec function pointers
34 */
35 _PUBLIC_ NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
36                               uint8_t *data, size_t length,
37                               const uint8_t *whole_pdu, size_t pdu_length,
38                               const DATA_BLOB *sig)
39 {
40         if (!gensec_security->ops->unseal_packet) {
41                 return NT_STATUS_NOT_IMPLEMENTED;
42         }
43         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
44                 return NT_STATUS_INVALID_PARAMETER;
45         }
46
47         return gensec_security->ops->unseal_packet(gensec_security,
48                                                    data, length,
49                                                    whole_pdu, pdu_length,
50                                                    sig);
51 }
52
53 _PUBLIC_ NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
54                              const uint8_t *data, size_t length,
55                              const uint8_t *whole_pdu, size_t pdu_length,
56                              const DATA_BLOB *sig)
57 {
58         if (!gensec_security->ops->check_packet) {
59                 return NT_STATUS_NOT_IMPLEMENTED;
60         }
61         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
62                 return NT_STATUS_INVALID_PARAMETER;
63         }
64
65         return gensec_security->ops->check_packet(gensec_security, data, length, whole_pdu, pdu_length, sig);
66 }
67
68 _PUBLIC_ NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
69                             TALLOC_CTX *mem_ctx,
70                             uint8_t *data, size_t length,
71                             const uint8_t *whole_pdu, size_t pdu_length,
72                             DATA_BLOB *sig)
73 {
74         if (!gensec_security->ops->seal_packet) {
75                 return NT_STATUS_NOT_IMPLEMENTED;
76         }
77         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
78                 return NT_STATUS_INVALID_PARAMETER;
79         }
80         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
81                 return NT_STATUS_INVALID_PARAMETER;
82         }
83
84         return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
85 }
86
87 _PUBLIC_ NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
88                             TALLOC_CTX *mem_ctx,
89                             const uint8_t *data, size_t length,
90                             const uint8_t *whole_pdu, size_t pdu_length,
91                             DATA_BLOB *sig)
92 {
93         if (!gensec_security->ops->sign_packet) {
94                 return NT_STATUS_NOT_IMPLEMENTED;
95         }
96         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
97                 return NT_STATUS_INVALID_PARAMETER;
98         }
99
100         return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
101 }
102
103 _PUBLIC_ size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size)
104 {
105         if (!gensec_security->ops->sig_size) {
106                 return 0;
107         }
108         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
109                 return 0;
110         }
111
112         return gensec_security->ops->sig_size(gensec_security, data_size);
113 }
114
115 _PUBLIC_ size_t gensec_max_wrapped_size(struct gensec_security *gensec_security)
116 {
117         if (!gensec_security->ops->max_wrapped_size) {
118                 return (1 << 17);
119         }
120
121         return gensec_security->ops->max_wrapped_size(gensec_security);
122 }
123
124 _PUBLIC_ size_t gensec_max_input_size(struct gensec_security *gensec_security)
125 {
126         if (!gensec_security->ops->max_input_size) {
127                 return (1 << 17) - gensec_sig_size(gensec_security, 1 << 17);
128         }
129
130         return gensec_security->ops->max_input_size(gensec_security);
131 }
132
133 _PUBLIC_ NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
134                      TALLOC_CTX *mem_ctx,
135                      const DATA_BLOB *in,
136                      DATA_BLOB *out)
137 {
138         if (!gensec_security->ops->wrap) {
139                 return NT_STATUS_NOT_IMPLEMENTED;
140         }
141         return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
142 }
143
144 _PUBLIC_ NTSTATUS gensec_unwrap(struct gensec_security *gensec_security,
145                        TALLOC_CTX *mem_ctx,
146                        const DATA_BLOB *in,
147                        DATA_BLOB *out)
148 {
149         if (!gensec_security->ops->unwrap) {
150                 return NT_STATUS_NOT_IMPLEMENTED;
151         }
152         return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
153 }
154
155 _PUBLIC_ NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
156                                      TALLOC_CTX *mem_ctx,
157                                      DATA_BLOB *session_key)
158 {
159         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SESSION_KEY)) {
160                 return NT_STATUS_NO_USER_SESSION_KEY;
161         }
162
163         if (!gensec_security->ops->session_key) {
164                 return NT_STATUS_NOT_IMPLEMENTED;
165         }
166
167         return gensec_security->ops->session_key(gensec_security, mem_ctx, session_key);
168 }
169
170 /**
171  * Return the credentials of a logged on user, including session keys
172  * etc.
173  *
174  * Only valid after a successful authentication
175  *
176  * May only be called once per authentication.
177  *
178  */
179
180 _PUBLIC_ NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
181                                       TALLOC_CTX *mem_ctx,
182                                       struct auth_session_info **session_info)
183 {
184         if (!gensec_security->ops->session_info) {
185                 return NT_STATUS_NOT_IMPLEMENTED;
186         }
187         return gensec_security->ops->session_info(gensec_security, mem_ctx, session_info);
188 }
189
190 _PUBLIC_ void gensec_set_max_update_size(struct gensec_security *gensec_security,
191                                 uint32_t max_update_size)
192 {
193         gensec_security->max_update_size = max_update_size;
194 }
195
196 _PUBLIC_ size_t gensec_max_update_size(struct gensec_security *gensec_security)
197 {
198         if (gensec_security->max_update_size == 0) {
199                 return UINT32_MAX;
200         }
201
202         return gensec_security->max_update_size;
203 }
204
205 /**
206  * Next state function for the GENSEC state machine
207  *
208  * @param gensec_security GENSEC State
209  * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
210  * @param in The request, as a DATA_BLOB
211  * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
212  * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
213  *                or NT_STATUS_OK if the user is authenticated.
214  */
215
216 _PUBLIC_ NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
217                                 struct tevent_context *ev,
218                                 const DATA_BLOB in, DATA_BLOB *out)
219 {
220         NTSTATUS status;
221
222         status = gensec_security->ops->update(gensec_security, out_mem_ctx,
223                                               ev, in, out);
224         if (!NT_STATUS_IS_OK(status)) {
225                 return status;
226         }
227
228         /*
229          * Because callers using the
230          * gensec_start_mech_by_auth_type() never call
231          * gensec_want_feature(), it isn't sensible for them
232          * to have to call gensec_have_feature() manually, and
233          * these are not points of negotiation, but are
234          * asserted by the client
235          */
236         switch (gensec_security->dcerpc_auth_level) {
237         case DCERPC_AUTH_LEVEL_INTEGRITY:
238                 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
239                         DEBUG(0,("Did not manage to negotiate mandetory feature "
240                                  "SIGN for dcerpc auth_level %u\n",
241                                  gensec_security->dcerpc_auth_level));
242                         return NT_STATUS_ACCESS_DENIED;
243                 }
244                 break;
245         case DCERPC_AUTH_LEVEL_PRIVACY:
246                 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
247                         DEBUG(0,("Did not manage to negotiate mandetory feature "
248                                  "SIGN for dcerpc auth_level %u\n",
249                                  gensec_security->dcerpc_auth_level));
250                         return NT_STATUS_ACCESS_DENIED;
251                 }
252                 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
253                         DEBUG(0,("Did not manage to negotiate mandetory feature "
254                                  "SEAL for dcerpc auth_level %u\n",
255                                  gensec_security->dcerpc_auth_level));
256                         return NT_STATUS_ACCESS_DENIED;
257                 }
258                 break;
259         default:
260                 break;
261         }
262
263         return NT_STATUS_OK;
264 }
265
266 struct gensec_update_state {
267         struct tevent_immediate *im;
268         struct gensec_security *gensec_security;
269         DATA_BLOB in;
270         DATA_BLOB out;
271 };
272
273 static void gensec_update_async_trigger(struct tevent_context *ctx,
274                                         struct tevent_immediate *im,
275                                         void *private_data);
276 /**
277  * Next state function for the GENSEC state machine async version
278  *
279  * @param mem_ctx The memory context for the request
280  * @param ev The event context for the request
281  * @param gensec_security GENSEC State
282  * @param in The request, as a DATA_BLOB
283  *
284  * @return The request handle or NULL on no memory failure
285  */
286
287 _PUBLIC_ struct tevent_req *gensec_update_send(TALLOC_CTX *mem_ctx,
288                                                struct tevent_context *ev,
289                                                struct gensec_security *gensec_security,
290                                                const DATA_BLOB in)
291 {
292         struct tevent_req *req;
293         struct gensec_update_state *state = NULL;
294
295         req = tevent_req_create(mem_ctx, &state,
296                                 struct gensec_update_state);
297         if (req == NULL) {
298                 return NULL;
299         }
300
301         state->gensec_security          = gensec_security;
302         state->in                       = in;
303         state->out                      = data_blob(NULL, 0);
304         state->im                       = tevent_create_immediate(state);
305         if (tevent_req_nomem(state->im, req)) {
306                 return tevent_req_post(req, ev);
307         }
308
309         tevent_schedule_immediate(state->im, ev,
310                                   gensec_update_async_trigger,
311                                   req);
312
313         return req;
314 }
315
316 static void gensec_update_async_trigger(struct tevent_context *ctx,
317                                         struct tevent_immediate *im,
318                                         void *private_data)
319 {
320         struct tevent_req *req =
321                 talloc_get_type_abort(private_data, struct tevent_req);
322         struct gensec_update_state *state =
323                 tevent_req_data(req, struct gensec_update_state);
324         NTSTATUS status;
325
326         status = gensec_update(state->gensec_security, state, ctx,
327                                state->in, &state->out);
328         if (tevent_req_nterror(req, status)) {
329                 return;
330         }
331
332         tevent_req_done(req);
333 }
334
335 /**
336  * Next state function for the GENSEC state machine
337  *
338  * @param req request state
339  * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
340  * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
341  * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
342  *                or NT_STATUS_OK if the user is authenticated.
343  */
344 _PUBLIC_ NTSTATUS gensec_update_recv(struct tevent_req *req,
345                                      TALLOC_CTX *out_mem_ctx,
346                                      DATA_BLOB *out)
347 {
348         struct gensec_update_state *state =
349                 tevent_req_data(req, struct gensec_update_state);
350         NTSTATUS status;
351
352         if (tevent_req_is_nterror(req, &status)) {
353                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
354                         tevent_req_received(req);
355                         return status;
356                 }
357         } else {
358                 status = NT_STATUS_OK;
359         }
360
361         *out = state->out;
362         talloc_steal(out_mem_ctx, out->data);
363
364         tevent_req_received(req);
365         return status;
366 }
367
368 /**
369  * Set the requirement for a certain feature on the connection
370  *
371  */
372
373 _PUBLIC_ void gensec_want_feature(struct gensec_security *gensec_security,
374                          uint32_t feature)
375 {
376         if (!gensec_security->ops || !gensec_security->ops->want_feature) {
377                 gensec_security->want_features |= feature;
378                 return;
379         }
380         gensec_security->ops->want_feature(gensec_security, feature);
381 }
382
383 /**
384  * Check the requirement for a certain feature on the connection
385  *
386  */
387
388 _PUBLIC_ bool gensec_have_feature(struct gensec_security *gensec_security,
389                          uint32_t feature)
390 {
391         if (!gensec_security->ops->have_feature) {
392                 return false;
393         }
394
395         /* We might 'have' features that we don't 'want', because the
396          * other end demanded them, or we can't neotiate them off */
397         return gensec_security->ops->have_feature(gensec_security, feature);
398 }
399
400 _PUBLIC_ NTTIME gensec_expire_time(struct gensec_security *gensec_security)
401 {
402         if (!gensec_security->ops->expire_time) {
403                 return GENSEC_EXPIRE_TIME_INFINITY;
404         }
405
406         return gensec_security->ops->expire_time(gensec_security);
407 }
408 /**
409  * Return the credentials structure associated with a GENSEC context
410  *
411  */
412
413 _PUBLIC_ struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security)
414 {
415         if (!gensec_security) {
416                 return NULL;
417         }
418         return gensec_security->credentials;
419 }
420
421 /**
422  * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
423  *
424  */
425
426 _PUBLIC_ NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
427 {
428         gensec_security->target.service = talloc_strdup(gensec_security, service);
429         if (!gensec_security->target.service) {
430                 return NT_STATUS_NO_MEMORY;
431         }
432         return NT_STATUS_OK;
433 }
434
435 _PUBLIC_ const char *gensec_get_target_service(struct gensec_security *gensec_security)
436 {
437         if (gensec_security->target.service) {
438                 return gensec_security->target.service;
439         }
440
441         return "host";
442 }
443
444 /**
445  * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
446  *
447  */
448
449 _PUBLIC_ NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
450 {
451         gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
452         if (hostname && !gensec_security->target.hostname) {
453                 return NT_STATUS_NO_MEMORY;
454         }
455         return NT_STATUS_OK;
456 }
457
458 _PUBLIC_ const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
459 {
460         /* We allow the target hostname to be overriden for testing purposes */
461         if (gensec_security->settings->target_hostname) {
462                 return gensec_security->settings->target_hostname;
463         }
464
465         if (gensec_security->target.hostname) {
466                 return gensec_security->target.hostname;
467         }
468
469         /* We could add use the 'set sockaddr' call, and do a reverse
470          * lookup, but this would be both insecure (compromising the
471          * way kerberos works) and add DNS timeouts */
472         return NULL;
473 }
474
475 /**
476  * Set (and copy) local and peer socket addresses onto a socket
477  * context on the GENSEC context.
478  *
479  * This is so that kerberos can include these addresses in
480  * cryptographic tokens, to avoid certain attacks.
481  */
482
483 /**
484  * @brief Set the local gensec address.
485  *
486  * @param  gensec_security   The gensec security context to use.
487  *
488  * @param  remote       The local address to set.
489  *
490  * @return              On success NT_STATUS_OK is returned or an NT_STATUS
491  *                      error.
492  */
493 _PUBLIC_ NTSTATUS gensec_set_local_address(struct gensec_security *gensec_security,
494                 const struct tsocket_address *local)
495 {
496         TALLOC_FREE(gensec_security->local_addr);
497
498         if (local == NULL) {
499                 return NT_STATUS_OK;
500         }
501
502         gensec_security->local_addr = tsocket_address_copy(local, gensec_security);
503         if (gensec_security->local_addr == NULL) {
504                 return NT_STATUS_NO_MEMORY;
505         }
506
507         return NT_STATUS_OK;
508 }
509
510 /**
511  * @brief Set the remote gensec address.
512  *
513  * @param  gensec_security   The gensec security context to use.
514  *
515  * @param  remote       The remote address to set.
516  *
517  * @return              On success NT_STATUS_OK is returned or an NT_STATUS
518  *                      error.
519  */
520 _PUBLIC_ NTSTATUS gensec_set_remote_address(struct gensec_security *gensec_security,
521                 const struct tsocket_address *remote)
522 {
523         TALLOC_FREE(gensec_security->remote_addr);
524
525         if (remote == NULL) {
526                 return NT_STATUS_OK;
527         }
528
529         gensec_security->remote_addr = tsocket_address_copy(remote, gensec_security);
530         if (gensec_security->remote_addr == NULL) {
531                 return NT_STATUS_NO_MEMORY;
532         }
533
534         return NT_STATUS_OK;
535 }
536
537 /**
538  * @brief Get the local address from a gensec security context.
539  *
540  * @param  gensec_security   The security context to get the address from.
541  *
542  * @return              The address as tsocket_address which could be NULL if
543  *                      no address is set.
544  */
545 _PUBLIC_ const struct tsocket_address *gensec_get_local_address(struct gensec_security *gensec_security)
546 {
547         if (gensec_security == NULL) {
548                 return NULL;
549         }
550         return gensec_security->local_addr;
551 }
552
553 /**
554  * @brief Get the remote address from a gensec security context.
555  *
556  * @param  gensec_security   The security context to get the address from.
557  *
558  * @return              The address as tsocket_address which could be NULL if
559  *                      no address is set.
560  */
561 _PUBLIC_ const struct tsocket_address *gensec_get_remote_address(struct gensec_security *gensec_security)
562 {
563         if (gensec_security == NULL) {
564                 return NULL;
565         }
566         return gensec_security->remote_addr;
567 }
568
569 /**
570  * Set the target principal (assuming it it known, say from the SPNEGO reply)
571  *  - ensures it is talloc()ed
572  *
573  */
574
575 _PUBLIC_ NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
576 {
577         gensec_security->target.principal = talloc_strdup(gensec_security, principal);
578         if (!gensec_security->target.principal) {
579                 return NT_STATUS_NO_MEMORY;
580         }
581         return NT_STATUS_OK;
582 }
583
584 _PUBLIC_ const char *gensec_get_target_principal(struct gensec_security *gensec_security)
585 {
586         if (gensec_security->target.principal) {
587                 return gensec_security->target.principal;
588         }
589
590         return NULL;
591 }