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 * Start a GENSEC sub-mechanism by an internal name
497 NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
500 gensec_security->ops = gensec_security_by_name(name);
501 if (!gensec_security->ops) {
502 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
503 return NT_STATUS_INVALID_PARAMETER;
505 return gensec_start_mech(gensec_security);
509 wrappers for the gensec function pointers
511 NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
513 uint8_t *data, size_t length,
514 const uint8_t *whole_pdu, size_t pdu_length,
515 const DATA_BLOB *sig)
517 if (!gensec_security->ops->unseal_packet) {
518 return NT_STATUS_NOT_IMPLEMENTED;
520 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
521 return NT_STATUS_INVALID_PARAMETER;
524 return gensec_security->ops->unseal_packet(gensec_security, mem_ctx,
526 whole_pdu, pdu_length,
530 NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
532 const uint8_t *data, size_t length,
533 const uint8_t *whole_pdu, size_t pdu_length,
534 const DATA_BLOB *sig)
536 if (!gensec_security->ops->check_packet) {
537 return NT_STATUS_NOT_IMPLEMENTED;
539 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
540 return NT_STATUS_INVALID_PARAMETER;
543 return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
546 NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
548 uint8_t *data, size_t length,
549 const uint8_t *whole_pdu, size_t pdu_length,
552 if (!gensec_security->ops->seal_packet) {
553 return NT_STATUS_NOT_IMPLEMENTED;
555 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
556 return NT_STATUS_INVALID_PARAMETER;
559 return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
562 NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
564 const uint8_t *data, size_t length,
565 const uint8_t *whole_pdu, size_t pdu_length,
568 if (!gensec_security->ops->sign_packet) {
569 return NT_STATUS_NOT_IMPLEMENTED;
571 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
572 return NT_STATUS_INVALID_PARAMETER;
575 return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
578 size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size)
580 if (!gensec_security->ops->sig_size) {
583 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
587 return gensec_security->ops->sig_size(gensec_security, data_size);
590 NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
595 if (!gensec_security->ops->wrap) {
596 return NT_STATUS_NOT_IMPLEMENTED;
598 return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
601 NTSTATUS gensec_unwrap(struct gensec_security *gensec_security,
606 if (!gensec_security->ops->unwrap) {
607 return NT_STATUS_NOT_IMPLEMENTED;
609 return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
612 NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
613 DATA_BLOB *session_key)
615 if (!gensec_security->ops->session_key) {
616 return NT_STATUS_NOT_IMPLEMENTED;
618 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SESSION_KEY)) {
619 return NT_STATUS_NO_USER_SESSION_KEY;
622 return gensec_security->ops->session_key(gensec_security, session_key);
626 * Return the credentials of a logged on user, including session keys
629 * Only valid after a successful authentication
631 * May only be called once per authentication.
635 NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
636 struct auth_session_info **session_info)
638 if (!gensec_security->ops->session_info) {
639 return NT_STATUS_NOT_IMPLEMENTED;
641 return gensec_security->ops->session_info(gensec_security, session_info);
645 * Next state function for the GENSEC state machine
647 * @param gensec_security GENSEC State
648 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
649 * @param in The request, as a DATA_BLOB
650 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
651 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
652 * or NT_STATUS_OK if the user is authenticated.
655 NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
656 const DATA_BLOB in, DATA_BLOB *out)
658 return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
662 * Set the requirement for a certain feature on the connection
666 void gensec_want_feature(struct gensec_security *gensec_security,
669 gensec_security->want_features |= feature;
673 * Check the requirement for a certain feature on the connection
677 BOOL gensec_have_feature(struct gensec_security *gensec_security,
680 if (!gensec_security->ops->have_feature) {
684 /* Can only 'have' a feature if you already 'want'ed it */
685 if (gensec_security->want_features & feature) {
686 return gensec_security->ops->have_feature(gensec_security, feature);
692 * Associate a credentails structure with a GENSEC context - talloc_reference()s it to the context
696 NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
698 gensec_security->credentials = talloc_reference(gensec_security, credentials);
703 * Return the credentails structure associated with a GENSEC context
707 struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security)
709 return gensec_security->credentials;
713 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
717 NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
719 gensec_security->target.service = talloc_strdup(gensec_security, service);
720 if (!gensec_security->target.service) {
721 return NT_STATUS_NO_MEMORY;
726 const char *gensec_get_target_service(struct gensec_security *gensec_security)
728 if (gensec_security->target.service) {
729 return gensec_security->target.service;
736 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
740 NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
742 gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
743 if (!gensec_security->target.hostname) {
744 return NT_STATUS_NO_MEMORY;
749 const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
751 if (gensec_security->target.hostname) {
752 return gensec_security->target.hostname;
755 /* TODO: Add a 'set sockaddr' call, and do a reverse lookup */
760 * Set the target principal (assuming it it known, say from the SPNEGO reply)
761 * - ensures it is talloc()ed
765 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
767 gensec_security->target.principal = talloc_strdup(gensec_security, principal);
768 if (!gensec_security->target.principal) {
769 return NT_STATUS_NO_MEMORY;
774 const char *gensec_get_target_principal(struct gensec_security *gensec_security)
776 if (gensec_security->target.principal) {
777 return gensec_security->target.principal;
784 register a GENSEC backend.
786 The 'name' can be later used by other backends to find the operations
787 structure for this backend.
789 NTSTATUS gensec_register(const void *_ops)
791 const struct gensec_security_ops *ops = _ops;
793 if (!lp_parm_bool(-1, "gensec", ops->name, ops->enabled)) {
794 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
798 if (gensec_security_by_name(ops->name) != NULL) {
799 /* its already registered! */
800 DEBUG(0,("GENSEC backend '%s' already registered\n",
802 return NT_STATUS_OBJECT_NAME_COLLISION;
805 generic_security_ops = realloc_p(generic_security_ops,
806 const struct gensec_security_ops *,
807 gensec_num_backends+1);
808 if (!generic_security_ops) {
809 smb_panic("out of memory in gensec_register");
812 generic_security_ops[gensec_num_backends] = ops;
814 gensec_num_backends++;
816 DEBUG(3,("GENSEC backend '%s' registered\n",
823 return the GENSEC interface version, and the size of some critical types
824 This can be used by backends to either detect compilation errors, or provide
825 multiple implementations for different smbd compilation options in one module
827 const struct gensec_critical_sizes *gensec_interface_version(void)
829 static const struct gensec_critical_sizes critical_sizes = {
830 GENSEC_INTERFACE_VERSION,
831 sizeof(struct gensec_security_ops),
832 sizeof(struct gensec_security),
835 return &critical_sizes;
839 initialise the GENSEC subsystem
841 NTSTATUS gensec_init(void)