Logo Search packages:      
Sourcecode: ldap2zone version File versions  Download package

ldap2zone.c

/*
 * Copyright (C) 2004, 2005 Stig Venaas <venaas@uninett.no>
 * $Id: ldap2zone.c,v 0.1 2005/04/23 21:30:12 venaas Exp $
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 */

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
#include <ctype.h>

#include <ldap.h>

00019 struct string {
    void *data;
    size_t len;
};

00024 struct assstack_entry {
    struct string key;
    struct string val;
    struct assstack_entry *next;
};

struct assstack_entry *assstack_find(struct assstack_entry *stack, struct string *key) {
    for (; stack; stack = stack->next)
      if (stack->key.len == key->len && !memcmp(stack->key.data, key->data, key->len))
          return stack;
    return NULL;
}

void assstack_push(struct assstack_entry **stack, struct assstack_entry *item) {
    item->next = *stack;
    *stack = item;
}

void assstack_insertbottom(struct assstack_entry **stack, struct assstack_entry *item) {
    struct assstack_entry *p;
    
    item->next = NULL;
    if (!*stack) {
      *stack = item;
      return;
    }
    /* find end, should keep track of end somewhere */
    /* really a queue, not a stack */
    p = *stack;
    while (p->next)
      p = p->next;
    p->next = item;
}

void printsoa(struct string *soa) {
    char *s;
    int i;
    
    s = (char *)soa->data;
    i = 0;
    while (i < soa->len) {
      putchar(s[i]);
      if (s[i++] == ' ')
          break;
    }
    while (i < soa->len) {
      putchar(s[i]);
      if (s[i++] == ' ')
          break;
    } 
    printf("(\n\t\t\t\t");
    while (i < soa->len) {
      putchar(s[i]);
      if (s[i++] == ' ')
          break;
    }
    printf("; Serialnumber\n\t\t\t\t");
    while (i < soa->len) {
      if (s[i] == ' ')
          break;
      putchar(s[i++]);
    }
    i++;
    printf("\t; Refresh\n\t\t\t\t");
    while (i < soa->len) {
      if (s[i] == ' ')
          break;
      putchar(s[i++]);
    }
    i++;
    printf("\t; Retry\n\t\t\t\t");
    while (i < soa->len) {
      if (s[i] == ' ')
          break;
      putchar(s[i++]);
    }
    i++;
    printf("\t; Expire\n\t\t\t\t");
    while (i < soa->len) {
      putchar(s[i++]);
    }
    printf(" )\t; Minimum TTL\n");
}

void printrrs(char *defaultttl, struct assstack_entry *item) {
    struct assstack_entry *stack;
    char *s;
    int first;
    int i;
    char *ttl, *type;
    int top;
    
    s = (char *)item->key.data;

    if (item->key.len == 1 && *s == '@') {
      top = 1;
      printf("@\t");
    } else {
      top = 0;
      for (i = 0; i < item->key.len; i++)
          putchar(s[i]);
      if (item->key.len < 8)
          putchar('\t');
      putchar('\t');
    }
    
    first = 1;
    for (stack = (struct assstack_entry *) item->val.data; stack; stack = stack->next) {
      ttl = (char *)stack->key.data;
      s = strchr(ttl, ' ');
      *s++ = '\0';
      type = s;
      
      if (first)
          first = 0;
        else
          printf("\t\t");
          
      if (strcmp(defaultttl, ttl))
          printf("%s", ttl);
      putchar('\t');
      
      if (top) {
          top = 0;
          printf("IN\t%s\t", type);
          /* Should always be SOA here */
          if (!strcmp(type, "SOA")) {
            printsoa(&stack->val);
            continue;
          }
      } else
          printf("%s\t", type);

      s = (char *)stack->val.data;
      for (i = 0; i < stack->val.len; i++)
          putchar(s[i]);
      putchar('\n');
    }
}

void print_zone(char *defaultttl, struct assstack_entry *stack) {
    printf("$TTL %s\n", defaultttl);
    for (; stack; stack = stack->next)
      printrrs(defaultttl, stack);
};

void usage(char *name) {
    fprintf(stderr, "Usage: %s zone-name LDAP-URL default-ttl [serial]\n", basename(name));
    exit(1);
};

void err(char *name, char *msg) {
    fprintf(stderr, "%s: %s\n", name, msg);
    exit(1);
};

int putrr(struct assstack_entry **stack, struct berval *name, char *type, char *ttl, struct berval *val) {
    struct string key;
    struct assstack_entry *rr, *rrdata;
    
    /* Do nothing if name or value have 0 length */
    if (!name->bv_len || !val->bv_len)
      return 0;

    /* see if already have an entry for this name */
    key.len = name->bv_len;
    key.data = name->bv_val;

    rr = assstack_find(*stack, &key);
    if (!rr) {
      /* Not found, create and push new entry */
      rr = (struct assstack_entry *) malloc(sizeof(struct assstack_entry));
      if (!rr)
          return -1;
      rr->key.len = name->bv_len;
      rr->key.data = (void *) malloc(rr->key.len);
      if (!rr->key.data) {
          free(rr);
          return -1;
      }
      memcpy(rr->key.data, name->bv_val, name->bv_len);
      rr->val.len = sizeof(void *);
      rr->val.data = NULL;
      if (name->bv_len == 1 && *(char *)name->bv_val == '@')
          assstack_push(stack, rr);
      else
          assstack_insertbottom(stack, rr);
    }

    rrdata = (struct assstack_entry *) malloc(sizeof(struct assstack_entry));
    if (!rrdata) {
      free(rr->key.data);
      free(rr);
      return -1;
    }
    rrdata->key.len = strlen(type) + strlen(ttl) + 1;
    rrdata->key.data = (void *) malloc(rrdata->key.len);
    if (!rrdata->key.data) {
      free(rrdata);
      free(rr->key.data);
      free(rr);
      return -1;
    }
    sprintf((char *)rrdata->key.data, "%s %s", ttl, type);
      
    rrdata->val.len = val->bv_len;
    rrdata->val.data = (void *) malloc(val->bv_len);
    if (!rrdata->val.data) {
      free(rrdata->key.data);
      free(rrdata);
      free(rr->key.data);
      free(rr);
      return -1;
    }
    memcpy(rrdata->val.data, val->bv_val, val->bv_len);

    if (!strcmp(type, "SOA"))
      assstack_push((struct assstack_entry **) &(rr->val.data), rrdata);
    else
      assstack_insertbottom((struct assstack_entry **) &(rr->val.data), rrdata);
    return 0;
}

int main(int argc, char **argv) {
    char *s, *hostporturl, *base = NULL;
    char *ttl, *defaultttl;
    LDAP *ld;
    char *fltr = NULL;
    LDAPMessage *res, *e;
    char *a, *serial;
    struct berval **vals, **names, **ttlvals, **soavals;
    char type[64];
    BerElement *ptr;
    int i, j, rc, msgid,msgidp,sizelimit = 0;
    struct assstack_entry *zone = NULL;
    LDAPControl **server = NULL, **client = NULL;
    struct timeval  timeout;

    if (argc < 4 || argc > 5)
        usage(argv[0]);

    hostporturl = argv[2];

    if (hostporturl != strstr( hostporturl, "ldap"))
      err(argv[0], "Not an LDAP URL");

    s = strchr(hostporturl, ':');

    if (!s || strlen(s) < 3 || s[1] != '/' || s[2] != '/')
      err(argv[0], "Not an LDAP URL");

    s = strchr(s+3, '/');
    if (s) {
      *s++ = '\0';
      base = s;
      s = strchr(base, '?');
      if (s)
          err(argv[0], "LDAP URL can only contain host, port and base");
    }

    defaultttl = argv[3];

    rc = ldap_initialize(&ld, hostporturl);
    if (rc != LDAP_SUCCESS)
      err(argv[0], "ldap_initialize() failed");

    if (argc == 5) {
      /* serial number specified, check if different from one in SOA */
      fltr = (char *)malloc(strlen(argv[1]) + strlen("(&(relativeDomainName=@)(zoneName=))") + 1);
      sprintf(fltr, "(&(relativeDomainName=@)(zoneName=%s))", argv[1]);
      msgid = ldap_search_ext(ld, base, LDAP_SCOPE_SUBTREE, fltr, NULL, 0, server, client, NULL, 0, &msgidp);

      if (msgid == -1)
          err(argv[0], "ldap_search() failed");

      while ((rc = ldap_result(ld, msgid, 0, NULL, &res)) != LDAP_RES_SEARCH_RESULT ) {
          /* not supporting continuation references at present */
          if (rc != LDAP_RES_SEARCH_ENTRY)
            err(argv[0], "ldap_result() returned cont.ref? Exiting");

          /* only one entry per result message */
          e = ldap_first_entry(ld, res);
          if (e == NULL) {
            ldap_msgfree(res);
            err(argv[0], "ldap_first_entry() failed");
          }
      
          soavals = ldap_get_values_len(ld, e, "SOARecord");

          if (soavals)
            break;
      }

      ldap_msgfree(res);
      if (!soavals) {
            err(argv[0], "No SOA Record found");
      }
      
      /* We have a SOA, compare serial numbers */
      /* Only checking first value, should be only one */
      /* chat changed to struct see where is problem */     
      s = strchr(soavals[0]->bv_val, ' ');
      s++;
      s = strchr(s, ' ');
      s++;
      serial = s;
      s = strchr(s, ' ');
      *s = '\0';

      if (!strcmp(serial, argv[4])) {
          ldap_value_free_len(soavals);

          err(argv[0], "serial numbers match");
      }
      ldap_value_free_len(soavals);
    }

    if (!fltr)
      fltr = (char *)malloc(strlen(argv[1]) + strlen("(zoneName=)") + 1);

    if (!fltr)
      err(argv[0], "Malloc failed");

    sprintf(fltr, "(zoneName=%s)", argv[1]);

    msgid = ldap_search_ext(ld, base, LDAP_SCOPE_SUBTREE, fltr, NULL, 0, server, client, 0, 0, &msgidp);
    if (msgid == -1)
      err(argv[0], "ldap_search() failed");

    while ((rc = ldap_result(ld, msgidp, 0, NULL, &res)) != LDAP_RES_SEARCH_RESULT ) {
      /* not supporting continuation references at present */
      if (rc != LDAP_RES_SEARCH_ENTRY)
          err(argv[0], "ldap_result() returned cont.ref? Exiting");

      /* only one entry per result message */
      e = ldap_first_entry(ld, res);
      if (e == NULL) {
          ldap_msgfree(res);
          err(argv[0], "ldap_first_entry() failed");
      }
      
      names = ldap_get_values_len(ld, e, "relativeDomainName");
      if (!names)
          continue;
      
      ttlvals = ldap_get_values_len(ld, e, "dNSTTL");
      ttl = ttlvals ? ttlvals[0]->bv_val : defaultttl;

      for (a = ldap_first_attribute(ld, e, &ptr); a != NULL; a = ldap_next_attribute(ld, e, ptr)) {
          char *s;

          for (s = a; *s; s++)
            *s = toupper(*s);
          s = strstr(a, "RECORD");
          if ((s == NULL) || (s == a) || (s - a >= (signed int)sizeof(type))) {
            ldap_memfree(a);
            continue;
          }
                  
          strncpy(type, a, s - a);
          type[s - a] = '\0';
          vals = ldap_get_values_len(ld, e, a);
          if (vals) {
            for (i = 0; vals[i]; i++)
                for (j = 0; names[j]; j++)
                  if (putrr(&zone, names[j], type, ttl, vals[i]))
                      err(argv[0], "malloc failed");
            ldap_value_free_len(vals);
          }
          ldap_memfree(a);
      }

      if (ptr)
          ber_free(ptr, 0);
      if (ttlvals)
          ldap_value_free_len(ttlvals);

      ldap_value_free_len(names);
      /* free this result */
      ldap_msgfree(res);
    }

    /* free final result */
    ldap_msgfree(res);

    print_zone(defaultttl, zone);
    return 0;
}

Generated by  Doxygen 1.6.0   Back to index