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"
27 /* the list of currently registered GENSEC backends */
28 const static struct gensec_security_ops **generic_security_ops;
29 static int gensec_num_backends;
31 static const struct gensec_security_ops *gensec_security_by_authtype(uint8_t auth_type)
34 for (i=0; i < gensec_num_backends; i++) {
35 if (generic_security_ops[i]->auth_type == auth_type) {
36 return generic_security_ops[i];
43 static const struct gensec_security_ops *gensec_security_by_oid(const char *oid_string)
46 for (i=0; i < gensec_num_backends; i++) {
47 if (generic_security_ops[i]->oid) {
48 for (j=0; generic_security_ops[i]->oid[j]; j++) {
49 if (generic_security_ops[i]->oid[j] &&
50 (strcmp(generic_security_ops[i]->oid[j], oid_string) == 0)) {
51 return generic_security_ops[i];
60 static const struct gensec_security_ops *gensec_security_by_sasl_name(const char *sasl_name)
63 for (i=0; i < gensec_num_backends; i++) {
64 if (generic_security_ops[i]->sasl_name
65 && (strcmp(generic_security_ops[i]->sasl_name, sasl_name) == 0)) {
66 return generic_security_ops[i];
73 static const struct gensec_security_ops *gensec_security_by_name(const char *name)
76 for (i=0; i < gensec_num_backends; i++) {
77 if (generic_security_ops[i]->name
78 && (strcmp(generic_security_ops[i]->name, name) == 0)) {
79 return generic_security_ops[i];
86 const struct gensec_security_ops **gensec_security_all(int *num_backends_out)
88 *num_backends_out = gensec_num_backends;
89 return generic_security_ops;
93 * Return a unique list of security subsystems from those specified in
94 * the OID list. That is, where two OIDs refer to the same module,
95 * return that module only once
97 * The list is in the exact order of the OIDs asked for, where available.
100 const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(TALLOC_CTX *mem_ctx,
101 const char **oid_strings,
104 struct gensec_security_ops_wrapper *backends_out;
105 const struct gensec_security_ops **backends;
106 int i, j, k, oid_idx;
107 int num_backends_out = 0;
114 backends = gensec_security_all(&num_backends);
116 backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
120 backends_out[0].op = NULL;
121 backends_out[0].oid = NULL;
123 for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) {
124 if (strcmp(oid_strings[oid_idx], skip) == 0) {
128 for (i=0; i < num_backends; i++) {
129 if (!backends[i]->oid) {
132 for (j=0; backends[i]->oid[j]; j++) {
133 if (!backends[i]->oid[j] ||
134 !(strcmp(backends[i]->oid[j],
135 oid_strings[oid_idx]) == 0)) {
139 for (k=0; backends_out[k].op; k++) {
140 if (backends_out[k].op == backends[i]) {
145 if (k < num_backends_out) {
146 /* already in there */
150 backends_out = talloc_realloc(mem_ctx, backends_out,
151 struct gensec_security_ops_wrapper,
152 num_backends_out + 2);
157 backends_out[num_backends_out].op = backends[i];
158 backends_out[num_backends_out].oid = backends[i]->oid[j];
160 backends_out[num_backends_out].op = NULL;
161 backends_out[num_backends_out].oid = NULL;
169 * Return OIDS from the security subsystems listed
172 const char **gensec_security_oids_from_ops(TALLOC_CTX *mem_ctx,
173 const struct gensec_security_ops **ops,
180 const char **oid_list;
184 oid_list = talloc_array(mem_ctx, const char *, 1);
189 for (i=0; i<num_backends; i++) {
194 for (k = 0; ops[i]->oid[k]; k++) {
195 if (skip && strcmp(skip, ops[i]->oid[k])==0) {
197 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
201 oid_list[j] = ops[i]->oid[k];
212 * Return all the security subsystems currently enabled in GENSEC
215 const char **gensec_security_oids(TALLOC_CTX *mem_ctx, const char *skip)
218 const struct gensec_security_ops **ops = gensec_security_all(&num_backends);
219 return gensec_security_oids_from_ops(mem_ctx, ops,
226 Start the GENSEC system, returning a context pointer.
227 @param mem_ctx The parent TALLOC memory context.
228 @param gensec_security Returned GENSEC context pointer.
229 @note The mem_ctx is only a parent and may be NULL.
231 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security)
233 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
234 if (!(*gensec_security)) {
235 return NT_STATUS_NO_MEMORY;
238 (*gensec_security)->ops = NULL;
240 ZERO_STRUCT((*gensec_security)->target);
242 (*gensec_security)->subcontext = False;
243 (*gensec_security)->want_features = 0;
248 * Start a GENSEC subcontext, with a copy of the properties of the parent
249 * @param mem_ctx The parent TALLOC memory context.
250 * @param parent The parent GENSEC context
251 * @param gensec_security Returned GENSEC context pointer.
252 * @note Used by SPNEGO in particular, for the actual implementation mechanism
255 NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
256 struct gensec_security *parent,
257 struct gensec_security **gensec_security)
259 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
260 if (!(*gensec_security)) {
261 return NT_STATUS_NO_MEMORY;
264 (**gensec_security) = *parent;
265 (*gensec_security)->ops = NULL;
266 (*gensec_security)->private_data = NULL;
268 (*gensec_security)->subcontext = True;
274 Start the GENSEC system, in client mode, returning a context pointer.
275 @param mem_ctx The parent TALLOC memory context.
276 @param gensec_security Returned GENSEC context pointer.
277 @note The mem_ctx is only a parent and may be NULL.
279 NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security)
282 status = gensec_start(mem_ctx, gensec_security);
283 if (!NT_STATUS_IS_OK(status)) {
286 (*gensec_security)->gensec_role = GENSEC_CLIENT;
287 (*gensec_security)->password_callback = NULL;
293 Start the GENSEC system, in server mode, returning a context pointer.
294 @param mem_ctx The parent TALLOC memory context.
295 @param gensec_security Returned GENSEC context pointer.
296 @note The mem_ctx is only a parent and may be NULL.
298 NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security)
301 status = gensec_start(mem_ctx, gensec_security);
302 if (!NT_STATUS_IS_OK(status)) {
305 (*gensec_security)->gensec_role = GENSEC_SERVER;
310 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
313 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
314 gensec_security->subcontext ? "sub" : "",
315 gensec_security->ops->name));
316 switch (gensec_security->gensec_role) {
318 if (gensec_security->ops->client_start) {
319 status = gensec_security->ops->client_start(gensec_security);
320 if (!NT_STATUS_IS_OK(status)) {
321 DEBUG(1, ("Failed to start GENSEC client mech %s: %s\n",
322 gensec_security->ops->name, nt_errstr(status)));
327 if (gensec_security->ops->server_start) {
328 status = gensec_security->ops->server_start(gensec_security);
329 if (!NT_STATUS_IS_OK(status)) {
330 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
331 gensec_security->ops->name, nt_errstr(status)));
336 return NT_STATUS_INVALID_PARAMETER;
340 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
341 * @param gensec_security GENSEC context pointer.
342 * @param auth_type DCERPC auth type
343 * @param auth_level DCERPC auth level
346 NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
347 uint8_t auth_type, uint8_t auth_level)
349 gensec_security->ops = gensec_security_by_authtype(auth_type);
350 if (!gensec_security->ops) {
351 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
352 return NT_STATUS_INVALID_PARAMETER;
354 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
355 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
356 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
357 } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
358 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
359 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
360 } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
361 /* Default features */
363 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
365 return NT_STATUS_INVALID_PARAMETER;
368 return gensec_start_mech(gensec_security);
371 const char *gensec_get_name_by_authtype(uint8_t authtype)
373 const struct gensec_security_ops *ops;
374 ops = gensec_security_by_authtype(authtype);
382 const char *gensec_get_name_by_oid(const char *oid_string)
384 const struct gensec_security_ops *ops;
385 ops = gensec_security_by_oid(oid_string);
394 * Start a GENSEC sub-mechanism with a specifed mechansim structure, used in SPNEGO
398 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
399 const struct gensec_security_ops *ops)
401 gensec_security->ops = ops;
402 return gensec_start_mech(gensec_security);
406 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
408 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
409 * well-known #define to hook it in.
412 NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
413 const char *mech_oid)
415 gensec_security->ops = gensec_security_by_oid(mech_oid);
416 if (!gensec_security->ops) {
417 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
418 return NT_STATUS_INVALID_PARAMETER;
420 return gensec_start_mech(gensec_security);
424 * Start a GENSEC sub-mechanism by a well know SASL name
428 NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
429 const char *sasl_name)
431 gensec_security->ops = gensec_security_by_sasl_name(sasl_name);
432 if (!gensec_security->ops) {
433 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
434 return NT_STATUS_INVALID_PARAMETER;
436 return gensec_start_mech(gensec_security);
440 wrappers for the gensec function pointers
442 NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
444 uint8_t *data, size_t length,
445 const uint8_t *whole_pdu, size_t pdu_length,
446 const DATA_BLOB *sig)
448 if (!gensec_security->ops->unseal_packet) {
449 return NT_STATUS_NOT_IMPLEMENTED;
451 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
452 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
453 return gensec_check_packet(gensec_security, mem_ctx,
455 whole_pdu, pdu_length,
458 return NT_STATUS_INVALID_PARAMETER;
461 return gensec_security->ops->unseal_packet(gensec_security, mem_ctx,
463 whole_pdu, pdu_length,
467 NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
469 const uint8_t *data, size_t length,
470 const uint8_t *whole_pdu, size_t pdu_length,
471 const DATA_BLOB *sig)
473 if (!gensec_security->ops->check_packet) {
474 return NT_STATUS_NOT_IMPLEMENTED;
476 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
477 return NT_STATUS_INVALID_PARAMETER;
480 return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
483 NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
485 uint8_t *data, size_t length,
486 const uint8_t *whole_pdu, size_t pdu_length,
489 if (!gensec_security->ops->seal_packet) {
490 return NT_STATUS_NOT_IMPLEMENTED;
492 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
493 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
494 return gensec_sign_packet(gensec_security, mem_ctx,
496 whole_pdu, pdu_length,
499 return NT_STATUS_INVALID_PARAMETER;
502 return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
505 NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
507 const uint8_t *data, size_t length,
508 const uint8_t *whole_pdu, size_t pdu_length,
511 if (!gensec_security->ops->sign_packet) {
512 return NT_STATUS_NOT_IMPLEMENTED;
514 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
515 return NT_STATUS_INVALID_PARAMETER;
518 return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
521 size_t gensec_sig_size(struct gensec_security *gensec_security)
523 if (!gensec_security->ops->sig_size) {
526 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
530 return gensec_security->ops->sig_size(gensec_security);
533 NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
538 if (!gensec_security->ops->wrap) {
539 return NT_STATUS_NOT_IMPLEMENTED;
541 return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
544 NTSTATUS gensec_unwrap(struct gensec_security *gensec_security,
549 if (!gensec_security->ops->unwrap) {
550 return NT_STATUS_NOT_IMPLEMENTED;
552 return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
555 NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
556 DATA_BLOB *session_key)
558 if (!gensec_security->ops->session_key) {
559 return NT_STATUS_NOT_IMPLEMENTED;
561 return gensec_security->ops->session_key(gensec_security, session_key);
565 * Return the credentials of a logged on user, including session keys
568 * Only valid after a successful authentication
570 * May only be called once per authentication.
574 NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
575 struct auth_session_info **session_info)
577 if (!gensec_security->ops->session_info) {
578 return NT_STATUS_NOT_IMPLEMENTED;
580 return gensec_security->ops->session_info(gensec_security, session_info);
584 * Next state function for the GENSEC state machine
586 * @param gensec_security GENSEC State
587 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
588 * @param in The request, as a DATA_BLOB
589 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
590 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
591 * or NT_STATUS_OK if the user is authenticated.
594 NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
595 const DATA_BLOB in, DATA_BLOB *out)
597 return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
601 * Set the requirement for a certain feature on the connection
605 void gensec_want_feature(struct gensec_security *gensec_security,
608 gensec_security->want_features |= feature;
612 * Check the requirement for a certain feature on the connection
616 BOOL gensec_have_feature(struct gensec_security *gensec_security,
619 if (!gensec_security->ops->have_feature) {
622 return gensec_security->ops->have_feature(gensec_security, feature);
626 * Associate a credentails structure with a GENSEC context - talloc_reference()s it to the context
630 NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
632 gensec_security->credentials = talloc_reference(gensec_security, credentials);
637 * Return the credentails structure associated with a GENSEC context
641 struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security)
643 return gensec_security->credentials;
647 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
651 NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
653 gensec_security->target.service = talloc_strdup(gensec_security, service);
654 if (!gensec_security->target.service) {
655 return NT_STATUS_NO_MEMORY;
661 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
665 NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
667 gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
668 if (!gensec_security->target.hostname) {
669 return NT_STATUS_NO_MEMORY;
674 const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
676 if (gensec_security->target.hostname) {
677 return gensec_security->target.hostname;
680 /* TODO: Add a 'set sockaddr' call, and do a reverse lookup */
684 const char *gensec_get_target_service(struct gensec_security *gensec_security)
686 if (gensec_security->target.service) {
687 return gensec_security->target.service;
694 register a GENSEC backend.
696 The 'name' can be later used by other backends to find the operations
697 structure for this backend.
699 NTSTATUS gensec_register(const void *_ops)
701 const struct gensec_security_ops *ops = _ops;
703 if (!lp_parm_bool(-1, "gensec", ops->name, ops->enabled)) {
704 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
708 if (gensec_security_by_name(ops->name) != NULL) {
709 /* its already registered! */
710 DEBUG(0,("GENSEC backend '%s' already registered\n",
712 return NT_STATUS_OBJECT_NAME_COLLISION;
715 generic_security_ops = realloc_p(generic_security_ops,
716 const struct gensec_security_ops *,
717 gensec_num_backends+1);
718 if (!generic_security_ops) {
719 smb_panic("out of memory in gensec_register");
722 generic_security_ops[gensec_num_backends] = ops;
724 gensec_num_backends++;
726 DEBUG(3,("GENSEC backend '%s' registered\n",
733 return the GENSEC interface version, and the size of some critical types
734 This can be used by backends to either detect compilation errors, or provide
735 multiple implementations for different smbd compilation options in one module
737 const struct gensec_critical_sizes *gensec_interface_version(void)
739 static const struct gensec_critical_sizes critical_sizes = {
740 GENSEC_INTERFACE_VERSION,
741 sizeof(struct gensec_security_ops),
742 sizeof(struct gensec_security),
745 return &critical_sizes;
749 initialise the GENSEC subsystem
751 NTSTATUS gensec_init(void)