4 Add a user to to the uid/maintainer/fingerprint table and
5 add his key to the GPGKeyring
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
12 ################################################################################
13 # <elmo> wow, sounds like it'll be a big step up.. configuring dak on a
14 # new machine even scares me :)
15 ################################################################################
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.
27 from daklib import database
28 from daklib import daklog
29 from daklib import queue
30 from daklib import utils
31 from daklib.regexes import re_gpg_fingerprint, re_user_address, re_user_mails, re_user_name
33 ################################################################################
41 ################################################################################
43 def usage(exit_code=0):
44 print """Usage: add-user [OPTION]...
45 Adds a new user to the dak databases and keyrings
47 -k, --key keyid of the User
48 -u, --user userid of the User
49 -c, --create create a system account for the user
50 -h, --help show this help and exit."""
53 ################################################################################
54 # Stolen from userdir-ldap
55 # Compute a random password using /dev/urandom.
57 # Generate a 10 character random string
58 SaltVals = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/."
59 Rand = open("/dev/urandom")
62 Password = Password + SaltVals[ord(Rand.read(1)[0]) % len(SaltVals)]
65 # Compute the MD5 crypted version of the given password
66 def HashPass(Password):
68 # Hash it telling glibc to use the MD5 algorithm - if you dont have
69 # glibc then just change Salt = "$1$" to Salt = ""
70 SaltVals = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/."
72 Rand = open("/dev/urandom")
74 Salt = Salt + SaltVals[ord(Rand.read(1)[0]) % len(SaltVals)]
75 Pass = crypt.crypt(Password,Salt)
77 raise "Password Error", "MD5 password hashing failed, not changing the password!"
80 ################################################################################
82 def createMail(login, passwd, keyid, keyring):
87 Additionally there is now an account created for you.
90 message+= "\nYour password for the login %s is: %s\n" % (login, passwd)
92 gnupg = GnuPGInterface.GnuPG()
93 gnupg.options.armor = 1
94 gnupg.options.meta_interactive = 0
95 gnupg.options.extra_args.append("--no-default-keyring")
96 gnupg.options.extra_args.append("--always-trust")
97 gnupg.options.extra_args.append("--no-secmem-warning")
98 gnupg.options.extra_args.append("--keyring=%s" % keyring)
99 gnupg.options.recipients = [keyid]
100 proc = gnupg.run(['--encrypt'], create_fhs=['stdin', 'stdout'])
101 proc.handles['stdin'].write(message)
102 proc.handles['stdin'].close()
103 output = proc.handles['stdout'].read()
104 proc.handles['stdout'].close()
108 ################################################################################
114 Cnf = utils.get_conf()
116 Arguments = [('h',"help","Add-User::Options::Help"),
117 ('c',"create","Add-User::Options::Create"),
118 ('k',"key","Add-User::Options::Key", "HasArg"),
119 ('u',"user","Add-User::Options::User", "HasArg"),
122 for i in [ "help", "create" ]:
123 if not Cnf.has_key("Add-User::Options::%s" % (i)):
124 Cnf["Add-User::Options::%s" % (i)] = ""
126 apt_pkg.ParseCommandLine(Cnf, Arguments, sys.argv)
128 Options = Cnf.SubTree("Add-User::Options")
132 projectB = pg.connect(Cnf["DB::Name"], Cnf["DB::Host"], int(Cnf["DB::Port"]))
133 database.init(Cnf, projectB)
136 keyrings = Cnf.ValueList("Dinstall::GPGKeyring")
138 # Ignore the PGP keyring for download of new keys. Ignore errors, if key is missing it will
139 # barf with the next commands.
140 cmd = "gpg --no-secmem-warning --no-default-keyring %s --recv-keys %s" \
141 % (utils.gpg_keyring_args(keyrings), Cnf["Add-User::Options::Key"])
142 (result, output) = commands.getstatusoutput(cmd)
144 cmd = "gpg --with-colons --no-secmem-warning --no-auto-check-trustdb --no-default-keyring %s --with-fingerprint --list-key %s" \
145 % (utils.gpg_keyring_args(keyrings),
146 Cnf["Add-User::Options::Key"])
147 (result, output) = commands.getstatusoutput(cmd)
148 m = re_gpg_fingerprint.search(output)
151 utils.fubar("0x%s: (1) No fingerprint found in gpg output but it returned 0?\n%s" \
152 % (Cnf["Add-User::Options::Key"], utils.prefix_multi_line_string(output, \
154 primary_key = m.group(1)
155 primary_key = primary_key.replace(" ","")
158 if Cnf.has_key("Add-User::Options::User") and Cnf["Add-User::Options::User"]:
159 uid = Cnf["Add-User::Options::User"]
160 name = Cnf["Add-User::Options::User"]
162 u = re_user_address.search(output)
165 utils.fubar("0x%s: (2) No userid found in gpg output but it returned 0?\n%s" \
166 % (Cnf["Add-User::Options::Key"], utils.prefix_multi_line_string(output, " [GPG output:] ")))
168 n = re_user_name.search(output)
171 # Look for all email addresses on the key.
173 for line in output.split('\n'):
174 e = re_user_mails.search(line)
177 emails.append(e.group(2))
180 print "0x%s -> %s <%s> -> %s -> %s" % (Cnf["Add-User::Options::Key"], name, emails[0], uid, primary_key)
182 prompt = "Add user %s with above data (y/N) ? " % (uid)
183 yn = utils.our_raw_input(prompt).lower()
186 # Create an account for the user?
188 if Cnf.FindB("Add-User::CreateAccount") or Cnf["Add-User::Options::Create"]:
190 pwcrypt = HashPass(password)
191 if Cnf.has_key("Add-User::GID"):
192 cmd = "sudo /usr/sbin/useradd -g users -m -p '%s' -c '%s' -G %s %s" \
193 % (pwcrypt, name, Cnf["Add-User::GID"], uid)
195 cmd = "sudo /usr/sbin/useradd -g users -m -p '%s' -c '%s' %s" \
196 % (pwcrypt, name, uid)
197 (result, output) = commands.getstatusoutput(cmd)
199 utils.fubar("Invocation of '%s' failed:\n%s\n" % (cmd, output), result)
201 summary+=createMail(uid, password, Cnf["Add-User::Options::Key"], Cnf["Dinstall::GPGKeyring"])
204 utils.warn("Could not prepare password information for mail, not sending password.")
206 # Now add user to the database.
207 projectB.query("BEGIN WORK")
208 uid_id = database.get_or_set_uid_id(uid)
209 projectB.query('CREATE USER "%s"' % (uid))
210 projectB.query("COMMIT WORK")
211 # The following two are kicked out in rhona, so we don't set them. kelly adds
212 # them as soon as she installs a package with unknown ones, so no problems to expect here.
213 # Just leave the comment in, to not think about "Why the hell aren't they added" in
214 # a year, if we ever touch uma again.
215 # maint_id = database.get_or_set_maintainer_id(name)
216 # projectB.query("INSERT INTO fingerprint (fingerprint, uid) VALUES ('%s', '%s')" % (primary_key, uid_id))
218 # Lets add user to the email-whitelist file if its configured.
219 if Cnf.has_key("Dinstall::MailWhiteList") and Cnf["Dinstall::MailWhiteList"] != "":
220 file = utils.open_file(Cnf["Dinstall::MailWhiteList"], "a")
222 file.write(mail+'\n')
225 print "Added:\nUid:\t %s (ID: %s)\nMaint:\t %s\nFP:\t %s" % (uid, uid_id, \
228 # Should we send mail to the newly added user?
229 if Cnf.FindB("Add-User::SendEmail"):
230 mail = name + "<" + emails[0] +">"
231 Upload = queue.Upload(Cnf)
233 Subst["__NEW_MAINTAINER__"] = mail
234 Subst["__UID__"] = uid
235 Subst["__KEYID__"] = Cnf["Add-User::Options::Key"]
236 Subst["__PRIMARY_KEY__"] = primary_key
237 Subst["__FROM_ADDRESS__"] = Cnf["Dinstall::MyEmailAddress"]
238 Subst["__HOSTNAME__"] = Cnf["Dinstall::MyHost"]
239 Subst["__SUMMARY__"] = summary
240 new_add_message = utils.TemplateSubst(Subst,Cnf["Dir::Templates"]+"/add-user.added")
241 utils.send_mail(new_add_message)
247 #######################################################################################
249 if __name__ == '__main__':