3 import userdir_gpg, userdir_ldap, sys, traceback, time, ldap, posix;
5 from userdir_gpg import *;
6 from userdir_ldap import *;
8 # Error codes from /usr/include/sysexits.h
9 ReplyTo = ConfModule.replyto;
10 PingFrom = ConfModule.pingfrom;
11 ChPassFrom = ConfModule.chpassfrom;
12 ReplayCacheFile = ConfModule.replaycachefile;
15 EX_PERMFAIL = 65; # EX_DATAERR
16 Error = 'Message Error';
18 # Handle ping handles an email sent to the 'ping' address (ie this program
19 # called with a ping argument) It replies with a dump of the public records.
20 def HandlePing(Reply,DnRecord,Key):
22 Subst["__FROM__"] = PingFrom;
23 Subst["__EMAIL__"] = EmailAddress(DnRecord);
24 Subst["__LDAPFIELDS__"] = PrettyShow(Attrs[0]);
25 Subst["__ADMIN__"] = ReplyTo;
27 return Reply + TemplateSubst(Subst,open(TemplatesDir+"ping-reply","r").read());
29 # Handle a change password email sent to the change password address
30 # (this program called with the chpass argument)
31 def HandleChPass(Reply,DnRecord,Key):
32 # Generate a random password
34 Pass = HashPass(Password);
36 # Use GPG to encrypt it
37 Message = GPGEncrypt("Your new password is '" + Password + "'\n",\
42 raise Error, "Unable to generate the encrypted reply, gpg failed.";
45 Type = "Your message was encrypted using PGP 2.x\ncompatibility mode.";
47 Type = "Your message was encrypted using GPG (OpenPGP)\ncompatibility "\
48 "mode, without IDEA. This message cannot be decoded using PGP 2.x";
51 Subst["__FROM__"] = ChPassFrom;
52 Subst["__EMAIL__"] = EmailAddress(DnRecord);
53 Subst["__CRYPTTYPE__"] = Type;
54 Subst["__PASSWORD__"] = Message;
55 Subst["__ADMIN__"] = ReplyTo;
56 Reply = Reply + TemplateSubst(Subst,open(TemplatesDir+"passwd-changed","r").read());
58 # Connect to the ldap server
59 l = ldap.open(LDAPServer);
60 F = open(PassDir+"/pass-"+pwd.getpwuid(posix.getuid())[0],"r");
61 AccessPass = string.split(string.strip(F.readline())," ");
65 l.simple_bind_s("uid="+AccessPass[0]+","+BaseDn,AccessPass[1]);
66 Rec = [(ldap.MOD_REPLACE,"userPassword","{crypt}"+Pass)];
67 Dn = "uid=" + GetAttr(DnRecord,"uid") + "," + BaseDn;
72 # Start of main program
73 ErrMsg = "Indeterminate Error";
74 ErrType = EX_TEMPFAIL;
76 # Startup the replay cache
77 ErrType = EX_TEMPFAIL;
78 ErrMsg = "Failed to initialize the replay cache:";
79 RC = ReplayCache(ReplayCacheFile);
83 ErrType = EX_PERMFAIL;
84 ErrMsg = "Failed to understand the email or find a signature:";
85 Email = mimetools.Message(sys.stdin,0);
86 Msg = GetClearSig(Email);
89 ErrMsg = "Unable to check the signature or the signature was invalid:";
90 Res = GPGCheckSig(Msg[0]);
96 raise Error, "Null signature text";
98 # Extract the plain message text in the event of mime encoding
99 ErrMsg = "Problem stripping MIME headers from the decoded message"
102 Index = string.index(Res[3],"\n\n") + 2;
104 Index = string.index(Res[3],"\n\r\n") + 3;
105 PlainText = Res[3][Index:];
109 # Check the signature against the replay cache
110 ErrMsg = "The replay cache rejected your message. Check your clock!";
111 Rply = RC.Check(Res[1]);
116 # Connect to the ldap server
117 ErrType = EX_TEMPFAIL;
118 ErrMsg = "An error occured while performing the LDAP lookup";
119 l = ldap.open(LDAPServer);
120 l.simple_bind_s("","");
122 # Search for the matching key fingerprint
123 Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"keyfingerprint=" + Res[2][1]);
125 raise Error, "Key not found"
127 raise Error, "Oddly your key fingerprint is assigned to more than one account.."
129 # Determine the sender address
130 ErrType = EX_PERMFAIL;
131 ErrMsg = "A problem occured while trying to formulate the reply";
132 Sender = Email.getheader("Reply-To");
134 Sender = Email.getheader("From");
136 raise Error, "Unable to determine the sender's address";
139 Date = time.strftime("%a, %d %b %Y %H:%M:%S +0000",time.gmtime(time.time()));
140 Reply = "To: %s\nReply-To: %s\nDate: %s\n" % (Sender,ReplyTo,Date);
143 if sys.argv[1] == "ping":
144 Reply = HandlePing(Reply,Attrs[0],Res[2]);
145 elif sys.argv[1] == "chpass":
146 if string.find(string.strip(PlainText),"Please change my Debian password") != 0:
147 raise Error,"Please send a signed message where the first line of text is the string 'Please change my Debian password'";
148 Reply = HandleChPass(Reply,Attrs[0],Res[2]);
151 raise Error, "Incorrect Invokation";
153 # Send the message through sendmail
154 ErrMsg = "A problem occured while trying to send the reply";
155 Child = posix.popen("/usr/sbin/sendmail -t","w");
156 # Child = posix.popen("cat","w");
158 if Child.close() != None:
159 raise Error, "Sendmail gave a non-zero return code";
163 print "==> %s: %s" %(sys.exc_type,sys.exc_value);
164 List = traceback.extract_tb(sys.exc_traceback);
168 print " %s %s:%u: %s" %(x[2],x[0],x[1],x[3]);