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.
26 /* the list of currently registered GENSEC backends */
27 const static struct gensec_security_ops **generic_security_ops;
28 static int gensec_num_backends;
30 static const struct gensec_security_ops *gensec_security_by_authtype(uint8_t auth_type)
33 for (i=0; i < gensec_num_backends; i++) {
34 if (generic_security_ops[i]->auth_type == auth_type) {
35 return generic_security_ops[i];
42 static const struct gensec_security_ops *gensec_security_by_oid(const char *oid_string)
45 for (i=0; i < gensec_num_backends; i++) {
46 if (generic_security_ops[i]->oid &&
47 (strcmp(generic_security_ops[i]->oid, oid_string) == 0)) {
48 return generic_security_ops[i];
55 static const struct gensec_security_ops *gensec_security_by_sasl_name(const char *sasl_name)
58 for (i=0; i < gensec_num_backends; i++) {
59 if (generic_security_ops[i]->sasl_name
60 && (strcmp(generic_security_ops[i]->sasl_name, sasl_name) == 0)) {
61 return generic_security_ops[i];
68 static const struct gensec_security_ops *gensec_security_by_name(const char *name)
71 for (i=0; i < gensec_num_backends; i++) {
72 if (generic_security_ops[i]->name
73 && (strcmp(generic_security_ops[i]->name, name) == 0)) {
74 return generic_security_ops[i];
81 const struct gensec_security_ops **gensec_security_all(int *num_backends_out)
83 *num_backends_out = gensec_num_backends;
84 return generic_security_ops;
87 const char **gensec_security_oids(TALLOC_CTX *mem_ctx, const char *skip)
90 const char **oid_list;
92 const struct gensec_security_ops **ops = gensec_security_all(&num_backends);
96 oid_list = talloc_array_p(mem_ctx, const char *, num_backends + 1);
101 for (i=0; i<num_backends; i++) {
106 if (skip && strcmp(skip, ops[i]->oid)==0) {
110 oid_list[j] = ops[i]->oid;
118 note that memory context is the parent context to hang this gensec context off. It may be NULL.
120 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security)
122 /* awaiting a correct fix from metze */
123 if (!gensec_init()) {
124 return NT_STATUS_INTERNAL_ERROR;
127 (*gensec_security) = talloc_p(mem_ctx, struct gensec_security);
128 if (!(*gensec_security)) {
129 return NT_STATUS_NO_MEMORY;
132 (*gensec_security)->ops = NULL;
134 ZERO_STRUCT((*gensec_security)->user);
135 ZERO_STRUCT((*gensec_security)->target);
136 ZERO_STRUCT((*gensec_security)->default_user);
138 (*gensec_security)->default_user.name = "";
139 (*gensec_security)->default_user.domain = talloc_strdup(*gensec_security, lp_workgroup());
140 (*gensec_security)->default_user.realm = talloc_strdup(*gensec_security, lp_realm());
142 (*gensec_security)->subcontext = False;
143 (*gensec_security)->want_features = 0;
148 * Start a GENSEC subcontext, with a copy of the properties of the parent
150 * @note Used by SPENGO in particular, for the actual implementation mechanism
153 NTSTATUS gensec_subcontext_start(struct gensec_security *parent,
154 struct gensec_security **gensec_security)
156 (*gensec_security) = talloc_p(parent, struct gensec_security);
157 if (!(*gensec_security)) {
158 return NT_STATUS_NO_MEMORY;
161 (**gensec_security) = *parent;
162 (*gensec_security)->ops = NULL;
163 (*gensec_security)->private_data = NULL;
165 (*gensec_security)->subcontext = True;
170 NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security)
173 status = gensec_start(mem_ctx, gensec_security);
174 if (!NT_STATUS_IS_OK(status)) {
177 (*gensec_security)->gensec_role = GENSEC_CLIENT;
178 (*gensec_security)->password_callback = NULL;
180 ZERO_STRUCT((*gensec_security)->user);
185 NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security)
188 status = gensec_start(mem_ctx, gensec_security);
189 if (!NT_STATUS_IS_OK(status)) {
192 (*gensec_security)->gensec_role = GENSEC_SERVER;
197 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
200 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
201 gensec_security->subcontext ? "sub" : "",
202 gensec_security->ops->name));
203 switch (gensec_security->gensec_role) {
205 if (gensec_security->ops->client_start) {
206 status = gensec_security->ops->client_start(gensec_security);
207 if (!NT_STATUS_IS_OK(status)) {
208 DEBUG(1, ("Faild to start GENSEC client mech %s: %s\n",
209 gensec_security->ops->name, nt_errstr(status)));
214 if (gensec_security->ops->server_start) {
215 status = gensec_security->ops->server_start(gensec_security);
216 if (!NT_STATUS_IS_OK(status)) {
217 DEBUG(1, ("Faild to start GENSEC server mech %s: %s\n",
218 gensec_security->ops->name, nt_errstr(status)));
223 return NT_STATUS_INVALID_PARAMETER;
227 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
230 NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
231 uint8_t auth_type, uint8_t auth_level)
233 gensec_security->ops = gensec_security_by_authtype(auth_type);
234 if (!gensec_security->ops) {
235 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
236 return NT_STATUS_INVALID_PARAMETER;
238 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
239 gensec_want_feature(gensec_security, GENSEC_WANT_SIGN);
241 if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
242 gensec_want_feature(gensec_security, GENSEC_WANT_SIGN);
243 gensec_want_feature(gensec_security, GENSEC_WANT_SEAL);
246 return gensec_start_mech(gensec_security);
249 const char *gensec_get_name_by_authtype(uint8_t authtype)
251 const struct gensec_security_ops *ops;
252 ops = gensec_security_by_authtype(authtype);
260 const char *gensec_get_name_by_oid(const char *oid_string)
262 const struct gensec_security_ops *ops;
263 ops = gensec_security_by_oid(oid_string);
272 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
274 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
275 * well-known #define to hook it in.
278 NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
279 const char *mech_oid)
281 gensec_security->ops = gensec_security_by_oid(mech_oid);
282 if (!gensec_security->ops) {
283 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
284 return NT_STATUS_INVALID_PARAMETER;
286 return gensec_start_mech(gensec_security);
290 * Start a GENSEC sub-mechanism by a well know SASL name
294 NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
295 const char *sasl_name)
297 gensec_security->ops = gensec_security_by_sasl_name(sasl_name);
298 if (!gensec_security->ops) {
299 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
300 return NT_STATUS_INVALID_PARAMETER;
302 return gensec_start_mech(gensec_security);
306 wrappers for the gensec function pointers
308 NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
310 uint8_t *data, size_t length,
311 const uint8_t *whole_pdu, size_t pdu_length,
314 if (!gensec_security->ops->unseal_packet) {
315 return NT_STATUS_NOT_IMPLEMENTED;
317 return gensec_security->ops->unseal_packet(gensec_security, mem_ctx,
319 whole_pdu, pdu_length,
323 NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
325 const uint8_t *data, size_t length,
326 const uint8_t *whole_pdu, size_t pdu_length,
327 const DATA_BLOB *sig)
329 if (!gensec_security->ops->check_packet) {
330 return NT_STATUS_NOT_IMPLEMENTED;
332 if (!(gensec_security->want_features & GENSEC_WANT_SIGN)) {
333 return NT_STATUS_INVALID_PARAMETER;
336 return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
339 NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
341 uint8_t *data, size_t length,
342 const uint8_t *whole_pdu, size_t pdu_length,
345 if (!gensec_security->ops->seal_packet) {
346 return NT_STATUS_NOT_IMPLEMENTED;
348 if (!(gensec_security->want_features & GENSEC_WANT_SEAL)) {
349 return NT_STATUS_INVALID_PARAMETER;
352 return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
355 NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
357 const uint8_t *data, size_t length,
358 const uint8_t *whole_pdu, size_t pdu_length,
361 if (!gensec_security->ops->sign_packet) {
362 return NT_STATUS_NOT_IMPLEMENTED;
364 if (!(gensec_security->want_features & GENSEC_WANT_SIGN)) {
365 return NT_STATUS_INVALID_PARAMETER;
368 return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
371 size_t gensec_sig_size(struct gensec_security *gensec_security)
373 if (!gensec_security->ops->sig_size) {
376 if (!(gensec_security->want_features & GENSEC_WANT_SIGN)) {
380 return gensec_security->ops->sig_size(gensec_security);
383 NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
384 DATA_BLOB *session_key)
386 if (!gensec_security->ops->session_key) {
387 return NT_STATUS_NOT_IMPLEMENTED;
389 if (!(gensec_security->want_features & GENSEC_WANT_SESSION_KEY)) {
390 return NT_STATUS_INVALID_PARAMETER;
393 return gensec_security->ops->session_key(gensec_security, session_key);
397 * Return the credentials of a logged on user, including session keys
400 * Only valid after a successful authentication
402 * May only be called once per authentication.
406 NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
407 struct auth_session_info **session_info)
409 if (!gensec_security->ops->session_info) {
410 return NT_STATUS_NOT_IMPLEMENTED;
412 return gensec_security->ops->session_info(gensec_security, session_info);
416 * Next state function for the GENSEC state machine
418 * @param gensec_security GENSEC State
419 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
420 * @param in The request, as a DATA_BLOB
421 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
422 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
423 * or NT_STATUS_OK if the user is authenticated.
426 NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
427 const DATA_BLOB in, DATA_BLOB *out)
429 return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
432 void gensec_end(struct gensec_security **gensec_security)
434 if ((*gensec_security)->ops) {
435 (*gensec_security)->ops->end(*gensec_security);
437 (*gensec_security)->private_data = NULL;
439 if (!(*gensec_security)->subcontext) {
440 /* don't destory this if this is a subcontext - it belongs to the parent */
441 talloc_free(*gensec_security);
443 gensec_security = NULL;
447 * Set the requirement for a certain feature on the connection
451 void gensec_want_feature(struct gensec_security *gensec_security,
454 gensec_security->want_features |= feature;
458 * Set a username on a GENSEC context - ensures it is talloc()ed
462 NTSTATUS gensec_set_unparsed_username(struct gensec_security *gensec_security, const char *user)
465 char *u = talloc_strdup(gensec_security, user);
467 return NT_STATUS_NO_MEMORY;
470 p = strchr_m(user, '@');
474 gensec_security->user.name = talloc_strdup(gensec_security, u);
475 if (!gensec_security->user.name) {
476 return NT_STATUS_NO_MEMORY;
479 gensec_security->user.realm = talloc_strdup(gensec_security, p+1);
480 if (!gensec_security->user.realm) {
481 return NT_STATUS_NO_MEMORY;
486 p = strchr_m(user, '\\');
488 p = strchr_m(user, '/');
493 gensec_security->user.domain = talloc_strdup(gensec_security, u);
494 if (!gensec_security->user.domain) {
495 return NT_STATUS_NO_MEMORY;
497 gensec_security->user.name = talloc_strdup(gensec_security, p+1);
498 if (!gensec_security->user.name) {
499 return NT_STATUS_NO_MEMORY;
505 gensec_security->user.name = u;
506 if (!gensec_security->user.name) {
507 return NT_STATUS_NO_MEMORY;
513 * Set a username on a GENSEC context - ensures it is talloc()ed
517 NTSTATUS gensec_set_username(struct gensec_security *gensec_security, const char *user)
519 gensec_security->user.name = talloc_strdup(gensec_security, user);
520 if (!gensec_security->user.name) {
521 return NT_STATUS_NO_MEMORY;
527 * Set a username on a GENSEC context - ensures it is talloc()ed
531 const char *gensec_get_username(struct gensec_security *gensec_security)
533 if (gensec_security->user.name) {
534 return gensec_security->user.name;
536 return gensec_security->default_user.name;
540 * Set a domain on a GENSEC context - ensures it is talloc()ed
544 NTSTATUS gensec_set_domain(struct gensec_security *gensec_security, const char *domain)
546 gensec_security->user.domain = talloc_strdup(gensec_security, domain);
547 if (!gensec_security->user.domain) {
548 return NT_STATUS_NO_MEMORY;
554 * Return the NT domain for this GENSEC context
558 const char *gensec_get_domain(struct gensec_security *gensec_security)
560 if (gensec_security->user.domain) {
561 return gensec_security->user.domain;
562 } else if (gensec_security->user.realm) {
563 return gensec_security->user.realm;
565 return gensec_security->default_user.domain;
569 * Set a kerberos realm on a GENSEC context - ensures it is talloc()ed
573 NTSTATUS gensec_set_realm(struct gensec_security *gensec_security, const char *realm)
575 gensec_security->user.realm = talloc_strdup(gensec_security, realm);
576 if (!gensec_security->user.realm) {
577 return NT_STATUS_NO_MEMORY;
583 * Return the Krb5 realm for this context
587 const char *gensec_get_realm(struct gensec_security *gensec_security)
589 if (gensec_security->user.realm) {
590 return gensec_security->user.realm;
591 } else if (gensec_security->user.domain) {
592 return gensec_security->user.domain;
594 return gensec_security->default_user.realm;
598 * Return a kerberos principal for this context, if one has been set
602 char *gensec_get_client_principal(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx)
604 const char *realm = gensec_get_realm(gensec_security);
606 return talloc_asprintf(mem_ctx, "%s@%s",
607 gensec_get_username(gensec_security),
608 gensec_get_realm(gensec_security));
610 return talloc_strdup(mem_ctx, gensec_get_username(gensec_security));
615 * Set the password outright on GENSEC context - ensures it is talloc()ed, and that we will
620 NTSTATUS gensec_set_password(struct gensec_security *gensec_security,
621 const char *password)
623 gensec_security->user.password = talloc_strdup(gensec_security, password);
624 if (!gensec_security->user.password) {
625 return NT_STATUS_NO_MEMORY;
631 * Set the target principal name (if already known) on a GENSEC context - ensures it is talloc()ed
635 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
637 gensec_security->target.principal = talloc_strdup(gensec_security, principal);
638 if (!gensec_security->target.principal) {
639 return NT_STATUS_NO_MEMORY;
645 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
649 NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
651 gensec_security->target.service = talloc_strdup(gensec_security, service);
652 if (!gensec_security->target.service) {
653 return NT_STATUS_NO_MEMORY;
659 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
663 NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
665 gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
666 if (!gensec_security->target.hostname) {
667 return NT_STATUS_NO_MEMORY;
672 const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
674 if (gensec_security->target.hostname) {
675 return gensec_security->target.hostname;
678 /* TODO: Add a 'set sockaddr' call, and do a reverse lookup */
682 const char *gensec_get_target_service(struct gensec_security *gensec_security)
684 if (gensec_security->target.service) {
685 return gensec_security->target.service;
692 * Set a password callback, if the gensec module we use demands a password
695 void gensec_set_password_callback(struct gensec_security *gensec_security,
696 gensec_password_callback callback, void *callback_private_data)
698 gensec_security->password_callback = callback;
699 gensec_security->password_callback_private = callback_private_data;
703 * Get (or call back for) a password.
706 NTSTATUS gensec_get_password(struct gensec_security *gensec_security,
710 if (gensec_security->user.password) {
711 *password = talloc_strdup(mem_ctx, gensec_security->user.password);
713 return NT_STATUS_NO_MEMORY;
718 if (!gensec_security->password_callback) {
719 return NT_STATUS_INVALID_PARAMETER;
721 return gensec_security->password_callback(gensec_security, mem_ctx, password);
725 register a GENSEC backend.
727 The 'name' can be later used by other backends to find the operations
728 structure for this backend.
730 static NTSTATUS gensec_register(const void *_ops)
732 const struct gensec_security_ops *ops = _ops;
734 if (!lp_parm_bool(-1, "gensec", ops->name, True)) {
735 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
739 if (gensec_security_by_name(ops->name) != NULL) {
740 /* its already registered! */
741 DEBUG(0,("GENSEC backend '%s' already registered\n",
743 return NT_STATUS_OBJECT_NAME_COLLISION;
746 generic_security_ops = Realloc(generic_security_ops, sizeof(generic_security_ops[0]) * (gensec_num_backends+1));
747 if (!generic_security_ops) {
748 smb_panic("out of memory in gensec_register");
751 generic_security_ops[gensec_num_backends] = ops;
753 gensec_num_backends++;
755 DEBUG(3,("GENSEC backend '%s' registered\n",
762 return the GENSEC interface version, and the size of some critical types
763 This can be used by backends to either detect compilation errors, or provide
764 multiple implementations for different smbd compilation options in one module
766 const struct gensec_critical_sizes *gensec_interface_version(void)
768 static const struct gensec_critical_sizes critical_sizes = {
769 GENSEC_INTERFACE_VERSION,
770 sizeof(struct gensec_security_ops),
771 sizeof(struct gensec_security),
774 return &critical_sizes;
778 initialise the GENSEC subsystem
780 BOOL gensec_init(void)
782 static BOOL initialised;
785 /* this is *completely* the wrong way to do this */
790 status = register_subsystem("gensec", gensec_register);
791 if (!NT_STATUS_IS_OK(status)) {
796 gensec_dcerpc_schannel_init();
799 DEBUG(3,("GENSEC subsystem version %d initialised\n", GENSEC_INTERFACE_VERSION));