2 Unix SMB/CIFS implementation.
4 Generic Authentication Interface
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
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 (strcmp(generic_security_ops[i]->oid, oid_string) == 0)) {
49 return generic_security_ops[i];
56 static const struct gensec_security_ops *gensec_security_by_sasl_name(const char *sasl_name)
59 for (i=0; i < gensec_num_backends; i++) {
60 if (generic_security_ops[i]->sasl_name
61 && (strcmp(generic_security_ops[i]->sasl_name, sasl_name) == 0)) {
62 return generic_security_ops[i];
69 static const struct gensec_security_ops *gensec_security_by_name(const char *name)
72 for (i=0; i < gensec_num_backends; i++) {
73 if (generic_security_ops[i]->name
74 && (strcmp(generic_security_ops[i]->name, name) == 0)) {
75 return generic_security_ops[i];
82 const struct gensec_security_ops **gensec_security_all(int *num_backends_out)
84 *num_backends_out = gensec_num_backends;
85 return generic_security_ops;
88 const char **gensec_security_oids(TALLOC_CTX *mem_ctx, const char *skip)
91 const char **oid_list;
93 const struct gensec_security_ops **ops = gensec_security_all(&num_backends);
97 oid_list = talloc_array_p(mem_ctx, const char *, num_backends + 1);
102 for (i=0; i<num_backends; i++) {
107 if (skip && strcmp(skip, ops[i]->oid)==0) {
111 oid_list[j] = ops[i]->oid;
119 note that memory context is the parent context to hang this gensec context off. It may be NULL.
121 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security)
123 (*gensec_security) = talloc_p(mem_ctx, struct gensec_security);
124 if (!(*gensec_security)) {
125 return NT_STATUS_NO_MEMORY;
128 (*gensec_security)->ops = NULL;
130 ZERO_STRUCT((*gensec_security)->user);
131 ZERO_STRUCT((*gensec_security)->target);
132 ZERO_STRUCT((*gensec_security)->default_user);
134 (*gensec_security)->default_user.name = "";
135 (*gensec_security)->default_user.domain = talloc_strdup(*gensec_security, lp_workgroup());
136 (*gensec_security)->default_user.realm = talloc_strdup(*gensec_security, lp_realm());
138 (*gensec_security)->subcontext = False;
139 (*gensec_security)->want_features = 0;
144 * Start a GENSEC subcontext, with a copy of the properties of the parent
146 * @note Used by SPENGO in particular, for the actual implementation mechanism
149 NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
150 struct gensec_security *parent,
151 struct gensec_security **gensec_security)
153 (*gensec_security) = talloc_p(mem_ctx, struct gensec_security);
154 if (!(*gensec_security)) {
155 return NT_STATUS_NO_MEMORY;
158 (**gensec_security) = *parent;
159 (*gensec_security)->ops = NULL;
160 (*gensec_security)->private_data = NULL;
162 (*gensec_security)->subcontext = True;
167 NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security)
170 status = gensec_start(mem_ctx, gensec_security);
171 if (!NT_STATUS_IS_OK(status)) {
174 (*gensec_security)->gensec_role = GENSEC_CLIENT;
175 (*gensec_security)->password_callback = NULL;
177 ZERO_STRUCT((*gensec_security)->user);
182 NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security)
185 status = gensec_start(mem_ctx, gensec_security);
186 if (!NT_STATUS_IS_OK(status)) {
189 (*gensec_security)->gensec_role = GENSEC_SERVER;
194 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
197 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
198 gensec_security->subcontext ? "sub" : "",
199 gensec_security->ops->name));
200 switch (gensec_security->gensec_role) {
202 if (gensec_security->ops->client_start) {
203 status = gensec_security->ops->client_start(gensec_security);
204 if (!NT_STATUS_IS_OK(status)) {
205 DEBUG(1, ("Failed to start GENSEC client mech %s: %s\n",
206 gensec_security->ops->name, nt_errstr(status)));
211 if (gensec_security->ops->server_start) {
212 status = gensec_security->ops->server_start(gensec_security);
213 if (!NT_STATUS_IS_OK(status)) {
214 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
215 gensec_security->ops->name, nt_errstr(status)));
220 return NT_STATUS_INVALID_PARAMETER;
224 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
227 NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
228 uint8_t auth_type, uint8_t auth_level)
230 gensec_security->ops = gensec_security_by_authtype(auth_type);
231 if (!gensec_security->ops) {
232 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
233 return NT_STATUS_INVALID_PARAMETER;
235 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
236 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
237 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
239 if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
240 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
241 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
244 return gensec_start_mech(gensec_security);
247 const char *gensec_get_name_by_authtype(uint8_t authtype)
249 const struct gensec_security_ops *ops;
250 ops = gensec_security_by_authtype(authtype);
258 const char *gensec_get_name_by_oid(const char *oid_string)
260 const struct gensec_security_ops *ops;
261 ops = gensec_security_by_oid(oid_string);
270 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
272 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
273 * well-known #define to hook it in.
276 NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
277 const char *mech_oid)
279 gensec_security->ops = gensec_security_by_oid(mech_oid);
280 if (!gensec_security->ops) {
281 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
282 return NT_STATUS_INVALID_PARAMETER;
284 return gensec_start_mech(gensec_security);
288 * Start a GENSEC sub-mechanism by a well know SASL name
292 NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
293 const char *sasl_name)
295 gensec_security->ops = gensec_security_by_sasl_name(sasl_name);
296 if (!gensec_security->ops) {
297 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
298 return NT_STATUS_INVALID_PARAMETER;
300 return gensec_start_mech(gensec_security);
304 wrappers for the gensec function pointers
306 NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
308 uint8_t *data, size_t length,
309 const uint8_t *whole_pdu, size_t pdu_length,
312 if (!gensec_security->ops->unseal_packet) {
313 return NT_STATUS_NOT_IMPLEMENTED;
315 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
316 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
317 return gensec_check_packet(gensec_security, mem_ctx,
319 whole_pdu, pdu_length,
322 return NT_STATUS_INVALID_PARAMETER;
325 return gensec_security->ops->unseal_packet(gensec_security, mem_ctx,
327 whole_pdu, pdu_length,
331 NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
333 const uint8_t *data, size_t length,
334 const uint8_t *whole_pdu, size_t pdu_length,
335 const DATA_BLOB *sig)
337 if (!gensec_security->ops->check_packet) {
338 return NT_STATUS_NOT_IMPLEMENTED;
340 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
341 return NT_STATUS_INVALID_PARAMETER;
344 return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
347 NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
349 uint8_t *data, size_t length,
350 const uint8_t *whole_pdu, size_t pdu_length,
353 if (!gensec_security->ops->seal_packet) {
354 return NT_STATUS_NOT_IMPLEMENTED;
356 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
357 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
358 return gensec_sign_packet(gensec_security, mem_ctx,
360 whole_pdu, pdu_length,
363 return NT_STATUS_INVALID_PARAMETER;
366 return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
369 NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
371 const uint8_t *data, size_t length,
372 const uint8_t *whole_pdu, size_t pdu_length,
375 if (!gensec_security->ops->sign_packet) {
376 return NT_STATUS_NOT_IMPLEMENTED;
378 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
379 return NT_STATUS_INVALID_PARAMETER;
382 return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
385 size_t gensec_sig_size(struct gensec_security *gensec_security)
387 if (!gensec_security->ops->sig_size) {
390 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
394 return gensec_security->ops->sig_size(gensec_security);
397 NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
402 if (!gensec_security->ops->wrap) {
403 return NT_STATUS_NOT_IMPLEMENTED;
405 return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
408 NTSTATUS gensec_unwrap(struct gensec_security *gensec_security,
413 if (!gensec_security->ops->unwrap) {
414 return NT_STATUS_NOT_IMPLEMENTED;
416 return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
419 NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
420 DATA_BLOB *session_key)
422 if (!gensec_security->ops->session_key) {
423 return NT_STATUS_NOT_IMPLEMENTED;
425 return gensec_security->ops->session_key(gensec_security, session_key);
429 * Return the credentials of a logged on user, including session keys
432 * Only valid after a successful authentication
434 * May only be called once per authentication.
438 NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
439 struct auth_session_info **session_info)
441 if (!gensec_security->ops->session_info) {
442 return NT_STATUS_NOT_IMPLEMENTED;
444 return gensec_security->ops->session_info(gensec_security, session_info);
448 * Next state function for the GENSEC state machine
450 * @param gensec_security GENSEC State
451 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
452 * @param in The request, as a DATA_BLOB
453 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
454 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
455 * or NT_STATUS_OK if the user is authenticated.
458 NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
459 const DATA_BLOB in, DATA_BLOB *out)
461 return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
465 * Set the requirement for a certain feature on the connection
469 void gensec_want_feature(struct gensec_security *gensec_security,
472 gensec_security->want_features |= feature;
476 * Check the requirement for a certain feature on the connection
480 BOOL gensec_have_feature(struct gensec_security *gensec_security,
483 if (!gensec_security->ops->have_feature) {
486 return gensec_security->ops->have_feature(gensec_security, feature);
490 * Set a username on a GENSEC context - ensures it is talloc()ed
494 NTSTATUS gensec_set_unparsed_username(struct gensec_security *gensec_security, const char *user)
497 char *u = talloc_strdup(gensec_security, user);
499 return NT_STATUS_NO_MEMORY;
502 p = strchr_m(user, '@');
506 gensec_security->user.name = talloc_strdup(gensec_security, u);
507 if (!gensec_security->user.name) {
508 return NT_STATUS_NO_MEMORY;
511 gensec_security->user.realm = talloc_strdup(gensec_security, p+1);
512 if (!gensec_security->user.realm) {
513 return NT_STATUS_NO_MEMORY;
518 p = strchr_m(user, '\\');
520 p = strchr_m(user, '/');
525 gensec_security->user.domain = talloc_strdup(gensec_security, u);
526 if (!gensec_security->user.domain) {
527 return NT_STATUS_NO_MEMORY;
529 gensec_security->user.name = talloc_strdup(gensec_security, p+1);
530 if (!gensec_security->user.name) {
531 return NT_STATUS_NO_MEMORY;
537 gensec_security->user.name = u;
538 if (!gensec_security->user.name) {
539 return NT_STATUS_NO_MEMORY;
545 * Set a username on a GENSEC context - ensures it is talloc()ed
549 NTSTATUS gensec_set_username(struct gensec_security *gensec_security, const char *user)
551 gensec_security->user.name = talloc_strdup(gensec_security, user);
552 if (!gensec_security->user.name) {
553 return NT_STATUS_NO_MEMORY;
559 * Set a username on a GENSEC context - ensures it is talloc()ed
563 const char *gensec_get_username(struct gensec_security *gensec_security)
565 if (gensec_security->user.name) {
566 return gensec_security->user.name;
568 return gensec_security->default_user.name;
572 * Set a domain on a GENSEC context - ensures it is talloc()ed
576 NTSTATUS gensec_set_domain(struct gensec_security *gensec_security, const char *domain)
578 gensec_security->user.domain = talloc_strdup(gensec_security, domain);
579 if (!gensec_security->user.domain) {
580 return NT_STATUS_NO_MEMORY;
586 * Return the NT domain for this GENSEC context
590 const char *gensec_get_domain(struct gensec_security *gensec_security)
592 if (gensec_security->user.domain) {
593 return gensec_security->user.domain;
594 } else if (gensec_security->user.realm) {
595 return gensec_security->user.realm;
597 return gensec_security->default_user.domain;
601 * Set a kerberos realm on a GENSEC context - ensures it is talloc()ed
605 NTSTATUS gensec_set_realm(struct gensec_security *gensec_security, const char *realm)
607 gensec_security->user.realm = talloc_strdup(gensec_security, realm);
608 if (!gensec_security->user.realm) {
609 return NT_STATUS_NO_MEMORY;
615 * Return the Krb5 realm for this context
619 const char *gensec_get_realm(struct gensec_security *gensec_security)
621 if (gensec_security->user.realm) {
622 return gensec_security->user.realm;
623 } else if (gensec_security->user.domain) {
624 return gensec_security->user.domain;
626 return gensec_security->default_user.realm;
630 * Return a kerberos principal for this context, if one has been set
634 char *gensec_get_client_principal(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx)
636 const char *realm = gensec_get_realm(gensec_security);
638 return talloc_asprintf(mem_ctx, "%s@%s",
639 gensec_get_username(gensec_security),
640 gensec_get_realm(gensec_security));
642 return talloc_strdup(mem_ctx, gensec_get_username(gensec_security));
647 * Set the password outright on GENSEC context - ensures it is talloc()ed, and that we will
652 NTSTATUS gensec_set_password(struct gensec_security *gensec_security,
653 const char *password)
655 gensec_security->user.password = talloc_strdup(gensec_security, password);
656 if (password && !gensec_security->user.password) {
657 return NT_STATUS_NO_MEMORY;
663 * Set the target principal name (if already known) on a GENSEC context - ensures it is talloc()ed
667 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
669 gensec_security->target.principal = talloc_strdup(gensec_security, principal);
670 if (!gensec_security->target.principal) {
671 return NT_STATUS_NO_MEMORY;
677 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
681 NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
683 gensec_security->target.service = talloc_strdup(gensec_security, service);
684 if (!gensec_security->target.service) {
685 return NT_STATUS_NO_MEMORY;
691 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
695 NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
697 gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
698 if (!gensec_security->target.hostname) {
699 return NT_STATUS_NO_MEMORY;
704 const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
706 if (gensec_security->target.hostname) {
707 return gensec_security->target.hostname;
710 /* TODO: Add a 'set sockaddr' call, and do a reverse lookup */
714 const char *gensec_get_target_service(struct gensec_security *gensec_security)
716 if (gensec_security->target.service) {
717 return gensec_security->target.service;
723 const char *gensec_get_target_principal(struct gensec_security *gensec_security)
725 const char *mechListMIC;
727 if (gensec_security->target.principal) {
728 return gensec_security->target.principal;
731 mechListMIC = talloc_asprintf(gensec_security,"%s$@%s",
738 * Set a password callback, if the gensec module we use demands a password
741 void gensec_set_password_callback(struct gensec_security *gensec_security,
742 gensec_password_callback callback, void *callback_private_data)
744 gensec_security->password_callback = callback;
745 gensec_security->password_callback_private = callback_private_data;
749 * Get (or call back for) a password.
752 NTSTATUS gensec_get_password(struct gensec_security *gensec_security,
756 if (gensec_security->user.password) {
757 *password = talloc_strdup(mem_ctx, gensec_security->user.password);
759 return NT_STATUS_NO_MEMORY;
764 if (!gensec_security->password_callback) {
768 return gensec_security->password_callback(gensec_security, mem_ctx, password);
772 register a GENSEC backend.
774 The 'name' can be later used by other backends to find the operations
775 structure for this backend.
777 NTSTATUS gensec_register(const void *_ops)
779 const struct gensec_security_ops *ops = _ops;
781 if (!lp_parm_bool(-1, "gensec", ops->name, !ops->disabled_by_default)) {
782 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
786 if (gensec_security_by_name(ops->name) != NULL) {
787 /* its already registered! */
788 DEBUG(0,("GENSEC backend '%s' already registered\n",
790 return NT_STATUS_OBJECT_NAME_COLLISION;
793 generic_security_ops = realloc_p(generic_security_ops,
794 const struct gensec_security_ops *,
795 gensec_num_backends+1);
796 if (!generic_security_ops) {
797 smb_panic("out of memory in gensec_register");
800 generic_security_ops[gensec_num_backends] = ops;
802 gensec_num_backends++;
804 DEBUG(3,("GENSEC backend '%s' registered\n",
811 return the GENSEC interface version, and the size of some critical types
812 This can be used by backends to either detect compilation errors, or provide
813 multiple implementations for different smbd compilation options in one module
815 const struct gensec_critical_sizes *gensec_interface_version(void)
817 static const struct gensec_critical_sizes critical_sizes = {
818 GENSEC_INTERFACE_VERSION,
819 sizeof(struct gensec_security_ops),
820 sizeof(struct gensec_security),
823 return &critical_sizes;
827 initialise the GENSEC subsystem
829 NTSTATUS gensec_init(void)
831 gensec_dcerpc_schannel_init();