]> git.decadent.org.uk Git - dak.git/blob - dak/add_user.py
Merge remote-tracking branch 'drkranz/misc' into merge
[dak.git] / dak / add_user.py
1 #!/usr/bin/env python
2
3 """
4 Add a user to to the uid/maintainer/fingerprint table and
5 add his key to the GPGKeyring
6
7 @contact: Debian FTP Master <ftpmaster@debian.org>
8 @copyright: 2004, 2009  Joerg Jaspert <joerg@ganneff.de>
9 @license: GNU General Public License version 2 or later
10 """
11
12 ################################################################################
13 # <elmo> wow, sounds like it'll be a big step up.. configuring dak on a
14 #        new machine even scares me :)
15 ################################################################################
16
17 # You don't want to read this script if you know python.
18 # I know what I say. I dont know python and I wrote it. So go and read some other stuff.
19
20 import commands
21 import sys
22 import apt_pkg
23
24 from daklib import utils
25 from daklib.dbconn import DBConn, get_or_set_uid, get_active_keyring_paths
26 from daklib.regexes import re_gpg_fingerprint_colon, re_user_address, re_user_mails, re_user_name
27
28 ################################################################################
29
30 Cnf = None
31 Logger = None
32
33 ################################################################################
34
35 def usage(exit_code=0):
36     print """Usage: add-user [OPTION]...
37 Adds a new user to the dak databases and keyrings
38
39     -k, --key                keyid of the User
40     -u, --user               userid of the User
41     -c, --create             create a system account for the user
42     -h, --help               show this help and exit."""
43     sys.exit(exit_code)
44
45 ################################################################################
46 # Stolen from userdir-ldap
47 # Compute a random password using /dev/urandom.
48 def GenPass():
49     # Generate a 10 character random string
50     SaltVals = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/."
51     Rand = open("/dev/urandom")
52     Password = ""
53     for i in range(0,15):
54         Password = Password + SaltVals[ord(Rand.read(1)[0]) % len(SaltVals)]
55     return Password
56
57 # Compute the MD5 crypted version of the given password
58 def HashPass(Password):
59     import crypt
60     # Hash it telling glibc to use the MD5 algorithm - if you dont have
61     # glibc then just change Salt = "$1$" to Salt = ""
62     SaltVals = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/."
63     Salt  = "$1$"
64     Rand = open("/dev/urandom")
65     for x in range(0,10):
66         Salt = Salt + SaltVals[ord(Rand.read(1)[0]) % len(SaltVals)]
67     Pass = crypt.crypt(Password,Salt)
68     if len(Pass) < 14:
69         raise RuntimeError("MD5 password hashing failed, not changing the password!")
70     return Pass
71
72 ################################################################################
73
74 def createMail(login, passwd, keyid, keyring):
75     import GnuPGInterface
76
77     message= """
78
79 Additionally there is now an account created for you.
80
81 """
82     message+= "\nYour password for the login %s is: %s\n" % (login, passwd)
83
84     gnupg = GnuPGInterface.GnuPG()
85     gnupg.options.armor = 1
86     gnupg.options.meta_interactive = 0
87     gnupg.options.extra_args.append("--no-default-keyring")
88     gnupg.options.extra_args.append("--always-trust")
89     gnupg.options.extra_args.append("--no-secmem-warning")
90     gnupg.options.extra_args.append("--keyring=%s" % keyring)
91     gnupg.options.recipients = [keyid]
92     proc = gnupg.run(['--encrypt'], create_fhs=['stdin', 'stdout'])
93     proc.handles['stdin'].write(message)
94     proc.handles['stdin'].close()
95     output = proc.handles['stdout'].read()
96     proc.handles['stdout'].close()
97     proc.wait()
98     return output
99
100 ################################################################################
101
102 def main():
103     global Cnf
104     keyrings = None
105
106     Cnf = utils.get_conf()
107
108     Arguments = [('h',"help","Add-User::Options::Help"),
109                  ('c',"create","Add-User::Options::Create"),
110                  ('k',"key","Add-User::Options::Key", "HasArg"),
111                  ('u',"user","Add-User::Options::User", "HasArg"),
112                  ]
113
114     for i in [ "help", "create" ]:
115         if not Cnf.has_key("Add-User::Options::%s" % (i)):
116             Cnf["Add-User::Options::%s" % (i)] = ""
117
118     apt_pkg.ParseCommandLine(Cnf, Arguments, sys.argv)
119
120     Options = Cnf.SubTree("Add-User::Options")
121     if Options["help"]:
122         usage()
123
124     session = DBConn().session()
125
126     if not keyrings:
127         keyrings = get_active_keyring_paths()
128
129     cmd = "gpg --with-colons --no-secmem-warning --no-auto-check-trustdb --no-default-keyring %s --with-fingerprint --list-key %s" \
130            % (utils.gpg_keyring_args(keyrings),
131               Cnf["Add-User::Options::Key"])
132     (result, output) = commands.getstatusoutput(cmd)
133     m = re_gpg_fingerprint_colon.search(output)
134     if not m:
135         print output
136         utils.fubar("0x%s: (1) No fingerprint found in gpg output but it returned 0?\n%s" \
137                                         % (Cnf["Add-User::Options::Key"], utils.prefix_multi_line_string(output, \
138                                                                                                                                                                 " [GPG output:] ")))
139     primary_key = m.group(1)
140     primary_key = primary_key.replace(" ","")
141
142     uid = ""
143     if Cnf.has_key("Add-User::Options::User") and Cnf["Add-User::Options::User"]:
144         uid = Cnf["Add-User::Options::User"]
145         name = Cnf["Add-User::Options::User"]
146     else:
147         u = re_user_address.search(output)
148         if not u:
149             print output
150             utils.fubar("0x%s: (2) No userid found in gpg output but it returned 0?\n%s" \
151                         % (Cnf["Add-User::Options::Key"], utils.prefix_multi_line_string(output, " [GPG output:] ")))
152         uid = u.group(1)
153         n = re_user_name.search(output)
154         name = n.group(1)
155
156 # Look for all email addresses on the key.
157     emails=[]
158     for line in output.split('\n'):
159         e = re_user_mails.search(line)
160         if not e:
161             continue
162         emails.append(e.group(2))
163
164     print "0x%s -> %s <%s> -> %s -> %s" % (Cnf["Add-User::Options::Key"], name, emails[0], uid, primary_key)
165
166     prompt = "Add user %s with above data (y/N) ? " % (uid)
167     yn = utils.our_raw_input(prompt).lower()
168
169     if yn == "y":
170         # Create an account for the user?
171         summary = ""
172
173         # Now add user to the database.
174         # Note that we provide a session, so we're responsible for committing
175         uidobj = get_or_set_uid(uid, session=session)
176         uid_id = uidobj.uid_id
177         session.commit()
178
179         # Lets add user to the email-whitelist file if its configured.
180         if Cnf.has_key("Dinstall::MailWhiteList") and Cnf["Dinstall::MailWhiteList"] != "":
181             f = utils.open_file(Cnf["Dinstall::MailWhiteList"], "a")
182             for mail in emails:
183                 f.write(mail+'\n')
184             f.close()
185
186         print "Added:\nUid:\t %s (ID: %s)\nMaint:\t %s\nFP:\t %s" % (uid, uid_id, \
187                      name, primary_key)
188
189         # Should we send mail to the newly added user?
190         if Cnf.FindB("Add-User::SendEmail"):
191             mail = name + "<" + emails[0] +">"
192             Subst = {}
193             Subst["__NEW_MAINTAINER__"] = mail
194             Subst["__UID__"] = uid
195             Subst["__KEYID__"] = Cnf["Add-User::Options::Key"]
196             Subst["__PRIMARY_KEY__"] = primary_key
197             Subst["__FROM_ADDRESS__"] = Cnf["Dinstall::MyEmailAddress"]
198             Subst["__ADMIN_ADDRESS__"] = Cnf["Dinstall::MyAdminAddress"]
199             Subst["__HOSTNAME__"] = Cnf["Dinstall::MyHost"]
200             Subst["__DISTRO__"] = Cnf["Dinstall::MyDistribution"]
201             Subst["__SUMMARY__"] = summary
202             new_add_message = utils.TemplateSubst(Subst,Cnf["Dir::Templates"]+"/add-user.added")
203             utils.send_mail(new_add_message)
204
205     else:
206         uid = None
207
208 #######################################################################################
209
210 if __name__ == '__main__':
211     main()