Add ud-krb-reset, and make ud-mailgate call it when receiving a mail at chpasswd...
authorPeter Palfrader <peter@palfrader.org>
Fri, 10 Sep 2010 12:53:44 +0000 (14:53 +0200)
committerPeter Palfrader <peter@palfrader.org>
Fri, 10 Sep 2010 12:53:44 +0000 (14:53 +0200)
debian/changelog
debian/install
ud-krb-reset [new file with mode: 0755]
ud-mailgate

index a608a32..f5973c2 100644 (file)
@@ -13,8 +13,11 @@ userdir-ldap (0.3.7x) xnstable; urgency=low
       functions.
   * userdir-ldap-slapd.conf: Fix ACL rule for keyring maintainers
     (we want group=..., not dn=...).
+  * Add ud-krb-reset, and make ud-mailgate call it when
+    receiving a mail at chpasswd@ saying
+    'Please change my Kerberos password'.
 
- -- Peter Palfrader <weasel@debian.org>  Wed, 11 Aug 2010 11:11:53 +0200
+ -- Peter Palfrader <weasel@debian.org>  Fri, 10 Sep 2010 14:52:43 +0200
 
 userdir-ldap (0.3.77) unstable; urgency=low
 
index 0a06f86..31d24f8 100644 (file)
@@ -11,6 +11,7 @@ ud-lock usr/bin
 ud-ldapshow usr/bin
 ud-userimport usr/bin
 ud-mailgate usr/bin
+ud-krb-reset usr/bin
 ud-generate usr/bin
 ud-passchk usr/bin
 ud-useradd usr/bin
diff --git a/ud-krb-reset b/ud-krb-reset
new file mode 100755 (executable)
index 0000000..d7e2eff
--- /dev/null
@@ -0,0 +1,68 @@
+#!/usr/bin/perl
+
+# Copyright (c) 2010 Peter Palfrader
+
+# Resets the password for a kerberos principal given on the command line.
+# If the principal does not exist, try to create them.
+
+use strict;
+use Heimdal::Kadm5;
+use Getopt::Long;
+use English;
+use String::Random;
+
+my $USAGE = "Usage: $PROGRAM_NAME [--admin=<admin>] [--keytab=<file>] <principal>\n";
+
+sub getname() {
+       my $username = getpwuid($UID);
+       die "Cannot get current username\n" unless defined $username;
+       return $username;
+};
+
+my $params;
+Getopt::Long::config('bundling');
+GetOptions (
+       '--help'        => \$params->{'help'},
+       '--admin=s'     => \$params->{'admin'},
+       '--keytab=s'    => \$params->{'keytab'},
+) or die ($USAGE);
+
+if ($params->{'help'}) {
+       print $USAGE;
+       exit (0);
+};
+
+die $USAGE if (scalar @ARGV != 1);
+my $name = shift @ARGV;
+
+unless (defined $params->{'admin'}) {
+       $params->{'admin'} = getname().'/admin';
+};
+unless (defined $params->{'keytab'}) {
+       $params->{'keytab'} = '/etc/userdir-ldap/keytab.'.getname();
+};
+
+my $client = Heimdal::Kadm5::Client->new(
+       Principal => $params->{'admin'},
+       Keytab => $params->{'keytab'}
+       );
+die "Unable to get Heimdal Client object.\n" unless defined $client;
+
+
+my $password = '844u6MrG0gTS';
+
+my $rnd = new String::Random;
+my $password = $rnd->randregex('[a-zA-Z0-9]{16}');
+
+my $principal = $client->getPrincipal($name);
+unless (defined $principal) {
+       print "Principal appears to not exist.  Trying to add.\n";
+       $principal = $client->makePrincipal($name);
+       my $ret = $client->createPrincipal($principal, $password, undef);
+       die "Failed to create principal $name.\n" unless ($ret);
+       print "Created principal $name with password '$password'.\n";
+} else {
+       my $ret = $client->changePassword($name, $password);
+       die "Failed to change password for $name.\n" unless ($ret);
+       print "Changed password of principal $name to '$password'.\n";
+};
index f3752ec..a37b047 100755 (executable)
@@ -9,6 +9,7 @@
 
 import userdir_gpg, userdir_ldap, sys, traceback, time, ldap, os, commands
 import pwd, tempfile
+import subprocess
 
 from userdir_gpg import *
 from userdir_ldap import *
@@ -568,6 +569,8 @@ def connect_to_ldap_and_check_if_locked(DnRecord):
              or GetAttr(Attrs[0],"userPassword").startswith("!"):
       raise UDNotAllowedError, "This account is locked";
 
+   return l
+
 # Handle an [almost] arbitary change
 def HandleChange(Reply,DnRecord,Key):
    global PlainText;
@@ -690,6 +693,44 @@ def HandleChPass(Reply,DnRecord,Key):
 
    return Reply;
 
+def HandleChKrbPass(Reply,DnRecord,Key):
+   # Connect to the ldap server, will throw an exception if account locked.
+   l = connect_to_ldap_and_check_if_locked(DnRecord)
+
+   user = GetAttr(DnRecord,"uid")
+   krb_proc = subprocess.Popen( ('ud-krb-reset', user), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+   krb_proc.stdin.close()
+   out = krb_proc.stdout.readlines()
+   krb_proc.wait()
+   exitcode = krb_proc.returncode
+
+   # Use GPG to encrypt it
+   m = "Tried to reset your kerberos principal's password.\n"
+   if exitcode == 0:
+      m += "The exitcode of the reset script was zero, indicating that everything\n"
+      m += "worked.  However, this being software who knows.  Script's output below."
+   else:
+      m += "The exitcode of the reset script was %d, indicating that something\n"%(exitcode)
+      m += "went terribly, terribly wrong.  Please consult the script's output below\n"
+      m += "for more information.  Contact the admins if you have any questions or\n"
+      m += "require assitance."
+
+   m += "\n"+''.join( map(lambda x: "| "+x, out)  )
+
+   Message = GPGEncrypt(m, "0x"+Key[1],Key[4]);
+   if Message == None:
+      raise UDFormatError, "Unable to generate the encrypted reply, gpg failed.";
+
+   Subst = {};
+   Subst["__FROM__"] = ChPassFrom;
+   Subst["__EMAIL__"] = EmailAddress(DnRecord);
+   Subst["__CRYPTTYPE__"] = get_crypttype_preamble(Key)
+   Subst["__PASSWORD__"] = Message;
+   Subst["__ADMIN__"] = ReplyTo;
+   Reply = Reply + TemplateSubst(Subst,open(TemplatesDir+"passwd-changed","r").read());
+
+   return Reply;
+
 # Start of main program
 
 # Drop messages from a mailer daemon.
@@ -787,8 +828,10 @@ try:
    if sys.argv[1] == "ping":
       Reply = HandlePing(Reply,Attrs[0],pgp.key_info);
    elif sys.argv[1] == "chpass":
-      if PlainText.strip().find("Please change my Debian password"):
+      if PlainText.strip().find("Please change my Debian password") >= 0:
          Reply = HandleChPass(Reply,Attrs[0],pgp.key_info);
+      elif PlainText.strip().find("Please change my Kerberos password") >= 0:
+         Reply = HandleChKrbPass(Reply,Attrs[0],pgp.key_info);
       else:
          raise UDFormatError,"Please send a signed message where the first line of text is the string 'Please change my Debian password' or some other string we accept here.";
    elif sys.argv[1] == "change":