summaryrefslogtreecommitdiffstats
path: root/daemons/ipa-otpd/forward.c
diff options
context:
space:
mode:
Diffstat (limited to 'daemons/ipa-otpd/forward.c')
-rw-r--r--daemons/ipa-otpd/forward.c124
1 files changed, 124 insertions, 0 deletions
diff --git a/daemons/ipa-otpd/forward.c b/daemons/ipa-otpd/forward.c
new file mode 100644
index 000000000..e6ae1e9d2
--- /dev/null
+++ b/daemons/ipa-otpd/forward.c
@@ -0,0 +1,124 @@
+/*
+ * 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 proxies the incoming RADIUS request (stdio.c/query.c) to a
+ * third-party RADIUS server if the user is configured for forwarding. The
+ * result is placed in the stdout queue (stdio.c).
+ */
+
+#include "internal.h"
+
+static void forward_cb(krb5_error_code retval, const krad_packet *request,
+ const krad_packet *response, void *data)
+{
+ krad_code code, acpt;
+ struct otpd_queue_item *item = data;
+ (void)request;
+
+ acpt = krad_code_name2num("Access-Accept");
+ code = krad_packet_get_code(response);
+ if (retval == 0 && code == acpt) {
+ item->sent = 0;
+ retval = krad_packet_new_response(ctx.kctx, SECRET, acpt,
+ NULL, item->req, &item->rsp);
+ }
+
+ otpd_log_req(item->req, "forward end: %s",
+ retval == 0
+ ? krad_code_num2name(code)
+ : krb5_get_error_message(ctx.kctx, retval));
+
+ 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);
+}
+
+krb5_error_code otpd_forward(struct otpd_queue_item **item)
+{
+ krad_attr usernameid, passwordid;
+ const krb5_data *password;
+ krb5_error_code retval;
+ char *username;
+ krb5_data data;
+
+ /* Find the username. */
+ username = (*item)->user.ipatokenRadiusUserName;
+ if (username == NULL) {
+ username = (*item)->user.other;
+ if (username == NULL)
+ username = (*item)->user.uid;
+ }
+
+ /* Check to see if we are supposed to forward. */
+ if ((*item)->radius.ipatokenRadiusServer == NULL ||
+ (*item)->radius.ipatokenRadiusSecret == NULL ||
+ username == NULL)
+ return 0;
+
+ otpd_log_req((*item)->req, "forward start: %s / %s", username,
+ (*item)->radius.ipatokenRadiusServer);
+
+ usernameid = krad_attr_name2num("User-Name");
+ passwordid = krad_attr_name2num("User-Password");
+
+ /* Set User-Name. */
+ data.data = username;
+ data.length = strlen(data.data);
+ retval = krad_attrset_add(ctx.attrs, usernameid, &data);
+ if (retval != 0)
+ goto error;
+
+ /* Set User-Password. */
+ password = krad_packet_get_attr((*item)->req, passwordid, 0);
+ if (password == NULL) {
+ krad_attrset_del(ctx.attrs, usernameid, 0);
+ goto error;
+ }
+ retval = krad_attrset_add(ctx.attrs, passwordid, password);
+ if (retval != 0) {
+ krad_attrset_del(ctx.attrs, usernameid, 0);
+ goto error;
+ }
+
+ /* Forward the request to the RADIUS server. */
+ retval = krad_client_send(ctx.client,
+ krad_code_name2num("Access-Request"),
+ ctx.attrs,
+ (*item)->radius.ipatokenRadiusServer,
+ (*item)->radius.ipatokenRadiusSecret,
+ (*item)->radius.ipatokenRadiusTimeout,
+ (*item)->radius.ipatokenRadiusRetries,
+ forward_cb, *item);
+ krad_attrset_del(ctx.attrs, usernameid, 0);
+ krad_attrset_del(ctx.attrs, passwordid, 0);
+ if (retval == 0)
+ *item = NULL;
+
+error:
+ if (retval != 0)
+ otpd_log_req((*item)->req, "forward end: %s",
+ krb5_get_error_message(ctx.kctx, retval));
+ return retval;
+}