etc/services - sync with NetBSD-8
[minix.git] / external / bsd / bind / dist / contrib / sdb / ldap / zone2ldap.c
blob615c31a9bfbb97610bd0f92697e33f46c2c45f04
1 /* $NetBSD: zone2ldap.c,v 1.4 2014/12/10 04:37:57 christos Exp $ */
3 /*
4 * Copyright (C) 2001 Jeff McNeil <jeff@snapcase.g-rock.net>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * Change Log
12 * Tue May 1 19:19:54 EDT 2001 - Jeff McNeil
13 * Update to objectClass code, and add_to_rr_list function
14 * (I need to rename that) to support the dNSZone schema,
15 * ditched dNSDomain2 schema support. Version 0.3-ALPHA
18 #include <errno.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <getopt.h>
24 #include <isc/buffer.h>
25 #include <isc/entropy.h>
26 #include <isc/hash.h>
27 #include <isc/mem.h>
28 #include <isc/print.h>
29 #include <isc/result.h>
31 #include <dns/db.h>
32 #include <dns/dbiterator.h>
33 #include <dns/fixedname.h>
34 #include <dns/name.h>
35 #include <dns/rdata.h>
36 #include <dns/rdataset.h>
37 #include <dns/rdatasetiter.h>
38 #include <dns/result.h>
39 #include <dns/rdatatype.h>
41 #include <ldap.h>
43 #define DNS_OBJECT 6
44 #define DNS_TOP 2
46 #define VERSION "0.4-ALPHA"
48 #define NO_SPEC 0
49 #define WI_SPEC 1
51 /* Global Zone Pointer */
52 char *gbl_zone = NULL;
54 typedef struct LDAP_INFO
56 char *dn;
57 LDAPMod **attrs;
58 struct LDAP_INFO *next;
59 int attrcnt;
61 ldap_info;
63 /* usage Info */
64 void usage ();
66 /* Add to the ldap dit */
67 void add_ldap_values (ldap_info * ldinfo);
69 /* Init an ldap connection */
70 void init_ldap_conn ();
72 /* Ldap error checking */
73 void ldap_result_check (char *msg, char *dn, int err);
75 /* Put a hostname into a char ** array */
76 char **hostname_to_dn_list (char *hostname, char *zone, unsigned int flags);
78 /* Find out how many items are in a char ** array */
79 int get_attr_list_size (char **tmp);
81 /* Get a DN */
82 char *build_dn_from_dc_list (char **dc_list, unsigned int ttl, int flag);
84 /* Add to RR list */
85 void add_to_rr_list (char *dn, char *name, char *type, char *data,
86 unsigned int ttl, unsigned int flags);
88 /* Error checking */
89 void isc_result_check (isc_result_t res, char *errorstr);
91 /* Generate LDIF Format files */
92 void generate_ldap (dns_name_t * dnsname, dns_rdata_t * rdata,
93 unsigned int ttl);
95 /* head pointer to the list */
96 ldap_info *ldap_info_base = NULL;
98 char *argzone, *ldapbase, *binddn, *bindpw = NULL;
99 char *ldapsystem = "localhost";
100 static char *objectClasses[] =
101 { "top", "dNSZone", NULL };
102 static char *topObjectClasses[] = { "top", NULL };
103 LDAP *conn;
104 unsigned int debug = 0;
106 #ifdef DEBUG
107 debug = 1;
108 #endif
111 main (int *argc, char **argv)
113 isc_mem_t *mctx = NULL;
114 isc_entropy_t *ectx = NULL;
115 isc_result_t result;
116 char *basedn;
117 ldap_info *tmp;
118 LDAPMod *base_attrs[2];
119 LDAPMod base;
120 isc_buffer_t buff;
121 char *zonefile;
122 char fullbasedn[1024];
123 char *ctmp;
124 dns_fixedname_t fixedzone, fixedname;
125 dns_rdataset_t rdataset;
126 char **dc_list;
127 dns_rdata_t rdata = DNS_RDATA_INIT;
128 dns_rdatasetiter_t *riter;
129 dns_name_t *zone, *name;
130 dns_db_t *db = NULL;
131 dns_dbiterator_t *dbit = NULL;
132 dns_dbnode_t *node;
133 extern char *optarg;
134 extern int optind, opterr, optopt;
135 int create_base = 0;
136 int topt;
138 if ((int) argc < 2)
140 usage ();
141 exit (-1);
144 while ((topt = getopt ((int) argc, argv, "D:w:b:z:f:h:?dcv")) != -1)
146 switch (topt)
148 case 'v':
149 printf("%s\n", VERSION);
150 exit(0);
151 case 'c':
152 create_base++;
153 break;
154 case 'd':
155 debug++;
156 break;
157 case 'D':
158 binddn = strdup (optarg);
159 break;
160 case 'w':
161 bindpw = strdup (optarg);
162 break;
163 case 'b':
164 ldapbase = strdup (optarg);
165 break;
166 case 'z':
167 argzone = strdup (optarg);
168 // We wipe argzone all to hell when we parse it for the DN */
169 gbl_zone = strdup(argzone);
170 break;
171 case 'f':
172 zonefile = strdup (optarg);
173 break;
174 case 'h':
175 ldapsystem = strdup (optarg);
176 break;
177 case '?':
178 default:
179 usage ();
180 exit (0);
184 if ((argzone == NULL) || (zonefile == NULL))
186 usage ();
187 exit (-1);
190 if (debug)
191 printf ("Initializing ISC Routines, parsing zone file\n");
193 result = isc_mem_create (0, 0, &mctx);
194 isc_result_check (result, "isc_mem_create");
196 result = isc_entropy_create(mctx, &ectx);
197 isc_result_check (result, "isc_entropy_create");
199 result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
200 isc_result_check (result, "isc_hash_create");
202 isc_buffer_init (&buff, argzone, strlen (argzone));
203 isc_buffer_add (&buff, strlen (argzone));
204 dns_fixedname_init (&fixedzone);
205 zone = dns_fixedname_name (&fixedzone);
206 result = dns_name_fromtext (zone, &buff, dns_rootname, 0, NULL);
207 isc_result_check (result, "dns_name_fromtext");
209 result = dns_db_create (mctx, "rbt", zone, dns_dbtype_zone,
210 dns_rdataclass_in, 0, NULL, &db);
211 isc_result_check (result, "dns_db_create");
213 result = dns_db_load (db, zonefile);
214 isc_result_check (result, "Check Zone Syntax: dns_db_load");
216 result = dns_db_createiterator (db, 0, &dbit);
217 isc_result_check (result, "dns_db_createiterator");
219 result = dns_dbiterator_first (dbit);
220 isc_result_check (result, "dns_dbiterator_first");
222 dns_fixedname_init (&fixedname);
223 name = dns_fixedname_name (&fixedname);
224 dns_rdataset_init (&rdataset);
225 dns_rdata_init (&rdata);
227 while (result == ISC_R_SUCCESS)
229 node = NULL;
230 result = dns_dbiterator_current (dbit, &node, name);
232 if (result == ISC_R_NOMORE)
233 break;
235 isc_result_check (result, "dns_dbiterator_current");
237 riter = NULL;
238 result = dns_db_allrdatasets (db, node, NULL, 0, &riter);
239 isc_result_check (result, "dns_db_allrdatasets");
241 result = dns_rdatasetiter_first (riter);
242 //isc_result_check(result, "dns_rdatasetiter_first");
244 while (result == ISC_R_SUCCESS)
246 dns_rdatasetiter_current (riter, &rdataset);
247 result = dns_rdataset_first (&rdataset);
248 isc_result_check (result, "dns_rdatasetiter_current");
250 while (result == ISC_R_SUCCESS)
252 dns_rdataset_current (&rdataset, &rdata);
253 generate_ldap (name, &rdata, rdataset.ttl);
254 dns_rdata_reset (&rdata);
255 result = dns_rdataset_next (&rdataset);
257 dns_rdataset_disassociate (&rdataset);
258 result = dns_rdatasetiter_next (riter);
261 dns_rdatasetiter_destroy (&riter);
262 result = dns_dbiterator_next (dbit);
266 /* Initialize the LDAP Connection */
267 if (debug)
268 printf ("Initializing LDAP Connection to %s as %s\n", ldapsystem, binddn);
270 init_ldap_conn ();
272 if (create_base)
274 if (debug)
275 printf ("Creating base zone DN %s\n", argzone);
277 dc_list = hostname_to_dn_list (argzone, argzone, DNS_TOP);
278 basedn = build_dn_from_dc_list (dc_list, 0, NO_SPEC);
280 for (ctmp = &basedn[strlen (basedn)]; ctmp >= &basedn[0]; ctmp--)
282 if ((*ctmp == ',') || (ctmp == &basedn[0]))
284 base.mod_op = LDAP_MOD_ADD;
285 base.mod_type = "objectClass";
286 base.mod_values = topObjectClasses;
287 base_attrs[0] = &base;
288 base_attrs[1] = NULL;
290 if (ldapbase)
292 if (ctmp != &basedn[0])
293 sprintf (fullbasedn, "%s,%s", ctmp + 1, ldapbase);
294 else
295 sprintf (fullbasedn, "%s,%s", ctmp, ldapbase);
298 else
300 if (ctmp != &basedn[0])
301 sprintf (fullbasedn, "%s", ctmp + 1);
302 else
303 sprintf (fullbasedn, "%s", ctmp);
305 result = ldap_add_s (conn, fullbasedn, base_attrs);
306 ldap_result_check ("intial ldap_add_s", fullbasedn, result);
311 else
313 if (debug)
314 printf ("Skipping zone base dn creation for %s\n", argzone);
317 for (tmp = ldap_info_base; tmp != NULL; tmp = tmp->next)
320 if (debug)
321 printf ("Adding DN: %s\n", tmp->dn);
323 add_ldap_values (tmp);
326 if (debug)
327 printf("Operation Complete.\n");
329 /* Cleanup */
330 isc_hash_destroy();
331 isc_entropy_detach(&ectx);
332 isc_mem_destroy(&mctx);
333 if (zonefile)
334 free(zonefile);
336 return 0;
340 /* Check the status of an isc_result_t after any isc routines.
341 * I should probably rename this function, as not to cause any
342 * confusion with the isc* routines. Will exit on error. */
343 void
344 isc_result_check (isc_result_t res, char *errorstr)
346 if (res != ISC_R_SUCCESS)
348 fprintf (stderr, " %s: %s\n", errorstr, isc_result_totext (res));
349 exit (-1);
354 /* Takes DNS information, in bind data structure format, and adds textual
355 * zone information to the LDAP run queue. */
356 void
357 generate_ldap (dns_name_t * dnsname, dns_rdata_t * rdata, unsigned int ttl)
359 unsigned char name[DNS_NAME_MAXTEXT + 1];
360 unsigned int len;
361 unsigned char type[20];
362 unsigned char data[2048];
363 char **dc_list;
364 char *dn;
366 isc_buffer_t buff;
367 isc_result_t result;
369 isc_buffer_init (&buff, name, sizeof (name));
370 result = dns_name_totext (dnsname, ISC_TRUE, &buff);
371 isc_result_check (result, "dns_name_totext");
372 name[isc_buffer_usedlength (&buff)] = 0;
374 isc_buffer_init (&buff, type, sizeof (type));
375 result = dns_rdatatype_totext (rdata->type, &buff);
376 isc_result_check (result, "dns_rdatatype_totext");
377 type[isc_buffer_usedlength (&buff)] = 0;
379 isc_buffer_init (&buff, data, sizeof (data));
380 result = dns_rdata_totext (rdata, NULL, &buff);
381 isc_result_check (result, "dns_rdata_totext");
382 data[isc_buffer_usedlength (&buff)] = 0;
384 dc_list = hostname_to_dn_list (name, argzone, DNS_OBJECT);
385 len = (get_attr_list_size (dc_list) - 2);
386 dn = build_dn_from_dc_list (dc_list, ttl, WI_SPEC);
388 if (debug)
389 printf ("Adding %s (%s %s) to run queue list.\n", dn, type, data);
391 add_to_rr_list (dn, dc_list[len], type, data, ttl, DNS_OBJECT);
395 /* Locate an item in the Run queue linked list, by DN. Used by functions
396 * which add items to the run queue.
398 ldap_info *
399 locate_by_dn (char *dn)
401 ldap_info *tmp;
402 for (tmp = ldap_info_base; tmp != (ldap_info *) NULL; tmp = tmp->next)
404 if (!strncmp (tmp->dn, dn, strlen (dn)))
405 return tmp;
407 return (ldap_info *) NULL;
412 /* Take textual zone data, and add to the LDAP Run queue. This works like so:
413 * If locate_by_dn does not return, alloc a new ldap_info structure, and then
414 * calloc a LDAPMod array, fill in the default "everyone needs this" information,
415 * including object classes and dc's. If it locate_by_dn does return, then we'll
416 * realloc for more LDAPMod structs, and appened the new data. If an LDAPMod exists
417 * for the parameter we're adding, then we'll realloc the mod_values array, and
418 * add the new value to the existing LDAPMod. Finnaly, it assures linkage exists
419 * within the Run queue linked ilst*/
421 void
422 add_to_rr_list (char *dn, char *name, char *type,
423 char *data, unsigned int ttl, unsigned int flags)
425 int i;
426 int x;
427 ldap_info *tmp;
428 int attrlist;
429 char ldap_type_buffer[128];
430 char charttl[64];
433 if ((tmp = locate_by_dn (dn)) == NULL)
436 /* There wasn't one already there, so we need to allocate a new one,
437 * and stick it on the list */
439 tmp = (ldap_info *) malloc (sizeof (ldap_info));
440 if (tmp == (ldap_info *) NULL)
442 fprintf (stderr, "malloc: %s\n", strerror (errno));
443 ldap_unbind_s (conn);
444 exit (-1);
447 tmp->dn = strdup (dn);
448 tmp->attrs = (LDAPMod **) calloc (sizeof (LDAPMod *), flags);
449 if (tmp->attrs == (LDAPMod **) NULL)
451 fprintf (stderr, "calloc: %s\n", strerror (errno));
452 ldap_unbind_s (conn);
453 exit (-1);
456 for (i = 0; i < flags; i++)
458 tmp->attrs[i] = (LDAPMod *) malloc (sizeof (LDAPMod));
459 if (tmp->attrs[i] == (LDAPMod *) NULL)
461 fprintf (stderr, "malloc: %s\n", strerror (errno));
462 exit (-1);
465 tmp->attrs[0]->mod_op = LDAP_MOD_ADD;
466 tmp->attrs[0]->mod_type = "objectClass";
468 if (flags == DNS_OBJECT)
469 tmp->attrs[0]->mod_values = objectClasses;
470 else
472 tmp->attrs[0]->mod_values = topObjectClasses;
473 tmp->attrs[1] = NULL;
474 tmp->attrcnt = 2;
475 tmp->next = ldap_info_base;
476 ldap_info_base = tmp;
477 return;
480 tmp->attrs[1]->mod_op = LDAP_MOD_ADD;
481 tmp->attrs[1]->mod_type = "relativeDomainName";
482 tmp->attrs[1]->mod_values = (char **) calloc (sizeof (char *), 2);
484 if (tmp->attrs[1]->mod_values == (char **)NULL)
485 exit(-1);
487 tmp->attrs[1]->mod_values[0] = strdup (name);
488 tmp->attrs[1]->mod_values[2] = NULL;
490 sprintf (ldap_type_buffer, "%sRecord", type);
492 tmp->attrs[2]->mod_op = LDAP_MOD_ADD;
493 tmp->attrs[2]->mod_type = strdup (ldap_type_buffer);
494 tmp->attrs[2]->mod_values = (char **) calloc (sizeof (char *), 2);
496 if (tmp->attrs[2]->mod_values == (char **)NULL)
497 exit(-1);
499 tmp->attrs[2]->mod_values[0] = strdup (data);
500 tmp->attrs[2]->mod_values[1] = NULL;
502 tmp->attrs[3]->mod_op = LDAP_MOD_ADD;
503 tmp->attrs[3]->mod_type = "dNSTTL";
504 tmp->attrs[3]->mod_values = (char **) calloc (sizeof (char *), 2);
506 if (tmp->attrs[3]->mod_values == (char **)NULL)
507 exit(-1);
509 sprintf (charttl, "%d", ttl);
510 tmp->attrs[3]->mod_values[0] = strdup (charttl);
511 tmp->attrs[3]->mod_values[1] = NULL;
513 tmp->attrs[4]->mod_op = LDAP_MOD_ADD;
514 tmp->attrs[4]->mod_type = "zoneName";
515 tmp->attrs[4]->mod_values = (char **)calloc(sizeof(char *), 2);
516 tmp->attrs[4]->mod_values[0] = gbl_zone;
517 tmp->attrs[4]->mod_values[1] = NULL;
519 tmp->attrs[5] = NULL;
520 tmp->attrcnt = flags;
521 tmp->next = ldap_info_base;
522 ldap_info_base = tmp;
524 else
527 for (i = 0; tmp->attrs[i] != NULL; i++)
529 sprintf (ldap_type_buffer, "%sRecord", type);
530 if (!strncmp
531 (ldap_type_buffer, tmp->attrs[i]->mod_type,
532 strlen (tmp->attrs[i]->mod_type)))
534 attrlist = get_attr_list_size (tmp->attrs[i]->mod_values);
535 tmp->attrs[i]->mod_values =
536 (char **) realloc (tmp->attrs[i]->mod_values,
537 sizeof (char *) * (attrlist + 1));
539 if (tmp->attrs[i]->mod_values == (char **) NULL)
541 fprintf (stderr, "realloc: %s\n", strerror (errno));
542 ldap_unbind_s (conn);
543 exit (-1);
545 for (x = 0; tmp->attrs[i]->mod_values[x] != NULL; x++);
547 tmp->attrs[i]->mod_values[x] = strdup (data);
548 tmp->attrs[i]->mod_values[x + 1] = NULL;
549 return;
552 tmp->attrs =
553 (LDAPMod **) realloc (tmp->attrs,
554 sizeof (LDAPMod) * ++(tmp->attrcnt));
555 if (tmp->attrs == NULL)
557 fprintf (stderr, "realloc: %s\n", strerror (errno));
558 ldap_unbind_s (conn);
559 exit (-1);
562 for (x = 0; tmp->attrs[x] != NULL; x++);
563 tmp->attrs[x] = (LDAPMod *) malloc (sizeof (LDAPMod));
564 tmp->attrs[x]->mod_op = LDAP_MOD_ADD;
565 tmp->attrs[x]->mod_type = strdup (ldap_type_buffer);
566 tmp->attrs[x]->mod_values = (char **) calloc (sizeof (char *), 2);
567 tmp->attrs[x]->mod_values[0] = strdup (data);
568 tmp->attrs[x]->mod_values[1] = NULL;
569 tmp->attrs[x + 1] = NULL;
573 /* Size of a mod_values list, plus the terminating NULL field. */
575 get_attr_list_size (char **tmp)
577 int i = 0;
578 char **ftmp = tmp;
579 while (*ftmp != NULL)
581 i++;
582 ftmp++;
584 return ++i;
588 /* take a hostname, and split it into a char ** of the dc parts,
589 * example, we have www.domain.com, this function will return:
590 * array[0] = com, array[1] = domain, array[2] = www. */
592 char **
593 hostname_to_dn_list (char *hostname, char *zone, unsigned int flags)
595 char *tmp;
596 static char *dn_buffer[64];
597 int i = 0;
598 char *zname;
599 char *hnamebuff;
601 zname = strdup (hostname);
603 if (flags == DNS_OBJECT)
606 if (strlen (zname) != strlen (zone))
608 tmp = &zname[strlen (zname) - strlen (zone)];
609 *--tmp = '\0';
610 hnamebuff = strdup (zname);
611 zname = ++tmp;
613 else
614 hnamebuff = "@";
616 else
618 zname = zone;
619 hnamebuff = NULL;
622 for (tmp = strrchr (zname, '.'); tmp != (char *) 0;
623 tmp = strrchr (zname, '.'))
625 *tmp++ = '\0';
626 dn_buffer[i++] = tmp;
628 dn_buffer[i++] = zname;
629 dn_buffer[i++] = hnamebuff;
630 dn_buffer[i] = NULL;
632 return dn_buffer;
636 /* build an sdb compatible LDAP DN from a "dc_list" (char **).
637 * will append dNSTTL information to each RR Record, with the
638 * exception of "@"/SOA. */
640 char *
641 build_dn_from_dc_list (char **dc_list, unsigned int ttl, int flag)
643 int size;
644 int x;
645 static char dn[1024];
646 char tmp[128];
648 bzero (tmp, sizeof (tmp));
649 bzero (dn, sizeof (dn));
650 size = get_attr_list_size (dc_list);
651 for (x = size - 2; x > 0; x--)
653 if (flag == WI_SPEC)
655 if (x == (size - 2) && (strncmp (dc_list[x], "@", 1) == 0) && (ttl))
656 sprintf (tmp, "relativeDomainName=%s + dNSTTL=%d,", dc_list[x], ttl);
657 else if (x == (size - 2))
658 sprintf(tmp, "relativeDomainName=%s,",dc_list[x]);
659 else
660 sprintf(tmp,"dc=%s,", dc_list[x]);
662 else
664 sprintf(tmp, "dc=%s,", dc_list[x]);
668 strncat (dn, tmp, sizeof (dn) - strlen (dn));
671 sprintf (tmp, "dc=%s", dc_list[0]);
672 strncat (dn, tmp, sizeof (dn) - strlen (dn));
674 fflush(NULL);
675 return dn;
679 /* Initialize LDAP Conn */
680 void
681 init_ldap_conn ()
683 int result;
684 conn = ldap_open (ldapsystem, LDAP_PORT);
685 if (conn == NULL)
687 fprintf (stderr, "Error opening Ldap connection: %s\n",
688 strerror (errno));
689 exit (-1);
692 result = ldap_simple_bind_s (conn, binddn, bindpw);
693 ldap_result_check ("ldap_simple_bind_s", "LDAP Bind", result);
696 /* Like isc_result_check, only for LDAP */
697 void
698 ldap_result_check (char *msg, char *dn, int err)
700 if ((err != LDAP_SUCCESS) && (err != LDAP_ALREADY_EXISTS))
702 fprintf(stderr, "Error while adding %s (%s):\n",
703 dn, msg);
704 ldap_perror (conn, dn);
705 ldap_unbind_s (conn);
706 exit (-1);
712 /* For running the ldap_info run queue. */
713 void
714 add_ldap_values (ldap_info * ldinfo)
716 int result;
717 char dnbuffer[1024];
720 if (ldapbase != NULL)
721 sprintf (dnbuffer, "%s,%s", ldinfo->dn, ldapbase);
722 else
723 sprintf (dnbuffer, "%s", ldinfo->dn);
725 result = ldap_add_s (conn, dnbuffer, ldinfo->attrs);
726 ldap_result_check ("ldap_add_s", dnbuffer, result);
732 /* name says it all */
733 void
734 usage ()
736 fprintf (stderr,
737 "zone2ldap -D [BIND DN] -w [BIND PASSWORD] -b [BASE DN] -z [ZONE] -f [ZONE FILE] -h [LDAP HOST]
738 [-c Create LDAP Base structure][-d Debug Output (lots !)] \n ");}