r8774: make some gensec errors a bit less verbose
[Samba/ekacnet.git] / source / auth / gensec / gensec.c
blobb500a09fdce439b89bf949fbdd261efa40d59662
1 /*
2 Unix SMB/CIFS implementation.
4 Generic Authentication Interface
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
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 2 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, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "includes.h"
25 #include "auth/auth.h"
26 #include "lib/events/events.h"
28 /* the list of currently registered GENSEC backends */
29 const static struct gensec_security_ops **generic_security_ops;
30 static int gensec_num_backends;
32 static const struct gensec_security_ops *gensec_security_by_authtype(uint8_t auth_type)
34 int i;
35 for (i=0; i < gensec_num_backends; i++) {
36 if (generic_security_ops[i]->auth_type == auth_type) {
37 return generic_security_ops[i];
41 return NULL;
44 static const struct gensec_security_ops *gensec_security_by_oid(const char *oid_string)
46 int i, j;
47 for (i=0; i < gensec_num_backends; i++) {
48 if (generic_security_ops[i]->oid) {
49 for (j=0; generic_security_ops[i]->oid[j]; j++) {
50 if (generic_security_ops[i]->oid[j] &&
51 (strcmp(generic_security_ops[i]->oid[j], oid_string) == 0)) {
52 return generic_security_ops[i];
58 return NULL;
61 static const struct gensec_security_ops *gensec_security_by_sasl_name(const char *sasl_name)
63 int i;
64 for (i=0; i < gensec_num_backends; i++) {
65 if (generic_security_ops[i]->sasl_name
66 && (strcmp(generic_security_ops[i]->sasl_name, sasl_name) == 0)) {
67 return generic_security_ops[i];
71 return NULL;
74 static const struct gensec_security_ops *gensec_security_by_name(const char *name)
76 int i;
77 for (i=0; i < gensec_num_backends; i++) {
78 if (generic_security_ops[i]->name
79 && (strcmp(generic_security_ops[i]->name, name) == 0)) {
80 return generic_security_ops[i];
84 return NULL;
87 const struct gensec_security_ops **gensec_security_all(int *num_backends_out)
89 *num_backends_out = gensec_num_backends;
90 return generic_security_ops;
93 /**
94 * Return a unique list of security subsystems from those specified in
95 * the OID list. That is, where two OIDs refer to the same module,
96 * return that module only once
98 * The list is in the exact order of the OIDs asked for, where available.
101 const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(TALLOC_CTX *mem_ctx,
102 const char **oid_strings,
103 const char *skip)
105 struct gensec_security_ops_wrapper *backends_out;
106 const struct gensec_security_ops **backends;
107 int i, j, k, oid_idx;
108 int num_backends_out = 0;
109 int num_backends;
111 if (!oid_strings) {
112 return NULL;
115 backends = gensec_security_all(&num_backends);
117 backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
118 if (!backends_out) {
119 return NULL;
121 backends_out[0].op = NULL;
122 backends_out[0].oid = NULL;
124 for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) {
125 if (strcmp(oid_strings[oid_idx], skip) == 0) {
126 continue;
129 for (i=0; i < num_backends; i++) {
130 if (!backends[i]->oid) {
131 continue;
133 for (j=0; backends[i]->oid[j]; j++) {
134 if (!backends[i]->oid[j] ||
135 !(strcmp(backends[i]->oid[j],
136 oid_strings[oid_idx]) == 0)) {
137 continue;
140 for (k=0; backends_out[k].op; k++) {
141 if (backends_out[k].op == backends[i]) {
142 break;
146 if (k < num_backends_out) {
147 /* already in there */
148 continue;
151 backends_out = talloc_realloc(mem_ctx, backends_out,
152 struct gensec_security_ops_wrapper,
153 num_backends_out + 2);
154 if (!backends_out) {
155 return NULL;
158 backends_out[num_backends_out].op = backends[i];
159 backends_out[num_backends_out].oid = backends[i]->oid[j];
160 num_backends_out++;
161 backends_out[num_backends_out].op = NULL;
162 backends_out[num_backends_out].oid = NULL;
166 return backends_out;
170 * Return OIDS from the security subsystems listed
173 const char **gensec_security_oids_from_ops(TALLOC_CTX *mem_ctx,
174 const struct gensec_security_ops **ops,
175 int num_backends,
176 const char *skip)
178 int i;
179 int j = 0;
180 int k;
181 const char **oid_list;
182 if (!ops) {
183 return NULL;
185 oid_list = talloc_array(mem_ctx, const char *, 1);
186 if (!oid_list) {
187 return NULL;
190 for (i=0; i<num_backends; i++) {
191 if (!ops[i]->oid) {
192 continue;
195 for (k = 0; ops[i]->oid[k]; k++) {
196 if (skip && strcmp(skip, ops[i]->oid[k])==0) {
197 } else {
198 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
199 if (!oid_list) {
200 return NULL;
202 oid_list[j] = ops[i]->oid[k];
203 j++;
207 oid_list[j] = NULL;
208 return oid_list;
213 * Return all the security subsystems currently enabled in GENSEC
216 const char **gensec_security_oids(TALLOC_CTX *mem_ctx, const char *skip)
218 int num_backends;
219 const struct gensec_security_ops **ops = gensec_security_all(&num_backends);
220 return gensec_security_oids_from_ops(mem_ctx, ops,
221 num_backends, skip);
227 Start the GENSEC system, returning a context pointer.
228 @param mem_ctx The parent TALLOC memory context.
229 @param gensec_security Returned GENSEC context pointer.
230 @note The mem_ctx is only a parent and may be NULL.
232 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
233 struct gensec_security **gensec_security,
234 struct event_context *ev)
236 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
237 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
239 (*gensec_security)->ops = NULL;
241 ZERO_STRUCT((*gensec_security)->target);
243 (*gensec_security)->subcontext = False;
244 (*gensec_security)->want_features = 0;
246 if (ev == NULL) {
247 ev = event_context_init(*gensec_security);
248 if (ev == NULL) {
249 talloc_free(*gensec_security);
250 return NT_STATUS_NO_MEMORY;
254 (*gensec_security)->event_ctx = ev;
256 return NT_STATUS_OK;
259 /**
260 * Start a GENSEC subcontext, with a copy of the properties of the parent
261 * @param mem_ctx The parent TALLOC memory context.
262 * @param parent The parent GENSEC context
263 * @param gensec_security Returned GENSEC context pointer.
264 * @note Used by SPNEGO in particular, for the actual implementation mechanism
267 NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
268 struct gensec_security *parent,
269 struct gensec_security **gensec_security)
271 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
272 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
274 (**gensec_security) = *parent;
275 (*gensec_security)->ops = NULL;
276 (*gensec_security)->private_data = NULL;
278 (*gensec_security)->subcontext = True;
279 (*gensec_security)->event_ctx = parent->event_ctx;
281 return NT_STATUS_OK;
285 Start the GENSEC system, in client mode, returning a context pointer.
286 @param mem_ctx The parent TALLOC memory context.
287 @param gensec_security Returned GENSEC context pointer.
288 @note The mem_ctx is only a parent and may be NULL.
290 NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
291 struct gensec_security **gensec_security,
292 struct event_context *ev)
294 NTSTATUS status;
295 status = gensec_start(mem_ctx, gensec_security, ev);
296 if (!NT_STATUS_IS_OK(status)) {
297 return status;
299 (*gensec_security)->gensec_role = GENSEC_CLIENT;
301 return status;
305 Start the GENSEC system, in server mode, returning a context pointer.
306 @param mem_ctx The parent TALLOC memory context.
307 @param gensec_security Returned GENSEC context pointer.
308 @note The mem_ctx is only a parent and may be NULL.
310 NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
311 struct gensec_security **gensec_security,
312 struct event_context *ev)
314 NTSTATUS status;
315 status = gensec_start(mem_ctx, gensec_security, ev);
316 if (!NT_STATUS_IS_OK(status)) {
317 return status;
319 (*gensec_security)->gensec_role = GENSEC_SERVER;
321 return status;
324 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
326 NTSTATUS status;
327 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
328 gensec_security->subcontext ? "sub" : "",
329 gensec_security->ops->name));
330 switch (gensec_security->gensec_role) {
331 case GENSEC_CLIENT:
332 if (gensec_security->ops->client_start) {
333 status = gensec_security->ops->client_start(gensec_security);
334 if (!NT_STATUS_IS_OK(status)) {
335 DEBUG(2, ("Failed to start GENSEC client mech %s: %s\n",
336 gensec_security->ops->name, nt_errstr(status)));
338 return status;
340 case GENSEC_SERVER:
341 if (gensec_security->ops->server_start) {
342 status = gensec_security->ops->server_start(gensec_security);
343 if (!NT_STATUS_IS_OK(status)) {
344 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
345 gensec_security->ops->name, nt_errstr(status)));
347 return status;
350 return NT_STATUS_INVALID_PARAMETER;
353 /**
354 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
355 * @param gensec_security GENSEC context pointer.
356 * @param auth_type DCERPC auth type
357 * @param auth_level DCERPC auth level
360 NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
361 uint8_t auth_type, uint8_t auth_level)
363 gensec_security->ops = gensec_security_by_authtype(auth_type);
364 if (!gensec_security->ops) {
365 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
366 return NT_STATUS_INVALID_PARAMETER;
368 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
369 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
370 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
371 } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
372 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
373 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
374 } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
375 /* Default features */
376 } else {
377 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
378 auth_level));
379 return NT_STATUS_INVALID_PARAMETER;
382 return gensec_start_mech(gensec_security);
385 const char *gensec_get_name_by_authtype(uint8_t authtype)
387 const struct gensec_security_ops *ops;
388 ops = gensec_security_by_authtype(authtype);
389 if (ops) {
390 return ops->name;
392 return NULL;
396 const char *gensec_get_name_by_oid(const char *oid_string)
398 const struct gensec_security_ops *ops;
399 ops = gensec_security_by_oid(oid_string);
400 if (ops) {
401 return ops->name;
403 return NULL;
407 /**
408 * Start a GENSEC sub-mechanism with a specifed mechansim structure, used in SPNEGO
412 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
413 const struct gensec_security_ops *ops)
415 gensec_security->ops = ops;
416 return gensec_start_mech(gensec_security);
419 /**
420 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
422 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
423 * well-known #define to hook it in.
426 NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
427 const char *mech_oid)
429 gensec_security->ops = gensec_security_by_oid(mech_oid);
430 if (!gensec_security->ops) {
431 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
432 return NT_STATUS_INVALID_PARAMETER;
434 return gensec_start_mech(gensec_security);
437 /**
438 * Start a GENSEC sub-mechanism by a well know SASL name
442 NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
443 const char *sasl_name)
445 gensec_security->ops = gensec_security_by_sasl_name(sasl_name);
446 if (!gensec_security->ops) {
447 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
448 return NT_STATUS_INVALID_PARAMETER;
450 return gensec_start_mech(gensec_security);
454 wrappers for the gensec function pointers
456 NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
457 TALLOC_CTX *mem_ctx,
458 uint8_t *data, size_t length,
459 const uint8_t *whole_pdu, size_t pdu_length,
460 const DATA_BLOB *sig)
462 if (!gensec_security->ops->unseal_packet) {
463 return NT_STATUS_NOT_IMPLEMENTED;
465 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
466 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
467 return gensec_check_packet(gensec_security, mem_ctx,
468 data, length,
469 whole_pdu, pdu_length,
470 sig);
472 return NT_STATUS_INVALID_PARAMETER;
475 return gensec_security->ops->unseal_packet(gensec_security, mem_ctx,
476 data, length,
477 whole_pdu, pdu_length,
478 sig);
481 NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
482 TALLOC_CTX *mem_ctx,
483 const uint8_t *data, size_t length,
484 const uint8_t *whole_pdu, size_t pdu_length,
485 const DATA_BLOB *sig)
487 if (!gensec_security->ops->check_packet) {
488 return NT_STATUS_NOT_IMPLEMENTED;
490 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
491 return NT_STATUS_INVALID_PARAMETER;
494 return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
497 NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
498 TALLOC_CTX *mem_ctx,
499 uint8_t *data, size_t length,
500 const uint8_t *whole_pdu, size_t pdu_length,
501 DATA_BLOB *sig)
503 if (!gensec_security->ops->seal_packet) {
504 return NT_STATUS_NOT_IMPLEMENTED;
506 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
507 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
508 return gensec_sign_packet(gensec_security, mem_ctx,
509 data, length,
510 whole_pdu, pdu_length,
511 sig);
513 return NT_STATUS_INVALID_PARAMETER;
516 return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
519 NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
520 TALLOC_CTX *mem_ctx,
521 const uint8_t *data, size_t length,
522 const uint8_t *whole_pdu, size_t pdu_length,
523 DATA_BLOB *sig)
525 if (!gensec_security->ops->sign_packet) {
526 return NT_STATUS_NOT_IMPLEMENTED;
528 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
529 return NT_STATUS_INVALID_PARAMETER;
532 return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
535 size_t gensec_sig_size(struct gensec_security *gensec_security)
537 if (!gensec_security->ops->sig_size) {
538 return 0;
540 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
541 return 0;
544 return gensec_security->ops->sig_size(gensec_security);
547 NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
548 TALLOC_CTX *mem_ctx,
549 const DATA_BLOB *in,
550 DATA_BLOB *out)
552 if (!gensec_security->ops->wrap) {
553 return NT_STATUS_NOT_IMPLEMENTED;
555 return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
558 NTSTATUS gensec_unwrap(struct gensec_security *gensec_security,
559 TALLOC_CTX *mem_ctx,
560 const DATA_BLOB *in,
561 DATA_BLOB *out)
563 if (!gensec_security->ops->unwrap) {
564 return NT_STATUS_NOT_IMPLEMENTED;
566 return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
569 NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
570 DATA_BLOB *session_key)
572 if (!gensec_security->ops->session_key) {
573 return NT_STATUS_NOT_IMPLEMENTED;
575 return gensec_security->ops->session_key(gensec_security, session_key);
578 /**
579 * Return the credentials of a logged on user, including session keys
580 * etc.
582 * Only valid after a successful authentication
584 * May only be called once per authentication.
588 NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
589 struct auth_session_info **session_info)
591 if (!gensec_security->ops->session_info) {
592 return NT_STATUS_NOT_IMPLEMENTED;
594 return gensec_security->ops->session_info(gensec_security, session_info);
598 * Next state function for the GENSEC state machine
600 * @param gensec_security GENSEC State
601 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
602 * @param in The request, as a DATA_BLOB
603 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
604 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
605 * or NT_STATUS_OK if the user is authenticated.
608 NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
609 const DATA_BLOB in, DATA_BLOB *out)
611 return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
614 /**
615 * Set the requirement for a certain feature on the connection
619 void gensec_want_feature(struct gensec_security *gensec_security,
620 uint32_t feature)
622 gensec_security->want_features |= feature;
625 /**
626 * Check the requirement for a certain feature on the connection
630 BOOL gensec_have_feature(struct gensec_security *gensec_security,
631 uint32_t feature)
633 if (!gensec_security->ops->have_feature) {
634 return False;
636 return gensec_security->ops->have_feature(gensec_security, feature);
639 /**
640 * Associate a credentails structure with a GENSEC context - talloc_reference()s it to the context
644 NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
646 gensec_security->credentials = talloc_reference(gensec_security, credentials);
647 return NT_STATUS_OK;
650 /**
651 * Return the credentails structure associated with a GENSEC context
655 struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security)
657 return gensec_security->credentials;
660 /**
661 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
665 NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
667 gensec_security->target.service = talloc_strdup(gensec_security, service);
668 if (!gensec_security->target.service) {
669 return NT_STATUS_NO_MEMORY;
671 return NT_STATUS_OK;
674 /**
675 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
679 NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
681 gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
682 if (!gensec_security->target.hostname) {
683 return NT_STATUS_NO_MEMORY;
685 return NT_STATUS_OK;
688 const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
690 if (gensec_security->target.hostname) {
691 return gensec_security->target.hostname;
694 /* TODO: Add a 'set sockaddr' call, and do a reverse lookup */
695 return NULL;
698 const char *gensec_get_target_service(struct gensec_security *gensec_security)
700 if (gensec_security->target.service) {
701 return gensec_security->target.service;
704 return "host";
708 register a GENSEC backend.
710 The 'name' can be later used by other backends to find the operations
711 structure for this backend.
713 NTSTATUS gensec_register(const void *_ops)
715 const struct gensec_security_ops *ops = _ops;
717 if (!lp_parm_bool(-1, "gensec", ops->name, ops->enabled)) {
718 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
719 return NT_STATUS_OK;
722 if (gensec_security_by_name(ops->name) != NULL) {
723 /* its already registered! */
724 DEBUG(0,("GENSEC backend '%s' already registered\n",
725 ops->name));
726 return NT_STATUS_OBJECT_NAME_COLLISION;
729 generic_security_ops = realloc_p(generic_security_ops,
730 const struct gensec_security_ops *,
731 gensec_num_backends+1);
732 if (!generic_security_ops) {
733 smb_panic("out of memory in gensec_register");
736 generic_security_ops[gensec_num_backends] = ops;
738 gensec_num_backends++;
740 DEBUG(3,("GENSEC backend '%s' registered\n",
741 ops->name));
743 return NT_STATUS_OK;
747 return the GENSEC interface version, and the size of some critical types
748 This can be used by backends to either detect compilation errors, or provide
749 multiple implementations for different smbd compilation options in one module
751 const struct gensec_critical_sizes *gensec_interface_version(void)
753 static const struct gensec_critical_sizes critical_sizes = {
754 GENSEC_INTERFACE_VERSION,
755 sizeof(struct gensec_security_ops),
756 sizeof(struct gensec_security),
759 return &critical_sizes;
763 initialise the GENSEC subsystem
765 NTSTATUS gensec_init(void)
767 return NT_STATUS_OK;