~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to scripts/usrmgt-server

  • Committer: dcoles
  • Date: 2008-02-13 04:10:55 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:443
Added Forum application along with unmodifed version of phpBB3 "Olympus" 3.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#!/usr/bin/python
2
2
 
3
 
import os
4
 
import pysvn
5
 
import subprocess
6
3
import sys
7
 
import urllib
8
 
from functools import partial
9
 
import traceback
10
 
import logging
11
 
import errno
12
4
 
13
 
import conf
14
 
import common.db
15
5
import common.chat
16
6
import common.makeuser
17
 
import common.studpath
18
7
 
19
8
# usage:
20
9
#   usrmgt-server <port> <magic>
21
10
 
22
 
# User management operations:
23
 
#   - Create local user
24
 
#   - [Re]Create jail for a user
25
 
#       - Create a svn repository for a user
26
 
#           - create repository
27
 
#           - svn config
28
 
#           - svn auth
29
 
#       - Checkout repository as home directory
30
 
#       - /etc/passwd entry
31
 
#   - Disable a user's account
32
 
#   - Enable a user's account
33
 
#   - Remove a user
34
 
#   - Rebuild svn config
35
 
#   - Rebuild svn auth file
36
 
#   - Rebuild passwd + push to nodes.
37
 
 
38
11
def create_user(props):
39
 
    """Create the database record for the given user.
40
 
       Expected properties:
41
 
        login       - used as a unix login name and svn repository name.
42
 
                      STRING REQUIRED 
43
 
        unixid      - the unix uid under which execution will take place
44
 
                      on the behalf of the user. Don't use 0! If not specified
45
 
                      or None, one will be allocated from the configured
46
 
                      numeric range.
47
 
                      INT OPTIONAL
48
 
        password    - the clear-text password for the user. If this property is
49
 
                      absent or None, this is an indication that external
50
 
                      authentication should be used (i.e. LDAP).
51
 
                      STRING OPTIONAL
52
 
        email       - the user's email address.
53
 
                      STRING OPTIONAL
54
 
        nick        - the display name to use.
55
 
                      STRING REQUIRED
56
 
        fullname    - The name of the user for results and/or other official
57
 
                      purposes.
58
 
                      STRING REQUIRED
59
 
        rolenm      - The user's role. Must be one of "anyone", "student",
60
 
                      "tutor", "lecturer", "admin".
61
 
                      STRING/ENUM REQUIRED
62
 
        studentid   - If supplied and not None, the student id of the user for
63
 
                      results and/or other official purposes.
64
 
                      STRING OPTIONAL
65
 
       Return Value: the uid associated with the user. INT
66
 
    """
67
 
 
68
 
    if 'unixid' not in props or props['unixid'] is None:
69
 
        # For the time being, just choose a random unixid.
70
 
        # This may result in duplicates, but the unixid is essentially
71
 
        # a monitoring/logging convenience only. Oh, and dups could kill
72
 
        # each other. <sigh>
73
 
        props['unixid'] = random.randrange(5000,10000)
74
 
        # raise NotImplementedError, "No algorithm for creating uids yet!"
75
 
        # unixid = invent-uid
76
 
        # props['unixid'] = unixid
77
 
 
78
 
    common.makeuser.make_user_db(**props)
79
 
 
80
 
    return int(props['unixid'])
81
 
 
82
 
def update_user(props):
83
 
    """Create the database record for the given user.
84
 
       Expected properties:
85
 
        login       - user who is making the change (not necessarily the one
86
 
                      being updated).
87
 
        update      - dict of fields to be updated. The fields are all those
88
 
                      in the login table of the db.
89
 
                      'login' required.
90
 
                      Omitted fields will not be set.
91
 
    """
92
 
    update = props['update']
93
 
    # Note: "login" is special - it is not part of the kwargs to
94
 
    # db.update_user, but the first arg - used to find the user to update.
95
 
    # However it doesn't need any special treatment here.
96
 
 
97
 
    db = common.db.DB()
98
 
    db.update_user(**update)
99
 
    db.close()
100
 
 
101
 
def get_login(login, passwd, realm, existing_login, _may_save):
102
 
    """Callback function used by pysvn for authentication.
103
 
    login, passwd: Credentials of the user attempting to log in.
104
 
        passwd in clear (this should be the user's svn_pass, a
105
 
        randomly-generated permanent password for this user, not their main
106
 
        IVLE password).
107
 
    realm, existing_login, _may_save: The 3 arguments passed by pysvn to
108
 
        callback_get_login.
109
 
        The following has been determined empirically, not from docs:
110
 
        existing_login will be the name of the user who owns the process on
111
 
        the first attempt, "" on subsequent attempts. We use this fact.
112
 
    """
113
 
    logging.debug("Getting password for %s (realm %s)" % (login, realm))
114
 
    # Only provide credentials on the _first_ attempt.
115
 
    # If we're being asked again, then it means the credentials failed for
116
 
    # some reason and we should just fail. (This is not desirable, but it's
117
 
    # better than being asked an infinite number of times).
118
 
    if existing_login == "":
119
 
        logging.warning("Could not authenticate SVN for %s" % login)
120
 
        return (False, login, passwd, False)
121
 
    else:
122
 
        return (True, login, passwd, False)
123
 
 
124
 
def activate_user(props):
125
 
    """Create the on-disk stuff for the given user.
126
 
       Sets the state of the user in the db from pending to enabled.
127
 
       Expected properties:
128
 
        login       - the user name for the jail
129
 
                      STRING REQUIRED
130
 
       Return Value: None
131
 
    """
132
 
 
133
 
    os.umask(0022) # Bad, but start_server sets it worse.
134
 
 
135
 
    login = props['login']
136
 
 
137
 
    db = common.db.DB()
138
 
 
139
 
    try:
140
 
 
141
 
        # FIXME: check we're pending
142
 
 
143
 
        details = db.get_user(login)
144
 
 
145
 
        # make svn config/auth
146
 
 
147
 
        logging.debug("Creating repo")
148
 
        common.makeuser.make_svn_repo(login, throw_on_error=False)
149
 
        logging.debug("Creating svn config")
150
 
        common.makeuser.make_svn_config(login, throw_on_error=False)
151
 
        logging.debug("Creating svn auth")
152
 
        passwd = common.makeuser.make_svn_auth(login, throw_on_error=False)
153
 
        logging.debug("passwd: %s" % passwd)
154
 
 
155
 
        svn = pysvn.Client()
156
 
        svn.callback_get_login = partial(get_login, login, passwd)
157
 
 
158
 
        if conf.svn_addr[-1] != '/':
159
 
            conf.svn_addr = conf.svn_addr + "/"
160
 
    
161
 
        # FIXME: This should be a loop over enrolements.
162
 
        #        We're not going to fix this now because it requires
163
 
        #        a large amount of admin console work to manage subject
164
 
        #        offerings.
165
 
        #        Instead, we're just going to use a single offering with
166
 
        #        a "short" name of "info1".
167
 
        logging.debug("Creating /info1")
168
 
        try:
169
 
            svn.mkdir(conf.svn_addr + login + "/info1",
170
 
                      "Initial creation of work directory for Informatics 1")
171
 
        except Exception, exc:
172
 
            logging.warning("While mkdiring info1: %s" % str(exc))
173
 
            pass
174
 
        logging.debug("Creating /stuff")
175
 
        try:
176
 
            svn.mkdir(conf.svn_addr + login + "/stuff",
177
 
                      "Initial creation of directory for miscellania")
178
 
        except Exception, exc:
179
 
            logging.warning("While mkdiring stuff: %s" % str(exc))
180
 
            pass
181
 
 
182
 
        logging.debug("Creating jail")
183
 
        common.makeuser.make_jail(login, details.unixid, svn_pass=passwd)
184
 
 
185
 
        common.makeuser.mount_jail(login)
186
 
 
187
 
        do_checkout(props, svn_pass=passwd)
188
 
 
189
 
        # FIXME: should this be nicer?
190
 
        os.system("chown -R %d:%d %s" \
191
 
                % (details.unixid, details.unixid,
192
 
                   common.studpath.url_to_local(login)[1]))
193
 
 
194
 
        logging.info("Enabling user")
195
 
        db.update_user(login, state='enabled')
196
 
 
197
 
        return {"response": "okay"}
198
 
 
199
 
    finally:
200
 
        db.close()
201
 
 
202
 
def do_checkout(props, svn_pass=None):
203
 
    """Create the default contents of a user's jail by checking out from the
204
 
    repositories.
205
 
    If any directory already exists, just fail silently (so this is not a
206
 
    "wipe-and-checkout", merely a checkout if it failed or something).
207
 
       Expected properties:
208
 
        login       - the user name for the jail
209
 
                      STRING REQUIRED
210
 
       Return Value: None
211
 
    """
212
 
    login = props['login']
213
 
 
214
 
    db = common.db.DB()
215
 
    user = db.get_user(login)
216
 
    # If svn_pass isn't supplied, grab it from the DB
217
 
    if svn_pass is None:
218
 
        svn_pass = user.svn_pass
219
 
    db.close()
220
 
 
221
 
    svn = pysvn.Client()
222
 
    svn.callback_get_login = partial(get_login, login, svn_pass)
223
 
 
224
 
    if conf.svn_addr[-1] != os.sep:
225
 
        conf.svn_addr += os.sep
226
 
 
227
 
    # FIXME: <hack>
228
 
 
229
 
    logging.debug("Checking out directories in the jail")
230
 
    try:
231
 
        svn.checkout(conf.svn_addr + login + "/stuff",
232
 
                     common.studpath.url_to_local(login + "/stuff")[1])
233
 
        os.system("chown -R %d:%d %s" \
234
 
                % (user.unixid, user.unixid,
235
 
                   common.studpath.url_to_local(login + "/stuff")[1]))
236
 
    except Exception, exc:
237
 
        logging.warning("While mkdiring stuff: %s" % str(exc))
238
 
        pass
239
 
    try:
240
 
        svn.checkout(conf.svn_addr + login + "/info1",
241
 
                     common.studpath.url_to_local(login + "/info1")[1])
242
 
        os.system("chown -R %d:%d %s" \
243
 
                % (user.unixid, user.unixid,
244
 
                   common.studpath.url_to_local(login + "/info1")[1]))
245
 
    except Exception, exc:
246
 
        logging.warning("While mkdiring info1: %s" % str(exc))
247
 
        pass
248
 
 
249
 
    # FIXME: </hack>
250
 
 
251
 
    return {"response": "okay"}
252
 
 
253
 
actions = {
254
 
        'create_user':create_user,
255
 
        'update_user':update_user,
256
 
        'activate_user':activate_user,
257
 
        'do_checkout':do_checkout,
258
 
    }
259
 
 
260
 
def initializer():
261
 
    try:
262
 
        pidfile = open('/var/run/usrmgt-server.pid', 'w')
263
 
        pidfile.write('%d\n' % os.getpid())
264
 
        pidfile.close()
265
 
    except IOError, (errno, strerror):
266
 
        print "Couldn't write PID file. IO error(%s): %s" % (errno, strerror)
267
 
        sys.exit(1)
268
 
 
269
 
def dispatch(props):
270
 
    logging.debug(repr(props))
271
 
    action = props.keys()[0]
272
 
    return actions[action](props[action])
 
12
 
 
13
    if 'uid' not in props:
 
14
        uid = invent-uid
 
15
        props['uid'] = uid
 
16
 
 
17
    common.makeuser.make_user_db(props['username'], props['uid'],
 
18
                                 props['password'], props['nick'],
 
19
                                 props['fullname'], props['rolenm'],
 
20
                                 props['studentid'])
 
21
 
 
22
    common.makeuser.make_jail(props['username'], props['uid'])
 
23
 
 
24
    # eventually, we're going to want to grant shell access, in which
 
25
    # case we'll need to add the uid to the password file. Magic to do
 
26
    # that should go here.
 
27
 
 
28
    return props['uid']
273
29
 
274
30
if __name__ == "__main__":
275
 
    if len(sys.argv) <3:
276
 
        print >>sys.stderr, "Usage: usrmgt-server <port> <magic>"
277
 
        sys.exit(1)
278
31
    port = int(sys.argv[1])
279
32
    magic = sys.argv[2]
280
33
 
281
 
    pid = os.getpid()
282
 
 
283
 
    logging.basicConfig(filename="/var/log/usrmgt.log", level=logging.INFO)
284
 
    logging.info("Starting usrmgt server on port %d (pid = %d)" % (port, pid))
285
 
 
286
 
    common.chat.start_server(port, magic, True, dispatch, initializer)
 
34
    common.chat.start_server(port, magic, False, create_user)