12014-04-30: 2 Most of the Q&A in this FAQ is dated around 2004. Most of the 3 content is still quite valid. With the exception(s) regarding *BSD, 4 and possibly Openldap. As things have changed, and version(s) are 5 newer. This is especially true where *BSD is concerned, as they 6 were all pure conjecture, anyway. :) 7 8note: this really is a FAQ. people asked me these questions at one point 9or another. i have found that most people could find the answer easily 10enough if they simply knew what question to ask. 11 12however, for convenience's sake (and my gigantic maildir) you may also 13find answers that i have given. 14 15------------------------------------------------------------------------------ 16------------------------------------------------------------------------------ 17 18preinstallation: 19 20Q: these version numbers are confusing! what do they mean? 21A: they shouldn't be anymore. To ease package maintainers jobs' I've 22 switched to a more conventional scheme. I had to change my 23 build-scripts to handle these changes, but that wasn't such a big 24 deal. 25 26 2.01 means simply that we're using LDAPDNS2, serial number 1. 27 28 if you're new to ldapdns, we've actually had 37 releases between 29 2.00 and 2.01. 30 31 32Q: what does ldapdns require? 33A: two pieces of software: pthreads library, and the openldap library. 34 build/install these first before using ldapdns. you'll probably want 35 a decent ldap browser like GQ (search freshmeat for it). 36 37 to run the admin scripts, you'll need perl, the Net::LDAP module, 38 and probably Net::LDAPS and Crypt::SSLeay. 39 40 beyond software? a good understanding of dns ldap schemas is nice, 41 but not completely required. a decent understanding of ldap is also 42 good, but (apparently) not completely required. 43 44Q: what platforms will ldapdns run on? 45A: ldapdns will run on any system with a semi-decent C library, and 46 even less-than-decent POSIX threads (pthreads) support. finally, 47 (and mostly obvious), ldapdns requires LDAP client library, and an 48 LDAP server. 49 50 version 2 has a very small test-base. let me know what platforms it 51 works on and i'll add them here. 52 53Q: how do I build it? 54A: read INSTALL. it contains all the build instructions you will need. 55 56Q: i'm getting a bunch of undefined references! what gives! 57A: you probably don't have openldap installed. install it (rpm is fine) 58A2:make sure you're using openldap 2. openldap 1 doesn't have 59 server-side schema support, and it's API is somewhat deficient. 60 61Q: it just won't compile! i have openldap installed. 62A: let me see the error. i may know what's going on and just not have 63 written it down into this faq... 64 65Q: what's this merge/ directory for? 66A: you unpacked ldapdns 2 into your ldapdns 1 source folder. dumbass. 67 delete the old tree and/or unpack elsewhere. 68 69Q: i'm getting a lot of undefined symbols for `_pthread_.*' 70A: make sure you set -I/-L properly in your Makefile 71A2:OpenBSD will find pthreads in -lc_r NOT -lpthread 72A3:Actually. You can solve this for lots of programs in the future with: 73 ln -s /usr/lib/libc_r.a /usr/lib/libpthread.a 74A4:The configure script should detect this for you. Please send the 75mailing list details about your system so that future versions of 76ldapdns will know about you. 77 78Q: i'm getting warnings when i compile, what does that mean? 79A: it means there's a bug. there shouldn't be _ANY_ warnings. if there 80 are, i'm not doing my job right... 81 82Q: is ldapdns secure? 83A: signs point to yes. 84A2:ldapdns has a very good security history. the biggest failure has 85 been a potential crash due to misconfiguration. i'm fairly sure 86 there simply aren't any places where a remote user can trigger a 87 buffer overflow, or a stack smash. 88 89 ldapdns doesn't run very long as root, and doesn't answer any 90 queries while it is root, so remote users can't gain root. 91 92 ldapdns chroots itself so even if a problem is discovered, remote 93 users can't manipulate any files. 94 95 the biggest risk to using ldapdns is ldap. you've got an ldap server 96 and a machine that can query it, or at least parts of it. don't give 97 ldapdns any more access than it absolutely needs to query your 98 directory, and you'll probably be fine. 99 100------------------------------------------------------------------------------ 101------------------------------------------------------------------------------ 102 103postinstallation: 104 105Q: how do i use it? 106A: similarly to tinydns. quickstart (using daemontools): 107 ldapdns-conf named nobody /var/ldapdns 172.16.0.2 192.168.0.15 \ 108 'cn=root,o=myorg' 'dc=dns,o=myorg' 109 [ assumes this will be a nameserver listening to 172.16.0.2 110 and talking to an ldap server on 192.168.0.15 ] 111 112 then put your password into /var/ldapdns/root/password 113 and finally: 114 ln -s /var/ldapdns /service/ldapdns 115 116 and svscan should notice the new directory and start it. check the 117 log to see if anything went wrong (it probably won't) 118A2:take a look at INSTALL 119 120Q: can i use kerberos with ldapdns? 121A: yes! you probably want to know how. 122 after initially configuring it (see previous question), do the 123 following: 124 125 rm -f $ROOT/env/LDAP_BINDDN 126 rm -f $ROOT/env/ROOT 127 rm -f $ROOT/root/password 128 129 then create: 130 131 echo 'xxx' > $ROOT/env/LDAP_SASL 132 133 replacing xxx with whatever your kerberos identity is. 134 ldapdns will try LDAP_AUTH_KRBV42 first (authentication against 135 DSA), then LDAP_AUTH_KRB41 (authentication directly against the ldap 136 server) 137 138Q: none of the admin scripts seem to work! 139A: you'll need perl to run them. you'll also need Net::LDAP , and 140 probably also Net::LDAPS + Crypt::SSLeay 141 142Q: i think ldapdns has a memory leak! it keeps growing! 143A: the openldap client libraries seem to "cache" attributes, and on a 144 heavy nameserver it may seem to grow for a while. make sure 145 softlimit is correct, and that you have a backup nameserver. one 146 day, i may write a more low-memory ldap client lib to fix this... 147 [ or i may find a bug in my code... or YOU might. it's possible; 148 especially since i refuse to look at code before 2am... ] 149 150 if it's a real bug. let me know, and i'll try to track it down. if 151 you can code, more power! let's squash it together! 152 153Q: how do i make ldapdns resolve domains not in the directory? 154A: you don't. and you shouldn't either. DNS is "supposed" to be a 155 unified space; however, if you're using a proper dns cache (like 156 djb's dnscache), you CAN load the "root" nameservers into ldapdns. 157 use: 158 $ROOT/transfer_zone dns.vrx.net . 159 then tell dnscache to use ldapdns as the only "root" server (in the 160 @ file). 161 [note: you will have to set up the admin tools first; see 162 README.admin] 163 164 there aren't a lot of good reasons to do this. if you come up with 165 one, let me know... 166 167Q: how do I get "generic" records to work? 168A: use the "photo" objectClass, and write your data directly into it. 169 note that you'll (probably) need to write a program to do this. 170A2:use the administrative tools: $ROOT/add_generic_record and 171 $ROOT/set_generic_record -- they both take a format string. see 172 README.generic-rr for details. 173 174Q: how do I create LOC records? 175A: you have to use "generic" records for now... if there's enough 176 demand, i'll add a parser for it. even if there isn't enough demand, 177 YOU can add it. just send patches. 178 179Q: how do I delagate PTR records? 180A: short answer: you can't. 181A2:long answer, if you point cNAMERecord inside the in-addr.arpa space 182 from inside the in-addr.arpa space you'll get a real CNAME. note 183 that this only works ONCE (RFC2317) so it probably won't do 184 everything you want. some clients will (erroniously) work better if 185 you use an nSRecord in there. 186A3:you can create users and allow ldap users to modify that part of your 187 directory. 188A4:seeAlso is encoded as a DN (as that's what the schema for seeAlso 189 requires) this attribute emits real PTR. 190A5:use regular ldap referrals. ldapdns understand them, and works fine 191 with them. this is best because you can get other people to use 192 ldapdns too :) 193 194Q: how do I listen for NOTIFY requests? 195A: set $HELPER_NOTIFY to your notify-helper program :) 196A2:I haven't written one yet... you could theoretically use 197 transfer_zone, although you might want to make sure the zone exists, 198 and that your source (the machine sending the notify request) is 199 allowed. The remote address is put in the environment variable 200 $REMOTE_ADDR. i don't think using transfer_zone would be safe. 201 202Q: i like to set the hostmaster address depending on the zone as I do a 203 lot of delagation. how can I do this with ldapdns? 204A: i would prefer that you setup seperate instances of ldapdns, but 205 that's not always possible. use the "mail" attribute in your 206 directory on an object that also has an nSRecord. It's simply an 207 email address; the last one listed will be used as the hostmaster 208 address. 209A2:when I said it was an email address, i mean you put: 210 hostmaster@nimh.org. not that stupid bind thing of 211 hostmaster.nimh.org. 212 213Q: sometimes ldapdns crashes after serving queries, what's going on? 214A: this appears to be a bug in the openldap libraries. it seems to be 215 getting better; all data comming into ldapdns is checked, so 216 whatever openldap is doing, it's doing it on it's own. normal 217 ldapdns operation should keep it running (by restarting it). I don't 218 know how other openldap clients work around this. 219 220Q: sometimes ldapdns hangs after serving queries, what's going on? 221A: again, i need to attribute this to openldap; all loops in ldapdns 222 are finite, so ldapdns should never hang. it might hang due to bugs 223 in the C library, or blocking errors, but at this point i'm betting 224 my chips on openldap. the only calls that openldap should block on 225 are: 226 227 ldap_result 228 229 using timeval, so max block time should be ~500usec 230 231 ldap_simple_bind_s 232 233 nameserver hasn't started yet normally, unless openldap hung up on 234 ldapdns - in which case a connection isn't possible yet. the log 235 will contain: ``handler XX was hung up on, restarting'' if this 236 happens. 237A2:there is a legitimate bug in many operating systems. if the operating 238 system is not reentrant, you will have better luck using 1:1 mode 239 (HANDLERS=1) if you are using an SMP system, your operating system 240 isn't using it any. trade it in on a nice 486 :) 241 242 openbsd and freebsd _both_ have problems using the fast threading 243 system. solaris does not, and oddly enough, LINUX does not- despite 244 all the hype about linux having such poor support for threads, 245 etc... 246 247Q: what does the following error mean? 248ldapdns: getattr.c:99: ldap_next_attribute: Assertion `entry != ((void *)0)' failed. 249Q: what does the following error mean? 250ldapdns: error.c:221: ldap_parse_result: Assertion `r != ((void *)0)' failed. 251A: it means there's a bug in openlap (imagine that)! try upgrading to a 252 newer version 253 254------------------------------------------------------------------------------ 255------------------------------------------------------------------------------ 256 257tweaking/tuning: 258 259 260Q: i have lots of A records and I want to load balance with them. 261A: well, DNS is the poorest place to put that, IMHO, but if you define 262 multiple aRecords, and: 263 264 echo random > env/SCHEDULE_ARECORD 265 266 you'll be set. 267 268Q: ldapdns appears to parse the ldap data each time the query occurs. 269 is there a way to speed this up? 270A: i've been using ldapdns for quite a while, and i haven't noticed any 271 speed problems. adding caching to this would probably slow things 272 down some, (because we have to expire the cache), and definately add 273 so much complexity that bugs would crop up. 274A2:enable the feature ACCELERATE_CACHE 275 but do so at your own risk: OpenLDAP presently has bugs in this 276 code. 277 278 this enables the OpenLDAP client-side cache into ldapdns thus 279 increasing speed. this can help GREATLY if your ldap server is 280 blocking. (buying faster hardware is probably better) 281 282 this value is measured in seconds, the default (60*5) is five 283 minutes. 284 285 under NO CIRCUMSTANCES should you set this above DEFAULT_RETRY (900, 286 or 15 minutes). you will force ldapdns to violate the DNS protocol 287 by doing this... 288 289 echo 900 > $ROOT/env/ACCELERATE_CACHE 290 291Q: how can i provide access control for ldapdns? 292A: you don't. use a dnscache in a method described by the previous 293 answer. 294 295Q: how do I provide a distributed directory to make sure things stay 296 running? 297A: here's the way I did it: 298 299 LDAPM (192.168.1.20) - master openldap server 300 LDAP1 (192.168.1.25) - slave openldap server 301 LDAP2 (192.168.1.26) - slave openldap server 302 DNS1 (192.168.1.40) - ldapdns 303 DNS2 (192.168.1.41) - ldapdns 304 305 then after ldapdns installation is complete, you go into 306 /service/ldapdns/env and delete the file: LDAP_HOST and create a new 307 file called LDAP_HOSTS which 308 309 has: 310 192.168.1.25,192.168.1.26,192.168.1.20 311 in it. this will cause ldapdns to try each one. 312 313 since ldapdns will die if an ldap query fails, daemontools will 314 restart ldapdns to try another host. 315 316 try to set a different order on each machine (if possible) as it 317 will speed recovery somewhat. 318 319Q: BIND has an option that XXX... how do I do this in ldapdns? 320A: chances are, you don't. however, in conjunction with other tools 321 (including tools distributed with djbdns), it SHOULD be possible to 322 do everything BIND does except crash [eratically]. 323 324Q: i'm used to using relative names and origins. how can I do this with 325 ldapdns? 326A: well, ordinarily you can't. fortunately another programmer saw this 327 to be necessary for him (<jordan@mjh.teddy-net.com>) and added 328 support for it. if you type: 329 330 echo 1 > $ROOT/env/RELATIVE_NAMES 331 332 the feature is now enabled. restart ldapdns. please remember that if 333 you're going to use some admin scripts the rely on this, make sure 334 to keep the environment variable RELATIVE_NAMES actually IN the 335 environment. 336 337 I do not recommend that you use this feature, as it makes your 338 directory confusing. It may be useful if you are handling the 339 directory by hand. 340 341Q: are there any general purpose speed improvements you can recommend? 342A: use dnscache as a front-line resolver. this is not appropriate for 343 all users of ldapdns, but should be suitable for a small number of 344 zones. 345A2:put slapd in replication mode on the same machine as ldapdns. this 346 will speed requests. 347A3:balance your requests by setting up multiple ldapdns's. use pickdns 348 to help load balance further. 349A4:enable the feature ACCELERATE_CACHE 350 this builds the OpenLDAP client-side cache into ldapdns thus 351 increasing speed. this can help GREATLY if your ldap server is 352 blocking. (OpenLDAP blocks horribly) this is measured in seconds, 353 the default (60*5) is five minutes. this is a recommended value for 354 most cases. 355 356 under NO CIRCUMSTANCES should you set this above DEFAULT_RETRY (900, 357 or 15 minutes). you will force ldapdns to violate the DNS spec by 358 doing this... 359 360 echo 900 > $ROOT/env/CACHE 361 362 just so you know. thie OpenLDAP client-side cache is broken at the 363 time of this writing. don't use it. 364 365Q: what's an optimal value for $HANDLERS ? 366A: the default :) 367A2:you want the value to be just a little bit greater than your AVERAGE 368 DNS REQUESTS PER UNIQUE LDAP CYCLE. this means that if you can yank 369 100 ldap records per second, and are receiving around 500 dns 370 requests per second, you'll want: 500/100 or 5 handlers. 8 should be 371 fine. however, if your ldap server is heavily loaded, you may only 372 be able to fit 50 records per second. 500/50 or 10 handlers. 12 373 should be fine. 374A3:i've found the above formula to also be a crock of shit when dealing 375 with OpenLDAP. Whatever number you get, multiply by ten, because 376 OpenLDAP likes to block at strange moments. 377A4:this number is SHARED, so if you say 128, then you really only have 378 128, not 1024 (with 8 threads). 379A5:HANDLERS=1 is good for broken threading libraries with non-reentrant 380 kernels. it does NOT seem to be necessary with LINUX or SOLARIS. if 381 you set HANDLERS=1, then ldapdns uses your THREADS count to set up 382 1:1: mode. 383 384Q: what's an optimal value for $THREADS ? 385A: usually, DOUBLE the number of cpu's is good. 386A2:this is extremely dependent on the schedular that your operating 387 system uses. 388A3:you can tune this: $LDAP_THREADS and $DNS_THREADS are seperate entities. 389A4:if using $HANDLERS=1 then set this number high. 100-200 seem good. 390 391------------------------------------------------------------------------------ 392------------------------------------------------------------------------------ 393 394migration: 395 396Q: how do i convert from using BIND/DJBDNS/Win2K/etc? 397A: at the moment? perform a zone transfer. see README.admin for details 398 of how to use the admin scripts. note see below for 399 behavior-modifying options to ldapdns. 400 401Q: How do I use ldapdns as a drop-in replacement for BIND+LDAP? 402A: very carefully. There are several BIND+LDAP patches; one set follows 403 RFC1279 which should work if: 404 405 echo 1 > $ROOT/env/RFC1279 406 407Q: How do I use ldapdns with Active Directory? 408A: very carefully. First you must enable MSDNS mode. this is presently 409 done by simply setting the LDAP suffix to: 410 411 CN=MicrosoftDNS,CN=System,DC=windowsdomain,DC=... 412 413[e.g. mydomain.local is: CN=MicrosoftDNS,CN=System,DC=mydomain,DC=local] 414 415 ldapdns will now attempt to search for dnsRecords that are encoded 416 in the manner that Active Directory uses. 417 418 [note that ldapdns will NOT SEARCH PROPERLY unless you're setting 419 your ldap_suffix properly. you CAN force it to use AD encoded 420 entries if you've mirrored your trees elsewhere by: 421 422 echo msdns > $ROOT/env/DNSRECORD 423 424 but please avoid doing this as Microsoft DNS records search slowly.] 425 426 ldapdns does not understand all RR's that MSDNS does. It should be 427 sufficient for gatewaying certain Win2K services (like IIS) to the 428 outside world, yet still provide the ease/management that Active 429 Directory can provide. 430 431 All my understanding of Active Directory was obtained through 432 reverse-engineering of the directory by examining the LDAP tree 433 directly. I can guarantee I am not supporting all features. I can 434 not guarantee that I am supporting _any_ of the features. Send 435 patches for additional queries that you find I'm performing 436 incorrectly. 437 438 big warning here: until I can handle SRV requests properly, you 439 cannot use ldapdns as a stand-in for Microsoft DNS. this is because 440 Microsoft REQUIRES the use of SRV records to locate the directory, 441 locate the keyservers, and to locate that big hole you have in your 442 head. 443 444 however, if you are MIGRATING from a MS-DNS platform, this option 445 MAY be of some use to you. on the other hand, if you are migrating, 446 zone transfers may be a better option... you have been warned. 447 448Q: i use bind. i provide name-services for my customers so that they 449 can have a NS1.EXAMPLE.COM and a NS2.EXAMPLE.COM of their own in the 450 whois records. how do i do this with ldapdns? 451A: set up multiple ldapdns instances- each on a seperate IP. 452A2:set up multiple ldapdns servers. just like bind :) 453 454Q: how do I setup ldapdns to be a secondary for a BIND-based machine? 455A: this is one of the most common ldapdns questions. i highly recommend 456 that you don't do this (nor the other way around). running two dns 457 databases is a bad idea, but transfer_zone and ldapaxfr can help you 458 do this... 459A2:the admin tool secondary_zone was built for this purpose. run it as: 460 secondary_zone ns zone ... periodically to keep the directory up to 461 date with your bind files. 462 - <jordan@mjh.teddy-net.com> 463 464Q: i used djbdns, and i really like the ability to send information 465 based on what address the client is comming from. how do i do this 466 in ldapdns? 467A: you couldn't until very recently: first you need to create a: 468 $ROOT/root/switch 469 the format is simple: 470 nym=subnet 471 nym=subnet 472 then, in your directory, set up multiple aRecords that end with 473 %nym; 474 to perform djb's example you'll have: 475 in=192.168.0.0/16 476 ex=0/0 477 and then records: 478 dc=juniper, dc=heaven, dc=af, dc=mil 479 aRecord=192.168.1.2%in 480 aRecord=1.2.3.4%ex 481 this feature is experimental. i have no use for it, but other people 482 seem to like it. so if you used this feature, you too might like it. 483A2:You can also create aRecords like this: 484 192.168.0.0/16=192.168.1.2 485 0/0=1.2.3.4 486 but note that this method depends on the order in which things come 487 back from the LDAP directory. Unless you have control of this, 488 you'll probably want to use the former method. 489 490------------------------------------------------------------------------------ 491------------------------------------------------------------------------------ 492 493bugs and problems: 494 495Q: i keep getting ber_dump: related things in my log. 496A: you enabled ACCELERATE_CACHE thinking it would be a good idea to use 497 overly complicated and experimental code on a production nameserver, 498 didn't you? :) 499 500 don't do that. ACCELERATE_CACHE is presently BROKEN in OpenLDAP 501 (2.0.11) this could change at any time. post the bug to the OpenLDAP 502 mailing lists; it isn't my fault. 503 504Q: there's a long delay before "starting ldapdns" is displayed. how do 505 i fix this? 506A: don't use names in defining your LDAP servers. ldapdns chroots into 507 it's directory so it cannot access your resolver files or your 508 static host map. 509A2:freebsd appears to have some weird resolver problems: 510 mkdir $ROOT/root/etc 511 cp /etc/hosts /etc/resolv.conf $ROOT/root/etc/. 512 echo hosts > $ROOT/root/etc/host.conf 513 yet another braindead thing freebsd does... 514 (should not probe 127.0.0.1 if no resolver is found) 515 (thanks to mg@bindone.de for helping me work this out) 516A3:ldapdns 2 should solve this issue (by bringing up ldap connections in a 517 different order). 518 519Q: it built fine on solaris, but it doesn't run! 520A2:solaris requires some device nodes. you need to: 521 mkdir $ROOT/root/dev 522 cp -p /devices/pseudo/clone@0:ip $ROOT/root/dev/ip 523 cp -p /devices/pseudo/clone@0:tcp $ROOT/root/dev/tcp 524 525Q: what does this mean? 526 ldapdns fatal: handler 91 has waited too long 527A: it means there's a bug in openlap (imagine that)! try upgrading to a 528 newer version 529A2:you can try and increase the number of threads/handlers so that it 530 won't affect DNS operation. 531A3:try disabling the client side cache if you have it enabled. I've 532 noticed some potentially infinite loops there... 533 534------------------------------------------------------------------------------ 535------------------------------------------------------------------------------ 536 537other questions: 538 539Q: how much of ldapdns is dependant on djbdns? 540A: none. not any more. djbdns is very quick so long as the 541 blocking-factor is the udp network. however with ldapdns, the 542 blocking factor is LDAP. 543 544Q: ldap2dns allows djbdns to use ldap. why do we need another gateway? 545A: because ldap2dns (despite the propaganda) is not an ldap to dns 546 gateway. it's a perl script that downloads records out of an ldap 547 directory and into a normal tinydns data file. i wanted something 548 that could speak directly. 549 550Q: why don't you support the ldap2dns schema format? 551A: because it's extremely slow, and doesn't appear to be well thought 552 out. it's fairly easy to reconstruct valid entries from the LDAP 553 tree that ldap2dns uses, but it is not easy to contort a valid DNS 554 query into one of these messages. storing the record type as part of 555 the DN is a bad idea. 556 557Q: bind can already read from an ldap directory? why not use that? 558A: honestly. do you really think i would be caught dead running ISC 559 software? 560A2:bind is slow, by-design bug prone, and it's methods in the directory 561 are quite silly. 562A3:some BIND people find this humerous. I will digress: BIND has got to 563 be the worst nameserver implementation ever. It is certainly the 564 first, and most certainly the most rhobust (all around), and for 565 that I am fortunate, for I have learned from many of the mistakes 566 BIND has (is, does) made. 567A4:BIND leaks memory even worse than the OpenLDAP client libs. 568A5:Okay, this one is for real: BIND's LDAP support is still very buggy, 569 and crashed on me several times when first trying it out. Perhaps 570 it's better now. Probably not. The BIND core isn't well suited for 571 anything except pulling records from memory. This is because BIND 572 uses the same blocks for caching DNS records as it uses for storing 573 the real authoritative records. This is probably the reason DNS 574 poisoning worked so well. Anyway, BIND isn't multithreaded, so no 575 matter which hacks you're using, BIND will either block when a query 576 is received, or it will suck up memory like mad. Your choice. 577 578Q: windows 2000 with active directory and three-dee-action stores DNS 579 records in active directory (ldap server), why not just use that? 580A: because nameservers should never be rebooted! 581A2:win2k requires lots of licensing. ldapdns is free (cost-wise). 582A3:win2k requires lots of licensing. ldapdns is free (freedom-wise). 583A4:win2k has many security-related problems. try a good *nix and 584 ldapdns. 585 586Q: will active directory/BIND+LDAP support improve over time? 587A: possibly. only you can answer that question by using it. tell me 588 what you need, write patches, run probes, and etc. I don't use 589 Microsoft anything, nor do I use BIND, so I can't help you a whole 590 lot. 591 592 the only reason I was able to do ANY active directory code is that a 593 client used MSDNS and I decided to take some snaps of parts of the 594 directory for perusal. 595 596Q: what do i do if my question isn't answered here? 597A: ask me! see http://www.nimh.org/ for directions on reaching my 598 contact page. 599