2 Unix SMB/CIFS implementation.
4 Generic Authentication Interface
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2006
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.
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.
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/>.
24 #include "system/network.h"
26 #include "lib/tsocket/tsocket.h"
27 #include "lib/util/tevent_ntstatus.h"
28 #include "auth/gensec/gensec.h"
31 wrappers for the gensec function pointers
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
,
38 if (!gensec_security
->ops
->unseal_packet
) {
39 return NT_STATUS_NOT_IMPLEMENTED
;
41 if (!gensec_have_feature(gensec_security
, GENSEC_FEATURE_SEAL
)) {
42 return NT_STATUS_INVALID_PARAMETER
;
45 return gensec_security
->ops
->unseal_packet(gensec_security
,
47 whole_pdu
, pdu_length
,
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
,
56 if (!gensec_security
->ops
->check_packet
) {
57 return NT_STATUS_NOT_IMPLEMENTED
;
59 if (!gensec_have_feature(gensec_security
, GENSEC_FEATURE_SIGN
)) {
60 return NT_STATUS_INVALID_PARAMETER
;
63 return gensec_security
->ops
->check_packet(gensec_security
, data
, length
, whole_pdu
, pdu_length
, sig
);
66 _PUBLIC_ NTSTATUS
gensec_seal_packet(struct gensec_security
*gensec_security
,
68 uint8_t *data
, size_t length
,
69 const uint8_t *whole_pdu
, size_t pdu_length
,
72 if (!gensec_security
->ops
->seal_packet
) {
73 return NT_STATUS_NOT_IMPLEMENTED
;
75 if (!gensec_have_feature(gensec_security
, GENSEC_FEATURE_SEAL
)) {
76 return NT_STATUS_INVALID_PARAMETER
;
79 return gensec_security
->ops
->seal_packet(gensec_security
, mem_ctx
, data
, length
, whole_pdu
, pdu_length
, sig
);
82 _PUBLIC_ NTSTATUS
gensec_sign_packet(struct gensec_security
*gensec_security
,
84 const uint8_t *data
, size_t length
,
85 const uint8_t *whole_pdu
, size_t pdu_length
,
88 if (!gensec_security
->ops
->sign_packet
) {
89 return NT_STATUS_NOT_IMPLEMENTED
;
91 if (!gensec_have_feature(gensec_security
, GENSEC_FEATURE_SIGN
)) {
92 return NT_STATUS_INVALID_PARAMETER
;
95 return gensec_security
->ops
->sign_packet(gensec_security
, mem_ctx
, data
, length
, whole_pdu
, pdu_length
, sig
);
98 _PUBLIC_
size_t gensec_sig_size(struct gensec_security
*gensec_security
, size_t data_size
)
100 if (!gensec_security
->ops
->sig_size
) {
103 if (!gensec_have_feature(gensec_security
, GENSEC_FEATURE_SIGN
)) {
107 return gensec_security
->ops
->sig_size(gensec_security
, data_size
);
110 size_t gensec_max_wrapped_size(struct gensec_security
*gensec_security
)
112 if (!gensec_security
->ops
->max_wrapped_size
) {
116 return gensec_security
->ops
->max_wrapped_size(gensec_security
);
119 size_t gensec_max_input_size(struct gensec_security
*gensec_security
)
121 if (!gensec_security
->ops
->max_input_size
) {
122 return (1 << 17) - gensec_sig_size(gensec_security
, 1 << 17);
125 return gensec_security
->ops
->max_input_size(gensec_security
);
128 _PUBLIC_ NTSTATUS
gensec_wrap(struct gensec_security
*gensec_security
,
133 if (!gensec_security
->ops
->wrap
) {
134 return NT_STATUS_NOT_IMPLEMENTED
;
136 return gensec_security
->ops
->wrap(gensec_security
, mem_ctx
, in
, out
);
139 _PUBLIC_ NTSTATUS
gensec_unwrap(struct gensec_security
*gensec_security
,
144 if (!gensec_security
->ops
->unwrap
) {
145 return NT_STATUS_NOT_IMPLEMENTED
;
147 return gensec_security
->ops
->unwrap(gensec_security
, mem_ctx
, in
, out
);
150 _PUBLIC_ NTSTATUS
gensec_session_key(struct gensec_security
*gensec_security
,
152 DATA_BLOB
*session_key
)
154 if (!gensec_security
->ops
->session_key
) {
155 return NT_STATUS_NOT_IMPLEMENTED
;
157 if (!gensec_have_feature(gensec_security
, GENSEC_FEATURE_SESSION_KEY
)) {
158 return NT_STATUS_NO_USER_SESSION_KEY
;
161 return gensec_security
->ops
->session_key(gensec_security
, mem_ctx
, session_key
);
165 * Return the credentials of a logged on user, including session keys
168 * Only valid after a successful authentication
170 * May only be called once per authentication.
174 _PUBLIC_ NTSTATUS
gensec_session_info(struct gensec_security
*gensec_security
,
176 struct auth_session_info
**session_info
)
178 if (!gensec_security
->ops
->session_info
) {
179 return NT_STATUS_NOT_IMPLEMENTED
;
181 return gensec_security
->ops
->session_info(gensec_security
, mem_ctx
, session_info
);
185 * Next state function for the GENSEC state machine
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.
195 _PUBLIC_ NTSTATUS
gensec_update(struct gensec_security
*gensec_security
, TALLOC_CTX
*out_mem_ctx
,
196 const DATA_BLOB in
, DATA_BLOB
*out
)
198 return gensec_security
->ops
->update(gensec_security
, out_mem_ctx
, in
, out
);
201 struct gensec_update_state
{
202 struct tevent_immediate
*im
;
203 struct gensec_security
*gensec_security
;
208 static void gensec_update_async_trigger(struct tevent_context
*ctx
,
209 struct tevent_immediate
*im
,
212 * Next state function for the GENSEC state machine async version
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
219 * @return The request handle or NULL on no memory failure
222 _PUBLIC_
struct tevent_req
*gensec_update_send(TALLOC_CTX
*mem_ctx
,
223 struct tevent_context
*ev
,
224 struct gensec_security
*gensec_security
,
227 struct tevent_req
*req
;
228 struct gensec_update_state
*state
= NULL
;
230 req
= tevent_req_create(mem_ctx
, &state
,
231 struct gensec_update_state
);
236 state
->gensec_security
= gensec_security
;
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
);
244 tevent_schedule_immediate(state
->im
, ev
,
245 gensec_update_async_trigger
,
251 static void gensec_update_async_trigger(struct tevent_context
*ctx
,
252 struct tevent_immediate
*im
,
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
);
261 status
= gensec_update(state
->gensec_security
, state
,
262 state
->in
, &state
->out
);
263 if (tevent_req_nterror(req
, status
)) {
267 tevent_req_done(req
);
271 * Next state function for the GENSEC state machine
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.
279 _PUBLIC_ NTSTATUS
gensec_update_recv(struct tevent_req
*req
,
280 TALLOC_CTX
*out_mem_ctx
,
283 struct gensec_update_state
*state
=
284 tevent_req_data(req
, struct gensec_update_state
);
287 if (tevent_req_is_nterror(req
, &status
)) {
288 if (!NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
289 tevent_req_received(req
);
293 status
= NT_STATUS_OK
;
297 talloc_steal(out_mem_ctx
, out
->data
);
299 tevent_req_received(req
);
304 * Set the requirement for a certain feature on the connection
308 _PUBLIC_
void gensec_want_feature(struct gensec_security
*gensec_security
,
311 if (!gensec_security
->ops
|| !gensec_security
->ops
->want_feature
) {
312 gensec_security
->want_features
|= feature
;
315 gensec_security
->ops
->want_feature(gensec_security
, feature
);
319 * Check the requirement for a certain feature on the connection
323 _PUBLIC_
bool gensec_have_feature(struct gensec_security
*gensec_security
,
326 if (!gensec_security
->ops
->have_feature
) {
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
);
336 * Return the credentials structure associated with a GENSEC context
340 _PUBLIC_
struct cli_credentials
*gensec_get_credentials(struct gensec_security
*gensec_security
)
342 if (!gensec_security
) {
345 return gensec_security
->credentials
;
349 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
353 _PUBLIC_ NTSTATUS
gensec_set_target_service(struct gensec_security
*gensec_security
, const char *service
)
355 gensec_security
->target
.service
= talloc_strdup(gensec_security
, service
);
356 if (!gensec_security
->target
.service
) {
357 return NT_STATUS_NO_MEMORY
;
362 _PUBLIC_
const char *gensec_get_target_service(struct gensec_security
*gensec_security
)
364 if (gensec_security
->target
.service
) {
365 return gensec_security
->target
.service
;
372 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
376 _PUBLIC_ NTSTATUS
gensec_set_target_hostname(struct gensec_security
*gensec_security
, const char *hostname
)
378 gensec_security
->target
.hostname
= talloc_strdup(gensec_security
, hostname
);
379 if (hostname
&& !gensec_security
->target
.hostname
) {
380 return NT_STATUS_NO_MEMORY
;
385 _PUBLIC_
const char *gensec_get_target_hostname(struct gensec_security
*gensec_security
)
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
;
392 if (gensec_security
->target
.hostname
) {
393 return gensec_security
->target
.hostname
;
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 */
403 * Set (and talloc_reference) local and peer socket addresses onto a socket
404 * context on the GENSEC context.
406 * This is so that kerberos can include these addresses in
407 * cryptographic tokens, to avoid certain attacks.
411 * @brief Set the local gensec address.
413 * @param gensec_security The gensec security context to use.
415 * @param remote The local address to set.
417 * @return On success NT_STATUS_OK is returned or an NT_STATUS
420 _PUBLIC_ NTSTATUS
gensec_set_local_address(struct gensec_security
*gensec_security
,
421 const struct tsocket_address
*local
)
423 TALLOC_FREE(gensec_security
->local_addr
);
429 gensec_security
->local_addr
= tsocket_address_copy(local
, gensec_security
);
430 if (gensec_security
->local_addr
== NULL
) {
431 return NT_STATUS_NO_MEMORY
;
438 * @brief Set the remote gensec address.
440 * @param gensec_security The gensec security context to use.
442 * @param remote The remote address to set.
444 * @return On success NT_STATUS_OK is returned or an NT_STATUS
447 _PUBLIC_ NTSTATUS
gensec_set_remote_address(struct gensec_security
*gensec_security
,
448 const struct tsocket_address
*remote
)
450 TALLOC_FREE(gensec_security
->remote_addr
);
452 if (remote
== NULL
) {
456 gensec_security
->remote_addr
= tsocket_address_copy(remote
, gensec_security
);
457 if (gensec_security
->remote_addr
== NULL
) {
458 return NT_STATUS_NO_MEMORY
;
465 * @brief Get the local address from a gensec security context.
467 * @param gensec_security The security context to get the address from.
469 * @return The address as tsocket_address which could be NULL if
472 _PUBLIC_
const struct tsocket_address
*gensec_get_local_address(struct gensec_security
*gensec_security
)
474 if (gensec_security
== NULL
) {
477 return gensec_security
->local_addr
;
481 * @brief Get the remote address from a gensec security context.
483 * @param gensec_security The security context to get the address from.
485 * @return The address as tsocket_address which could be NULL if
488 _PUBLIC_
const struct tsocket_address
*gensec_get_remote_address(struct gensec_security
*gensec_security
)
490 if (gensec_security
== NULL
) {
493 return gensec_security
->remote_addr
;
497 * Set the target principal (assuming it it known, say from the SPNEGO reply)
498 * - ensures it is talloc()ed
502 _PUBLIC_ NTSTATUS
gensec_set_target_principal(struct gensec_security
*gensec_security
, const char *principal
)
504 gensec_security
->target
.principal
= talloc_strdup(gensec_security
, principal
);
505 if (!gensec_security
->target
.principal
) {
506 return NT_STATUS_NO_MEMORY
;
511 const char *gensec_get_target_principal(struct gensec_security
*gensec_security
)
513 if (gensec_security
->target
.principal
) {
514 return gensec_security
->target
.principal
;