summaryrefslogtreecommitdiffstats
path: root/daemons/ipa-otpd/parse.c
diff options
context:
space:
mode:
authorNathaniel McCallum <npmccallum@redhat.com>2013-04-11 14:03:25 -0400
committerMartin Kosek <mkosek@redhat.com>2013-05-17 09:30:51 +0200
commit203754691c28243dd3cf378e98390fc0a455b485 (patch)
treef1574334a744f2b2b54c90a0eec08a985151447b /daemons/ipa-otpd/parse.c
parent5d51ae50a59466fa2d6d230d7f2879de34210f0c (diff)
downloadfreeipa-203754691c28243dd3cf378e98390fc0a455b485.tar.gz
freeipa-203754691c28243dd3cf378e98390fc0a455b485.tar.xz
freeipa-203754691c28243dd3cf378e98390fc0a455b485.zip
Add the krb5/FreeIPA RADIUS companion daemon
This daemon listens for RADIUS packets on a well known UNIX domain socket. When a packet is received, it queries LDAP to see if the user is configured for RADIUS authentication. If so, then the packet is forwarded to the 3rd party RADIUS server. Otherwise, a bind is attempted against the LDAP server. https://fedorahosted.org/freeipa/ticket/3366 http://freeipa.org/page/V3/OTP
Diffstat (limited to 'daemons/ipa-otpd/parse.c')
-rw-r--r--daemons/ipa-otpd/parse.c176
1 files changed, 176 insertions, 0 deletions
diff --git a/daemons/ipa-otpd/parse.c b/daemons/ipa-otpd/parse.c
new file mode 100644
index 000000000..062b64037
--- /dev/null
+++ b/daemons/ipa-otpd/parse.c
@@ -0,0 +1,176 @@
+/*
+ * 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 parses the user's configuration received from LDAP (see query.c).
+ */
+
+#include "internal.h"
+#include <ctype.h>
+
+#define DEFAULT_TIMEOUT 15
+#define DEFAULT_RETRIES 3
+
+/* Convert an LDAP entry into an allocated string. */
+static int get_string(LDAP *ldp, LDAPMessage *entry, const char *name,
+ char **out)
+{
+ struct berval **vals;
+ ber_len_t i;
+ char *buf;
+
+ vals = ldap_get_values_len(ldp, entry, name);
+ if (vals == NULL)
+ return ENOENT;
+
+ buf = calloc(vals[0]->bv_len + 1, sizeof(char));
+ if (buf == NULL) {
+ ldap_value_free_len(vals);
+ return ENOMEM;
+ }
+
+ for (i = 0; i < vals[0]->bv_len; i++) {
+ if (!isprint(vals[0]->bv_val[i])) {
+ free(buf);
+ ldap_value_free_len(vals);
+ return EINVAL;
+ }
+
+ buf[i] = vals[0]->bv_val[i];
+ }
+
+ if (*out != NULL)
+ free(*out);
+ *out = buf;
+ ldap_value_free_len(vals);
+ return 0;
+}
+
+/* Convert an LDAP entry into an unsigned long. */
+static int get_ulong(LDAP *ldp, LDAPMessage *entry, const char *name,
+ unsigned long *out)
+{
+ struct berval **vals;
+ char buffer[32];
+
+ vals = ldap_get_values_len(ldp, entry, name);
+ if (vals == NULL)
+ return ENOENT;
+
+ if (vals[0]->bv_len > sizeof(buffer) - 1) {
+ ldap_value_free_len(vals);
+ return ERANGE;
+ }
+
+ memcpy(buffer, vals[0]->bv_val, vals[0]->bv_len);
+ buffer[vals[0]->bv_len] = '\0';
+ ldap_value_free_len(vals);
+
+ *out = strtoul(buffer, NULL, 10);
+ if (*out == ULONG_MAX)
+ return errno;
+
+ return 0;
+}
+
+/* Parse basic user configuration. */
+const char *otpd_parse_user(LDAP *ldp, LDAPMessage *entry,
+ struct otpd_queue_item *item)
+{
+ int i, j;
+
+ i = get_string(ldp, entry, "uid", &item->user.uid);
+ if (i != 0)
+ return strerror(i);
+
+ i = get_string(ldp, entry, "ipatokenRadiusUserName",
+ &item->user.ipatokenRadiusUserName);
+ if (i != 0 && i != ENOENT)
+ return strerror(i);
+
+ i = get_string(ldp, entry, "ipatokenRadiusConfigLink",
+ &item->user.ipatokenRadiusConfigLink);
+ if (i != 0 && i != ENOENT)
+ return strerror(i);
+
+ /* Get the DN. */
+ item->user.dn = ldap_get_dn(ldp, entry);
+ if (item->user.dn == NULL) {
+ i = ldap_get_option(ldp, LDAP_OPT_RESULT_CODE, &j);
+ return ldap_err2string(i == LDAP_OPT_SUCCESS ? j : i);
+ }
+
+ return NULL;
+}
+
+/* Parse the user's RADIUS configuration. */
+const char *otpd_parse_radius(LDAP *ldp, LDAPMessage *entry,
+ struct otpd_queue_item *item)
+{
+ unsigned long l;
+ int i;
+
+ i = get_string(ldp, entry, "ipatokenRadiusServer",
+ &item->radius.ipatokenRadiusServer);
+ if (i != 0)
+ return strerror(i);
+
+ i = get_string(ldp, entry, "ipatokenRadiusSecret",
+ &item->radius.ipatokenRadiusSecret);
+ if (i != 0)
+ return strerror(i);
+
+ i = get_string(ldp, entry, "ipatokenUserMapAttribute",
+ &item->radius.ipatokenUserMapAttribute);
+ if (i != 0 && i != ENOENT)
+ return strerror(i);
+
+ i = get_ulong(ldp, entry, "ipatokenRadiusTimeout", &l);
+ if (i == ENOENT)
+ l = DEFAULT_TIMEOUT;
+ else if (i != 0)
+ return strerror(i);
+ item->radius.ipatokenRadiusTimeout = l * 1000;
+
+ i = get_ulong(ldp, entry, "ipatokenRadiusRetries", &l);
+ if (i == ENOENT)
+ l = DEFAULT_RETRIES;
+ else if (i != 0)
+ return strerror(i);
+ item->radius.ipatokenRadiusRetries = l;
+
+ return NULL;
+}
+
+/* Parse the user's RADIUS username. */
+const char *otpd_parse_radius_username(LDAP *ldp, LDAPMessage *entry,
+ struct otpd_queue_item *item)
+{
+ int i;
+
+ i = get_string(ldp, entry, item->radius.ipatokenUserMapAttribute,
+ &item->user.other);
+ if (i != 0)
+ return strerror(i);
+
+ return NULL;
+}