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.
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)
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];
44 static const struct gensec_security_ops *gensec_security_by_oid(const char *oid_string)
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];
61 static const struct gensec_security_ops *gensec_security_by_sasl_name(const char *sasl_name)
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];
74 static const struct gensec_security_ops *gensec_security_by_name(const char *name)
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];
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;
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,
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;
115 backends = gensec_security_all(&num_backends);
117 backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
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) {
129 for (i=0; i < num_backends; i++) {
130 if (!backends[i]->oid) {
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)) {
140 for (k=0; backends_out[k].op; k++) {
141 if (backends_out[k].op == backends[i]) {
146 if (k < num_backends_out) {
147 /* already in there */
151 backends_out = talloc_realloc(mem_ctx, backends_out,
152 struct gensec_security_ops_wrapper,
153 num_backends_out + 2);
158 backends_out[num_backends_out].op = backends[i];
159 backends_out[num_backends_out].oid = backends[i]->oid[j];
161 backends_out[num_backends_out].op = NULL;
162 backends_out[num_backends_out].oid = NULL;
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,
181 const char **oid_list;
185 oid_list = talloc_array(mem_ctx, const char *, 1);
190 for (i=0; i<num_backends; i++) {
195 for (k = 0; ops[i]->oid[k]; k++) {
196 if (skip && strcmp(skip, ops[i]->oid[k])==0) {
198 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
202 oid_list[j] = ops[i]->oid[k];
213 * Return OIDS from the security subsystems listed
216 const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx,
217 const struct gensec_security_ops_wrapper *wops)
222 const char **oid_list;
226 oid_list = talloc_array(mem_ctx, const char *, 1);
231 for (i=0; wops[i].op; i++) {
232 if (!wops[i].op->oid) {
236 for (k = 0; wops[i].op->oid[k]; k++) {
237 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
241 oid_list[j] = wops[i].op->oid[k];
251 * Return all the security subsystems currently enabled in GENSEC
254 const char **gensec_security_oids(TALLOC_CTX *mem_ctx, const char *skip)
257 const struct gensec_security_ops **ops = gensec_security_all(&num_backends);
258 return gensec_security_oids_from_ops(mem_ctx, ops,
265 Start the GENSEC system, returning a context pointer.
266 @param mem_ctx The parent TALLOC memory context.
267 @param gensec_security Returned GENSEC context pointer.
268 @note The mem_ctx is only a parent and may be NULL.
270 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
271 struct gensec_security **gensec_security,
272 struct event_context *ev)
274 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
275 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
277 (*gensec_security)->ops = NULL;
279 ZERO_STRUCT((*gensec_security)->target);
281 (*gensec_security)->subcontext = False;
282 (*gensec_security)->want_features = 0;
285 ev = event_context_init(*gensec_security);
287 talloc_free(*gensec_security);
288 return NT_STATUS_NO_MEMORY;
292 (*gensec_security)->event_ctx = ev;
298 * Start a GENSEC subcontext, with a copy of the properties of the parent
299 * @param mem_ctx The parent TALLOC memory context.
300 * @param parent The parent GENSEC context
301 * @param gensec_security Returned GENSEC context pointer.
302 * @note Used by SPNEGO in particular, for the actual implementation mechanism
305 NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
306 struct gensec_security *parent,
307 struct gensec_security **gensec_security)
309 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
310 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
312 (**gensec_security) = *parent;
313 (*gensec_security)->ops = NULL;
314 (*gensec_security)->private_data = NULL;
316 (*gensec_security)->subcontext = True;
317 (*gensec_security)->event_ctx = parent->event_ctx;
323 Start the GENSEC system, in client mode, returning a context pointer.
324 @param mem_ctx The parent TALLOC memory context.
325 @param gensec_security Returned GENSEC context pointer.
326 @note The mem_ctx is only a parent and may be NULL.
328 NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
329 struct gensec_security **gensec_security,
330 struct event_context *ev)
333 status = gensec_start(mem_ctx, gensec_security, ev);
334 if (!NT_STATUS_IS_OK(status)) {
337 (*gensec_security)->gensec_role = GENSEC_CLIENT;
343 Start the GENSEC system, in server mode, returning a context pointer.
344 @param mem_ctx The parent TALLOC memory context.
345 @param gensec_security Returned GENSEC context pointer.
346 @note The mem_ctx is only a parent and may be NULL.
348 NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
349 struct gensec_security **gensec_security,
350 struct event_context *ev)
353 status = gensec_start(mem_ctx, gensec_security, ev);
354 if (!NT_STATUS_IS_OK(status)) {
357 (*gensec_security)->gensec_role = GENSEC_SERVER;
362 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
365 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
366 gensec_security->subcontext ? "sub" : "",
367 gensec_security->ops->name));
368 switch (gensec_security->gensec_role) {
370 if (gensec_security->ops->client_start) {
371 status = gensec_security->ops->client_start(gensec_security);
372 if (!NT_STATUS_IS_OK(status)) {
373 DEBUG(2, ("Failed to start GENSEC client mech %s: %s\n",
374 gensec_security->ops->name, nt_errstr(status)));
379 if (gensec_security->ops->server_start) {
380 status = gensec_security->ops->server_start(gensec_security);
381 if (!NT_STATUS_IS_OK(status)) {
382 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
383 gensec_security->ops->name, nt_errstr(status)));
388 return NT_STATUS_INVALID_PARAMETER;
392 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
393 * @param gensec_security GENSEC context pointer.
394 * @param auth_type DCERPC auth type
395 * @param auth_level DCERPC auth level
398 NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
399 uint8_t auth_type, uint8_t auth_level)
401 gensec_security->ops = gensec_security_by_authtype(auth_type);
402 if (!gensec_security->ops) {
403 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
404 return NT_STATUS_INVALID_PARAMETER;
406 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
407 gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
408 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
409 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
410 } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
411 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
412 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
413 } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
414 /* Default features */
416 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
418 return NT_STATUS_INVALID_PARAMETER;
421 return gensec_start_mech(gensec_security);
424 const char *gensec_get_name_by_authtype(uint8_t authtype)
426 const struct gensec_security_ops *ops;
427 ops = gensec_security_by_authtype(authtype);
435 const char *gensec_get_name_by_oid(const char *oid_string)
437 const struct gensec_security_ops *ops;
438 ops = gensec_security_by_oid(oid_string);
447 * Start a GENSEC sub-mechanism with a specifed mechansim structure, used in SPNEGO
451 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
452 const struct gensec_security_ops *ops)
454 gensec_security->ops = ops;
455 return gensec_start_mech(gensec_security);
459 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
461 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
462 * well-known #define to hook it in.
465 NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
466 const char *mech_oid)
468 gensec_security->ops = gensec_security_by_oid(mech_oid);
469 if (!gensec_security->ops) {
470 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
471 return NT_STATUS_INVALID_PARAMETER;
473 return gensec_start_mech(gensec_security);
477 * Start a GENSEC sub-mechanism by a well know SASL name
481 NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
482 const char *sasl_name)
484 gensec_security->ops = gensec_security_by_sasl_name(sasl_name);
485 if (!gensec_security->ops) {
486 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
487 return NT_STATUS_INVALID_PARAMETER;
489 return gensec_start_mech(gensec_security);
493 wrappers for the gensec function pointers
495 NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
497 uint8_t *data, size_t length,
498 const uint8_t *whole_pdu, size_t pdu_length,
499 const DATA_BLOB *sig)
501 if (!gensec_security->ops->unseal_packet) {
502 return NT_STATUS_NOT_IMPLEMENTED;
504 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
505 return NT_STATUS_INVALID_PARAMETER;
508 return gensec_security->ops->unseal_packet(gensec_security, mem_ctx,
510 whole_pdu, pdu_length,
514 NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
516 const uint8_t *data, size_t length,
517 const uint8_t *whole_pdu, size_t pdu_length,
518 const DATA_BLOB *sig)
520 if (!gensec_security->ops->check_packet) {
521 return NT_STATUS_NOT_IMPLEMENTED;
523 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
524 return NT_STATUS_INVALID_PARAMETER;
527 return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
530 NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
532 uint8_t *data, size_t length,
533 const uint8_t *whole_pdu, size_t pdu_length,
536 if (!gensec_security->ops->seal_packet) {
537 return NT_STATUS_NOT_IMPLEMENTED;
539 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
540 return NT_STATUS_INVALID_PARAMETER;
543 return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
546 NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
548 const uint8_t *data, size_t length,
549 const uint8_t *whole_pdu, size_t pdu_length,
552 if (!gensec_security->ops->sign_packet) {
553 return NT_STATUS_NOT_IMPLEMENTED;
555 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
556 return NT_STATUS_INVALID_PARAMETER;
559 return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
562 size_t gensec_sig_size(struct gensec_security *gensec_security)
564 if (!gensec_security->ops->sig_size) {
567 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
571 return gensec_security->ops->sig_size(gensec_security);
574 NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
579 if (!gensec_security->ops->wrap) {
580 return NT_STATUS_NOT_IMPLEMENTED;
582 return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
585 NTSTATUS gensec_unwrap(struct gensec_security *gensec_security,
590 if (!gensec_security->ops->unwrap) {
591 return NT_STATUS_NOT_IMPLEMENTED;
593 return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
596 NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
597 DATA_BLOB *session_key)
599 if (!gensec_security->ops->session_key) {
600 return NT_STATUS_NOT_IMPLEMENTED;
602 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SESSION_KEY)) {
603 return NT_STATUS_NO_USER_SESSION_KEY;
606 return gensec_security->ops->session_key(gensec_security, session_key);
610 * Return the credentials of a logged on user, including session keys
613 * Only valid after a successful authentication
615 * May only be called once per authentication.
619 NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
620 struct auth_session_info **session_info)
622 if (!gensec_security->ops->session_info) {
623 return NT_STATUS_NOT_IMPLEMENTED;
625 return gensec_security->ops->session_info(gensec_security, session_info);
629 * Next state function for the GENSEC state machine
631 * @param gensec_security GENSEC State
632 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
633 * @param in The request, as a DATA_BLOB
634 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
635 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
636 * or NT_STATUS_OK if the user is authenticated.
639 NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
640 const DATA_BLOB in, DATA_BLOB *out)
642 return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
646 * Set the requirement for a certain feature on the connection
650 void gensec_want_feature(struct gensec_security *gensec_security,
653 gensec_security->want_features |= feature;
657 * Check the requirement for a certain feature on the connection
661 BOOL gensec_have_feature(struct gensec_security *gensec_security,
664 if (!gensec_security->ops->have_feature) {
668 /* Can only 'have' a feature if you already 'want'ed it */
669 if (gensec_security->want_features & feature) {
670 return gensec_security->ops->have_feature(gensec_security, feature);
676 * Associate a credentails structure with a GENSEC context - talloc_reference()s it to the context
680 NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
682 gensec_security->credentials = talloc_reference(gensec_security, credentials);
687 * Return the credentails structure associated with a GENSEC context
691 struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security)
693 return gensec_security->credentials;
697 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
701 NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
703 gensec_security->target.service = talloc_strdup(gensec_security, service);
704 if (!gensec_security->target.service) {
705 return NT_STATUS_NO_MEMORY;
711 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
715 NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
717 gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
718 if (!gensec_security->target.hostname) {
719 return NT_STATUS_NO_MEMORY;
724 const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
726 if (gensec_security->target.hostname) {
727 return gensec_security->target.hostname;
730 /* TODO: Add a 'set sockaddr' call, and do a reverse lookup */
734 const char *gensec_get_target_service(struct gensec_security *gensec_security)
736 if (gensec_security->target.service) {
737 return gensec_security->target.service;
744 register a GENSEC backend.
746 The 'name' can be later used by other backends to find the operations
747 structure for this backend.
749 NTSTATUS gensec_register(const void *_ops)
751 const struct gensec_security_ops *ops = _ops;
753 if (!lp_parm_bool(-1, "gensec", ops->name, ops->enabled)) {
754 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
758 if (gensec_security_by_name(ops->name) != NULL) {
759 /* its already registered! */
760 DEBUG(0,("GENSEC backend '%s' already registered\n",
762 return NT_STATUS_OBJECT_NAME_COLLISION;
765 generic_security_ops = realloc_p(generic_security_ops,
766 const struct gensec_security_ops *,
767 gensec_num_backends+1);
768 if (!generic_security_ops) {
769 smb_panic("out of memory in gensec_register");
772 generic_security_ops[gensec_num_backends] = ops;
774 gensec_num_backends++;
776 DEBUG(3,("GENSEC backend '%s' registered\n",
783 return the GENSEC interface version, and the size of some critical types
784 This can be used by backends to either detect compilation errors, or provide
785 multiple implementations for different smbd compilation options in one module
787 const struct gensec_critical_sizes *gensec_interface_version(void)
789 static const struct gensec_critical_sizes critical_sizes = {
790 GENSEC_INTERFACE_VERSION,
791 sizeof(struct gensec_security_ops),
792 sizeof(struct gensec_security),
795 return &critical_sizes;
799 initialise the GENSEC subsystem
801 NTSTATUS gensec_init(void)