2 * Copyright (C) 2001 Jeff McNeil <jeff@snapcase.g-rock.net>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
10 * Tue May 1 19:19:54 EDT 2001 - Jeff McNeil
11 * Update to objectClass code, and add_to_rr_list function
12 * (I need to rename that) to support the dNSZone schema,
13 * ditched dNSDomain2 schema support. Version 0.3-ALPHA
22 #include <isc/buffer.h>
23 #include <isc/entropy.h>
26 #include <isc/print.h>
27 #include <isc/result.h>
30 #include <dns/dbiterator.h>
31 #include <dns/fixedname.h>
33 #include <dns/rdata.h>
34 #include <dns/rdataset.h>
35 #include <dns/rdatasetiter.h>
36 #include <dns/result.h>
37 #include <dns/rdatatype.h>
44 #define VERSION "0.4-ALPHA"
49 /* Global Zone Pointer */
50 char *gbl_zone = NULL;
52 typedef struct LDAP_INFO
56 struct LDAP_INFO *next;
64 /* Add to the ldap dit */
65 void add_ldap_values (ldap_info * ldinfo);
67 /* Init an ldap connection */
68 void init_ldap_conn ();
70 /* Ldap error checking */
71 void ldap_result_check (char *msg, char *dn, int err);
73 /* Put a hostname into a char ** array */
74 char **hostname_to_dn_list (char *hostname, char *zone, unsigned int flags);
76 /* Find out how many items are in a char ** array */
77 int get_attr_list_size (char **tmp);
80 char *build_dn_from_dc_list (char **dc_list, unsigned int ttl, int flag);
83 void add_to_rr_list (char *dn, char *name, char *type, char *data,
84 unsigned int ttl, unsigned int flags);
87 void isc_result_check (isc_result_t res, char *errorstr);
89 /* Generate LDIF Format files */
90 void generate_ldap (dns_name_t * dnsname, dns_rdata_t * rdata,
93 /* head pointer to the list */
94 ldap_info *ldap_info_base = NULL;
96 char *argzone, *ldapbase, *binddn, *bindpw = NULL;
97 char *ldapsystem = "localhost";
98 static char *objectClasses[] =
99 { "top", "dNSZone", NULL };
100 static char *topObjectClasses[] = { "top", NULL };
102 unsigned int debug = 0;
109 main (int *argc, char **argv)
111 isc_mem_t *mctx = NULL;
112 isc_entropy_t *ectx = NULL;
116 LDAPMod *base_attrs[2];
120 char fullbasedn[1024];
122 dns_fixedname_t fixedzone, fixedname;
123 dns_rdataset_t rdataset;
125 dns_rdata_t rdata = DNS_RDATA_INIT;
126 dns_rdatasetiter_t *riter;
127 dns_name_t *zone, *name;
129 dns_dbiterator_t *dbit = NULL;
132 extern int optind, opterr, optopt;
142 while ((topt = getopt ((int) argc, argv, "D:w:b:z:f:h:?dcv")) != -1)
147 printf("%s\n", VERSION);
156 binddn = strdup (optarg);
159 bindpw = strdup (optarg);
162 ldapbase = strdup (optarg);
165 argzone = strdup (optarg);
166 // We wipe argzone all to hell when we parse it for the DN */
167 gbl_zone = strdup(argzone);
170 zonefile = strdup (optarg);
173 ldapsystem = strdup (optarg);
182 if ((argzone == NULL) || (zonefile == NULL))
189 printf ("Initializing ISC Routines, parsing zone file\n");
191 result = isc_mem_create (0, 0, &mctx);
192 isc_result_check (result, "isc_mem_create");
194 result = isc_entropy_create(mctx, &ectx);
195 isc_result_check (result, "isc_entropy_create");
197 result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
198 isc_result_check (result, "isc_hash_create");
200 isc_buffer_init (&buff, argzone, strlen (argzone));
201 isc_buffer_add (&buff, strlen (argzone));
202 dns_fixedname_init (&fixedzone);
203 zone = dns_fixedname_name (&fixedzone);
204 result = dns_name_fromtext (zone, &buff, dns_rootname, 0, NULL);
205 isc_result_check (result, "dns_name_fromtext");
207 result = dns_db_create (mctx, "rbt", zone, dns_dbtype_zone,
208 dns_rdataclass_in, 0, NULL, &db);
209 isc_result_check (result, "dns_db_create");
211 result = dns_db_load (db, zonefile);
212 isc_result_check (result, "Check Zone Syntax: dns_db_load");
214 result = dns_db_createiterator (db, 0, &dbit);
215 isc_result_check (result, "dns_db_createiterator");
217 result = dns_dbiterator_first (dbit);
218 isc_result_check (result, "dns_dbiterator_first");
220 dns_fixedname_init (&fixedname);
221 name = dns_fixedname_name (&fixedname);
222 dns_rdataset_init (&rdataset);
223 dns_rdata_init (&rdata);
225 while (result == ISC_R_SUCCESS)
228 result = dns_dbiterator_current (dbit, &node, name);
230 if (result == ISC_R_NOMORE)
233 isc_result_check (result, "dns_dbiterator_current");
236 result = dns_db_allrdatasets (db, node, NULL, 0, &riter);
237 isc_result_check (result, "dns_db_allrdatasets");
239 result = dns_rdatasetiter_first (riter);
240 //isc_result_check(result, "dns_rdatasetiter_first");
242 while (result == ISC_R_SUCCESS)
244 dns_rdatasetiter_current (riter, &rdataset);
245 result = dns_rdataset_first (&rdataset);
246 isc_result_check (result, "dns_rdatasetiter_current");
248 while (result == ISC_R_SUCCESS)
250 dns_rdataset_current (&rdataset, &rdata);
251 generate_ldap (name, &rdata, rdataset.ttl);
252 dns_rdata_reset (&rdata);
253 result = dns_rdataset_next (&rdataset);
255 dns_rdataset_disassociate (&rdataset);
256 result = dns_rdatasetiter_next (riter);
259 dns_rdatasetiter_destroy (&riter);
260 result = dns_dbiterator_next (dbit);
264 /* Initialize the LDAP Connection */
266 printf ("Initializing LDAP Connection to %s as %s\n", ldapsystem, binddn);
273 printf ("Creating base zone DN %s\n", argzone);
275 dc_list = hostname_to_dn_list (argzone, argzone, DNS_TOP);
276 basedn = build_dn_from_dc_list (dc_list, 0, NO_SPEC);
278 for (ctmp = &basedn[strlen (basedn)]; ctmp >= &basedn[0]; ctmp--)
280 if ((*ctmp == ',') || (ctmp == &basedn[0]))
282 base.mod_op = LDAP_MOD_ADD;
283 base.mod_type = "objectClass";
284 base.mod_values = topObjectClasses;
285 base_attrs[0] = &base;
286 base_attrs[1] = NULL;
290 if (ctmp != &basedn[0])
291 sprintf (fullbasedn, "%s,%s", ctmp + 1, ldapbase);
293 sprintf (fullbasedn, "%s,%s", ctmp, ldapbase);
298 if (ctmp != &basedn[0])
299 sprintf (fullbasedn, "%s", ctmp + 1);
301 sprintf (fullbasedn, "%s", ctmp);
303 result = ldap_add_s (conn, fullbasedn, base_attrs);
304 ldap_result_check ("intial ldap_add_s", fullbasedn, result);
312 printf ("Skipping zone base dn creation for %s\n", argzone);
315 for (tmp = ldap_info_base; tmp != NULL; tmp = tmp->next)
319 printf ("Adding DN: %s\n", tmp->dn);
321 add_ldap_values (tmp);
325 printf("Operation Complete.\n");
329 isc_entropy_detach(&ectx);
330 isc_mem_destroy(&mctx);
336 /* Check the status of an isc_result_t after any isc routines.
337 * I should probably rename this function, as not to cause any
338 * confusion with the isc* routines. Will exit on error. */
340 isc_result_check (isc_result_t res, char *errorstr)
342 if (res != ISC_R_SUCCESS)
344 fprintf (stderr, " %s: %s\n", errorstr, isc_result_totext (res));
350 /* Takes DNS information, in bind data structure format, and adds textual
351 * zone information to the LDAP run queue. */
353 generate_ldap (dns_name_t * dnsname, dns_rdata_t * rdata, unsigned int ttl)
355 unsigned char name[DNS_NAME_MAXTEXT + 1];
357 unsigned char type[20];
358 unsigned char data[2048];
365 isc_buffer_init (&buff, name, sizeof (name));
366 result = dns_name_totext (dnsname, ISC_TRUE, &buff);
367 isc_result_check (result, "dns_name_totext");
368 name[isc_buffer_usedlength (&buff)] = 0;
370 isc_buffer_init (&buff, type, sizeof (type));
371 result = dns_rdatatype_totext (rdata->type, &buff);
372 isc_result_check (result, "dns_rdatatype_totext");
373 type[isc_buffer_usedlength (&buff)] = 0;
375 isc_buffer_init (&buff, data, sizeof (data));
376 result = dns_rdata_totext (rdata, NULL, &buff);
377 isc_result_check (result, "dns_rdata_totext");
378 data[isc_buffer_usedlength (&buff)] = 0;
380 dc_list = hostname_to_dn_list (name, argzone, DNS_OBJECT);
381 len = (get_attr_list_size (dc_list) - 2);
382 dn = build_dn_from_dc_list (dc_list, ttl, WI_SPEC);
385 printf ("Adding %s (%s %s) to run queue list.\n", dn, type, data);
387 add_to_rr_list (dn, dc_list[len], type, data, ttl, DNS_OBJECT);
391 /* Locate an item in the Run queue linked list, by DN. Used by functions
392 * which add items to the run queue.
395 locate_by_dn (char *dn)
398 for (tmp = ldap_info_base; tmp != (ldap_info *) NULL; tmp = tmp->next)
400 if (!strncmp (tmp->dn, dn, strlen (dn)))
403 return (ldap_info *) NULL;
408 /* Take textual zone data, and add to the LDAP Run queue. This works like so:
409 * If locate_by_dn does not return, alloc a new ldap_info structure, and then
410 * calloc a LDAPMod array, fill in the default "everyone needs this" information,
411 * including object classes and dc's. If it locate_by_dn does return, then we'll
412 * realloc for more LDAPMod structs, and appened the new data. If an LDAPMod exists
413 * for the parameter we're adding, then we'll realloc the mod_values array, and
414 * add the new value to the existing LDAPMod. Finnaly, it assures linkage exists
415 * within the Run queue linked ilst*/
418 add_to_rr_list (char *dn, char *name, char *type,
419 char *data, unsigned int ttl, unsigned int flags)
425 char ldap_type_buffer[128];
429 if ((tmp = locate_by_dn (dn)) == NULL)
432 /* There wasn't one already there, so we need to allocate a new one,
433 * and stick it on the list */
435 tmp = (ldap_info *) malloc (sizeof (ldap_info));
436 if (tmp == (ldap_info *) NULL)
438 fprintf (stderr, "malloc: %s\n", strerror (errno));
439 ldap_unbind_s (conn);
443 tmp->dn = strdup (dn);
444 tmp->attrs = (LDAPMod **) calloc (sizeof (LDAPMod *), flags);
445 if (tmp->attrs == (LDAPMod **) NULL)
447 fprintf (stderr, "calloc: %s\n", strerror (errno));
448 ldap_unbind_s (conn);
452 for (i = 0; i < flags; i++)
454 tmp->attrs[i] = (LDAPMod *) malloc (sizeof (LDAPMod));
455 if (tmp->attrs[i] == (LDAPMod *) NULL)
457 fprintf (stderr, "malloc: %s\n", strerror (errno));
461 tmp->attrs[0]->mod_op = LDAP_MOD_ADD;
462 tmp->attrs[0]->mod_type = "objectClass";
464 if (flags == DNS_OBJECT)
465 tmp->attrs[0]->mod_values = objectClasses;
468 tmp->attrs[0]->mod_values = topObjectClasses;
469 tmp->attrs[1] = NULL;
471 tmp->next = ldap_info_base;
472 ldap_info_base = tmp;
476 tmp->attrs[1]->mod_op = LDAP_MOD_ADD;
477 tmp->attrs[1]->mod_type = "relativeDomainName";
478 tmp->attrs[1]->mod_values = (char **) calloc (sizeof (char *), 2);
480 if (tmp->attrs[1]->mod_values == (char **)NULL)
483 tmp->attrs[1]->mod_values[0] = strdup (name);
484 tmp->attrs[1]->mod_values[2] = NULL;
486 sprintf (ldap_type_buffer, "%sRecord", type);
488 tmp->attrs[2]->mod_op = LDAP_MOD_ADD;
489 tmp->attrs[2]->mod_type = strdup (ldap_type_buffer);
490 tmp->attrs[2]->mod_values = (char **) calloc (sizeof (char *), 2);
492 if (tmp->attrs[2]->mod_values == (char **)NULL)
495 tmp->attrs[2]->mod_values[0] = strdup (data);
496 tmp->attrs[2]->mod_values[1] = NULL;
498 tmp->attrs[3]->mod_op = LDAP_MOD_ADD;
499 tmp->attrs[3]->mod_type = "dNSTTL";
500 tmp->attrs[3]->mod_values = (char **) calloc (sizeof (char *), 2);
502 if (tmp->attrs[3]->mod_values == (char **)NULL)
505 sprintf (charttl, "%d", ttl);
506 tmp->attrs[3]->mod_values[0] = strdup (charttl);
507 tmp->attrs[3]->mod_values[1] = NULL;
509 tmp->attrs[4]->mod_op = LDAP_MOD_ADD;
510 tmp->attrs[4]->mod_type = "zoneName";
511 tmp->attrs[4]->mod_values = (char **)calloc(sizeof(char *), 2);
512 tmp->attrs[4]->mod_values[0] = gbl_zone;
513 tmp->attrs[4]->mod_values[1] = NULL;
515 tmp->attrs[5] = NULL;
516 tmp->attrcnt = flags;
517 tmp->next = ldap_info_base;
518 ldap_info_base = tmp;
523 for (i = 0; tmp->attrs[i] != NULL; i++)
525 sprintf (ldap_type_buffer, "%sRecord", type);
527 (ldap_type_buffer, tmp->attrs[i]->mod_type,
528 strlen (tmp->attrs[i]->mod_type)))
530 attrlist = get_attr_list_size (tmp->attrs[i]->mod_values);
531 tmp->attrs[i]->mod_values =
532 (char **) realloc (tmp->attrs[i]->mod_values,
533 sizeof (char *) * (attrlist + 1));
535 if (tmp->attrs[i]->mod_values == (char **) NULL)
537 fprintf (stderr, "realloc: %s\n", strerror (errno));
538 ldap_unbind_s (conn);
541 for (x = 0; tmp->attrs[i]->mod_values[x] != NULL; x++);
543 tmp->attrs[i]->mod_values[x] = strdup (data);
544 tmp->attrs[i]->mod_values[x + 1] = NULL;
549 (LDAPMod **) realloc (tmp->attrs,
550 sizeof (LDAPMod) * ++(tmp->attrcnt));
551 if (tmp->attrs == NULL)
553 fprintf (stderr, "realloc: %s\n", strerror (errno));
554 ldap_unbind_s (conn);
558 for (x = 0; tmp->attrs[x] != NULL; x++);
559 tmp->attrs[x] = (LDAPMod *) malloc (sizeof (LDAPMod));
560 tmp->attrs[x]->mod_op = LDAP_MOD_ADD;
561 tmp->attrs[x]->mod_type = strdup (ldap_type_buffer);
562 tmp->attrs[x]->mod_values = (char **) calloc (sizeof (char *), 2);
563 tmp->attrs[x]->mod_values[0] = strdup (data);
564 tmp->attrs[x]->mod_values[1] = NULL;
565 tmp->attrs[x + 1] = NULL;
569 /* Size of a mod_values list, plus the terminating NULL field. */
571 get_attr_list_size (char **tmp)
575 while (*ftmp != NULL)
584 /* take a hostname, and split it into a char ** of the dc parts,
585 * example, we have www.domain.com, this function will return:
586 * array[0] = com, array[1] = domain, array[2] = www. */
589 hostname_to_dn_list (char *hostname, char *zone, unsigned int flags)
592 static char *dn_buffer[64];
597 zname = strdup (hostname);
599 if (flags == DNS_OBJECT)
602 if (strlen (zname) != strlen (zone))
604 tmp = &zname[strlen (zname) - strlen (zone)];
606 hnamebuff = strdup (zname);
618 for (tmp = strrchr (zname, '.'); tmp != (char *) 0;
619 tmp = strrchr (zname, '.'))
622 dn_buffer[i++] = tmp;
624 dn_buffer[i++] = zname;
625 dn_buffer[i++] = hnamebuff;
632 /* build an sdb compatible LDAP DN from a "dc_list" (char **).
633 * will append dNSTTL information to each RR Record, with the
634 * exception of "@"/SOA. */
637 build_dn_from_dc_list (char **dc_list, unsigned int ttl, int flag)
641 static char dn[1024];
644 bzero (tmp, sizeof (tmp));
645 bzero (dn, sizeof (dn));
646 size = get_attr_list_size (dc_list);
647 for (x = size - 2; x > 0; x--)
651 if (x == (size - 2) && (strncmp (dc_list[x], "@", 1) == 0) && (ttl))
652 sprintf (tmp, "relativeDomainName=%s + dNSTTL=%d,", dc_list[x], ttl);
653 else if (x == (size - 2))
654 sprintf(tmp, "relativeDomainName=%s,",dc_list[x]);
656 sprintf(tmp,"dc=%s,", dc_list[x]);
660 sprintf(tmp, "dc=%s,", dc_list[x]);
664 strncat (dn, tmp, sizeof (dn) - strlen (dn));
667 sprintf (tmp, "dc=%s", dc_list[0]);
668 strncat (dn, tmp, sizeof (dn) - strlen (dn));
675 /* Initialize LDAP Conn */
680 conn = ldap_open (ldapsystem, LDAP_PORT);
683 fprintf (stderr, "Error opening Ldap connection: %s\n",
688 result = ldap_simple_bind_s (conn, binddn, bindpw);
689 ldap_result_check ("ldap_simple_bind_s", "LDAP Bind", result);
692 /* Like isc_result_check, only for LDAP */
694 ldap_result_check (char *msg, char *dn, int err)
696 if ((err != LDAP_SUCCESS) && (err != LDAP_ALREADY_EXISTS))
698 fprintf(stderr, "Error while adding %s (%s):\n",
700 ldap_perror (conn, dn);
701 ldap_unbind_s (conn);
708 /* For running the ldap_info run queue. */
710 add_ldap_values (ldap_info * ldinfo)
716 if (ldapbase != NULL)
717 sprintf (dnbuffer, "%s,%s", ldinfo->dn, ldapbase);
719 sprintf (dnbuffer, "%s", ldinfo->dn);
721 result = ldap_add_s (conn, dnbuffer, ldinfo->attrs);
722 ldap_result_check ("ldap_add_s", dnbuffer, result);
728 /* name says it all */
733 "zone2ldap -D [BIND DN] -w [BIND PASSWORD] -b [BASE DN] -z [ZONE] -f [ZONE FILE] -h [LDAP HOST]
734 [-c Create LDAP Base structure][-d Debug Output (lots !)] \n ");}