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 /* awaiting a correct fix from metze */
124 if (!gensec_init()) {
125 return NT_STATUS_INTERNAL_ERROR;
128 (*gensec_security) = talloc_p(mem_ctx, struct gensec_security);
129 if (!(*gensec_security)) {
130 return NT_STATUS_NO_MEMORY;
133 (*gensec_security)->ops = NULL;
135 ZERO_STRUCT((*gensec_security)->user);
136 ZERO_STRUCT((*gensec_security)->target);
137 ZERO_STRUCT((*gensec_security)->default_user);
139 (*gensec_security)->default_user.name = "";
140 (*gensec_security)->default_user.domain = talloc_strdup(*gensec_security, lp_workgroup());
141 (*gensec_security)->default_user.realm = talloc_strdup(*gensec_security, lp_realm());
143 (*gensec_security)->subcontext = False;
144 (*gensec_security)->want_features = 0;
149 * Start a GENSEC subcontext, with a copy of the properties of the parent
151 * @note Used by SPENGO in particular, for the actual implementation mechanism
154 NTSTATUS gensec_subcontext_start(struct gensec_security *parent,
155 struct gensec_security **gensec_security)
157 (*gensec_security) = talloc_p(parent, struct gensec_security);
158 if (!(*gensec_security)) {
159 return NT_STATUS_NO_MEMORY;
162 (**gensec_security) = *parent;
163 (*gensec_security)->ops = NULL;
164 (*gensec_security)->private_data = NULL;
166 (*gensec_security)->subcontext = True;
171 NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security)
174 status = gensec_start(mem_ctx, gensec_security);
175 if (!NT_STATUS_IS_OK(status)) {
178 (*gensec_security)->gensec_role = GENSEC_CLIENT;
179 (*gensec_security)->password_callback = NULL;
181 ZERO_STRUCT((*gensec_security)->user);
186 NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security)
189 status = gensec_start(mem_ctx, gensec_security);
190 if (!NT_STATUS_IS_OK(status)) {
193 (*gensec_security)->gensec_role = GENSEC_SERVER;
198 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
201 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
202 gensec_security->subcontext ? "sub" : "",
203 gensec_security->ops->name));
204 switch (gensec_security->gensec_role) {
206 if (gensec_security->ops->client_start) {
207 status = gensec_security->ops->client_start(gensec_security);
208 if (!NT_STATUS_IS_OK(status)) {
209 DEBUG(1, ("Faild to start GENSEC client mech %s: %s\n",
210 gensec_security->ops->name, nt_errstr(status)));
215 if (gensec_security->ops->server_start) {
216 status = gensec_security->ops->server_start(gensec_security);
217 if (!NT_STATUS_IS_OK(status)) {
218 DEBUG(1, ("Faild to start GENSEC server mech %s: %s\n",
219 gensec_security->ops->name, nt_errstr(status)));
224 return NT_STATUS_INVALID_PARAMETER;
228 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
231 NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
232 uint8_t auth_type, uint8_t auth_level)
234 gensec_security->ops = gensec_security_by_authtype(auth_type);
235 if (!gensec_security->ops) {
236 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
237 return NT_STATUS_INVALID_PARAMETER;
239 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
240 gensec_want_feature(gensec_security, GENSEC_WANT_SIGN);
242 if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
243 gensec_want_feature(gensec_security, GENSEC_WANT_SIGN);
244 gensec_want_feature(gensec_security, GENSEC_WANT_SEAL);
247 return gensec_start_mech(gensec_security);
250 const char *gensec_get_name_by_authtype(uint8_t authtype)
252 const struct gensec_security_ops *ops;
253 ops = gensec_security_by_authtype(authtype);
261 const char *gensec_get_name_by_oid(const char *oid_string)
263 const struct gensec_security_ops *ops;
264 ops = gensec_security_by_oid(oid_string);
273 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
275 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
276 * well-known #define to hook it in.
279 NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
280 const char *mech_oid)
282 gensec_security->ops = gensec_security_by_oid(mech_oid);
283 if (!gensec_security->ops) {
284 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
285 return NT_STATUS_INVALID_PARAMETER;
287 return gensec_start_mech(gensec_security);
291 * Start a GENSEC sub-mechanism by a well know SASL name
295 NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
296 const char *sasl_name)
298 gensec_security->ops = gensec_security_by_sasl_name(sasl_name);
299 if (!gensec_security->ops) {
300 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
301 return NT_STATUS_INVALID_PARAMETER;
303 return gensec_start_mech(gensec_security);
307 wrappers for the gensec function pointers
309 NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
311 uint8_t *data, size_t length,
312 const uint8_t *whole_pdu, size_t pdu_length,
315 if (!gensec_security->ops->unseal_packet) {
316 return NT_STATUS_NOT_IMPLEMENTED;
318 if (!(gensec_security->want_features & GENSEC_WANT_SEAL)) {
319 if (gensec_security->want_features & GENSEC_WANT_SIGN) {
320 return gensec_check_packet(gensec_security, mem_ctx,
322 whole_pdu, pdu_length,
325 return NT_STATUS_INVALID_PARAMETER;
328 return gensec_security->ops->unseal_packet(gensec_security, mem_ctx,
330 whole_pdu, pdu_length,
334 NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
336 const uint8_t *data, size_t length,
337 const uint8_t *whole_pdu, size_t pdu_length,
338 const DATA_BLOB *sig)
340 if (!gensec_security->ops->check_packet) {
341 return NT_STATUS_NOT_IMPLEMENTED;
343 if (!(gensec_security->want_features & GENSEC_WANT_SIGN)) {
344 return NT_STATUS_INVALID_PARAMETER;
347 return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
350 NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
352 uint8_t *data, size_t length,
353 const uint8_t *whole_pdu, size_t pdu_length,
356 if (!gensec_security->ops->seal_packet) {
357 return NT_STATUS_NOT_IMPLEMENTED;
359 if (!(gensec_security->want_features & GENSEC_WANT_SEAL)) {
360 if (gensec_security->want_features & GENSEC_WANT_SIGN) {
361 return gensec_sign_packet(gensec_security, mem_ctx,
363 whole_pdu, pdu_length,
366 return NT_STATUS_INVALID_PARAMETER;
369 return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
372 NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
374 const uint8_t *data, size_t length,
375 const uint8_t *whole_pdu, size_t pdu_length,
378 if (!gensec_security->ops->sign_packet) {
379 return NT_STATUS_NOT_IMPLEMENTED;
381 if (!(gensec_security->want_features & GENSEC_WANT_SIGN)) {
382 return NT_STATUS_INVALID_PARAMETER;
385 return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
388 size_t gensec_sig_size(struct gensec_security *gensec_security)
390 if (!gensec_security->ops->sig_size) {
393 if (!(gensec_security->want_features & GENSEC_WANT_SIGN)) {
397 return gensec_security->ops->sig_size(gensec_security);
400 NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
401 DATA_BLOB *session_key)
403 if (!gensec_security->ops->session_key) {
404 return NT_STATUS_NOT_IMPLEMENTED;
406 if (!(gensec_security->want_features & GENSEC_WANT_SESSION_KEY)) {
407 return NT_STATUS_INVALID_PARAMETER;
410 return gensec_security->ops->session_key(gensec_security, session_key);
414 * Return the credentials of a logged on user, including session keys
417 * Only valid after a successful authentication
419 * May only be called once per authentication.
423 NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
424 struct auth_session_info **session_info)
426 if (!gensec_security->ops->session_info) {
427 return NT_STATUS_NOT_IMPLEMENTED;
429 return gensec_security->ops->session_info(gensec_security, session_info);
433 * Next state function for the GENSEC state machine
435 * @param gensec_security GENSEC State
436 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
437 * @param in The request, as a DATA_BLOB
438 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
439 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
440 * or NT_STATUS_OK if the user is authenticated.
443 NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
444 const DATA_BLOB in, DATA_BLOB *out)
446 return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
449 void gensec_end(struct gensec_security **gensec_security)
451 if ((*gensec_security)->ops) {
452 (*gensec_security)->ops->end(*gensec_security);
454 (*gensec_security)->private_data = NULL;
456 talloc_free(*gensec_security);
457 *gensec_security = NULL;
461 * Set the requirement for a certain feature on the connection
465 void gensec_want_feature(struct gensec_security *gensec_security,
468 gensec_security->want_features |= feature;
472 * Check the requirement for a certain feature on the connection
476 BOOL gensec_have_feature(struct gensec_security *gensec_security,
479 if (gensec_security->want_features & feature) {
487 * Set a username on a GENSEC context - ensures it is talloc()ed
491 NTSTATUS gensec_set_unparsed_username(struct gensec_security *gensec_security, const char *user)
494 char *u = talloc_strdup(gensec_security, user);
496 return NT_STATUS_NO_MEMORY;
499 p = strchr_m(user, '@');
503 gensec_security->user.name = talloc_strdup(gensec_security, u);
504 if (!gensec_security->user.name) {
505 return NT_STATUS_NO_MEMORY;
508 gensec_security->user.realm = talloc_strdup(gensec_security, p+1);
509 if (!gensec_security->user.realm) {
510 return NT_STATUS_NO_MEMORY;
515 p = strchr_m(user, '\\');
517 p = strchr_m(user, '/');
522 gensec_security->user.domain = talloc_strdup(gensec_security, u);
523 if (!gensec_security->user.domain) {
524 return NT_STATUS_NO_MEMORY;
526 gensec_security->user.name = talloc_strdup(gensec_security, p+1);
527 if (!gensec_security->user.name) {
528 return NT_STATUS_NO_MEMORY;
534 gensec_security->user.name = u;
535 if (!gensec_security->user.name) {
536 return NT_STATUS_NO_MEMORY;
542 * Set a username on a GENSEC context - ensures it is talloc()ed
546 NTSTATUS gensec_set_username(struct gensec_security *gensec_security, const char *user)
548 gensec_security->user.name = talloc_strdup(gensec_security, user);
549 if (!gensec_security->user.name) {
550 return NT_STATUS_NO_MEMORY;
556 * Set a username on a GENSEC context - ensures it is talloc()ed
560 const char *gensec_get_username(struct gensec_security *gensec_security)
562 if (gensec_security->user.name) {
563 return gensec_security->user.name;
565 return gensec_security->default_user.name;
569 * Set a domain on a GENSEC context - ensures it is talloc()ed
573 NTSTATUS gensec_set_domain(struct gensec_security *gensec_security, const char *domain)
575 gensec_security->user.domain = talloc_strdup(gensec_security, domain);
576 if (!gensec_security->user.domain) {
577 return NT_STATUS_NO_MEMORY;
583 * Return the NT domain for this GENSEC context
587 const char *gensec_get_domain(struct gensec_security *gensec_security)
589 if (gensec_security->user.domain) {
590 return gensec_security->user.domain;
591 } else if (gensec_security->user.realm) {
592 return gensec_security->user.realm;
594 return gensec_security->default_user.domain;
598 * Set a kerberos realm on a GENSEC context - ensures it is talloc()ed
602 NTSTATUS gensec_set_realm(struct gensec_security *gensec_security, const char *realm)
604 gensec_security->user.realm = talloc_strdup(gensec_security, realm);
605 if (!gensec_security->user.realm) {
606 return NT_STATUS_NO_MEMORY;
612 * Return the Krb5 realm for this context
616 const char *gensec_get_realm(struct gensec_security *gensec_security)
618 if (gensec_security->user.realm) {
619 return gensec_security->user.realm;
620 } else if (gensec_security->user.domain) {
621 return gensec_security->user.domain;
623 return gensec_security->default_user.realm;
627 * Return a kerberos principal for this context, if one has been set
631 char *gensec_get_client_principal(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx)
633 const char *realm = gensec_get_realm(gensec_security);
635 return talloc_asprintf(mem_ctx, "%s@%s",
636 gensec_get_username(gensec_security),
637 gensec_get_realm(gensec_security));
639 return talloc_strdup(mem_ctx, gensec_get_username(gensec_security));
644 * Set the password outright on GENSEC context - ensures it is talloc()ed, and that we will
649 NTSTATUS gensec_set_password(struct gensec_security *gensec_security,
650 const char *password)
652 gensec_security->user.password = talloc_strdup(gensec_security, password);
653 if (!gensec_security->user.password) {
654 return NT_STATUS_NO_MEMORY;
660 * Set the target principal name (if already known) on a GENSEC context - ensures it is talloc()ed
664 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
666 gensec_security->target.principal = talloc_strdup(gensec_security, principal);
667 if (!gensec_security->target.principal) {
668 return NT_STATUS_NO_MEMORY;
674 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
678 NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
680 gensec_security->target.service = talloc_strdup(gensec_security, service);
681 if (!gensec_security->target.service) {
682 return NT_STATUS_NO_MEMORY;
688 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
692 NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
694 gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
695 if (!gensec_security->target.hostname) {
696 return NT_STATUS_NO_MEMORY;
701 const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
703 if (gensec_security->target.hostname) {
704 return gensec_security->target.hostname;
707 /* TODO: Add a 'set sockaddr' call, and do a reverse lookup */
711 const char *gensec_get_target_service(struct gensec_security *gensec_security)
713 if (gensec_security->target.service) {
714 return gensec_security->target.service;
721 * Set a password callback, if the gensec module we use demands a password
724 void gensec_set_password_callback(struct gensec_security *gensec_security,
725 gensec_password_callback callback, void *callback_private_data)
727 gensec_security->password_callback = callback;
728 gensec_security->password_callback_private = callback_private_data;
732 * Get (or call back for) a password.
735 NTSTATUS gensec_get_password(struct gensec_security *gensec_security,
739 if (gensec_security->user.password) {
740 *password = talloc_strdup(mem_ctx, gensec_security->user.password);
742 return NT_STATUS_NO_MEMORY;
747 if (!gensec_security->password_callback) {
748 return NT_STATUS_INVALID_PARAMETER;
750 return gensec_security->password_callback(gensec_security, mem_ctx, password);
754 register a GENSEC backend.
756 The 'name' can be later used by other backends to find the operations
757 structure for this backend.
759 static NTSTATUS gensec_register(const void *_ops)
761 const struct gensec_security_ops *ops = _ops;
763 if (!lp_parm_bool(-1, "gensec", ops->name, True)) {
764 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
768 if (gensec_security_by_name(ops->name) != NULL) {
769 /* its already registered! */
770 DEBUG(0,("GENSEC backend '%s' already registered\n",
772 return NT_STATUS_OBJECT_NAME_COLLISION;
775 generic_security_ops = Realloc(generic_security_ops, sizeof(generic_security_ops[0]) * (gensec_num_backends+1));
776 if (!generic_security_ops) {
777 smb_panic("out of memory in gensec_register");
780 generic_security_ops[gensec_num_backends] = ops;
782 gensec_num_backends++;
784 DEBUG(3,("GENSEC backend '%s' registered\n",
791 return the GENSEC interface version, and the size of some critical types
792 This can be used by backends to either detect compilation errors, or provide
793 multiple implementations for different smbd compilation options in one module
795 const struct gensec_critical_sizes *gensec_interface_version(void)
797 static const struct gensec_critical_sizes critical_sizes = {
798 GENSEC_INTERFACE_VERSION,
799 sizeof(struct gensec_security_ops),
800 sizeof(struct gensec_security),
803 return &critical_sizes;
807 initialise the GENSEC subsystem
809 BOOL gensec_init(void)
811 static BOOL initialised;
814 /* this is *completely* the wrong way to do this */
819 status = register_subsystem("gensec", gensec_register);
820 if (!NT_STATUS_IS_OK(status)) {
825 gensec_dcerpc_schannel_init();
828 DEBUG(3,("GENSEC subsystem version %d initialised\n", GENSEC_INTERFACE_VERSION));