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(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 Start the GENSEC system, returning a context pointer.
120 @param mem_ctx The parent TALLOC memory context.
121 @param gensec_security Returned GENSEC context pointer.
122 @note The mem_ctx is only a parent and may be NULL.
124 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security)
126 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
127 if (!(*gensec_security)) {
128 return NT_STATUS_NO_MEMORY;
131 (*gensec_security)->ops = NULL;
133 ZERO_STRUCT((*gensec_security)->user);
134 ZERO_STRUCT((*gensec_security)->target);
135 ZERO_STRUCT((*gensec_security)->default_user);
137 (*gensec_security)->default_user.name = "";
138 (*gensec_security)->default_user.domain = talloc_strdup(*gensec_security, lp_workgroup());
139 (*gensec_security)->default_user.realm = talloc_strdup(*gensec_security, lp_realm());
141 (*gensec_security)->subcontext = False;
142 (*gensec_security)->want_features = 0;
147 * Start a GENSEC subcontext, with a copy of the properties of the parent
148 * @param mem_ctx The parent TALLOC memory context.
149 * @param parent The parent GENSEC context
150 * @param gensec_security Returned GENSEC context pointer.
151 * @note Used by SPNEGO in particular, for the actual implementation mechanism
154 NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
155 struct gensec_security *parent,
156 struct gensec_security **gensec_security)
158 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
159 if (!(*gensec_security)) {
160 return NT_STATUS_NO_MEMORY;
163 (**gensec_security) = *parent;
164 (*gensec_security)->ops = NULL;
165 (*gensec_security)->private_data = NULL;
167 (*gensec_security)->subcontext = True;
173 Start the GENSEC system, in client mode, returning a context pointer.
174 @param mem_ctx The parent TALLOC memory context.
175 @param gensec_security Returned GENSEC context pointer.
176 @note The mem_ctx is only a parent and may be NULL.
178 NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security)
181 status = gensec_start(mem_ctx, gensec_security);
182 if (!NT_STATUS_IS_OK(status)) {
185 (*gensec_security)->gensec_role = GENSEC_CLIENT;
186 (*gensec_security)->password_callback = NULL;
188 ZERO_STRUCT((*gensec_security)->user);
194 Start the GENSEC system, in server mode, returning a context pointer.
195 @param mem_ctx The parent TALLOC memory context.
196 @param gensec_security Returned GENSEC context pointer.
197 @note The mem_ctx is only a parent and may be NULL.
199 NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security)
202 status = gensec_start(mem_ctx, gensec_security);
203 if (!NT_STATUS_IS_OK(status)) {
206 (*gensec_security)->gensec_role = GENSEC_SERVER;
211 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
214 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
215 gensec_security->subcontext ? "sub" : "",
216 gensec_security->ops->name));
217 switch (gensec_security->gensec_role) {
219 if (gensec_security->ops->client_start) {
220 status = gensec_security->ops->client_start(gensec_security);
221 if (!NT_STATUS_IS_OK(status)) {
222 DEBUG(1, ("Failed to start GENSEC client mech %s: %s\n",
223 gensec_security->ops->name, nt_errstr(status)));
228 if (gensec_security->ops->server_start) {
229 status = gensec_security->ops->server_start(gensec_security);
230 if (!NT_STATUS_IS_OK(status)) {
231 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
232 gensec_security->ops->name, nt_errstr(status)));
237 return NT_STATUS_INVALID_PARAMETER;
241 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
242 * @param gensec_security GENSEC context pointer.
243 * @param auth_type DCERPC auth type
244 * @param auth_level DCERPC auth level
247 NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
248 uint8_t auth_type, uint8_t auth_level)
250 gensec_security->ops = gensec_security_by_authtype(auth_type);
251 if (!gensec_security->ops) {
252 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
253 return NT_STATUS_INVALID_PARAMETER;
255 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
256 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
257 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
259 if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
260 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
261 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
264 return gensec_start_mech(gensec_security);
267 const char *gensec_get_name_by_authtype(uint8_t authtype)
269 const struct gensec_security_ops *ops;
270 ops = gensec_security_by_authtype(authtype);
278 const char *gensec_get_name_by_oid(const char *oid_string)
280 const struct gensec_security_ops *ops;
281 ops = gensec_security_by_oid(oid_string);
290 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
292 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
293 * well-known #define to hook it in.
296 NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
297 const char *mech_oid)
299 gensec_security->ops = gensec_security_by_oid(mech_oid);
300 if (!gensec_security->ops) {
301 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
302 return NT_STATUS_INVALID_PARAMETER;
304 return gensec_start_mech(gensec_security);
308 * Start a GENSEC sub-mechanism by a well know SASL name
312 NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
313 const char *sasl_name)
315 gensec_security->ops = gensec_security_by_sasl_name(sasl_name);
316 if (!gensec_security->ops) {
317 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
318 return NT_STATUS_INVALID_PARAMETER;
320 return gensec_start_mech(gensec_security);
324 wrappers for the gensec function pointers
326 NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
328 uint8_t *data, size_t length,
329 const uint8_t *whole_pdu, size_t pdu_length,
332 if (!gensec_security->ops->unseal_packet) {
333 return NT_STATUS_NOT_IMPLEMENTED;
335 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
336 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
337 return gensec_check_packet(gensec_security, mem_ctx,
339 whole_pdu, pdu_length,
342 return NT_STATUS_INVALID_PARAMETER;
345 return gensec_security->ops->unseal_packet(gensec_security, mem_ctx,
347 whole_pdu, pdu_length,
351 NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
353 const uint8_t *data, size_t length,
354 const uint8_t *whole_pdu, size_t pdu_length,
355 const DATA_BLOB *sig)
357 if (!gensec_security->ops->check_packet) {
358 return NT_STATUS_NOT_IMPLEMENTED;
360 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
361 return NT_STATUS_INVALID_PARAMETER;
364 return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
367 NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
369 uint8_t *data, size_t length,
370 const uint8_t *whole_pdu, size_t pdu_length,
373 if (!gensec_security->ops->seal_packet) {
374 return NT_STATUS_NOT_IMPLEMENTED;
376 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
377 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
378 return gensec_sign_packet(gensec_security, mem_ctx,
380 whole_pdu, pdu_length,
383 return NT_STATUS_INVALID_PARAMETER;
386 return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
389 NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
391 const uint8_t *data, size_t length,
392 const uint8_t *whole_pdu, size_t pdu_length,
395 if (!gensec_security->ops->sign_packet) {
396 return NT_STATUS_NOT_IMPLEMENTED;
398 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
399 return NT_STATUS_INVALID_PARAMETER;
402 return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
405 size_t gensec_sig_size(struct gensec_security *gensec_security)
407 if (!gensec_security->ops->sig_size) {
410 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
414 return gensec_security->ops->sig_size(gensec_security);
417 NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
422 if (!gensec_security->ops->wrap) {
423 return NT_STATUS_NOT_IMPLEMENTED;
425 return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
428 NTSTATUS gensec_unwrap(struct gensec_security *gensec_security,
433 if (!gensec_security->ops->unwrap) {
434 return NT_STATUS_NOT_IMPLEMENTED;
436 return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
439 NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
440 DATA_BLOB *session_key)
442 if (!gensec_security->ops->session_key) {
443 return NT_STATUS_NOT_IMPLEMENTED;
445 return gensec_security->ops->session_key(gensec_security, session_key);
449 * Return the credentials of a logged on user, including session keys
452 * Only valid after a successful authentication
454 * May only be called once per authentication.
458 NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
459 struct auth_session_info **session_info)
461 if (!gensec_security->ops->session_info) {
462 return NT_STATUS_NOT_IMPLEMENTED;
464 return gensec_security->ops->session_info(gensec_security, session_info);
468 * Next state function for the GENSEC state machine
470 * @param gensec_security GENSEC State
471 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
472 * @param in The request, as a DATA_BLOB
473 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
474 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
475 * or NT_STATUS_OK if the user is authenticated.
478 NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
479 const DATA_BLOB in, DATA_BLOB *out)
481 return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
485 * Set the requirement for a certain feature on the connection
489 void gensec_want_feature(struct gensec_security *gensec_security,
492 gensec_security->want_features |= feature;
496 * Check the requirement for a certain feature on the connection
500 BOOL gensec_have_feature(struct gensec_security *gensec_security,
503 if (!gensec_security->ops->have_feature) {
506 return gensec_security->ops->have_feature(gensec_security, feature);
510 * Set a username on a GENSEC context - ensures it is talloc()ed
514 NTSTATUS gensec_set_unparsed_username(struct gensec_security *gensec_security, const char *user)
517 char *u = talloc_strdup(gensec_security, user);
519 return NT_STATUS_NO_MEMORY;
522 p = strchr_m(user, '@');
526 gensec_security->user.name = talloc_strdup(gensec_security, u);
527 if (!gensec_security->user.name) {
528 return NT_STATUS_NO_MEMORY;
531 gensec_security->user.realm = talloc_strdup(gensec_security, p+1);
532 if (!gensec_security->user.realm) {
533 return NT_STATUS_NO_MEMORY;
538 p = strchr_m(user, '\\');
540 p = strchr_m(user, '/');
545 gensec_security->user.domain = talloc_strdup(gensec_security, u);
546 if (!gensec_security->user.domain) {
547 return NT_STATUS_NO_MEMORY;
549 gensec_security->user.name = talloc_strdup(gensec_security, p+1);
550 if (!gensec_security->user.name) {
551 return NT_STATUS_NO_MEMORY;
557 gensec_security->user.name = u;
558 if (!gensec_security->user.name) {
559 return NT_STATUS_NO_MEMORY;
565 * Set a username on a GENSEC context - ensures it is talloc()ed
569 NTSTATUS gensec_set_username(struct gensec_security *gensec_security, const char *user)
571 gensec_security->user.name = talloc_strdup(gensec_security, user);
572 if (!gensec_security->user.name) {
573 return NT_STATUS_NO_MEMORY;
579 * Set a username on a GENSEC context - ensures it is talloc()ed
583 const char *gensec_get_username(struct gensec_security *gensec_security)
585 if (gensec_security->user.name) {
586 return gensec_security->user.name;
588 return gensec_security->default_user.name;
592 * Set a domain on a GENSEC context - ensures it is talloc()ed
596 NTSTATUS gensec_set_domain(struct gensec_security *gensec_security, const char *domain)
598 gensec_security->user.domain = talloc_strdup(gensec_security, domain);
599 if (!gensec_security->user.domain) {
600 return NT_STATUS_NO_MEMORY;
606 * Return the NT domain for this GENSEC context
610 const char *gensec_get_domain(struct gensec_security *gensec_security)
612 if (gensec_security->user.domain) {
613 return gensec_security->user.domain;
614 } else if (gensec_security->user.realm) {
615 return gensec_security->user.realm;
617 return gensec_security->default_user.domain;
621 * Set the client workstation on a GENSEC context - ensures it is talloc()ed
625 NTSTATUS gensec_set_workstation(struct gensec_security *gensec_security, const char *workstation)
627 gensec_security->user.workstation = talloc_strdup(gensec_security, workstation);
628 if (!gensec_security->user.workstation) {
629 return NT_STATUS_NO_MEMORY;
635 * Return the client workstation on a GENSEC context - ensures it is talloc()ed
639 const char *gensec_get_workstation(struct gensec_security *gensec_security)
641 if (gensec_security->user.workstation) {
642 return gensec_security->user.workstation;
644 return lp_netbios_name();
649 * Set a kerberos realm on a GENSEC context - ensures it is talloc()ed
653 NTSTATUS gensec_set_realm(struct gensec_security *gensec_security, const char *realm)
655 gensec_security->user.realm = talloc_strdup(gensec_security, realm);
656 if (!gensec_security->user.realm) {
657 return NT_STATUS_NO_MEMORY;
663 * Return the Krb5 realm for this context
667 const char *gensec_get_realm(struct gensec_security *gensec_security)
669 if (gensec_security->user.realm) {
670 return gensec_security->user.realm;
671 } else if (gensec_security->user.domain) {
672 return gensec_security->user.domain;
674 return gensec_security->default_user.realm;
678 * Return a kerberos principal for this context, if one has been set
682 char *gensec_get_client_principal(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx)
684 const char *realm = gensec_get_realm(gensec_security);
686 return talloc_asprintf(mem_ctx, "%s@%s",
687 gensec_get_username(gensec_security),
688 gensec_get_realm(gensec_security));
690 return talloc_strdup(mem_ctx, gensec_get_username(gensec_security));
695 * Set the password outright on GENSEC context - ensures it is talloc()ed, and that we will
700 NTSTATUS gensec_set_password(struct gensec_security *gensec_security,
701 const char *password)
703 gensec_security->user.password = talloc_strdup(gensec_security, password);
704 if (password && !gensec_security->user.password) {
705 return NT_STATUS_NO_MEMORY;
711 * Set the target principal name (if already known) on a GENSEC context - ensures it is talloc()ed
715 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
717 gensec_security->target.principal = talloc_strdup(gensec_security, principal);
718 if (!gensec_security->target.principal) {
719 return NT_STATUS_NO_MEMORY;
725 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
729 NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
731 gensec_security->target.service = talloc_strdup(gensec_security, service);
732 if (!gensec_security->target.service) {
733 return NT_STATUS_NO_MEMORY;
739 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
743 NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
745 gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
746 if (!gensec_security->target.hostname) {
747 return NT_STATUS_NO_MEMORY;
752 const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
754 if (gensec_security->target.hostname) {
755 return gensec_security->target.hostname;
758 /* TODO: Add a 'set sockaddr' call, and do a reverse lookup */
762 const char *gensec_get_target_service(struct gensec_security *gensec_security)
764 if (gensec_security->target.service) {
765 return gensec_security->target.service;
771 const char *gensec_get_target_principal(struct gensec_security *gensec_security)
773 const char *mechListMIC;
775 if (gensec_security->target.principal) {
776 return gensec_security->target.principal;
779 mechListMIC = talloc_asprintf(gensec_security,"%s$@%s",
786 * Set a password callback, if the gensec module we use demands a password
789 void gensec_set_password_callback(struct gensec_security *gensec_security,
790 gensec_password_callback callback, void *callback_private_data)
792 gensec_security->password_callback = callback;
793 gensec_security->password_callback_private = callback_private_data;
797 * Get (or call back for) a password.
800 NTSTATUS gensec_get_password(struct gensec_security *gensec_security,
804 if (gensec_security->user.password) {
805 *password = talloc_strdup(mem_ctx, gensec_security->user.password);
807 return NT_STATUS_NO_MEMORY;
812 if (!gensec_security->password_callback) {
816 return gensec_security->password_callback(gensec_security, mem_ctx, password);
820 register a GENSEC backend.
822 The 'name' can be later used by other backends to find the operations
823 structure for this backend.
825 NTSTATUS gensec_register(const void *_ops)
827 const struct gensec_security_ops *ops = _ops;
829 if (!lp_parm_bool(-1, "gensec", ops->name, ops->enabled)) {
830 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
834 if (gensec_security_by_name(ops->name) != NULL) {
835 /* its already registered! */
836 DEBUG(0,("GENSEC backend '%s' already registered\n",
838 return NT_STATUS_OBJECT_NAME_COLLISION;
841 generic_security_ops = realloc_p(generic_security_ops,
842 const struct gensec_security_ops *,
843 gensec_num_backends+1);
844 if (!generic_security_ops) {
845 smb_panic("out of memory in gensec_register");
848 generic_security_ops[gensec_num_backends] = ops;
850 gensec_num_backends++;
852 DEBUG(3,("GENSEC backend '%s' registered\n",
859 return the GENSEC interface version, and the size of some critical types
860 This can be used by backends to either detect compilation errors, or provide
861 multiple implementations for different smbd compilation options in one module
863 const struct gensec_critical_sizes *gensec_interface_version(void)
865 static const struct gensec_critical_sizes critical_sizes = {
866 GENSEC_INTERFACE_VERSION,
867 sizeof(struct gensec_security_ops),
868 sizeof(struct gensec_security),
871 return &critical_sizes;
875 initialise the GENSEC subsystem
877 NTSTATUS gensec_init(void)
879 gensec_dcerpc_schannel_init();