Reorganize namespace
[mspang/pyceo.git] / bin / csc-chfn
1 #!/usr/bin/python
2 """
3 chfn - change real user name and information
4
5 This utility imitates chfn(1) from the shadow password suite, but makes its
6 changes in the LDAP directory rather than in the passwd file.
7
8 When run from an unprivileged account, authentication will be performed
9 before the account information is changed.
10 """
11 import os, sys, pwd, getopt, PAM
12 from ceo import accounts
13 from ceo.excep import InvalidArgument
14
15 progname = os.path.basename(sys.argv[0])
16
17 OPTION_MAP = {
18             '-f': 'fullname',
19             '-r': 'roomnumber',
20             '-w': 'workphone',
21             '-h': 'homephone',
22             '-o': 'other'
23 }
24 LONG_NAMES = [
25         ('fullname', 'Full Name'),
26         ('roomnumber', 'Room Number'),
27         ('workphone', 'Work Phone'),
28         ('homephone', 'Home Phone'),
29         ('other', 'Other')
30 ]
31 READONLY_FIELDS = [ 'fullname', 'other' ]
32
33 def usage():
34     umesg = "Usage: %s [-f full name] [-r room no] [-w work ph] " + \
35             "[-h home ph] [-o other] [user]"
36     print umesg % progname
37     sys.exit(2)
38
39
40 def whoami():
41     uid = os.getuid()
42     username = os.getlogin()
43     if pwd.getpwnam(username).pw_uid != uid:
44         username = pwd.getpwuid(uid).pw_name
45     return (uid, username)
46
47 def authenticate(username):
48     auth = PAM.pam()
49     auth.start('chsh', username)
50     try:
51         auth.authenticate()
52         auth.acct_mgmt()
53     except PAM.error, resp:
54         print "%s: %s" % (progname, resp.args[0])
55         sys.exit(1)
56
57 def main():
58
59     pwuid, pwnam = whoami()
60
61     euid = os.geteuid()
62     os.setreuid(euid, euid)
63
64     gecos_params = {}
65
66     try:
67         options, arguments = getopt.gnu_getopt(sys.argv[1:], 'f:r:w:h:o:')
68         for opt, val in options:
69             gecos_params[OPTION_MAP[opt]] = val
70         if len(arguments) > 1:
71             usage()
72         elif len(arguments) == 1:
73             username = arguments[0]
74         else:
75             username = pwnam
76     except getopt.GetoptError, e:
77         usage()
78
79     for field in READONLY_FIELDS:
80         if field in gecos_params and pwuid:
81             print "%s: Permission denied." % progname
82             sys.exit(1)
83
84     try:
85         if pwuid and pwd.getpwnam(username).pw_uid != pwuid:
86             print "%s: Permission denied." % progname
87             sys.exit(1)
88     except KeyError:
89         print "%s: unknown user %s" % (progname, username)
90         sys.exit(1)
91
92     try:
93         accounts.connect()
94         gecos_raw = accounts.get_gecos(username)
95         gecos = accounts.parse_gecos(gecos_raw)
96
97         if pwuid:
98             authenticate(username)
99
100         if not gecos_params:
101             print "Changing the user information for %s" % username
102             print "Enter the new value, or press ENTER for the default"
103             for field, longname in LONG_NAMES:
104                 if pwuid and field == 'other' and 'other' in READONLY_FIELDS:
105                     continue
106                 if gecos[field] is None:
107                     gecos[field] = ""
108                 if field in READONLY_FIELDS and pwuid:
109                     print "        %s: %s" % (longname, gecos[field])
110                 else:
111                     print "        %s: [%s]:" % (longname, gecos[field]),
112                     new_value = raw_input()
113                     if new_value:
114                         gecos[field] = new_value.strip()
115         else:
116             gecos.update(gecos_params)
117
118         gecos_raw_new = accounts.build_gecos(**gecos)
119         if gecos_raw != gecos_raw_new:
120             accounts.update_gecos(username, gecos_raw_new)
121
122     except InvalidArgument, e:
123         longnames = dict(LONG_NAMES)
124         longname = longnames.get(e.argname, e.argname).lower()
125         print "%s: invalid %s: %s" % (progname, longname, e.argval)
126         sys.exit(1)
127
128 if __name__ == '__main__':
129     exceps = ( accounts.ConfigurationException, accounts.LDAPException,
130             accounts.KrbException, accounts.AccountException )
131     try:
132         main()
133     except KeyboardInterrupt:
134         sys.exit(130) 
135     except IOError, e:
136         print "%s: %s: %s" % (progname, e.filename, e.strerror)
137         sys.exit(1)
138     except exceps, e:
139         print "%s: %s" % (progname, e)
140         sys.exit(1)