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 **gensec_security_by_sasl(TALLOC_CTX *mem_ctx,
102 const char **sasl_names)
104 const struct gensec_security_ops **backends_out;
105 const struct gensec_security_ops **backends;
107 int num_backends_out = 0;
114 backends = gensec_security_all(&num_backends);
116 backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1);
120 backends_out[0] = NULL;
122 /* Find backends in our preferred order, by walking our list,
123 * then looking in the supplied list */
124 for (i=0; i < num_backends; i++) {
125 for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) {
126 if (!backends[i]->sasl_name ||
127 !(strcmp(backends[i]->sasl_name,
128 sasl_names[sasl_idx]) == 0)) {
132 for (k=0; backends_out[k]; k++) {
133 if (backends_out[k] == backends[i]) {
138 if (k < num_backends_out) {
139 /* already in there */
143 backends_out = talloc_realloc(mem_ctx, backends_out,
144 const struct gensec_security_ops *,
145 num_backends_out + 2);
150 backends_out[num_backends_out] = backends[i];
152 backends_out[num_backends_out] = NULL;
159 * Return a unique list of security subsystems from those specified in
160 * the OID list. That is, where two OIDs refer to the same module,
161 * return that module only once
163 * The list is in the exact order of the OIDs asked for, where available.
166 const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(TALLOC_CTX *mem_ctx,
167 const char **oid_strings,
170 struct gensec_security_ops_wrapper *backends_out;
171 const struct gensec_security_ops **backends;
172 int i, j, k, oid_idx;
173 int num_backends_out = 0;
180 backends = gensec_security_all(&num_backends);
182 backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
186 backends_out[0].op = NULL;
187 backends_out[0].oid = NULL;
189 /* Find backends in our preferred order, by walking our list,
190 * then looking in the supplied list */
191 for (i=0; i < num_backends; i++) {
192 if (!backends[i]->oid) {
195 for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) {
196 if (strcmp(oid_strings[oid_idx], skip) == 0) {
200 for (j=0; backends[i]->oid[j]; j++) {
201 if (!backends[i]->oid[j] ||
202 !(strcmp(backends[i]->oid[j],
203 oid_strings[oid_idx]) == 0)) {
207 for (k=0; backends_out[k].op; k++) {
208 if (backends_out[k].op == backends[i]) {
213 if (k < num_backends_out) {
214 /* already in there */
218 backends_out = talloc_realloc(mem_ctx, backends_out,
219 struct gensec_security_ops_wrapper,
220 num_backends_out + 2);
225 backends_out[num_backends_out].op = backends[i];
226 backends_out[num_backends_out].oid = backends[i]->oid[j];
228 backends_out[num_backends_out].op = NULL;
229 backends_out[num_backends_out].oid = NULL;
237 * Return OIDS from the security subsystems listed
240 const char **gensec_security_oids_from_ops(TALLOC_CTX *mem_ctx,
241 const struct gensec_security_ops **ops,
248 const char **oid_list;
252 oid_list = talloc_array(mem_ctx, const char *, 1);
257 for (i=0; i<num_backends; i++) {
262 for (k = 0; ops[i]->oid[k]; k++) {
263 if (skip && strcmp(skip, ops[i]->oid[k])==0) {
265 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
269 oid_list[j] = ops[i]->oid[k];
280 * Return OIDS from the security subsystems listed
283 const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx,
284 const struct gensec_security_ops_wrapper *wops)
289 const char **oid_list;
293 oid_list = talloc_array(mem_ctx, const char *, 1);
298 for (i=0; wops[i].op; i++) {
299 if (!wops[i].op->oid) {
303 for (k = 0; wops[i].op->oid[k]; k++) {
304 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
308 oid_list[j] = wops[i].op->oid[k];
318 * Return all the security subsystems currently enabled in GENSEC
321 const char **gensec_security_oids(TALLOC_CTX *mem_ctx, const char *skip)
324 const struct gensec_security_ops **ops = gensec_security_all(&num_backends);
325 return gensec_security_oids_from_ops(mem_ctx, ops,
332 Start the GENSEC system, returning a context pointer.
333 @param mem_ctx The parent TALLOC memory context.
334 @param gensec_security Returned GENSEC context pointer.
335 @note The mem_ctx is only a parent and may be NULL.
337 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
338 struct gensec_security **gensec_security,
339 struct event_context *ev)
341 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
342 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
344 (*gensec_security)->ops = NULL;
346 ZERO_STRUCT((*gensec_security)->target);
348 (*gensec_security)->subcontext = False;
349 (*gensec_security)->want_features = 0;
352 ev = event_context_init(*gensec_security);
354 talloc_free(*gensec_security);
355 return NT_STATUS_NO_MEMORY;
359 (*gensec_security)->event_ctx = ev;
365 * Start a GENSEC subcontext, with a copy of the properties of the parent
366 * @param mem_ctx The parent TALLOC memory context.
367 * @param parent The parent GENSEC context
368 * @param gensec_security Returned GENSEC context pointer.
369 * @note Used by SPNEGO in particular, for the actual implementation mechanism
372 NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
373 struct gensec_security *parent,
374 struct gensec_security **gensec_security)
376 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
377 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
379 (**gensec_security) = *parent;
380 (*gensec_security)->ops = NULL;
381 (*gensec_security)->private_data = NULL;
383 (*gensec_security)->subcontext = True;
384 (*gensec_security)->event_ctx = parent->event_ctx;
390 Start the GENSEC system, in client mode, returning a context pointer.
391 @param mem_ctx The parent TALLOC memory context.
392 @param gensec_security Returned GENSEC context pointer.
393 @note The mem_ctx is only a parent and may be NULL.
395 NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
396 struct gensec_security **gensec_security,
397 struct event_context *ev)
400 status = gensec_start(mem_ctx, gensec_security, ev);
401 if (!NT_STATUS_IS_OK(status)) {
404 (*gensec_security)->gensec_role = GENSEC_CLIENT;
410 Start the GENSEC system, in server mode, returning a context pointer.
411 @param mem_ctx The parent TALLOC memory context.
412 @param gensec_security Returned GENSEC context pointer.
413 @note The mem_ctx is only a parent and may be NULL.
415 NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
416 struct gensec_security **gensec_security,
417 struct event_context *ev)
420 status = gensec_start(mem_ctx, gensec_security, ev);
421 if (!NT_STATUS_IS_OK(status)) {
424 (*gensec_security)->gensec_role = GENSEC_SERVER;
429 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
432 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
433 gensec_security->subcontext ? "sub" : "",
434 gensec_security->ops->name));
435 switch (gensec_security->gensec_role) {
437 if (gensec_security->ops->client_start) {
438 status = gensec_security->ops->client_start(gensec_security);
439 if (!NT_STATUS_IS_OK(status)) {
440 DEBUG(2, ("Failed to start GENSEC client mech %s: %s\n",
441 gensec_security->ops->name, nt_errstr(status)));
446 if (gensec_security->ops->server_start) {
447 status = gensec_security->ops->server_start(gensec_security);
448 if (!NT_STATUS_IS_OK(status)) {
449 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
450 gensec_security->ops->name, nt_errstr(status)));
455 return NT_STATUS_INVALID_PARAMETER;
459 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
460 * @param gensec_security GENSEC context pointer.
461 * @param auth_type DCERPC auth type
462 * @param auth_level DCERPC auth level
465 NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
466 uint8_t auth_type, uint8_t auth_level)
468 gensec_security->ops = gensec_security_by_authtype(auth_type);
469 if (!gensec_security->ops) {
470 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
471 return NT_STATUS_INVALID_PARAMETER;
473 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
474 gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
475 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
476 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
477 } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
478 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
479 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
480 } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
481 /* Default features */
483 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
485 return NT_STATUS_INVALID_PARAMETER;
488 return gensec_start_mech(gensec_security);
491 const char *gensec_get_name_by_authtype(uint8_t authtype)
493 const struct gensec_security_ops *ops;
494 ops = gensec_security_by_authtype(authtype);
502 const char *gensec_get_name_by_oid(const char *oid_string)
504 const struct gensec_security_ops *ops;
505 ops = gensec_security_by_oid(oid_string);
514 * Start a GENSEC sub-mechanism with a specifed mechansim structure, used in SPNEGO
518 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
519 const struct gensec_security_ops *ops)
521 gensec_security->ops = ops;
522 return gensec_start_mech(gensec_security);
526 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
528 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
529 * well-known #define to hook it in.
532 NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
533 const char *mech_oid)
535 gensec_security->ops = gensec_security_by_oid(mech_oid);
536 if (!gensec_security->ops) {
537 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
538 return NT_STATUS_INVALID_PARAMETER;
540 return gensec_start_mech(gensec_security);
544 * Start a GENSEC sub-mechanism by a well know SASL name
548 NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
549 const char *sasl_name)
551 gensec_security->ops = gensec_security_by_sasl_name(sasl_name);
552 if (!gensec_security->ops) {
553 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
554 return NT_STATUS_INVALID_PARAMETER;
556 return gensec_start_mech(gensec_security);
560 * Start a GENSEC sub-mechanism by an internal name
564 NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
567 gensec_security->ops = gensec_security_by_name(name);
568 if (!gensec_security->ops) {
569 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
570 return NT_STATUS_INVALID_PARAMETER;
572 return gensec_start_mech(gensec_security);
576 wrappers for the gensec function pointers
578 NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
580 uint8_t *data, size_t length,
581 const uint8_t *whole_pdu, size_t pdu_length,
582 const DATA_BLOB *sig)
584 if (!gensec_security->ops->unseal_packet) {
585 return NT_STATUS_NOT_IMPLEMENTED;
587 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
588 return NT_STATUS_INVALID_PARAMETER;
591 return gensec_security->ops->unseal_packet(gensec_security, mem_ctx,
593 whole_pdu, pdu_length,
597 NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
599 const uint8_t *data, size_t length,
600 const uint8_t *whole_pdu, size_t pdu_length,
601 const DATA_BLOB *sig)
603 if (!gensec_security->ops->check_packet) {
604 return NT_STATUS_NOT_IMPLEMENTED;
606 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
607 return NT_STATUS_INVALID_PARAMETER;
610 return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
613 NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
615 uint8_t *data, size_t length,
616 const uint8_t *whole_pdu, size_t pdu_length,
619 if (!gensec_security->ops->seal_packet) {
620 return NT_STATUS_NOT_IMPLEMENTED;
622 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
623 return NT_STATUS_INVALID_PARAMETER;
626 return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
629 NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
631 const uint8_t *data, size_t length,
632 const uint8_t *whole_pdu, size_t pdu_length,
635 if (!gensec_security->ops->sign_packet) {
636 return NT_STATUS_NOT_IMPLEMENTED;
638 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
639 return NT_STATUS_INVALID_PARAMETER;
642 return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
645 size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size)
647 if (!gensec_security->ops->sig_size) {
650 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
654 return gensec_security->ops->sig_size(gensec_security, data_size);
657 NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
662 if (!gensec_security->ops->wrap) {
663 return NT_STATUS_NOT_IMPLEMENTED;
665 return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
668 NTSTATUS gensec_unwrap(struct gensec_security *gensec_security,
673 if (!gensec_security->ops->unwrap) {
674 return NT_STATUS_NOT_IMPLEMENTED;
676 return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
679 NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
680 DATA_BLOB *session_key)
682 if (!gensec_security->ops->session_key) {
683 return NT_STATUS_NOT_IMPLEMENTED;
685 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SESSION_KEY)) {
686 return NT_STATUS_NO_USER_SESSION_KEY;
689 return gensec_security->ops->session_key(gensec_security, session_key);
693 * Return the credentials of a logged on user, including session keys
696 * Only valid after a successful authentication
698 * May only be called once per authentication.
702 NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
703 struct auth_session_info **session_info)
705 if (!gensec_security->ops->session_info) {
706 return NT_STATUS_NOT_IMPLEMENTED;
708 return gensec_security->ops->session_info(gensec_security, session_info);
712 * Next state function for the GENSEC state machine
714 * @param gensec_security GENSEC State
715 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
716 * @param in The request, as a DATA_BLOB
717 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
718 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
719 * or NT_STATUS_OK if the user is authenticated.
722 NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
723 const DATA_BLOB in, DATA_BLOB *out)
725 return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
729 * Set the requirement for a certain feature on the connection
733 void gensec_want_feature(struct gensec_security *gensec_security,
736 gensec_security->want_features |= feature;
740 * Check the requirement for a certain feature on the connection
744 BOOL gensec_have_feature(struct gensec_security *gensec_security,
747 if (!gensec_security->ops->have_feature) {
751 /* Can only 'have' a feature if you already 'want'ed it */
752 if (gensec_security->want_features & feature) {
753 return gensec_security->ops->have_feature(gensec_security, feature);
759 * Associate a credentails structure with a GENSEC context - talloc_reference()s it to the context
763 NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
765 gensec_security->credentials = talloc_reference(gensec_security, credentials);
770 * Return the credentails structure associated with a GENSEC context
774 struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security)
776 return gensec_security->credentials;
780 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
784 NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
786 gensec_security->target.service = talloc_strdup(gensec_security, service);
787 if (!gensec_security->target.service) {
788 return NT_STATUS_NO_MEMORY;
793 const char *gensec_get_target_service(struct gensec_security *gensec_security)
795 if (gensec_security->target.service) {
796 return gensec_security->target.service;
803 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
807 NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
809 gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
810 if (!gensec_security->target.hostname) {
811 return NT_STATUS_NO_MEMORY;
816 const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
818 if (gensec_security->target.hostname) {
819 return gensec_security->target.hostname;
822 /* TODO: Add a 'set sockaddr' call, and do a reverse lookup */
827 * Set the target principal (assuming it it known, say from the SPNEGO reply)
828 * - ensures it is talloc()ed
832 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
834 gensec_security->target.principal = talloc_strdup(gensec_security, principal);
835 if (!gensec_security->target.principal) {
836 return NT_STATUS_NO_MEMORY;
841 const char *gensec_get_target_principal(struct gensec_security *gensec_security)
843 if (gensec_security->target.principal) {
844 return gensec_security->target.principal;
851 register a GENSEC backend.
853 The 'name' can be later used by other backends to find the operations
854 structure for this backend.
856 NTSTATUS gensec_register(const void *_ops)
858 const struct gensec_security_ops *ops = _ops;
860 if (!lp_parm_bool(-1, "gensec", ops->name, ops->enabled)) {
861 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
865 if (gensec_security_by_name(ops->name) != NULL) {
866 /* its already registered! */
867 DEBUG(0,("GENSEC backend '%s' already registered\n",
869 return NT_STATUS_OBJECT_NAME_COLLISION;
872 generic_security_ops = realloc_p(generic_security_ops,
873 const struct gensec_security_ops *,
874 gensec_num_backends+1);
875 if (!generic_security_ops) {
876 smb_panic("out of memory in gensec_register");
879 generic_security_ops[gensec_num_backends] = ops;
881 gensec_num_backends++;
883 DEBUG(3,("GENSEC backend '%s' registered\n",
890 return the GENSEC interface version, and the size of some critical types
891 This can be used by backends to either detect compilation errors, or provide
892 multiple implementations for different smbd compilation options in one module
894 const struct gensec_critical_sizes *gensec_interface_version(void)
896 static const struct gensec_critical_sizes critical_sizes = {
897 GENSEC_INTERFACE_VERSION,
898 sizeof(struct gensec_security_ops),
899 sizeof(struct gensec_security),
902 return &critical_sizes;
906 initialise the GENSEC subsystem
908 NTSTATUS gensec_init(void)