auth/gensec: call gensec_verify_features() also after update_recv() in gensec_update_ev()
[vlendec/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 #define TEVENT_DEPRECATED 1
26 #include <tevent.h>
27 #include "lib/tsocket/tsocket.h"
28 #include "lib/util/tevent_ntstatus.h"
29 #include "auth/gensec/gensec.h"
30 #include "auth/gensec/gensec_internal.h"
31 #include "librpc/gen_ndr/dcerpc.h"
32 #include "auth/common_auth.h"
33
34 _PRIVATE_ NTSTATUS gensec_may_reset_crypto(struct gensec_security *gensec_security,
35                                            bool full_reset)
36 {
37         if (!gensec_security->ops->may_reset_crypto) {
38                 return NT_STATUS_OK;
39         }
40
41         return gensec_security->ops->may_reset_crypto(gensec_security, full_reset);
42 }
43
44 /*
45   wrappers for the gensec function pointers
46 */
47 _PUBLIC_ NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
48                               uint8_t *data, size_t length,
49                               const uint8_t *whole_pdu, size_t pdu_length,
50                               const DATA_BLOB *sig)
51 {
52         if (!gensec_security->ops->unseal_packet) {
53                 return NT_STATUS_NOT_IMPLEMENTED;
54         }
55         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
56                 return NT_STATUS_INVALID_PARAMETER;
57         }
58         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
59                 return NT_STATUS_INVALID_PARAMETER;
60         }
61         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE)) {
62                 return NT_STATUS_INVALID_PARAMETER;
63         }
64
65         return gensec_security->ops->unseal_packet(gensec_security,
66                                                    data, length,
67                                                    whole_pdu, pdu_length,
68                                                    sig);
69 }
70
71 _PUBLIC_ NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
72                              const uint8_t *data, size_t length,
73                              const uint8_t *whole_pdu, size_t pdu_length,
74                              const DATA_BLOB *sig)
75 {
76         if (!gensec_security->ops->check_packet) {
77                 return NT_STATUS_NOT_IMPLEMENTED;
78         }
79         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
80                 return NT_STATUS_INVALID_PARAMETER;
81         }
82
83         return gensec_security->ops->check_packet(gensec_security, data, length, whole_pdu, pdu_length, sig);
84 }
85
86 _PUBLIC_ NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
87                             TALLOC_CTX *mem_ctx,
88                             uint8_t *data, size_t length,
89                             const uint8_t *whole_pdu, size_t pdu_length,
90                             DATA_BLOB *sig)
91 {
92         if (!gensec_security->ops->seal_packet) {
93                 return NT_STATUS_NOT_IMPLEMENTED;
94         }
95         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
96                 return NT_STATUS_INVALID_PARAMETER;
97         }
98         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
99                 return NT_STATUS_INVALID_PARAMETER;
100         }
101         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE)) {
102                 return NT_STATUS_INVALID_PARAMETER;
103         }
104
105         return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
106 }
107
108 _PUBLIC_ NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
109                             TALLOC_CTX *mem_ctx,
110                             const uint8_t *data, size_t length,
111                             const uint8_t *whole_pdu, size_t pdu_length,
112                             DATA_BLOB *sig)
113 {
114         if (!gensec_security->ops->sign_packet) {
115                 return NT_STATUS_NOT_IMPLEMENTED;
116         }
117         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
118                 return NT_STATUS_INVALID_PARAMETER;
119         }
120
121         return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
122 }
123
124 _PUBLIC_ size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size)
125 {
126         if (!gensec_security->ops->sig_size) {
127                 return 0;
128         }
129         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
130                 return 0;
131         }
132         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
133                 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE)) {
134                         return 0;
135                 }
136         }
137
138         return gensec_security->ops->sig_size(gensec_security, data_size);
139 }
140
141 _PUBLIC_ size_t gensec_max_wrapped_size(struct gensec_security *gensec_security)
142 {
143         if (!gensec_security->ops->max_wrapped_size) {
144                 return (1 << 17);
145         }
146
147         return gensec_security->ops->max_wrapped_size(gensec_security);
148 }
149
150 _PUBLIC_ size_t gensec_max_input_size(struct gensec_security *gensec_security)
151 {
152         if (!gensec_security->ops->max_input_size) {
153                 return (1 << 17) - gensec_sig_size(gensec_security, 1 << 17);
154         }
155
156         return gensec_security->ops->max_input_size(gensec_security);
157 }
158
159 _PUBLIC_ NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
160                      TALLOC_CTX *mem_ctx,
161                      const DATA_BLOB *in,
162                      DATA_BLOB *out)
163 {
164         if (!gensec_security->ops->wrap) {
165                 return NT_STATUS_NOT_IMPLEMENTED;
166         }
167         return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
168 }
169
170 _PUBLIC_ NTSTATUS gensec_unwrap(struct gensec_security *gensec_security,
171                        TALLOC_CTX *mem_ctx,
172                        const DATA_BLOB *in,
173                        DATA_BLOB *out)
174 {
175         if (!gensec_security->ops->unwrap) {
176                 return NT_STATUS_NOT_IMPLEMENTED;
177         }
178         return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
179 }
180
181 _PUBLIC_ NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
182                                      TALLOC_CTX *mem_ctx,
183                                      DATA_BLOB *session_key)
184 {
185         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SESSION_KEY)) {
186                 return NT_STATUS_NO_USER_SESSION_KEY;
187         }
188
189         if (!gensec_security->ops->session_key) {
190                 return NT_STATUS_NOT_IMPLEMENTED;
191         }
192
193         return gensec_security->ops->session_key(gensec_security, mem_ctx, session_key);
194 }
195
196 const char *gensec_final_auth_type(struct gensec_security *gensec_security)
197 {
198         if (!gensec_security->ops->final_auth_type) {
199                 return gensec_security->ops->name;
200         }
201
202         return gensec_security->ops->final_auth_type(gensec_security);
203 }
204
205 /*
206  * Log details of a successful GENSEC authorization to a service.
207  *
208  * Only successful authorizations are logged, as only these call gensec_session_info()
209  *
210  * The service may later refuse authorization due to an ACL.
211  *
212  */
213 static void log_successful_gensec_authz_event(struct gensec_security *gensec_security,
214                                               struct auth_session_info *session_info)
215 {
216         const struct tsocket_address *remote
217                 = gensec_get_remote_address(gensec_security);
218         const struct tsocket_address *local
219                 = gensec_get_local_address(gensec_security);
220         const char *service_description
221                 = gensec_get_target_service_description(gensec_security);
222         const char *final_auth_type
223                 = gensec_final_auth_type(gensec_security);
224         const char *transport_protection = NULL;
225         if (gensec_security->want_features & GENSEC_FEATURE_SMB_TRANSPORT) {
226                 transport_protection = AUTHZ_TRANSPORT_PROTECTION_SMB;
227         } else if (gensec_security->want_features & GENSEC_FEATURE_LDAPS_TRANSPORT) {
228                 transport_protection = AUTHZ_TRANSPORT_PROTECTION_TLS;
229         } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
230                 transport_protection = AUTHZ_TRANSPORT_PROTECTION_SEAL;
231         } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
232                 transport_protection = AUTHZ_TRANSPORT_PROTECTION_SIGN;
233         } else {
234                 transport_protection = AUTHZ_TRANSPORT_PROTECTION_NONE;
235         }
236         log_successful_authz_event(gensec_security->auth_context->msg_ctx,
237                                    gensec_security->auth_context->lp_ctx,
238                                    remote, local,
239                                    service_description,
240                                    final_auth_type,
241                                    transport_protection,
242                                    session_info);
243 }
244
245
246 /**
247  * Return the credentials of a logged on user, including session keys
248  * etc.
249  *
250  * Only valid after a successful authentication
251  *
252  * May only be called once per authentication.  This will also make an
253  * authorization log entry, as it is already called by all the
254  * callers.
255  *
256  */
257
258 _PUBLIC_ NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
259                                       TALLOC_CTX *mem_ctx,
260                                       struct auth_session_info **session_info)
261 {
262         NTSTATUS status;
263         if (!gensec_security->ops->session_info) {
264                 return NT_STATUS_NOT_IMPLEMENTED;
265         }
266         status = gensec_security->ops->session_info(gensec_security, mem_ctx, session_info);
267
268         if (NT_STATUS_IS_OK(status) && !gensec_security->subcontext
269             && (gensec_security->want_features & GENSEC_FEATURE_NO_AUTHZ_LOG) == 0) {
270                 log_successful_gensec_authz_event(gensec_security, *session_info);
271         }
272
273         return status;
274 }
275
276 _PUBLIC_ void gensec_set_max_update_size(struct gensec_security *gensec_security,
277                                 uint32_t max_update_size)
278 {
279         gensec_security->max_update_size = max_update_size;
280 }
281
282 _PUBLIC_ size_t gensec_max_update_size(struct gensec_security *gensec_security)
283 {
284         if (gensec_security->max_update_size == 0) {
285                 return UINT32_MAX;
286         }
287
288         return gensec_security->max_update_size;
289 }
290
291 static NTSTATUS gensec_verify_features(struct gensec_security *gensec_security)
292 {
293         /*
294          * gensec_want_feature(GENSEC_FEATURE_SIGN)
295          * and
296          * gensec_want_feature(GENSEC_FEATURE_SEAL)
297          * require these flags to be available.
298          */
299         if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
300                 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
301                         DEBUG(0,("Did not manage to negotiate mandatory feature "
302                                  "SIGN\n"));
303                         return NT_STATUS_ACCESS_DENIED;
304                 }
305         }
306         if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
307                 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
308                         DEBUG(0,("Did not manage to negotiate mandatory feature "
309                                  "SEAL\n"));
310                         return NT_STATUS_ACCESS_DENIED;
311                 }
312                 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
313                         DEBUG(0,("Did not manage to negotiate mandatory feature "
314                                  "SIGN for SEAL\n"));
315                         return NT_STATUS_ACCESS_DENIED;
316                 }
317         }
318
319         return NT_STATUS_OK;
320 }
321
322 _PUBLIC_ NTSTATUS gensec_update_ev(struct gensec_security *gensec_security,
323                                    TALLOC_CTX *out_mem_ctx,
324                                    struct tevent_context *ev,
325                                    const DATA_BLOB in, DATA_BLOB *out)
326 {
327         NTSTATUS status;
328         const struct gensec_security_ops *ops = gensec_security->ops;
329         TALLOC_CTX *frame = NULL;
330         struct tevent_req *subreq = NULL;
331         bool ok;
332
333         if (ops->update_send == NULL) {
334
335                 if (ev == NULL) {
336                         frame = talloc_stackframe();
337
338                         ev = samba_tevent_context_init(frame);
339                         if (ev == NULL) {
340                                 status = NT_STATUS_NO_MEMORY;
341                                 goto fail;
342                         }
343
344                         /*
345                          * TODO: remove this hack once the backends
346                          * are fixed.
347                          */
348                         tevent_loop_allow_nesting(ev);
349                 }
350
351                 status = ops->update(gensec_security, out_mem_ctx,
352                                      ev, in, out);
353                 TALLOC_FREE(frame);
354                 if (!NT_STATUS_IS_OK(status)) {
355                         return status;
356                 }
357
358                 /*
359                  * Because callers using the
360                  * gensec_start_mech_by_auth_type() never call
361                  * gensec_want_feature(), it isn't sensible for them
362                  * to have to call gensec_have_feature() manually, and
363                  * these are not points of negotiation, but are
364                  * asserted by the client
365                  */
366                 status = gensec_verify_features(gensec_security);
367                 if (!NT_STATUS_IS_OK(status)) {
368                         return status;
369                 }
370
371                 return NT_STATUS_OK;
372         }
373
374         frame = talloc_stackframe();
375
376         if (ev == NULL) {
377                 ev = samba_tevent_context_init(frame);
378                 if (ev == NULL) {
379                         status = NT_STATUS_NO_MEMORY;
380                         goto fail;
381                 }
382
383                 /*
384                  * TODO: remove this hack once the backends
385                  * are fixed.
386                  */
387                 tevent_loop_allow_nesting(ev);
388         }
389
390         subreq = ops->update_send(frame, ev, gensec_security, in);
391         if (subreq == NULL) {
392                 status = NT_STATUS_NO_MEMORY;
393                 goto fail;
394         }
395         ok = tevent_req_poll_ntstatus(subreq, ev, &status);
396         if (!ok) {
397                 goto fail;
398         }
399         status = ops->update_recv(subreq, out_mem_ctx, out);
400         if (!NT_STATUS_IS_OK(status)) {
401                 goto fail;
402         }
403
404         /*
405          * Because callers using the
406          * gensec_start_mech_by_auth_type() never call
407          * gensec_want_feature(), it isn't sensible for them
408          * to have to call gensec_have_feature() manually, and
409          * these are not points of negotiation, but are
410          * asserted by the client
411          */
412         status = gensec_verify_features(gensec_security);
413  fail:
414         TALLOC_FREE(frame);
415         return status;
416 }
417
418 /**
419  * Next state function for the GENSEC state machine
420  *
421  * @param gensec_security GENSEC State
422  * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
423  * @param in The request, as a DATA_BLOB
424  * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
425  * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
426  *                or NT_STATUS_OK if the user is authenticated.
427  */
428
429 _PUBLIC_ NTSTATUS gensec_update(struct gensec_security *gensec_security,
430                                 TALLOC_CTX *out_mem_ctx,
431                                 const DATA_BLOB in, DATA_BLOB *out)
432 {
433         return gensec_update_ev(gensec_security, out_mem_ctx, NULL, in, out);
434 }
435
436 struct gensec_update_state {
437         const struct gensec_security_ops *ops;
438         struct tevent_req *subreq;
439         struct gensec_security *gensec_security;
440         DATA_BLOB out;
441
442         /*
443          * only for sync backends, we should remove this
444          * once all backends are async.
445          */
446         struct tevent_immediate *im;
447         DATA_BLOB in;
448 };
449
450 static void gensec_update_async_trigger(struct tevent_context *ctx,
451                                         struct tevent_immediate *im,
452                                         void *private_data);
453 static void gensec_update_subreq_done(struct tevent_req *subreq);
454
455 /**
456  * Next state function for the GENSEC state machine async version
457  *
458  * @param mem_ctx The memory context for the request
459  * @param ev The event context for the request
460  * @param gensec_security GENSEC State
461  * @param in The request, as a DATA_BLOB
462  *
463  * @return The request handle or NULL on no memory failure
464  */
465
466 _PUBLIC_ struct tevent_req *gensec_update_send(TALLOC_CTX *mem_ctx,
467                                                struct tevent_context *ev,
468                                                struct gensec_security *gensec_security,
469                                                const DATA_BLOB in)
470 {
471         struct tevent_req *req;
472         struct gensec_update_state *state = NULL;
473
474         req = tevent_req_create(mem_ctx, &state,
475                                 struct gensec_update_state);
476         if (req == NULL) {
477                 return NULL;
478         }
479
480         state->ops = gensec_security->ops;
481         state->gensec_security = gensec_security;
482
483         if (state->ops->update_send == NULL) {
484                 state->in = in;
485                 state->im = tevent_create_immediate(state);
486                 if (tevent_req_nomem(state->im, req)) {
487                         return tevent_req_post(req, ev);
488                 }
489
490                 tevent_schedule_immediate(state->im, ev,
491                                           gensec_update_async_trigger,
492                                           req);
493
494                 return req;
495         }
496
497         state->subreq = state->ops->update_send(state, ev, gensec_security, in);
498         if (tevent_req_nomem(state->subreq, req)) {
499                 return tevent_req_post(req, ev);
500         }
501
502         tevent_req_set_callback(state->subreq,
503                                 gensec_update_subreq_done,
504                                 req);
505
506         return req;
507 }
508
509 static void gensec_update_async_trigger(struct tevent_context *ctx,
510                                         struct tevent_immediate *im,
511                                         void *private_data)
512 {
513         struct tevent_req *req =
514                 talloc_get_type_abort(private_data, struct tevent_req);
515         struct gensec_update_state *state =
516                 tevent_req_data(req, struct gensec_update_state);
517         NTSTATUS status;
518
519         status = state->ops->update(state->gensec_security, state, ctx,
520                                     state->in, &state->out);
521         if (tevent_req_nterror(req, status)) {
522                 return;
523         }
524
525         tevent_req_done(req);
526 }
527
528 static void gensec_update_subreq_done(struct tevent_req *subreq)
529 {
530         struct tevent_req *req =
531                 tevent_req_callback_data(subreq,
532                 struct tevent_req);
533         struct gensec_update_state *state =
534                 tevent_req_data(req,
535                 struct gensec_update_state);
536         NTSTATUS status;
537
538         state->subreq = NULL;
539
540         status = state->ops->update_recv(subreq, state, &state->out);
541         TALLOC_FREE(subreq);
542         if (tevent_req_nterror(req, status)) {
543                 return;
544         }
545
546         /*
547          * Because callers using the
548          * gensec_start_mech_by_authtype() never call
549          * gensec_want_feature(), it isn't sensible for them
550          * to have to call gensec_have_feature() manually, and
551          * these are not points of negotiation, but are
552          * asserted by the client
553          */
554         status = gensec_verify_features(state->gensec_security);
555         if (tevent_req_nterror(req, status)) {
556                 return;
557         }
558
559         tevent_req_done(req);
560 }
561
562 /**
563  * Next state function for the GENSEC state machine
564  *
565  * @param req request state
566  * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
567  * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
568  * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
569  *                or NT_STATUS_OK if the user is authenticated.
570  */
571 _PUBLIC_ NTSTATUS gensec_update_recv(struct tevent_req *req,
572                                      TALLOC_CTX *out_mem_ctx,
573                                      DATA_BLOB *out)
574 {
575         struct gensec_update_state *state =
576                 tevent_req_data(req, struct gensec_update_state);
577         NTSTATUS status;
578
579         if (tevent_req_is_nterror(req, &status)) {
580                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
581                         tevent_req_received(req);
582                         return status;
583                 }
584         } else {
585                 status = NT_STATUS_OK;
586         }
587
588         *out = state->out;
589         talloc_steal(out_mem_ctx, out->data);
590
591         tevent_req_received(req);
592         return status;
593 }
594
595 /**
596  * Set the requirement for a certain feature on the connection
597  *
598  */
599
600 _PUBLIC_ void gensec_want_feature(struct gensec_security *gensec_security,
601                          uint32_t feature)
602 {
603         if (!gensec_security->ops || !gensec_security->ops->want_feature) {
604                 gensec_security->want_features |= feature;
605                 return;
606         }
607         gensec_security->ops->want_feature(gensec_security, feature);
608 }
609
610 /**
611  * Check the requirement for a certain feature on the connection
612  *
613  */
614
615 _PUBLIC_ bool gensec_have_feature(struct gensec_security *gensec_security,
616                          uint32_t feature)
617 {
618         if (!gensec_security->ops || !gensec_security->ops->have_feature) {
619                 return false;
620         }
621
622         /* We might 'have' features that we don't 'want', because the
623          * other end demanded them, or we can't neotiate them off */
624         return gensec_security->ops->have_feature(gensec_security, feature);
625 }
626
627 _PUBLIC_ NTTIME gensec_expire_time(struct gensec_security *gensec_security)
628 {
629         if (!gensec_security->ops->expire_time) {
630                 return GENSEC_EXPIRE_TIME_INFINITY;
631         }
632
633         return gensec_security->ops->expire_time(gensec_security);
634 }
635 /**
636  * Return the credentials structure associated with a GENSEC context
637  *
638  */
639
640 _PUBLIC_ struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security)
641 {
642         if (!gensec_security) {
643                 return NULL;
644         }
645         return gensec_security->credentials;
646 }
647
648 /**
649  * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
650  *
651  * This is used for Kerberos service principal name resolution.
652  */
653
654 _PUBLIC_ NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
655 {
656         gensec_security->target.service = talloc_strdup(gensec_security, service);
657         if (!gensec_security->target.service) {
658                 return NT_STATUS_NO_MEMORY;
659         }
660         return NT_STATUS_OK;
661 }
662
663 _PUBLIC_ const char *gensec_get_target_service(struct gensec_security *gensec_security)
664 {
665         if (gensec_security->target.service) {
666                 return gensec_security->target.service;
667         }
668
669         return "host";
670 }
671
672 /**
673  * Set the target service (such as 'samr') on an GENSEC context - ensures it is talloc()ed.
674  *
675  * This is not the Kerberos service principal, instead this is a
676  * constant value that can be logged as part of authentication and
677  * authorization logging
678  */
679 _PUBLIC_ NTSTATUS gensec_set_target_service_description(struct gensec_security *gensec_security,
680                                                         const char *service)
681 {
682         gensec_security->target.service_description = talloc_strdup(gensec_security, service);
683         if (!gensec_security->target.service_description) {
684                 return NT_STATUS_NO_MEMORY;
685         }
686         return NT_STATUS_OK;
687 }
688
689 _PUBLIC_ const char *gensec_get_target_service_description(struct gensec_security *gensec_security)
690 {
691         if (gensec_security->target.service_description) {
692                 return gensec_security->target.service_description;
693         } else if (gensec_security->target.service) {
694                 return gensec_security->target.service;
695         }
696
697         return NULL;
698 }
699
700 /**
701  * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
702  *
703  */
704
705 _PUBLIC_ NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
706 {
707         gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
708         if (hostname && !gensec_security->target.hostname) {
709                 return NT_STATUS_NO_MEMORY;
710         }
711         return NT_STATUS_OK;
712 }
713
714 _PUBLIC_ const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
715 {
716         /* We allow the target hostname to be overridden for testing purposes */
717         if (gensec_security->settings->target_hostname) {
718                 return gensec_security->settings->target_hostname;
719         }
720
721         if (gensec_security->target.hostname) {
722                 return gensec_security->target.hostname;
723         }
724
725         /* We could add use the 'set sockaddr' call, and do a reverse
726          * lookup, but this would be both insecure (compromising the
727          * way kerberos works) and add DNS timeouts */
728         return NULL;
729 }
730
731 /**
732  * Set (and copy) local and peer socket addresses onto a socket
733  * context on the GENSEC context.
734  *
735  * This is so that kerberos can include these addresses in
736  * cryptographic tokens, to avoid certain attacks.
737  */
738
739 /**
740  * @brief Set the local gensec address.
741  *
742  * @param  gensec_security   The gensec security context to use.
743  *
744  * @param  remote       The local address to set.
745  *
746  * @return              On success NT_STATUS_OK is returned or an NT_STATUS
747  *                      error.
748  */
749 _PUBLIC_ NTSTATUS gensec_set_local_address(struct gensec_security *gensec_security,
750                 const struct tsocket_address *local)
751 {
752         TALLOC_FREE(gensec_security->local_addr);
753
754         if (local == NULL) {
755                 return NT_STATUS_OK;
756         }
757
758         gensec_security->local_addr = tsocket_address_copy(local, gensec_security);
759         if (gensec_security->local_addr == NULL) {
760                 return NT_STATUS_NO_MEMORY;
761         }
762
763         return NT_STATUS_OK;
764 }
765
766 /**
767  * @brief Set the remote gensec address.
768  *
769  * @param  gensec_security   The gensec security context to use.
770  *
771  * @param  remote       The remote address to set.
772  *
773  * @return              On success NT_STATUS_OK is returned or an NT_STATUS
774  *                      error.
775  */
776 _PUBLIC_ NTSTATUS gensec_set_remote_address(struct gensec_security *gensec_security,
777                 const struct tsocket_address *remote)
778 {
779         TALLOC_FREE(gensec_security->remote_addr);
780
781         if (remote == NULL) {
782                 return NT_STATUS_OK;
783         }
784
785         gensec_security->remote_addr = tsocket_address_copy(remote, gensec_security);
786         if (gensec_security->remote_addr == NULL) {
787                 return NT_STATUS_NO_MEMORY;
788         }
789
790         return NT_STATUS_OK;
791 }
792
793 /**
794  * @brief Get the local address from a gensec security context.
795  *
796  * @param  gensec_security   The security context to get the address from.
797  *
798  * @return              The address as tsocket_address which could be NULL if
799  *                      no address is set.
800  */
801 _PUBLIC_ const struct tsocket_address *gensec_get_local_address(struct gensec_security *gensec_security)
802 {
803         if (gensec_security == NULL) {
804                 return NULL;
805         }
806         return gensec_security->local_addr;
807 }
808
809 /**
810  * @brief Get the remote address from a gensec security context.
811  *
812  * @param  gensec_security   The security context to get the address from.
813  *
814  * @return              The address as tsocket_address which could be NULL if
815  *                      no address is set.
816  */
817 _PUBLIC_ const struct tsocket_address *gensec_get_remote_address(struct gensec_security *gensec_security)
818 {
819         if (gensec_security == NULL) {
820                 return NULL;
821         }
822         return gensec_security->remote_addr;
823 }
824
825 /**
826  * Set the target principal (assuming it it known, say from the SPNEGO reply)
827  *  - ensures it is talloc()ed
828  *
829  */
830
831 _PUBLIC_ NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
832 {
833         gensec_security->target.principal = talloc_strdup(gensec_security, principal);
834         if (!gensec_security->target.principal) {
835                 return NT_STATUS_NO_MEMORY;
836         }
837         return NT_STATUS_OK;
838 }
839
840 _PUBLIC_ const char *gensec_get_target_principal(struct gensec_security *gensec_security)
841 {
842         if (gensec_security->target.principal) {
843                 return gensec_security->target.principal;
844         }
845
846         return NULL;
847 }