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;
140 (*gensec_security)->have_features = 0;
145 * Start a GENSEC subcontext, with a copy of the properties of the parent
147 * @note Used by SPENGO in particular, for the actual implementation mechanism
150 NTSTATUS gensec_subcontext_start(struct gensec_security *parent,
151 struct gensec_security **gensec_security)
153 (*gensec_security) = talloc_p(parent, 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_session_key(struct gensec_security *gensec_security,
398 DATA_BLOB *session_key)
400 if (!gensec_security->ops->session_key) {
401 return NT_STATUS_NOT_IMPLEMENTED;
403 return gensec_security->ops->session_key(gensec_security, session_key);
407 * Return the credentials of a logged on user, including session keys
410 * Only valid after a successful authentication
412 * May only be called once per authentication.
416 NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
417 struct auth_session_info **session_info)
419 if (!gensec_security->ops->session_info) {
420 return NT_STATUS_NOT_IMPLEMENTED;
422 return gensec_security->ops->session_info(gensec_security, session_info);
426 * Next state function for the GENSEC state machine
428 * @param gensec_security GENSEC State
429 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
430 * @param in The request, as a DATA_BLOB
431 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
432 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
433 * or NT_STATUS_OK if the user is authenticated.
436 NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
437 const DATA_BLOB in, DATA_BLOB *out)
439 return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
442 void gensec_end(struct gensec_security **gensec_security)
444 if (!*gensec_security) {
447 if ((*gensec_security)->ops) {
448 (*gensec_security)->ops->end(*gensec_security);
450 (*gensec_security)->private_data = NULL;
452 talloc_free(*gensec_security);
453 *gensec_security = NULL;
457 * Set the requirement for a certain feature on the connection
461 void gensec_want_feature(struct gensec_security *gensec_security,
464 gensec_security->want_features |= feature;
468 * Check the requirement for a certain feature on the connection
472 BOOL gensec_have_feature(struct gensec_security *gensec_security,
475 if (gensec_security->have_features & feature) {
483 * Set a username on a GENSEC context - ensures it is talloc()ed
487 NTSTATUS gensec_set_unparsed_username(struct gensec_security *gensec_security, const char *user)
490 char *u = talloc_strdup(gensec_security, user);
492 return NT_STATUS_NO_MEMORY;
495 p = strchr_m(user, '@');
499 gensec_security->user.name = talloc_strdup(gensec_security, u);
500 if (!gensec_security->user.name) {
501 return NT_STATUS_NO_MEMORY;
504 gensec_security->user.realm = talloc_strdup(gensec_security, p+1);
505 if (!gensec_security->user.realm) {
506 return NT_STATUS_NO_MEMORY;
511 p = strchr_m(user, '\\');
513 p = strchr_m(user, '/');
518 gensec_security->user.domain = talloc_strdup(gensec_security, u);
519 if (!gensec_security->user.domain) {
520 return NT_STATUS_NO_MEMORY;
522 gensec_security->user.name = talloc_strdup(gensec_security, p+1);
523 if (!gensec_security->user.name) {
524 return NT_STATUS_NO_MEMORY;
530 gensec_security->user.name = u;
531 if (!gensec_security->user.name) {
532 return NT_STATUS_NO_MEMORY;
538 * Set a username on a GENSEC context - ensures it is talloc()ed
542 NTSTATUS gensec_set_username(struct gensec_security *gensec_security, const char *user)
544 gensec_security->user.name = talloc_strdup(gensec_security, user);
545 if (!gensec_security->user.name) {
546 return NT_STATUS_NO_MEMORY;
552 * Set a username on a GENSEC context - ensures it is talloc()ed
556 const char *gensec_get_username(struct gensec_security *gensec_security)
558 if (gensec_security->user.name) {
559 return gensec_security->user.name;
561 return gensec_security->default_user.name;
565 * Set a domain on a GENSEC context - ensures it is talloc()ed
569 NTSTATUS gensec_set_domain(struct gensec_security *gensec_security, const char *domain)
571 gensec_security->user.domain = talloc_strdup(gensec_security, domain);
572 if (!gensec_security->user.domain) {
573 return NT_STATUS_NO_MEMORY;
579 * Return the NT domain for this GENSEC context
583 const char *gensec_get_domain(struct gensec_security *gensec_security)
585 if (gensec_security->user.domain) {
586 return gensec_security->user.domain;
587 } else if (gensec_security->user.realm) {
588 return gensec_security->user.realm;
590 return gensec_security->default_user.domain;
594 * Set a kerberos realm on a GENSEC context - ensures it is talloc()ed
598 NTSTATUS gensec_set_realm(struct gensec_security *gensec_security, const char *realm)
600 gensec_security->user.realm = talloc_strdup(gensec_security, realm);
601 if (!gensec_security->user.realm) {
602 return NT_STATUS_NO_MEMORY;
608 * Return the Krb5 realm for this context
612 const char *gensec_get_realm(struct gensec_security *gensec_security)
614 if (gensec_security->user.realm) {
615 return gensec_security->user.realm;
616 } else if (gensec_security->user.domain) {
617 return gensec_security->user.domain;
619 return gensec_security->default_user.realm;
623 * Return a kerberos principal for this context, if one has been set
627 char *gensec_get_client_principal(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx)
629 const char *realm = gensec_get_realm(gensec_security);
631 return talloc_asprintf(mem_ctx, "%s@%s",
632 gensec_get_username(gensec_security),
633 gensec_get_realm(gensec_security));
635 return talloc_strdup(mem_ctx, gensec_get_username(gensec_security));
640 * Set the password outright on GENSEC context - ensures it is talloc()ed, and that we will
645 NTSTATUS gensec_set_password(struct gensec_security *gensec_security,
646 const char *password)
648 gensec_security->user.password = talloc_strdup(gensec_security, password);
649 if (!gensec_security->user.password) {
650 return NT_STATUS_NO_MEMORY;
656 * Set the target principal name (if already known) on a GENSEC context - ensures it is talloc()ed
660 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
662 gensec_security->target.principal = talloc_strdup(gensec_security, principal);
663 if (!gensec_security->target.principal) {
664 return NT_STATUS_NO_MEMORY;
670 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
674 NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
676 gensec_security->target.service = talloc_strdup(gensec_security, service);
677 if (!gensec_security->target.service) {
678 return NT_STATUS_NO_MEMORY;
684 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
688 NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
690 gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
691 if (!gensec_security->target.hostname) {
692 return NT_STATUS_NO_MEMORY;
697 const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
699 if (gensec_security->target.hostname) {
700 return gensec_security->target.hostname;
703 /* TODO: Add a 'set sockaddr' call, and do a reverse lookup */
707 const char *gensec_get_target_service(struct gensec_security *gensec_security)
709 if (gensec_security->target.service) {
710 return gensec_security->target.service;
717 * Set a password callback, if the gensec module we use demands a password
720 void gensec_set_password_callback(struct gensec_security *gensec_security,
721 gensec_password_callback callback, void *callback_private_data)
723 gensec_security->password_callback = callback;
724 gensec_security->password_callback_private = callback_private_data;
728 * Get (or call back for) a password.
731 NTSTATUS gensec_get_password(struct gensec_security *gensec_security,
735 if (gensec_security->user.password) {
736 *password = talloc_strdup(mem_ctx, gensec_security->user.password);
738 return NT_STATUS_NO_MEMORY;
743 if (!gensec_security->password_callback) {
744 return NT_STATUS_INVALID_PARAMETER;
746 return gensec_security->password_callback(gensec_security, mem_ctx, password);
750 register a GENSEC backend.
752 The 'name' can be later used by other backends to find the operations
753 structure for this backend.
755 NTSTATUS gensec_register(const void *_ops)
757 const struct gensec_security_ops *ops = _ops;
759 if (!lp_parm_bool(-1, "gensec", ops->name, True)) {
760 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
764 if (gensec_security_by_name(ops->name) != NULL) {
765 /* its already registered! */
766 DEBUG(0,("GENSEC backend '%s' already registered\n",
768 return NT_STATUS_OBJECT_NAME_COLLISION;
771 generic_security_ops = realloc_p(generic_security_ops,
772 const struct gensec_security_ops *,
773 gensec_num_backends+1);
774 if (!generic_security_ops) {
775 smb_panic("out of memory in gensec_register");
778 generic_security_ops[gensec_num_backends] = ops;
780 gensec_num_backends++;
782 DEBUG(3,("GENSEC backend '%s' registered\n",
789 return the GENSEC interface version, and the size of some critical types
790 This can be used by backends to either detect compilation errors, or provide
791 multiple implementations for different smbd compilation options in one module
793 const struct gensec_critical_sizes *gensec_interface_version(void)
795 static const struct gensec_critical_sizes critical_sizes = {
796 GENSEC_INTERFACE_VERSION,
797 sizeof(struct gensec_security_ops),
798 sizeof(struct gensec_security),
801 return &critical_sizes;
805 initialise the GENSEC subsystem
807 NTSTATUS gensec_init(void)
809 gensec_dcerpc_schannel_init();