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"
29 #include "librpc/rpc/dcerpc.h"
32 wrappers for the gensec function pointers
34 _PUBLIC_ NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
35 uint8_t *data, size_t length,
36 const uint8_t *whole_pdu, size_t pdu_length,
39 if (!gensec_security->ops->unseal_packet) {
40 return NT_STATUS_NOT_IMPLEMENTED;
42 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
43 return NT_STATUS_INVALID_PARAMETER;
46 return gensec_security->ops->unseal_packet(gensec_security,
48 whole_pdu, pdu_length,
52 _PUBLIC_ NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
53 const uint8_t *data, size_t length,
54 const uint8_t *whole_pdu, size_t pdu_length,
57 if (!gensec_security->ops->check_packet) {
58 return NT_STATUS_NOT_IMPLEMENTED;
60 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
61 return NT_STATUS_INVALID_PARAMETER;
64 return gensec_security->ops->check_packet(gensec_security, data, length, whole_pdu, pdu_length, sig);
67 _PUBLIC_ NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
69 uint8_t *data, size_t length,
70 const uint8_t *whole_pdu, size_t pdu_length,
73 if (!gensec_security->ops->seal_packet) {
74 return NT_STATUS_NOT_IMPLEMENTED;
76 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
77 return NT_STATUS_INVALID_PARAMETER;
80 return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
83 _PUBLIC_ NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
85 const uint8_t *data, size_t length,
86 const uint8_t *whole_pdu, size_t pdu_length,
89 if (!gensec_security->ops->sign_packet) {
90 return NT_STATUS_NOT_IMPLEMENTED;
92 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
93 return NT_STATUS_INVALID_PARAMETER;
96 return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
99 _PUBLIC_ size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size)
101 if (!gensec_security->ops->sig_size) {
104 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
108 return gensec_security->ops->sig_size(gensec_security, data_size);
111 size_t gensec_max_wrapped_size(struct gensec_security *gensec_security)
113 if (!gensec_security->ops->max_wrapped_size) {
117 return gensec_security->ops->max_wrapped_size(gensec_security);
120 size_t gensec_max_input_size(struct gensec_security *gensec_security)
122 if (!gensec_security->ops->max_input_size) {
123 return (1 << 17) - gensec_sig_size(gensec_security, 1 << 17);
126 return gensec_security->ops->max_input_size(gensec_security);
129 _PUBLIC_ NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
134 if (!gensec_security->ops->wrap) {
135 return NT_STATUS_NOT_IMPLEMENTED;
137 return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
140 _PUBLIC_ NTSTATUS gensec_unwrap(struct gensec_security *gensec_security,
145 if (!gensec_security->ops->unwrap) {
146 return NT_STATUS_NOT_IMPLEMENTED;
148 return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
151 _PUBLIC_ NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
153 DATA_BLOB *session_key)
155 if (!gensec_security->ops->session_key) {
156 return NT_STATUS_NOT_IMPLEMENTED;
158 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SESSION_KEY)) {
159 return NT_STATUS_NO_USER_SESSION_KEY;
162 return gensec_security->ops->session_key(gensec_security, mem_ctx, session_key);
166 * Return the credentials of a logged on user, including session keys
169 * Only valid after a successful authentication
171 * May only be called once per authentication.
175 _PUBLIC_ NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
177 struct auth_session_info **session_info)
179 if (!gensec_security->ops->session_info) {
180 return NT_STATUS_NOT_IMPLEMENTED;
182 return gensec_security->ops->session_info(gensec_security, mem_ctx, session_info);
186 * Next state function for the GENSEC state machine
188 * @param gensec_security GENSEC State
189 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
190 * @param in The request, as a DATA_BLOB
191 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
192 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
193 * or NT_STATUS_OK if the user is authenticated.
196 _PUBLIC_ NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
197 const DATA_BLOB in, DATA_BLOB *out)
201 status = gensec_security->ops->update(gensec_security, out_mem_ctx,
203 if (!NT_STATUS_IS_OK(status)) {
208 * Because callers using the
209 * gensec_start_mech_by_auth_type() never call
210 * gensec_want_feature(), it isn't sensible for them
211 * to have to call gensec_have_feature() manually, and
212 * these are not points of negotiation, but are
213 * asserted by the client
215 switch (gensec_security->dcerpc_auth_level) {
216 case DCERPC_AUTH_LEVEL_INTEGRITY:
217 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
218 DEBUG(0,("Did not manage to negotiate mandetory feature "
219 "SIGN for dcerpc auth_level %u\n",
220 gensec_security->dcerpc_auth_level));
221 return NT_STATUS_ACCESS_DENIED;
224 case DCERPC_AUTH_LEVEL_PRIVACY:
225 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
226 DEBUG(0,("Did not manage to negotiate mandetory feature "
227 "SIGN for dcerpc auth_level %u\n",
228 gensec_security->dcerpc_auth_level));
229 return NT_STATUS_ACCESS_DENIED;
231 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
232 DEBUG(0,("Did not manage to negotiate mandetory feature "
233 "SEAL for dcerpc auth_level %u\n",
234 gensec_security->dcerpc_auth_level));
235 return NT_STATUS_ACCESS_DENIED;
245 struct gensec_update_state {
246 struct tevent_immediate *im;
247 struct gensec_security *gensec_security;
252 static void gensec_update_async_trigger(struct tevent_context *ctx,
253 struct tevent_immediate *im,
256 * Next state function for the GENSEC state machine async version
258 * @param mem_ctx The memory context for the request
259 * @param ev The event context for the request
260 * @param gensec_security GENSEC State
261 * @param in The request, as a DATA_BLOB
263 * @return The request handle or NULL on no memory failure
266 _PUBLIC_ struct tevent_req *gensec_update_send(TALLOC_CTX *mem_ctx,
267 struct tevent_context *ev,
268 struct gensec_security *gensec_security,
271 struct tevent_req *req;
272 struct gensec_update_state *state = NULL;
274 req = tevent_req_create(mem_ctx, &state,
275 struct gensec_update_state);
280 state->gensec_security = gensec_security;
282 state->out = data_blob(NULL, 0);
283 state->im = tevent_create_immediate(state);
284 if (tevent_req_nomem(state->im, req)) {
285 return tevent_req_post(req, ev);
288 tevent_schedule_immediate(state->im, ev,
289 gensec_update_async_trigger,
295 static void gensec_update_async_trigger(struct tevent_context *ctx,
296 struct tevent_immediate *im,
299 struct tevent_req *req =
300 talloc_get_type_abort(private_data, struct tevent_req);
301 struct gensec_update_state *state =
302 tevent_req_data(req, struct gensec_update_state);
305 status = gensec_update(state->gensec_security, state,
306 state->in, &state->out);
307 if (tevent_req_nterror(req, status)) {
311 tevent_req_done(req);
315 * Next state function for the GENSEC state machine
317 * @param req request state
318 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
319 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
320 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
321 * or NT_STATUS_OK if the user is authenticated.
323 _PUBLIC_ NTSTATUS gensec_update_recv(struct tevent_req *req,
324 TALLOC_CTX *out_mem_ctx,
327 struct gensec_update_state *state =
328 tevent_req_data(req, struct gensec_update_state);
331 if (tevent_req_is_nterror(req, &status)) {
332 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
333 tevent_req_received(req);
337 status = NT_STATUS_OK;
341 talloc_steal(out_mem_ctx, out->data);
343 tevent_req_received(req);
348 * Set the requirement for a certain feature on the connection
352 _PUBLIC_ void gensec_want_feature(struct gensec_security *gensec_security,
355 if (!gensec_security->ops || !gensec_security->ops->want_feature) {
356 gensec_security->want_features |= feature;
359 gensec_security->ops->want_feature(gensec_security, feature);
363 * Check the requirement for a certain feature on the connection
367 _PUBLIC_ bool gensec_have_feature(struct gensec_security *gensec_security,
370 if (!gensec_security->ops->have_feature) {
374 /* We might 'have' features that we don't 'want', because the
375 * other end demanded them, or we can't neotiate them off */
376 return gensec_security->ops->have_feature(gensec_security, feature);
380 * Return the credentials structure associated with a GENSEC context
384 _PUBLIC_ struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security)
386 if (!gensec_security) {
389 return gensec_security->credentials;
393 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
397 _PUBLIC_ NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
399 gensec_security->target.service = talloc_strdup(gensec_security, service);
400 if (!gensec_security->target.service) {
401 return NT_STATUS_NO_MEMORY;
406 _PUBLIC_ const char *gensec_get_target_service(struct gensec_security *gensec_security)
408 if (gensec_security->target.service) {
409 return gensec_security->target.service;
416 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
420 _PUBLIC_ NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
422 gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
423 if (hostname && !gensec_security->target.hostname) {
424 return NT_STATUS_NO_MEMORY;
429 _PUBLIC_ const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
431 /* We allow the target hostname to be overriden for testing purposes */
432 if (gensec_security->settings->target_hostname) {
433 return gensec_security->settings->target_hostname;
436 if (gensec_security->target.hostname) {
437 return gensec_security->target.hostname;
440 /* We could add use the 'set sockaddr' call, and do a reverse
441 * lookup, but this would be both insecure (compromising the
442 * way kerberos works) and add DNS timeouts */
447 * Set (and talloc_reference) local and peer socket addresses onto a socket
448 * context on the GENSEC context.
450 * This is so that kerberos can include these addresses in
451 * cryptographic tokens, to avoid certain attacks.
455 * @brief Set the local gensec address.
457 * @param gensec_security The gensec security context to use.
459 * @param remote The local address to set.
461 * @return On success NT_STATUS_OK is returned or an NT_STATUS
464 _PUBLIC_ NTSTATUS gensec_set_local_address(struct gensec_security *gensec_security,
465 const struct tsocket_address *local)
467 TALLOC_FREE(gensec_security->local_addr);
473 gensec_security->local_addr = tsocket_address_copy(local, gensec_security);
474 if (gensec_security->local_addr == NULL) {
475 return NT_STATUS_NO_MEMORY;
482 * @brief Set the remote gensec address.
484 * @param gensec_security The gensec security context to use.
486 * @param remote The remote address to set.
488 * @return On success NT_STATUS_OK is returned or an NT_STATUS
491 _PUBLIC_ NTSTATUS gensec_set_remote_address(struct gensec_security *gensec_security,
492 const struct tsocket_address *remote)
494 TALLOC_FREE(gensec_security->remote_addr);
496 if (remote == NULL) {
500 gensec_security->remote_addr = tsocket_address_copy(remote, gensec_security);
501 if (gensec_security->remote_addr == NULL) {
502 return NT_STATUS_NO_MEMORY;
509 * @brief Get the local address from a gensec security context.
511 * @param gensec_security The security context to get the address from.
513 * @return The address as tsocket_address which could be NULL if
516 _PUBLIC_ const struct tsocket_address *gensec_get_local_address(struct gensec_security *gensec_security)
518 if (gensec_security == NULL) {
521 return gensec_security->local_addr;
525 * @brief Get the remote address from a gensec security context.
527 * @param gensec_security The security context to get the address from.
529 * @return The address as tsocket_address which could be NULL if
532 _PUBLIC_ const struct tsocket_address *gensec_get_remote_address(struct gensec_security *gensec_security)
534 if (gensec_security == NULL) {
537 return gensec_security->remote_addr;
541 * Set the target principal (assuming it it known, say from the SPNEGO reply)
542 * - ensures it is talloc()ed
546 _PUBLIC_ NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
548 gensec_security->target.principal = talloc_strdup(gensec_security, principal);
549 if (!gensec_security->target.principal) {
550 return NT_STATUS_NO_MEMORY;
555 const char *gensec_get_target_principal(struct gensec_security *gensec_security)
557 if (gensec_security->target.principal) {
558 return gensec_security->target.principal;