]> the.earth.li Git - autodns.git/commitdiff
cscvs to tla changeset 1
authorJonathan McDowell <noodles@earth.li>
Wed, 15 Jun 2005 10:41:41 +0000 (10:41 +0000)
committerJonathan McDowell <noodles@earth.li>
Wed, 15 Jun 2005 10:41:41 +0000 (10:41 +0000)
Author: noodles
Date: 2003/06/04 17:21:57
Initial revision

git-archimport-id: noodles@earth.li--pie/autodns--mainline--1.0--base-0

ACKNOWLEDGEMENTS [new file with mode: 0644]
HISTORY [new file with mode: 0644]
LICENSE [new file with mode: 0644]
README [new file with mode: 0644]
TODO [new file with mode: 0644]
autodns.pl [new file with mode: 0755]
autodns.users [new file with mode: 0644]
contrib/add-dns.pl [new file with mode: 0644]

diff --git a/ACKNOWLEDGEMENTS b/ACKNOWLEDGEMENTS
new file mode 100644 (file)
index 0000000..022deb2
--- /dev/null
@@ -0,0 +1,28 @@
+Stephen White <stephen@earth.li>
+
+Provided much testing and suggestions for improvement.
+
+
+Simon Huggins <huggie@earth.li>
+
+Answered annoying Perl questions when I was too lazy to RTFM. Fixed
+various bugs (including locale stuff, deletion of domains, stricter
+checking of domain validity).
+
+
+Peter Warasin <warpet@ines.org>
+
+Provided patches to improve functionality (users file, better GPG error
+checking etc).
+
+
+Matthew Byng-Maddick <mbm@colondot.net>
+
+Provided patches to improve functionality (locking, help, tidier command
+processing).
+
+
+Dominic Hargreaves <dom@earth.li>
+
+Provided add-dns.pl, the beginning (and possibly end) of the contrib
+directory.
diff --git a/HISTORY b/HISTORY
new file mode 100644 (file)
index 0000000..f847116
--- /dev/null
+++ b/HISTORY
@@ -0,0 +1,35 @@
+0.0.1 - 11th December 1999
+
+* First release.
+
+0.0.2 - 22nd December 1999
+
+* Added check to make sure there are no illegal characters in the
+  domain name we are adding.
+* Added checking of existing zones so that it's not possible to add the
+  same zone twice.
+
+0.0.3 - 17th February 2000
+
+* Added check for mail from mailer-daemon, so we don't try to parse
+  bounces.
+* Fixed to work with use strict.
+* Wrote a README.
+* Forced domains into all lower case.
+
+0.0.4 - 12th July 2001
+
+* Fixed stupid bug that meant we could add zones that already existed.
+* Added HELP command.
+* Added DEL command.
+* Added better checking of domain syntax.
+* Fixed gpg locale error (we assumed English messages for parsing).
+* Added user configuration file.
+* Added locking.
+* Don't reply to the same address twice (cc & to).
+* Better GPG error checking.
+* Added contrib directory (currently with just add-dns.pl in it)
+
+0.0.5 - 10th November 2002
+
+* Changed valid domain regex to allow 4 character TLDs (triggered by .info).
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..b2852a9
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,280 @@
+GNU GENERAL PUBLIC LICENSE
+
+   Version 2, June 1991
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+
+Preamble
+
+   The licenses for most software are designed to take away your freedom
+   to share and change it. By contrast, the GNU General Public License is
+   intended to guarantee your freedom to share and change free
+   software--to make sure the software is free for all its users. This
+   General Public License applies to most of the Free Software
+   Foundation's software and to any other program whose authors commit to
+   using it. (Some other Free Software Foundation software is covered by
+   the GNU Library General Public License instead.) You can apply it to
+   your programs, too.
+   
+   When we speak of free software, we are referring to freedom, not
+   price. Our General Public Licenses are designed to make sure that you
+   have the freedom to distribute copies of free software (and charge for
+   this service if you wish), that you receive source code or can get it
+   if you want it, that you can change the software or use pieces of it
+   in new free programs; and that you know you can do these things.
+   
+   To protect your rights, we need to make restrictions that forbid
+   anyone to deny you these rights or to ask you to surrender the rights.
+   These restrictions translate to certain responsibilities for you if
+   you distribute copies of the software, or if you modify it.
+   
+   For example, if you distribute copies of such a program, whether
+   gratis or for a fee, you must give the recipients all the rights that
+   you have. You must make sure that they, too, receive or can get the
+   source code. And you must show them these terms so they know their
+   rights.
+   
+   We protect your rights with two steps: (1) copyright the software, and
+   (2) offer you this license which gives you legal permission to copy,
+   distribute and/or modify the software.
+   
+   Also, for each author's protection and ours, we want to make certain
+   that everyone understands that there is no warranty for this free
+   software. If the software is modified by someone else and passed on,
+   we want its recipients to know that what they have is not the
+   original, so that any problems introduced by others will not reflect
+   on the original authors' reputations.
+   
+   Finally, any free program is threatened constantly by software
+   patents. We wish to avoid the danger that redistributors of a free
+   program will individually obtain patent licenses, in effect making the
+   program proprietary. To prevent this, we have made it clear that any
+   patent must be licensed for everyone's free use or not licensed at
+   all.
+   
+   The precise terms and conditions for copying, distribution and
+   modification follow.
+   
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+   0. This License applies to any program or other work which contains a
+   notice placed by the copyright holder saying it may be distributed
+   under the terms of this General Public License. The "Program", below,
+   refers to any such program or work, and a "work based on the Program"
+   means either the Program or any derivative work under copyright law:
+   that is to say, a work containing the Program or a portion of it,
+   either verbatim or with modifications and/or translated into another
+   language. (Hereinafter, translation is included without limitation in
+   the term "modification".) Each licensee is addressed as "you".
+   
+   Activities other than copying, distribution and modification are not
+   covered by this License; they are outside its scope. The act of
+   running the Program is not restricted, and the output from the Program
+   is covered only if its contents constitute a work based on the Program
+   (independent of having been made by running the Program). Whether that
+   is true depends on what the Program does.
+   
+   1. You may copy and distribute verbatim copies of the Program's source
+   code as you receive it, in any medium, provided that you conspicuously
+   and appropriately publish on each copy an appropriate copyright notice
+   and disclaimer of warranty; keep intact all the notices that refer to
+   this License and to the absence of any warranty; and give any other
+   recipients of the Program a copy of this License along with the
+   Program.
+   
+   You may charge a fee for the physical act of transferring a copy, and
+   you may at your option offer warranty protection in exchange for a
+   fee.
+   
+   2. You may modify your copy or copies of the Program or any portion of
+   it, thus forming a work based on the Program, and copy and distribute
+   such modifications or work under the terms of Section 1 above,
+   provided that you also meet all of these conditions:
+   
+     * a) You must cause the modified files to carry prominent notices
+       stating that you changed the files and the date of any change.
+     * b) You must cause any work that you distribute or publish, that in
+       whole or in part contains or is derived from the Program or any
+       part thereof, to be licensed as a whole at no charge to all third
+       parties under the terms of this License.
+     * c) If the modified program normally reads commands interactively
+       when run, you must cause it, when started running for such
+       interactive use in the most ordinary way, to print or display an
+       announcement including an appropriate copyright notice and a
+       notice that there is no warranty (or else, saying that you provide
+       a warranty) and that users may redistribute the program under
+       these conditions, and telling the user how to view a copy of this
+       License. (Exception: if the Program itself is interactive but does
+       not normally print such an announcement, your work based on the
+       Program is not required to print an announcement.)
+       
+   These requirements apply to the modified work as a whole. If
+   identifiable sections of that work are not derived from the Program,
+   and can be reasonably considered independent and separate works in
+   themselves, then this License, and its terms, do not apply to those
+   sections when you distribute them as separate works. But when you
+   distribute the same sections as part of a whole which is a work based
+   on the Program, the distribution of the whole must be on the terms of
+   this License, whose permissions for other licensees extend to the
+   entire whole, and thus to each and every part regardless of who wrote
+   it.
+   
+   Thus, it is not the intent of this section to claim rights or contest
+   your rights to work written entirely by you; rather, the intent is to
+   exercise the right to control the distribution of derivative or
+   collective works based on the Program.
+   
+   In addition, mere aggregation of another work not based on the Program
+   with the Program (or with a work based on the Program) on a volume of
+   a storage or distribution medium does not bring the other work under
+   the scope of this License.
+   
+   3. You may copy and distribute the Program (or a work based on it,
+   under Section 2) in object code or executable form under the terms of
+   Sections 1 and 2 above provided that you also do one of the following:
+     * a) Accompany it with the complete corresponding machine-readable
+       source code, which must be distributed under the terms of Sections
+       1 and 2 above on a medium customarily used for software
+       interchange; or,
+     * b) Accompany it with a written offer, valid for at least three
+       years, to give any third party, for a charge no more than your
+       cost of physically performing source distribution, a complete
+       machine-readable copy of the corresponding source code, to be
+       distributed under the terms of Sections 1 and 2 above on a medium
+       customarily used for software interchange; or,
+     * c) Accompany it with the information you received as to the offer
+       to distribute corresponding source code. (This alternative is
+       allowed only for noncommercial distribution and only if you
+       received the program in object code or executable form with such
+       an offer, in accord with Subsection b above.)
+       
+   The source code for a work means the preferred form of the work for
+   making modifications to it. For an executable work, complete source
+   code means all the source code for all modules it contains, plus any
+   associated interface definition files, plus the scripts used to
+   control compilation and installation of the executable. However, as a
+   special exception, the source code distributed need not include
+   anything that is normally distributed (in either source or binary
+   form) with the major components (compiler, kernel, and so on) of the
+   operating system on which the executable runs, unless that component
+   itself accompanies the executable.
+   
+   If distribution of executable or object code is made by offering
+   access to copy from a designated place, then offering equivalent
+   access to copy the source code from the same place counts as
+   distribution of the source code, even though third parties are not
+   compelled to copy the source along with the object code.
+   
+   4. You may not copy, modify, sublicense, or distribute the Program
+   except as expressly provided under this License. Any attempt otherwise
+   to copy, modify, sublicense or distribute the Program is void, and
+   will automatically terminate your rights under this License. However,
+   parties who have received copies, or rights, from you under this
+   License will not have their licenses terminated so long as such
+   parties remain in full compliance.
+   
+   5. You are not required to accept this License, since you have not
+   signed it. However, nothing else grants you permission to modify or
+   distribute the Program or its derivative works. These actions are
+   prohibited by law if you do not accept this License. Therefore, by
+   modifying or distributing the Program (or any work based on the
+   Program), you indicate your acceptance of this License to do so, and
+   all its terms and conditions for copying, distributing or modifying
+   the Program or works based on it.
+   
+   6. Each time you redistribute the Program (or any work based on the
+   Program), the recipient automatically receives a license from the
+   original licensor to copy, distribute or modify the Program subject to
+   these terms and conditions. You may not impose any further
+   restrictions on the recipients' exercise of the rights granted herein.
+   You are not responsible for enforcing compliance by third parties to
+   this License.
+   
+   7. If, as a consequence of a court judgment or allegation of patent
+   infringement or for any other reason (not limited to patent issues),
+   conditions are imposed on you (whether by court order, agreement or
+   otherwise) that contradict the conditions of this License, they do not
+   excuse you from the conditions of this License. If you cannot
+   distribute so as to satisfy simultaneously your obligations under this
+   License and any other pertinent obligations, then as a consequence you
+   may not distribute the Program at all. For example, if a patent
+   license would not permit royalty-free redistribution of the Program by
+   all those who receive copies directly or indirectly through you, then
+   the only way you could satisfy both it and this License would be to
+   refrain entirely from distribution of the Program.
+   
+   If any portion of this section is held invalid or unenforceable under
+   any particular circumstance, the balance of the section is intended to
+   apply and the section as a whole is intended to apply in other
+   circumstances.
+   
+   It is not the purpose of this section to induce you to infringe any
+   patents or other property right claims or to contest validity of any
+   such claims; this section has the sole purpose of protecting the
+   integrity of the free software distribution system, which is
+   implemented by public license practices. Many people have made
+   generous contributions to the wide range of software distributed
+   through that system in reliance on consistent application of that
+   system; it is up to the author/donor to decide if he or she is willing
+   to distribute software through any other system and a licensee cannot
+   impose that choice.
+   
+   This section is intended to make thoroughly clear what is believed to
+   be a consequence of the rest of this License.
+   
+   8. If the distribution and/or use of the Program is restricted in
+   certain countries either by patents or by copyrighted interfaces, the
+   original copyright holder who places the Program under this License
+   may add an explicit geographical distribution limitation excluding
+   those countries, so that distribution is permitted only in or among
+   countries not thus excluded. In such case, this License incorporates
+   the limitation as if written in the body of this License.
+   
+   9. The Free Software Foundation may publish revised and/or new
+   versions of the General Public License from time to time. Such new
+   versions will be similar in spirit to the present version, but may
+   differ in detail to address new problems or concerns.
+   
+   Each version is given a distinguishing version number. If the Program
+   specifies a version number of this License which applies to it and
+   "any later version", you have the option of following the terms and
+   conditions either of that version or of any later version published by
+   the Free Software Foundation. If the Program does not specify a
+   version number of this License, you may choose any version ever
+   published by the Free Software Foundation.
+   
+   10. If you wish to incorporate parts of the Program into other free
+   programs whose distribution conditions are different, write to the
+   author to ask for permission. For software which is copyrighted by the
+   Free Software Foundation, write to the Free Software Foundation; we
+   sometimes make exceptions for this. Our decision will be guided by the
+   two goals of preserving the free status of all derivatives of our free
+   software and of promoting the sharing and reuse of software generally.
+   
+   NO WARRANTY
+   
+   11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO
+   WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+   EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+   OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY
+   KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+   PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+   PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
+   THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+   
+   12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+   WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+   AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU
+   FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+   CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+   PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+   RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+   FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF
+   SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+   DAMAGES.
+   
+END OF TERMS AND CONDITIONS
\ No newline at end of file
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..e87cba5
--- /dev/null
+++ b/README
@@ -0,0 +1,78 @@
+autodns 0.0.4 - A program to aid auto addition of secondary DNS.
+Copyright 1999-2001 Jonathan McDowell for Project Purple.
+http://www.earth.li/projectpurple/progs/autodns.html
+
+
+Introduction:
+
+AutoDNS is a simple Perl script designed to allow the easy addition of
+secondary DNS zones controlled via email.
+
+The principle is simple. AutoDNS accepts a GPG clear signed email on
+stdin, so can simply be added to a .forward file or whatever. You
+configure it to know about the key IDs of all the people you wish to be
+able to setup secondaries on your server and add their keys to the GPG
+keyring for the user it runs under.
+
+Most of the configuration options are at the top of autodns.pl, just
+after where VERSION is defined. The other bit of config that's needed is
+a users file.
+
+You'll also need a way for the script to be able to do a "ndc reconfig"
+to load the info about the new secondary domains - I do this using sudo.
+
+The format of commands to AutoDNS is very simple. It current accepts 5
+commands:
+
+BEGIN
+       Indicate the beginning of a block of commands.
+END
+       Indicate the end of a block of commands.
+ADD <domain>
+       Add <domain> to the list of secondaried domains.
+DEL <domain>
+       Delete <domain> from the list of secondaried domains, assuming
+       it's owned by the current user and is being secondaried
+       currently.
+LIST
+       List secondaried domains.
+HELP
+       Show basic help.
+
+So a typical email would contain:
+
+BEGIN
+ADD foo.bar
+END
+
+as the body, which would then be signed with gpg --clearsign and sent.
+AutoDNS will reply with the results of the commands sent to it.
+
+
+Users file
+
+The users file is of a very simple format. It contains one user per
+line like so:
+
+<userid>:<gpgkeyid>:<priv>:<master server>
+
+So an example would be:
+
+noodles:5B430367:0:212.135.138.190
+
+Lines beginning with a '#' are treated as comments. See autodns.users in
+the tarball for an example.
+
+
+Contacting the author:
+
+I can be reached as noodles@earth.li or on Fidonet as Jonathan McDowell
+@ 2:443/21
+
+All constructive criticism about autodns is welcome.
+
+
+License:
+
+autodns is distributed under the GNU Public License, a copy of which
+should have been provided with this archive as LICENSE.
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..65cae4a
--- /dev/null
+++ b/TODO
@@ -0,0 +1,16 @@
+* MIME PGP support (so it'll work nicely with mutt).
+
+* man page.
+
+* Check nameserver is alive afterwards.
+
+* Different priviledge levels (users allowed to change master server IP,
+  allowed to list/delete any domain etc)
+
+* Restructure to be more modular and cleaner code.
+
+* Configuration file.
+
+* Web interface?
+
+* More (better) documentation?
diff --git a/autodns.pl b/autodns.pl
new file mode 100755 (executable)
index 0000000..9a739d0
--- /dev/null
@@ -0,0 +1,438 @@
+#!/usr/bin/perl -Tw
+# autodns 0.0.5
+# Copyright 1999-2001 Project Purple. Written by Jonathan McDowell
+# See ACKNOWLEDGEMENTS file for full details of contributors.
+# http://www.earth.li/projectpurple/progs/autodns.html
+# Released under the GPL.
+
+use strict;
+use IPC::Open3;
+use Fcntl qw(:flock);
+
+$ENV{'PATH'}="/usr/local/bin:/usr/bin:/bin:/usr/sbin";
+
+my ($from, $subject, $gpguser, $gpggood, $usersfile, $lockfile, $priv);
+my ($user, $server, $inprocess, $delcount, $addcount, $reload_command);
+my ($domain, @MAIL, @GPGERROR, @COMMANDS, %zones);
+my ($me, $ccreply, $conffile, $domainlistroot, @cfgfiles, $VERSION);
+
+$VERSION="0.0.5";
+
+#
+# Local configuration here (until it gets moved to a config file).
+#
+# These are sort of suitable for a Debian setup.
+#
+
+# Who I should reply as.
+$me="autodns\@earth.li";
+
+# Who replies should be CCed to.
+$ccreply="noodles\@earth.li";
+
+# Where to look for zones we're already hosting.
+@cfgfiles=("/etc/bind/named.conf",
+       "/etc/bind/named.secondary.conf");
+
+# The file we should add/delete domains from.
+$conffile="/etc/bind/named.secondary.conf";
+
+# The file that contains details of the authorized users.
+$usersfile="/etc/bind/autodns.users";
+
+# Base file name to for list of users domains.
+$domainlistroot="/etc/bind/domains.";
+
+# The lockfile we use to ensure we have exclusive access to the
+# $domainlistroot$user files and $conffile.
+$lockfile="/etc/bind/autodns.lck";
+
+# The command to reload the nameserver domains list.
+$reload_command="sudo ndc reconfig 2>&1";
+
+###
+### There should be no need to edit anything below (unless you're not
+### using BIND). This statement might even be true now - let me know if not.
+###
+
+#
+# Try to figure out what zones we currently know about by parsing config
+# files. Sets the item in %zones to 1 for each zone it finds.
+#
+# Call with the name of a config file to read:
+#
+# &getzones("/etc/named.conf");
+#
+sub getzones {
+       my ($namedfile) = @_;
+
+       open (NAMEDCONF, "< $namedfile") or
+               &fatalerror("Can't open $namedfile");
+
+       while (<NAMEDCONF>) {
+               if (/^\s*zone\s*"([^"]+)"/) {
+                       $zones{$1}=1;
+               }
+       }
+
+       close NAMEDCONF;
+}
+
+#
+# Check that a domain is only made up of valid characters.
+#
+# These are: a-z, 0-9, - or .
+#
+sub valid_domain {
+       my $domain = shift;
+       $domain = lc $domain;
+       if ($domain =~ /^(?:[a-z0-9-]+\.)+[a-z]{2,4}$/) {
+               return 1;
+       } else {
+               return 0;
+       }
+}
+
+#
+# Deal with a fatal error by printing an error message, closing the pipe to
+# sendmail and exiting.
+#
+# fatalerror("I'm melting!");
+#
+sub fatalerror {
+       my $message = shift;
+
+       print REPLY $message;
+       close(REPLY);
+
+       flock(LOCKFILE, LOCK_UN);
+       close(LOCKFILE);
+       unlink($lockfile);
+
+#      die $message;
+       exit;
+}
+
+#
+# Get user details from usersfile based on a PGP ID.
+#
+# A users entry looks like:
+#
+# <username>:<keyid>:<priviledge level>:<master server ip>
+#
+# Priviledge level is not currently used.
+#
+# ($user, $priv, $server) = &getuserinfo("5B430367");
+#
+sub getuserinfo {
+       my $gpguser = shift;
+       my ($user, $priviledge, $server);
+
+       open (CONFIGFILE, "< $usersfile") or
+               &fatalerror("Couldn't open user configuration file.");
+
+       foreach (<CONFIGFILE>) {
+               if (/^([^#.]+):$gpguser:(\d+):(.+)$/) {
+                       $user=$1;
+                       $priviledge=$2;
+                       $server=$3;
+                       chomp $user;
+                       chomp $priviledge;
+                       chomp $server;
+       
+                       if ($user !~ /^.+$/) {
+                               close(CONFIGFILE);
+                               &fatalerror("Error in user configuration file: Can't get username.\n");
+                       }
+
+                       if ($server !~ /^(\d{1,3}\.){3}\d{1,3}$/) {
+                               $server =~ s/\d\.]//g;
+                               close(CONFIGFILE); 
+                               &fatalerror("Error in user configuration file: Invalid primary server IP address ($server)\n");
+                               exit;
+                       } 
+               }
+       } 
+       close(CONFIGFILE);
+
+       if ($user =~ /^$/) {
+               &fatalerror("User not found.\n");
+       }
+
+       return ($user, $priviledge, $server);
+}
+
+$delcount=$addcount=$inprocess=0;
+
+# Read in the mail from stdin.
+@MAIL=<>;
+
+$subject = "Reply from AutoDNS";
+# Now lets try to find out who it's from.
+foreach (@MAIL) {
+       if (/^$/) { last; }
+       if (/^From: (.*)/i) { $from=$1; chomp $from;}
+       if (/^Subject:\s+(re:)?(.*)$/i) { $subject="Re: ".$2 if ($2);}
+}
+
+if ((! defined($from)) || $from =~ /^$/ ) {
+       die "Couldn't find a from address.";
+} elsif ($from =~ /mailer-daemon@/i) {
+       die "From address is mailer-daemon, ignoring.";
+}
+
+if (! defined($subject)) { $subject="Reply from AutoDNS"; };
+
+# We've got a from address. Start a reply.
+
+open(REPLY, "|sendmail -t -oem -oi") or die "Couldn't spawn sendmail";
+
+print REPLY "From: $me\n";
+print REPLY "To: $from\n";
+#
+# Check to see if our CC address is the same as the from address and if so
+# don't CC.
+#
+if ($from ne $ccreply) {
+       print REPLY "Cc: $ccreply\n";
+}
+print REPLY <<EOF;
+Subject: $subject
+
+AutoDNS $VERSION
+Copyright 1999-2001 Project Purple. Written by Jonathan McDowell.
+Released under the GPL.
+
+EOF
+
+#
+# Now run GPG against our incoming mail, first making sure that our locale is
+# set to C so that we get the messages in English as we expect.
+#
+$ENV{'LC_ALL'}="C";
+open3(\*GPGIN, \*GPGOUT, \*GPGERR, "gpg --batch");
+
+# Feed it the mail.
+print GPGIN @MAIL;
+close GPGIN;
+
+# And grab what it has to say.
+@GPGERROR=<GPGERR>;
+@COMMANDS=<GPGOUT>;
+close GPGERR;
+close GPGOUT;
+
+# Check who it's from and if the signature was a good one.
+$gpggood=1;
+foreach (@GPGERROR) {
+       chomp;
+       if (/Signature made.* (.*)$/) {
+               $gpguser=$1; 
+       } elsif (/error/) {
+               $gpggood = 0;
+               print REPLY "Some errors ocurred\n";
+       } elsif (/BAD signature/) {
+               $gpggood = 0;
+               print REPLY "BAD signature!\n";
+       } elsif (/public key not found/) {
+               $gpggood = 0;
+               print REPLY "Public Key not found\n";
+       }
+}
+
+# If we have an empty user it probably wasn't signed.
+if (! $gpguser) {
+       print REPLY "Message appears not to be GPG signed.\n";
+       close REPLY;
+       exit;
+}
+
+# Check the signature we got was ok.
+if ($gpggood) {
+       print REPLY "Good GPG signature found. ($gpguser)\n";
+} else {
+       print REPLY "Bad GPG signature!\n";
+       close REPLY;
+       exit;
+}
+
+# Now let's check if we know this person.
+($user, $priv, $server) = &getuserinfo($gpguser);
+
+if (! defined($user) || ! $user) {
+       print REPLY "Unknown user.\n";
+       close REPLY;
+       exit;
+}
+
+print REPLY "Got user '$user'\n";
+
+# Right. We know this is a valid user. Get a lock to ensure we have exclusive
+# access to the configs from here on in.
+open (LOCKFILE,">$lockfile") ||
+        &fatalerror("Couldn't open lock file\n");
+&fatalerror("Couldn't get lock\n") unless(flock(LOCKFILE,LOCK_EX));
+
+# Ok, now we should figure out what domains we already know about.
+foreach my $cfgfile (@cfgfiles) {
+       getzones($cfgfile);
+}
+
+foreach (@COMMANDS) {
+       # Remove trailing CRs and leading/trailing whitespace
+       chomp;
+       s/\r//;
+       s/^\s*//;
+       s/\s*$//;
+
+       if ($inprocess) {
+               print REPLY ">>>$_\n";
+       }
+
+       if (/^$/) {
+               #
+               # Empty line, so ignore it.
+               # 
+       } elsif (/^END$/) {
+               $inprocess=0;
+       } elsif (/^BEGIN$/) {
+               $inprocess=1;
+       } elsif ($inprocess && /^ADD\s+(.*)$/) {
+               $domain = $1;
+
+               # Convert domain to lower case.
+               $domain =~ tr/[A-Z]/[a-z]/;
+               if (! valid_domain($domain)) {
+                       $domain =~ s/[-a-z0-9.]//g;
+                       print REPLY "Invalid character(s) in domain name: $domain\n";
+               } elsif (defined($zones{$domain}) && $zones{$domain}) {
+                       print REPLY "We already secondary $domain\n";
+               } else {
+                       print REPLY "Adding domain $domain\n";
+                       $zones{$domain}=1;
+
+                       open (DOMAINSFILE, ">>$conffile");
+                       print DOMAINSFILE "
+### Domain added for '$user'
+
+zone \"$domain\" {
+       type slave;
+       masters { $server; };
+       file \"secondary/$user/$domain\";
+       allow-transfer { none; };
+       allow-query { any; };
+};\n";
+                       close DOMAINSFILE;
+
+                       open (DOMAINLIST, ">>$domainlistroot$user") or
+                               &fatalerror("Couldn't open file.\n");
+                       print DOMAINLIST "$domain\n";
+                       close DOMAINLIST;
+                       $addcount++;
+               }
+       } elsif ($inprocess && /^DEL\s(.*)$/) {
+               $domain = $1;
+
+               # Convert domain to lower case.
+               $domain =~ tr/[A-Z]/[a-z]/;
+               if (!valid_domain($domain)) {
+                       $domain =~ s/[-a-z0-9.]//g;
+                       print REPLY "Invalid character(s) in domain name: $domain\n";
+               } elsif (!defined($zones{$domain}) || !$zones{$domain}) {
+                               print REPLY "$domain does not exist!\n";
+               } else {
+                       print REPLY "Deleting domain $domain\n";
+                       my (@newcfg,$found);
+
+                       open (DOMAINLIST, "<$domainlistroot$user") or
+                               &fatalerror("Couldn't open file $domainlistroot$user for reading: $!.\n");
+                       my @cfg = <DOMAINLIST>;
+                       close(DOMAINLIST);
+                       @newcfg = grep { ! /^$domain$/ } @cfg;
+                       if (scalar @cfg == scalar @newcfg) {
+                               print REPLY "Didn't find $domain in $domainlistroot$user!\n";
+                               print REPLY "You are only allowed to delete your own domains that exist.\n";
+                               next;
+                       }
+
+                       open (DOMAINLIST, ">$domainlistroot$user") or 
+                               &fatalerror("Couldn't open file $domainlistroot$user for writing: $!.\n");
+                       print DOMAINLIST @newcfg;
+                       close DOMAINLIST;
+
+                       $found=0;
+                       @newcfg=();
+                       open (DOMAINSFILE, "<$conffile") or
+                               &fatalerror("Couldn't open file $conffile for reading: $!\n");
+                       {
+                       local $/ = ''; # eat whole paragraphs
+                       while (<DOMAINSFILE>) {
+                               unless (/^\s*zone\s+"$domain"/) {
+                                       push @newcfg, $_;
+                               } else {
+                                       $found=1;
+                                       if ($newcfg[-1] =~ /^###/) {
+                                               # remove comment and \n
+                                               pop @newcfg;
+                                       }
+                               }
+                       }
+                       } # end of paragraph eating
+
+                       if (!$found) {
+                               print REPLY "Didn't find $domain in $conffile!\n";
+                               next;
+                       }
+
+                       open (DOMAINSFILE, ">$conffile") or
+                               &fatalerror("Couldn't open $conffile for writing: $!\n");
+                       print DOMAINSFILE @newcfg;
+                       close DOMAINSFILE;
+                       $delcount++;
+                       $zones{$domain} = 0;
+               }
+       } elsif ($inprocess && /^LIST$/) {
+               print REPLY "Listing domains for user $user\n";
+               print REPLY "------\n";
+               if (open (DOMAINLIST, "<$domainlistroot$user")) {
+                       my $count = 0;
+                       while (<DOMAINLIST>) {
+                               $count++;
+                               print REPLY;
+                       }
+                       close (DOMAINLIST);
+                       print REPLY "------\n";
+                       print REPLY "Total of $count domains.\n";
+               } else {
+                       print REPLY "Couldn't open $domainlistroot$user: $!\n";
+               }
+       } elsif ($inprocess && /^HELP$/) {
+               print REPLY "In order to use the service, you will need to send GPG signed\n";
+               print REPLY "messages.\n\n";
+               print REPLY "The format of the text in these messages is important, as they represent\n";
+               print REPLY "commands to autodns. Commands are formatted one per line, and enclosed\n";
+               print REPLY "by \"BEGIN\" and \"END\" commands (without the quotes).\n";
+               print REPLY "Current valid commands are:\n";
+               print REPLY "BEGIN - begin processing.\n";
+               print REPLY "END - end processing.\n";
+               print REPLY "HELP - display this message.\n";
+               print REPLY "LIST - show all the zones currently held by you.\n";
+               print REPLY "ADD <domain> - adds the domain <domain> for processing.\n";
+               print REPLY "DEL <domain> - removes the domain <domain> if you own it.\n";
+       } elsif ($inprocess) {
+               print REPLY "Unknown command!\n";
+       }
+}
+flock(LOCKFILE, LOCK_UN);
+close(LOCKFILE);
+unlink($lockfile);
+
+print REPLY "Added $addcount domains.\n" if $addcount;
+print REPLY "Removed $delcount domains.\n" if $delcount;
+if ($addcount || $delcount) {
+       print REPLY "Reloading nameserver config.\n";
+       print REPLY `$reload_command`;
+}
+close REPLY;
+
+exit 0;
diff --git a/autodns.users b/autodns.users
new file mode 100644 (file)
index 0000000..56a6979
--- /dev/null
@@ -0,0 +1,3 @@
+# <userid>:<gpgkeyid>:<priv>:<master server>
+noodles:5B430367:0:212.135.138.190
+testuser:12345678:0:0.0.0.0
diff --git a/contrib/add-dns.pl b/contrib/add-dns.pl
new file mode 100644 (file)
index 0000000..53a0e3a
--- /dev/null
@@ -0,0 +1,148 @@
+#!/usr/bin/perl -w
+#
+# add-dns.pl version 0.0.4alpha
+# Dominic Hargreaves <dom@earth.li>
+#
+# Use this to tell nameservers supporting AutoDNS
+# (http://www.earth.li/projectpurple/progs/autodns.html) to slave for you.
+#
+# Changelog:
+#
+# 03/07/01 dom: Added remotehelp and remove command for AutoDNS 0.0.4alpha
+#               Changed to header to ns1 (from terry)
+# 22/05/01 dom: Initial code completed for AutoDNS 0.0.3
+
+use strict;
+use IPC::Open3;
+
+sub usage;
+
+my $sendmail = "/usr/sbin/sendmail";
+my $gpg = "/usr/bin/gpg";
+
+my $to = 'dns-auto@tuschin.blackcatnetworks.co.uk,
+      dns-auto@ns1.blackcatnetworks.co.uk';
+#my $to = 'dom';
+my $from = 'Urchin Hostmaster <hostmaster@urchin.earth.li>';
+my $cc = $from;
+#my $cc = "";
+my $keyid = "25B2616D";
+my $command;
+my @validcommands = qw(add remove list remotehelp);
+
+# Only proceed if we have been given a valid command
+
+die usage unless $ARGV[0];
+
+my $ok = 0;
+for (@validcommands) {
+   if ($ARGV[0] eq $_) {
+      $ok = 1;
+   }
+}
+
+die usage unless ($ok == 1);
+
+# Open gpg filehandle
+
+open3(\*GPGIN, \*GPGOUT, \*GPGERR, "$gpg --default-key $keyid --clearsign");
+
+# Generate AutoDNS commands
+
+print GPGIN "BEGIN\n";
+
+$command = shift(@ARGV);
+
+if ($command eq "list") {
+   print GPGIN "LIST\n";
+} elsif ($command eq "remotehelp") {
+   print GPGIN "HELP\n";
+} elsif ($command eq "add") {
+   for (@ARGV) {
+      print GPGIN "ADD $_\n";
+   }
+} elsif ($command eq "remove") {
+   for (@ARGV) {
+      print GPGIN "DEL $_\n";
+   }
+} else {
+   die usage;
+}
+
+print GPGIN "END\n";
+
+close GPGIN;
+
+my @gpgerror=<GPGERR>;
+my @gpgout=<GPGOUT>;
+close GPGERR;
+close GPGOUT;
+
+# Show user any error output from gpg...
+
+for (@gpgerror) {
+   print STDERR $_;
+}
+
+# ...and what we intend to send
+
+for (@gpgout) {
+   print $_;
+}
+
+# Ask user whether this is ok
+
+print "Send this mail to:\n";
+print $to;
+print "\nand\n";
+print $cc;
+print "\n? (y/n): ";
+
+my $mark = "0";
+while (<STDIN>) {
+   if (/^y/i) {
+      $mark = "1";
+      last;
+   }
+   /^n/i and last;
+}
+
+if (!($mark eq "1")) {
+   print "Mail NOT sent.\n";
+   exit 1;
+}
+
+# Compose email
+
+open MAIL, "|$sendmail -t -oi" or die $!;
+print MAIL "From: $from\n" or die "Configuration error: $!";
+print MAIL "To: $to\n" or die "Configuration error: $!";
+print MAIL "Cc: $cc\n" if $cc;
+print MAIL "Subject: AutoDNS commands\n";
+print MAIL "X-Mailer: add-dns.pl 0.0.4alpha\n\n";
+
+for (@gpgout) {
+   print MAIL $_;
+}
+
+print MAIL "\n";
+
+# Send email
+
+close MAIL;
+
+sub usage {
+   print<<EOF;
+Usage: $0 <command> [list of domains]
+
+Possible commands: add: Adds domains
+                   remove: Removes domains
+                   list: Lists current domains
+                   remotehelp: Requests help from remote end
+
+(You must have the private key $keyid in your gpg keyring
+for this to work)
+EOF
+
+}
+