+++ /dev/null
-/*
- * ITKACL control library.
- *
- * (C) 2004-2013 Steinar H. Gunderson
- * GPL, v2.
- */
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <errno.h>
-#include <ctype.h>
-#include <unbound.h>
-
-struct itkacl_config {
- char nszone[256];
- int require_dnssec;
- char dnssec_public_key[256];
-};
-
-#define CONFIG_FILENAME "/etc/itkacl.conf"
-
-static int itkacl_read_config(const char * const filename,
- struct itkacl_config *config,
- char *errmsg, size_t errmsg_size)
-{
- FILE *fp;
- int lineno = 0;
-
- /* Defaults. */
- strcpy(config->nszone, "");
- config->require_dnssec = 0;
- strcpy(config->dnssec_public_key, "");
-
- fp = fopen(CONFIG_FILENAME, "r");
- if (fp == NULL) {
- if (errmsg)
- snprintf(errmsg, errmsg_size, "%s: %s",
- CONFIG_FILENAME, strerror(errno));
- return -1;
- }
-
- while (!feof(fp)) {
- char line[256], arg[256], *ptr;
-
- if (fgets(line, sizeof(line), fp) == NULL) {
- break;
- }
- ++lineno;
-
- /* Remove trailing newlines and then comments. */
- ptr = strchr(line, '\n');
- if (ptr != NULL)
- *ptr = 0;
-
- ptr = strchr(line, '\r');
- if (ptr != NULL)
- *ptr = 0;
-
- ptr = strchr(line, '#');
- if (ptr != NULL)
- *ptr = 0;
-
- /* Remove trailing whitespace, if any. */
- ptr = line + strlen(line) - 1;
- while (ptr >= line && isspace(*ptr))
- *ptr-- = 0;
-
- /* Skip lines that now ended up blank. */
- if (line[0] == 0)
- continue;
-
- if (sscanf(line, "zone %255s", arg) == 1) {
- strcpy(config->nszone, arg);
- continue;
- }
- if (strcmp(line, "require-dnssec") == 0) {
- config->require_dnssec = 1;
- continue;
- }
- if (sscanf(line, "dnssec-public-key %255s", arg) == 1) {
- strcpy(config->dnssec_public_key, arg);
- continue;
- }
-
- if (errmsg)
- snprintf(errmsg, errmsg_size, "%s: Could not parse line %d",
- CONFIG_FILENAME, lineno);
- fclose(fp);
- return -1;
- }
-
- if (strlen(config->nszone) == 0) {
- if (errmsg)
- snprintf(errmsg, errmsg_size, "%s: Missing 'zone' directive",
- CONFIG_FILENAME);
- fclose(fp);
- return -1;
- }
-
- fclose(fp);
- return 0;
-}
-
-int itkacl_check(const char * const realm, const char * const user,
- char *errmsg, size_t errmsg_size)
-{
- struct itkacl_config config;
- int ret, nxdomain;
- const char *ptr;
- char nszone[256];
- char temp[256];
- struct ub_ctx* ctx;
- struct ub_result* result;
-
- if (itkacl_read_config(CONFIG_FILENAME, &config, errmsg, errmsg_size) != 0) {
- return -1;
- }
-
- if (realm[0] != '/') {
- if (errmsg)
- snprintf(errmsg, errmsg_size, "Invalid realm '%s' (missing leading /)",
- realm);
- return -1;
- }
- if (strlen(user) > 64) {
- if (errmsg)
- snprintf(errmsg, errmsg_size, "Invalid user '%s' (above 64 characters)",
- user);
- return -1;
- }
- if (strlen(realm) > 64) {
- if (errmsg)
- snprintf(errmsg, errmsg_size, "Invalid realm '%s' (above 64 characters)",
- realm);
- return -1;
- }
-
- /* check that the user name is valid */
- ptr = user;
- while (*ptr) {
- /* only allow [a-z0-9-] */
- if (!((*ptr >= 'a' && *ptr <= 'z') ||
- (*ptr >= '0' && *ptr <= '9') ||
- *ptr == '-')) {
- if (errmsg) {
- snprintf(errmsg, errmsg_size, "Invalid realm '%s' (illegal characters)",
- realm);
- }
- return -1;
- }
- ++ptr;
- }
-
- /* traverse the realm entry by entry from the root,
- * creating a DNS zone name as we go */
- strcpy(nszone, config.nszone);
- ptr = realm;
- while (*ptr) {
- /* copy all characters to next / or end of string */
- char this_part[64];
- int i = 0;
- this_part[0] = 0;
-
- ++ptr;
- while (*ptr && *ptr != '/') {
- /* only allow [a-z0-9-] */
- if (!((*ptr >= 'a' && *ptr <= 'z') ||
- (*ptr >= '0' && *ptr <= '9') ||
- *ptr == '-')) {
- if (errmsg) {
- snprintf(errmsg, errmsg_size, "Invalid realm '%s' (illegal characters)",
- realm);
- }
- return -1;
- }
- this_part[i++] = *ptr++;
- }
- this_part[i] = 0;
-
- strcpy(temp, nszone);
- snprintf(nszone, 256, "%s.%s", this_part, temp);
- }
-
- /* finally, prepend the username */
- strcpy(temp, nszone);
- sprintf(nszone, "%s.%s", user, temp);
-
- /* Create the DNS resolver context. */
- ctx = ub_ctx_create();
- if (ctx == NULL) {
- if (errmsg)
- snprintf(errmsg, errmsg_size, "Host name lookup failure: Could not create DNS context");
- return -1;
- }
-
- ret = ub_ctx_resolvconf(ctx, "/etc/resolv.conf");
- if (ret != 0) {
- if (errmsg)
- snprintf(errmsg, errmsg_size,
- "Host name lookup failure: Could not read /etc/resolv.conf "
- "(resolver error: %s) (system error: %s)",
- ub_strerror(ret), strerror(errno));
- ub_ctx_delete(ctx);
- return -1;
- }
-
- ret = ub_ctx_hosts(ctx, "/etc/hosts");
- if (ret != 0) {
- if (errmsg)
- snprintf(errmsg, errmsg_size,
- "Host name lookup failure: Could not read /etc/hosts "
- "(resolver error: %s) (system error: %s)",
- ub_strerror(ret), strerror(errno));
- ub_ctx_delete(ctx);
- return -1;
- }
-
- if (strlen(config.dnssec_public_key) != 0) {
- ret = ub_ctx_add_ta_file(ctx, config.dnssec_public_key);
- if (ret != 0) {
- if (errmsg)
- snprintf(errmsg, errmsg_size,
- "Host name lookup failure: Error adding keys from %s "
- "(resolver error: %s) (system error: %s)",
- config.dnssec_public_key,
- ub_strerror(ret), strerror(errno));
- ub_ctx_delete(ctx);
- return -1;
- }
- }
-
- /* Do the actual DNS lookup (TYPE A, CLASS IN). */
- ret = ub_resolve(ctx, nszone, 1, 1, &result);
- if (ret != 0) {
- if (errmsg)
- snprintf(errmsg, errmsg_size, "Host name lookup failure: %s",
- ub_strerror(ret));
- ub_ctx_delete(ctx);
- return -1;
- }
-
- /* Verify DNSSEC. */
- if (result->bogus) {
- if (errmsg)
- snprintf(errmsg, errmsg_size,
- "Host name lookup failure: Bogus DNSSEC result (security failure)");
- ub_resolve_free(result);
- ub_ctx_delete(ctx);
- return -1;
- }
- if (config.require_dnssec && !result->secure) {
- if (errmsg)
- snprintf(errmsg, errmsg_size,
- "Host name lookup failure: Result was not secured with DNSSEC");
- ub_resolve_free(result);
- ub_ctx_delete(ctx);
- return -1;
- }
-
- nxdomain = result->nxdomain;
-
- ub_resolve_free(result);
- ub_ctx_delete(ctx);
-
- if (nxdomain)
- return 1;
- else
- return 0;
-}