1 /* $NetBSD: zone2ldap.c,v 1.4 2014/12/10 04:37:57 christos Exp $ */
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.
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
24 #include <isc/buffer.h>
25 #include <isc/entropy.h>
28 #include <isc/print.h>
29 #include <isc/result.h>
32 #include <dns/dbiterator.h>
33 #include <dns/fixedname.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>
46 #define VERSION "0.4-ALPHA"
51 /* Global Zone Pointer */
52 char *gbl_zone
= NULL
;
54 typedef struct LDAP_INFO
58 struct LDAP_INFO
*next
;
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
);
82 char *build_dn_from_dc_list (char **dc_list
, unsigned int ttl
, int flag
);
85 void add_to_rr_list (char *dn
, char *name
, char *type
, char *data
,
86 unsigned int ttl
, unsigned int flags
);
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
,
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
};
104 unsigned int debug
= 0;
111 main (int *argc
, char **argv
)
113 isc_mem_t
*mctx
= NULL
;
114 isc_entropy_t
*ectx
= NULL
;
118 LDAPMod
*base_attrs
[2];
122 char fullbasedn
[1024];
124 dns_fixedname_t fixedzone
, fixedname
;
125 dns_rdataset_t rdataset
;
127 dns_rdata_t rdata
= DNS_RDATA_INIT
;
128 dns_rdatasetiter_t
*riter
;
129 dns_name_t
*zone
, *name
;
131 dns_dbiterator_t
*dbit
= NULL
;
134 extern int optind
, opterr
, optopt
;
144 while ((topt
= getopt ((int) argc
, argv
, "D:w:b:z:f:h:?dcv")) != -1)
149 printf("%s\n", VERSION
);
158 binddn
= strdup (optarg
);
161 bindpw
= strdup (optarg
);
164 ldapbase
= strdup (optarg
);
167 argzone
= strdup (optarg
);
168 // We wipe argzone all to hell when we parse it for the DN */
169 gbl_zone
= strdup(argzone
);
172 zonefile
= strdup (optarg
);
175 ldapsystem
= strdup (optarg
);
184 if ((argzone
== NULL
) || (zonefile
== NULL
))
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
)
230 result
= dns_dbiterator_current (dbit
, &node
, name
);
232 if (result
== ISC_R_NOMORE
)
235 isc_result_check (result
, "dns_dbiterator_current");
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 */
268 printf ("Initializing LDAP Connection to %s as %s\n", ldapsystem
, binddn
);
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
;
292 if (ctmp
!= &basedn
[0])
293 sprintf (fullbasedn
, "%s,%s", ctmp
+ 1, ldapbase
);
295 sprintf (fullbasedn
, "%s,%s", ctmp
, ldapbase
);
300 if (ctmp
!= &basedn
[0])
301 sprintf (fullbasedn
, "%s", ctmp
+ 1);
303 sprintf (fullbasedn
, "%s", ctmp
);
305 result
= ldap_add_s (conn
, fullbasedn
, base_attrs
);
306 ldap_result_check ("intial ldap_add_s", fullbasedn
, result
);
314 printf ("Skipping zone base dn creation for %s\n", argzone
);
317 for (tmp
= ldap_info_base
; tmp
!= NULL
; tmp
= tmp
->next
)
321 printf ("Adding DN: %s\n", tmp
->dn
);
323 add_ldap_values (tmp
);
327 printf("Operation Complete.\n");
331 isc_entropy_detach(&ectx
);
332 isc_mem_destroy(&mctx
);
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. */
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
));
354 /* Takes DNS information, in bind data structure format, and adds textual
355 * zone information to the LDAP run queue. */
357 generate_ldap (dns_name_t
* dnsname
, dns_rdata_t
* rdata
, unsigned int ttl
)
359 unsigned char name
[DNS_NAME_MAXTEXT
+ 1];
361 unsigned char type
[20];
362 unsigned char data
[2048];
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
);
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.
399 locate_by_dn (char *dn
)
402 for (tmp
= ldap_info_base
; tmp
!= (ldap_info
*) NULL
; tmp
= tmp
->next
)
404 if (!strncmp (tmp
->dn
, dn
, strlen (dn
)))
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*/
422 add_to_rr_list (char *dn
, char *name
, char *type
,
423 char *data
, unsigned int ttl
, unsigned int flags
)
429 char ldap_type_buffer
[128];
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
);
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
);
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
));
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
;
472 tmp
->attrs
[0]->mod_values
= topObjectClasses
;
473 tmp
->attrs
[1] = NULL
;
475 tmp
->next
= ldap_info_base
;
476 ldap_info_base
= tmp
;
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
)
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
)
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
)
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
;
527 for (i
= 0; tmp
->attrs
[i
] != NULL
; i
++)
529 sprintf (ldap_type_buffer
, "%sRecord", type
);
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
);
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
;
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
);
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
)
579 while (*ftmp
!= NULL
)
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. */
593 hostname_to_dn_list (char *hostname
, char *zone
, unsigned int flags
)
596 static char *dn_buffer
[64];
601 zname
= strdup (hostname
);
603 if (flags
== DNS_OBJECT
)
606 if (strlen (zname
) != strlen (zone
))
608 tmp
= &zname
[strlen (zname
) - strlen (zone
)];
610 hnamebuff
= strdup (zname
);
622 for (tmp
= strrchr (zname
, '.'); tmp
!= (char *) 0;
623 tmp
= strrchr (zname
, '.'))
626 dn_buffer
[i
++] = tmp
;
628 dn_buffer
[i
++] = zname
;
629 dn_buffer
[i
++] = hnamebuff
;
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. */
641 build_dn_from_dc_list (char **dc_list
, unsigned int ttl
, int flag
)
645 static char dn
[1024];
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
--)
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
]);
660 sprintf(tmp
,"dc=%s,", dc_list
[x
]);
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
));
679 /* Initialize LDAP Conn */
684 conn
= ldap_open (ldapsystem
, LDAP_PORT
);
687 fprintf (stderr
, "Error opening Ldap connection: %s\n",
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 */
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",
704 ldap_perror (conn
, dn
);
705 ldap_unbind_s (conn
);
712 /* For running the ldap_info run queue. */
714 add_ldap_values (ldap_info
* ldinfo
)
720 if (ldapbase
!= NULL
)
721 sprintf (dnbuffer
, "%s,%s", ldinfo
->dn
, ldapbase
);
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 */
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 ");}