diff options
Diffstat (limited to 'daemons/ipa-otpd/bind.c')
-rw-r--r-- | daemons/ipa-otpd/bind.c | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/daemons/ipa-otpd/bind.c b/daemons/ipa-otpd/bind.c new file mode 100644 index 00000000..c985ccd7 --- /dev/null +++ b/daemons/ipa-otpd/bind.c @@ -0,0 +1,144 @@ +/* + * FreeIPA 2FA companion daemon + * + * Authors: Nathaniel McCallum <npmccallum@redhat.com> + * + * Copyright (C) 2013 Nathaniel McCallum, Red Hat + * see file 'COPYING' for use and warranty information + * + * This program is free software you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * This file takes requests from query.c and performs an LDAP bind on behalf + * of the user. The results are placed in the stdout queue (stdio.c). + */ + +#include "internal.h" + +static void on_bind_writable(verto_ctx *vctx, verto_ev *ev) +{ + struct otpd_queue *push = &ctx.stdio.responses; + const krb5_data *data; + struct berval cred; + struct otpd_queue_item *item; + int i; + (void)vctx; + + item = otpd_queue_pop(&ctx.bind.requests); + if (item == NULL) { + verto_set_flags(ctx.bind.io, VERTO_EV_FLAG_PERSIST | + VERTO_EV_FLAG_IO_ERROR | + VERTO_EV_FLAG_IO_READ); + return; + } + + if (item->user.dn == NULL) + goto error; + + data = krad_packet_get_attr(item->req, + krad_attr_name2num("User-Password"), 0); + if (data == NULL) + goto error; + + cred.bv_val = data->data; + cred.bv_len = data->length; + i = ldap_sasl_bind(verto_get_private(ev), item->user.dn, LDAP_SASL_SIMPLE, + &cred, NULL, NULL, &item->msgid); + if (i != LDAP_SUCCESS) { + otpd_log_err(errno, "Unable to initiate bind: %s", ldap_err2string(i)); + verto_break(ctx.vctx); + ctx.exitstatus = 1; + } + + otpd_log_req(item->req, "bind start: %s", item->user.dn); + push = &ctx.bind.responses; + +error: + otpd_queue_push(push, item); +} + +static void on_bind_readable(verto_ctx *vctx, verto_ev *ev) +{ + const char *errstr = "error"; + LDAPMessage *results; + struct otpd_queue_item *item = NULL; + int i, rslt; + (void)vctx; + + rslt = ldap_result(verto_get_private(ev), LDAP_RES_ANY, 0, NULL, &results); + if (rslt != LDAP_RES_BIND) { + if (rslt <= 0) + results = NULL; + ldap_msgfree(results); + return; + } + + item = otpd_queue_pop_msgid(&ctx.bind.responses, ldap_msgid(results)); + if (item == NULL) { + ldap_msgfree(results); + return; + } + item->msgid = -1; + + rslt = ldap_parse_result(verto_get_private(ev), results, &i, + NULL, NULL, NULL, NULL, 0); + if (rslt != LDAP_SUCCESS) { + errstr = ldap_err2string(rslt); + goto error; + } + + rslt = i; + if (rslt != LDAP_SUCCESS) { + errstr = ldap_err2string(rslt); + goto error; + } + + item->sent = 0; + i = krad_packet_new_response(ctx.kctx, SECRET, + krad_code_name2num("Access-Accept"), + NULL, item->req, &item->rsp); + if (i != 0) { + errstr = krb5_get_error_message(ctx.kctx, i); + goto error; + } + +error: + if (item != NULL) + otpd_log_req(item->req, "bind end: %s", + item->rsp != NULL ? "success" : errstr); + + ldap_msgfree(results); + otpd_queue_push(&ctx.stdio.responses, item); + verto_set_flags(ctx.stdio.writer, VERTO_EV_FLAG_PERSIST | + VERTO_EV_FLAG_IO_ERROR | + VERTO_EV_FLAG_IO_READ | + VERTO_EV_FLAG_IO_WRITE); +} + +void otpd_on_bind_io(verto_ctx *vctx, verto_ev *ev) +{ + verto_ev_flag flags; + + flags = verto_get_fd_state(ev); + if (flags & VERTO_EV_FLAG_IO_WRITE) + on_bind_writable(vctx, ev); + if (flags & VERTO_EV_FLAG_IO_READ) + on_bind_readable(vctx, ev); + if (flags & VERTO_EV_FLAG_IO_ERROR) { + otpd_log_err(EIO, "IO error received on bind socket"); + verto_break(ctx.vctx); + ctx.exitstatus = 1; + } +} |