r3737: - Get rid of the register_subsystem() and register_backend() functions.
[Samba/aatanasov.git] / source / libcli / auth / gensec.c
blob360a69c0e0359f78adc0a9594618d8940a2f7f0e
1 /*
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.
24 #include "includes.h"
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)
33 int i;
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];
40 return NULL;
43 static const struct gensec_security_ops *gensec_security_by_oid(const char *oid_string)
45 int i;
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];
53 return NULL;
56 static const struct gensec_security_ops *gensec_security_by_sasl_name(const char *sasl_name)
58 int i;
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];
66 return NULL;
69 static const struct gensec_security_ops *gensec_security_by_name(const char *name)
71 int i;
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];
79 return NULL;
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)
90 int i, j = 0;
91 const char **oid_list;
92 int num_backends;
93 const struct gensec_security_ops **ops = gensec_security_all(&num_backends);
94 if (!ops) {
95 return NULL;
97 oid_list = talloc_array_p(mem_ctx, const char *, num_backends + 1);
98 if (!oid_list) {
99 return NULL;
102 for (i=0; i<num_backends; i++) {
103 if (!ops[i]->oid) {
104 continue;
107 if (skip && strcmp(skip, ops[i]->oid)==0) {
108 continue;
111 oid_list[j] = ops[i]->oid;
112 j++;
114 oid_list[j] = NULL;
115 return oid_list;
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 return NT_STATUS_OK;
143 /**
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(struct gensec_security *parent,
150 struct gensec_security **gensec_security)
152 (*gensec_security) = talloc_p(parent, struct gensec_security);
153 if (!(*gensec_security)) {
154 return NT_STATUS_NO_MEMORY;
157 (**gensec_security) = *parent;
158 (*gensec_security)->ops = NULL;
159 (*gensec_security)->private_data = NULL;
161 (*gensec_security)->subcontext = True;
163 return NT_STATUS_OK;
166 NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security)
168 NTSTATUS status;
169 status = gensec_start(mem_ctx, gensec_security);
170 if (!NT_STATUS_IS_OK(status)) {
171 return status;
173 (*gensec_security)->gensec_role = GENSEC_CLIENT;
174 (*gensec_security)->password_callback = NULL;
176 ZERO_STRUCT((*gensec_security)->user);
178 return status;
181 NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security)
183 NTSTATUS status;
184 status = gensec_start(mem_ctx, gensec_security);
185 if (!NT_STATUS_IS_OK(status)) {
186 return status;
188 (*gensec_security)->gensec_role = GENSEC_SERVER;
190 return status;
193 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
195 NTSTATUS status;
196 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
197 gensec_security->subcontext ? "sub" : "",
198 gensec_security->ops->name));
199 switch (gensec_security->gensec_role) {
200 case GENSEC_CLIENT:
201 if (gensec_security->ops->client_start) {
202 status = gensec_security->ops->client_start(gensec_security);
203 if (!NT_STATUS_IS_OK(status)) {
204 DEBUG(1, ("Failed to start GENSEC client mech %s: %s\n",
205 gensec_security->ops->name, nt_errstr(status)));
207 return status;
209 case GENSEC_SERVER:
210 if (gensec_security->ops->server_start) {
211 status = gensec_security->ops->server_start(gensec_security);
212 if (!NT_STATUS_IS_OK(status)) {
213 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
214 gensec_security->ops->name, nt_errstr(status)));
216 return status;
219 return NT_STATUS_INVALID_PARAMETER;
222 /**
223 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
226 NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
227 uint8_t auth_type, uint8_t auth_level)
229 gensec_security->ops = gensec_security_by_authtype(auth_type);
230 if (!gensec_security->ops) {
231 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
232 return NT_STATUS_INVALID_PARAMETER;
234 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
235 gensec_want_feature(gensec_security, GENSEC_WANT_SIGN);
237 if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
238 gensec_want_feature(gensec_security, GENSEC_WANT_SIGN);
239 gensec_want_feature(gensec_security, GENSEC_WANT_SEAL);
242 return gensec_start_mech(gensec_security);
245 const char *gensec_get_name_by_authtype(uint8_t authtype)
247 const struct gensec_security_ops *ops;
248 ops = gensec_security_by_authtype(authtype);
249 if (ops) {
250 return ops->name;
252 return NULL;
256 const char *gensec_get_name_by_oid(const char *oid_string)
258 const struct gensec_security_ops *ops;
259 ops = gensec_security_by_oid(oid_string);
260 if (ops) {
261 return ops->name;
263 return NULL;
267 /**
268 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
270 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
271 * well-known #define to hook it in.
274 NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
275 const char *mech_oid)
277 gensec_security->ops = gensec_security_by_oid(mech_oid);
278 if (!gensec_security->ops) {
279 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
280 return NT_STATUS_INVALID_PARAMETER;
282 return gensec_start_mech(gensec_security);
285 /**
286 * Start a GENSEC sub-mechanism by a well know SASL name
290 NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
291 const char *sasl_name)
293 gensec_security->ops = gensec_security_by_sasl_name(sasl_name);
294 if (!gensec_security->ops) {
295 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
296 return NT_STATUS_INVALID_PARAMETER;
298 return gensec_start_mech(gensec_security);
302 wrappers for the gensec function pointers
304 NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
305 TALLOC_CTX *mem_ctx,
306 uint8_t *data, size_t length,
307 const uint8_t *whole_pdu, size_t pdu_length,
308 DATA_BLOB *sig)
310 if (!gensec_security->ops->unseal_packet) {
311 return NT_STATUS_NOT_IMPLEMENTED;
313 if (!(gensec_security->want_features & GENSEC_WANT_SEAL)) {
314 if (gensec_security->want_features & GENSEC_WANT_SIGN) {
315 return gensec_check_packet(gensec_security, mem_ctx,
316 data, length,
317 whole_pdu, pdu_length,
318 sig);
320 return NT_STATUS_INVALID_PARAMETER;
323 return gensec_security->ops->unseal_packet(gensec_security, mem_ctx,
324 data, length,
325 whole_pdu, pdu_length,
326 sig);
329 NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
330 TALLOC_CTX *mem_ctx,
331 const uint8_t *data, size_t length,
332 const uint8_t *whole_pdu, size_t pdu_length,
333 const DATA_BLOB *sig)
335 if (!gensec_security->ops->check_packet) {
336 return NT_STATUS_NOT_IMPLEMENTED;
338 if (!(gensec_security->want_features & GENSEC_WANT_SIGN)) {
339 return NT_STATUS_INVALID_PARAMETER;
342 return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
345 NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
346 TALLOC_CTX *mem_ctx,
347 uint8_t *data, size_t length,
348 const uint8_t *whole_pdu, size_t pdu_length,
349 DATA_BLOB *sig)
351 if (!gensec_security->ops->seal_packet) {
352 return NT_STATUS_NOT_IMPLEMENTED;
354 if (!(gensec_security->want_features & GENSEC_WANT_SEAL)) {
355 if (gensec_security->want_features & GENSEC_WANT_SIGN) {
356 return gensec_sign_packet(gensec_security, mem_ctx,
357 data, length,
358 whole_pdu, pdu_length,
359 sig);
361 return NT_STATUS_INVALID_PARAMETER;
364 return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
367 NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
368 TALLOC_CTX *mem_ctx,
369 const uint8_t *data, size_t length,
370 const uint8_t *whole_pdu, size_t pdu_length,
371 DATA_BLOB *sig)
373 if (!gensec_security->ops->sign_packet) {
374 return NT_STATUS_NOT_IMPLEMENTED;
376 if (!(gensec_security->want_features & GENSEC_WANT_SIGN)) {
377 return NT_STATUS_INVALID_PARAMETER;
380 return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
383 size_t gensec_sig_size(struct gensec_security *gensec_security)
385 if (!gensec_security->ops->sig_size) {
386 return 0;
388 if (!(gensec_security->want_features & GENSEC_WANT_SIGN)) {
389 return 0;
392 return gensec_security->ops->sig_size(gensec_security);
395 NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
396 DATA_BLOB *session_key)
398 if (!gensec_security->ops->session_key) {
399 return NT_STATUS_NOT_IMPLEMENTED;
401 if (!(gensec_security->want_features & GENSEC_WANT_SESSION_KEY)) {
402 return NT_STATUS_INVALID_PARAMETER;
405 return gensec_security->ops->session_key(gensec_security, session_key);
408 /**
409 * Return the credentials of a logged on user, including session keys
410 * etc.
412 * Only valid after a successful authentication
414 * May only be called once per authentication.
418 NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
419 struct auth_session_info **session_info)
421 if (!gensec_security->ops->session_info) {
422 return NT_STATUS_NOT_IMPLEMENTED;
424 return gensec_security->ops->session_info(gensec_security, session_info);
428 * Next state function for the GENSEC state machine
430 * @param gensec_security GENSEC State
431 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
432 * @param in The request, as a DATA_BLOB
433 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
434 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
435 * or NT_STATUS_OK if the user is authenticated.
438 NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
439 const DATA_BLOB in, DATA_BLOB *out)
441 return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
444 void gensec_end(struct gensec_security **gensec_security)
446 if ((*gensec_security)->ops) {
447 (*gensec_security)->ops->end(*gensec_security);
449 (*gensec_security)->private_data = NULL;
451 talloc_free(*gensec_security);
452 *gensec_security = NULL;
455 /**
456 * Set the requirement for a certain feature on the connection
460 void gensec_want_feature(struct gensec_security *gensec_security,
461 uint32 feature)
463 gensec_security->want_features |= feature;
466 /**
467 * Check the requirement for a certain feature on the connection
471 BOOL gensec_have_feature(struct gensec_security *gensec_security,
472 uint32 feature)
474 if (gensec_security->want_features & feature) {
475 return True;
478 return False;
481 /**
482 * Set a username on a GENSEC context - ensures it is talloc()ed
486 NTSTATUS gensec_set_unparsed_username(struct gensec_security *gensec_security, const char *user)
488 char *p;
489 char *u = talloc_strdup(gensec_security, user);
490 if (!u) {
491 return NT_STATUS_NO_MEMORY;
494 p = strchr_m(user, '@');
496 if (p) {
497 *p = '\0';
498 gensec_security->user.name = talloc_strdup(gensec_security, u);
499 if (!gensec_security->user.name) {
500 return NT_STATUS_NO_MEMORY;
503 gensec_security->user.realm = talloc_strdup(gensec_security, p+1);
504 if (!gensec_security->user.realm) {
505 return NT_STATUS_NO_MEMORY;
507 return NT_STATUS_OK;
510 p = strchr_m(user, '\\');
511 if (!p) {
512 p = strchr_m(user, '/');
515 if (p) {
516 *p = '\0';
517 gensec_security->user.domain = talloc_strdup(gensec_security, u);
518 if (!gensec_security->user.domain) {
519 return NT_STATUS_NO_MEMORY;
521 gensec_security->user.name = talloc_strdup(gensec_security, p+1);
522 if (!gensec_security->user.name) {
523 return NT_STATUS_NO_MEMORY;
526 return NT_STATUS_OK;
529 gensec_security->user.name = u;
530 if (!gensec_security->user.name) {
531 return NT_STATUS_NO_MEMORY;
533 return NT_STATUS_OK;
536 /**
537 * Set a username on a GENSEC context - ensures it is talloc()ed
541 NTSTATUS gensec_set_username(struct gensec_security *gensec_security, const char *user)
543 gensec_security->user.name = talloc_strdup(gensec_security, user);
544 if (!gensec_security->user.name) {
545 return NT_STATUS_NO_MEMORY;
547 return NT_STATUS_OK;
550 /**
551 * Set a username on a GENSEC context - ensures it is talloc()ed
555 const char *gensec_get_username(struct gensec_security *gensec_security)
557 if (gensec_security->user.name) {
558 return gensec_security->user.name;
560 return gensec_security->default_user.name;
563 /**
564 * Set a domain on a GENSEC context - ensures it is talloc()ed
568 NTSTATUS gensec_set_domain(struct gensec_security *gensec_security, const char *domain)
570 gensec_security->user.domain = talloc_strdup(gensec_security, domain);
571 if (!gensec_security->user.domain) {
572 return NT_STATUS_NO_MEMORY;
574 return NT_STATUS_OK;
577 /**
578 * Return the NT domain for this GENSEC context
582 const char *gensec_get_domain(struct gensec_security *gensec_security)
584 if (gensec_security->user.domain) {
585 return gensec_security->user.domain;
586 } else if (gensec_security->user.realm) {
587 return gensec_security->user.realm;
589 return gensec_security->default_user.domain;
592 /**
593 * Set a kerberos realm on a GENSEC context - ensures it is talloc()ed
597 NTSTATUS gensec_set_realm(struct gensec_security *gensec_security, const char *realm)
599 gensec_security->user.realm = talloc_strdup(gensec_security, realm);
600 if (!gensec_security->user.realm) {
601 return NT_STATUS_NO_MEMORY;
603 return NT_STATUS_OK;
606 /**
607 * Return the Krb5 realm for this context
611 const char *gensec_get_realm(struct gensec_security *gensec_security)
613 if (gensec_security->user.realm) {
614 return gensec_security->user.realm;
615 } else if (gensec_security->user.domain) {
616 return gensec_security->user.domain;
618 return gensec_security->default_user.realm;
621 /**
622 * Return a kerberos principal for this context, if one has been set
626 char *gensec_get_client_principal(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx)
628 const char *realm = gensec_get_realm(gensec_security);
629 if (realm) {
630 return talloc_asprintf(mem_ctx, "%s@%s",
631 gensec_get_username(gensec_security),
632 gensec_get_realm(gensec_security));
633 } else {
634 return talloc_strdup(mem_ctx, gensec_get_username(gensec_security));
638 /**
639 * Set the password outright on GENSEC context - ensures it is talloc()ed, and that we will
640 * not do a callback
644 NTSTATUS gensec_set_password(struct gensec_security *gensec_security,
645 const char *password)
647 gensec_security->user.password = talloc_strdup(gensec_security, password);
648 if (!gensec_security->user.password) {
649 return NT_STATUS_NO_MEMORY;
651 return NT_STATUS_OK;
654 /**
655 * Set the target principal name (if already known) on a GENSEC context - ensures it is talloc()ed
659 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
661 gensec_security->target.principal = talloc_strdup(gensec_security, principal);
662 if (!gensec_security->target.principal) {
663 return NT_STATUS_NO_MEMORY;
665 return NT_STATUS_OK;
668 /**
669 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
673 NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
675 gensec_security->target.service = talloc_strdup(gensec_security, service);
676 if (!gensec_security->target.service) {
677 return NT_STATUS_NO_MEMORY;
679 return NT_STATUS_OK;
682 /**
683 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
687 NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
689 gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
690 if (!gensec_security->target.hostname) {
691 return NT_STATUS_NO_MEMORY;
693 return NT_STATUS_OK;
696 const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
698 if (gensec_security->target.hostname) {
699 return gensec_security->target.hostname;
702 /* TODO: Add a 'set sockaddr' call, and do a reverse lookup */
703 return NULL;
706 const char *gensec_get_target_service(struct gensec_security *gensec_security)
708 if (gensec_security->target.service) {
709 return gensec_security->target.service;
712 return "host";
715 /**
716 * Set a password callback, if the gensec module we use demands a password
719 void gensec_set_password_callback(struct gensec_security *gensec_security,
720 gensec_password_callback callback, void *callback_private_data)
722 gensec_security->password_callback = callback;
723 gensec_security->password_callback_private = callback_private_data;
727 * Get (or call back for) a password.
730 NTSTATUS gensec_get_password(struct gensec_security *gensec_security,
731 TALLOC_CTX *mem_ctx,
732 char **password)
734 if (gensec_security->user.password) {
735 *password = talloc_strdup(mem_ctx, gensec_security->user.password);
736 if (!*password) {
737 return NT_STATUS_NO_MEMORY;
738 } else {
739 return NT_STATUS_OK;
742 if (!gensec_security->password_callback) {
743 return NT_STATUS_INVALID_PARAMETER;
745 return gensec_security->password_callback(gensec_security, mem_ctx, password);
749 register a GENSEC backend.
751 The 'name' can be later used by other backends to find the operations
752 structure for this backend.
754 NTSTATUS gensec_register(const void *_ops)
756 const struct gensec_security_ops *ops = _ops;
758 if (!lp_parm_bool(-1, "gensec", ops->name, True)) {
759 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
760 return NT_STATUS_OK;
763 if (gensec_security_by_name(ops->name) != NULL) {
764 /* its already registered! */
765 DEBUG(0,("GENSEC backend '%s' already registered\n",
766 ops->name));
767 return NT_STATUS_OBJECT_NAME_COLLISION;
770 generic_security_ops = Realloc(generic_security_ops, sizeof(generic_security_ops[0]) * (gensec_num_backends+1));
771 if (!generic_security_ops) {
772 smb_panic("out of memory in gensec_register");
775 generic_security_ops[gensec_num_backends] = ops;
777 gensec_num_backends++;
779 DEBUG(3,("GENSEC backend '%s' registered\n",
780 ops->name));
782 return NT_STATUS_OK;
786 return the GENSEC interface version, and the size of some critical types
787 This can be used by backends to either detect compilation errors, or provide
788 multiple implementations for different smbd compilation options in one module
790 const struct gensec_critical_sizes *gensec_interface_version(void)
792 static const struct gensec_critical_sizes critical_sizes = {
793 GENSEC_INTERFACE_VERSION,
794 sizeof(struct gensec_security_ops),
795 sizeof(struct gensec_security),
798 return &critical_sizes;
802 initialise the GENSEC subsystem
804 NTSTATUS gensec_init(void)
806 gensec_dcerpc_schannel_init();
807 return NT_STATUS_OK;