naming your variable like a module is unsmart
[mirror/userdir-ldap.git] / ud-mailgate
index f3752ec..1ec0e9f 100755 (executable)
@@ -9,6 +9,8 @@
 
 import userdir_gpg, userdir_ldap, sys, traceback, time, ldap, os, commands
 import pwd, tempfile
+import subprocess
+import email, email.parser
 
 from userdir_gpg import *
 from userdir_ldap import *
@@ -40,12 +42,12 @@ ValidHostNames = [] # will be initialized in later
 SSHFingerprint = re.compile('^(\d+) ([0-9a-f\:]{47}) (.+)$')
 SSHRSA1Match = re.compile('^^(.* )?\d+ \d+ \d+')
 
-GenderTable = {"male": 1,
-              "1": 1,
-              "female": 2,
-              "2": 2,
-              "unspecified": 9,
-              "9": 9,
+GenderTable = {"male": '1',
+              "1": '1',
+              "female": '2',
+              "2": '2',
+              "unspecified": '9',
+              "9": '9',
 };
 
 ArbChanges = {"c": "..",
@@ -505,6 +507,9 @@ def FinishConfirmSudopassword(l, uid, Attrs):
    global SudoPasswd
    result = "\n"
 
+   if len(SudoPasswd) == 0:
+       return None
+
    res = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"uid="+uid, ['sudoPassword']);
    if len(res) != 1:
       raise UDFormatError, "Not exactly one hit when searching for user"
@@ -568,6 +573,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;
@@ -611,7 +618,8 @@ def HandleChange(Reply,DnRecord,Key):
    if CommitChanges == 1: # only if we are still good to go
       try:
          Res = FinishConfirmSudopassword(l, GetAttr(DnRecord,"uid"), Attrs)
-         Result = Result + Res + "\n";
+         if not Res is None:
+            Result = Result + Res + "\n";
       except Error, e:
          CommitChanges = 0
          Result = Result + "FinishConfirmSudopassword raised an error (%s) - no changes committed\n"%(e);
@@ -690,6 +698,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.
@@ -706,8 +752,8 @@ try:
    # Get the email 
    ErrType = EX_PERMFAIL;
    ErrMsg = "Failed to understand the email or find a signature:";
-   Email = mimetools.Message(sys.stdin,0);
-   Msg = GetClearSig(Email);
+   mail = email.parser.Parser().parse(sys.stdin);
+   Msg = GetClearSig(mail);
 
    ErrMsg = "Message is not PGP signed:"
    if Msg[0].find("-----BEGIN PGP SIGNED MESSAGE-----") == -1 and \
@@ -728,11 +774,8 @@ try:
    global PlainText;
    ErrMsg = "Problem stripping MIME headers from the decoded message"
    if Msg[1] == 1:
-      try:
-         Index = pgp.text.index("\n\n") + 2
-      except ValueError:
-         Index = pgp.text.index("\n\r\n") + 3
-      PlainText = pgp.text[Index:]
+      e = email.parser.Parser().parsestr(pgp.text)
+      PlainText = e.get_payload(decode=True)
    else:
       PlainText = pgp.text
 
@@ -755,22 +798,13 @@ try:
 
    # Check the signature against the replay cache
    RC = ReplayCache(ReplayCacheFile);
-   RC.Clean();
-   ErrMsg = "The replay cache rejected your message. Check your clock!";
-   Rply = RC.Check(pgp.sig_info);
-   if Rply != None:
-      RC.close()
-      raise UDNotAllowedError, Rply;
-   RC.Add(pgp.sig_info);
-   RC.close()
+   RC.process(pgp.sig_info)
 
    # Determine the sender address
    ErrMsg = "A problem occured while trying to formulate the reply";
-   Sender = Email.getheader("Reply-To");
-   if Sender == None:
-      Sender = Email.getheader("From");
-   if Sender == None:
-      raise UDFormatError, "Unable to determine the sender's address";
+   Sender = mail['Reply-To']
+   if not Sender: Sender = mail['From']
+   if not Sender: raise UDFormatError, "Unable to determine the sender's address";
 
    # Formulate a reply
    Date = time.strftime("%a, %d %b %Y %H:%M:%S +0000",time.gmtime(time.time()));
@@ -787,8 +821,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":