2
# pam.py - functions authentication, authorisation and session handling
4
# Copyright (C) 2010, 2011 Arthur de Jong
6
# This library is free software; you can redistribute it and/or
7
# modify it under the terms of the GNU Lesser General Public
8
# License as published by the Free Software Foundation; either
9
# version 2.1 of the License, or (at your option) any later version.
11
# This library is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
# Lesser General Public License for more details.
16
# You should have received a copy of the GNU Lesser General Public
17
# License along with this library; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
30
def try_bind(userdn, password):
31
# open a new connection
32
conn = ldap.initialize(cfg.ldap_uri)
33
# bind using the specified credentials
34
conn.simple_bind_s(userdn, password)
35
# perform search for own object (just to do any kind of search)
36
res = conn.search_s(userdn, ldap.SCOPE_BASE, '(objectClass=*)', [ 'dn', ])
38
if entry[0] == userdn:
40
raise ldap.NO_SUCH_OBJECT()
43
class PAMRequest(common.Request):
45
def validate_request(self, parameters):
46
"""This method checks the provided username for validity and fills
47
in the DN if needed."""
48
# check username for validity
49
common.validate_name(parameters['username'])
50
# look up user DN if not known
51
if not parameters['userdn']:
52
entry = passwd.uid2entry(self.conn, parameters['username'])
54
raise ValueError('%r: user not found' % parameters['username'])
56
parameters['userdn'] = entry[0]
57
# get the "real" username
58
value = common.get_rdn_value(entry[0], passwd.attmap['uid'])
60
# get the username from the uid attribute
61
values = myldap_get_values(entry, passwd.attmap['uid'])
62
if not values or not values[0]:
63
logging.warn('%s: is missing a %s attribute', dn, passwd.attmap['uid'])
66
if value and not common.isvalidname(value):
67
raise ValueError('%s: has invalid %s attribute', dn, passwd.attmap['uid'])
68
# check if the username is different and update it if needed
69
if value != parameters['username']:
70
logging.info('username changed from %r to %r', parameters['username'], value)
71
parameters['username'] = value
74
class PAMAuthenticationRequest(PAMRequest):
76
action = constants.NSLCD_ACTION_PAM_AUTHC
78
def read_parameters(self, fp):
79
return dict(username=fp.read_string(),
80
userdn=fp.read_string(),
81
servicename=fp.read_string(),
82
password=fp.read_string())
83
#self.validate_request()
84
# TODO: log call with parameters
86
def write(self, parameters, code=constants.NSLCD_PAM_SUCCESS, msg=''):
87
self.fp.write_int32(constants.NSLCD_RESULT_BEGIN)
88
self.fp.write_string(parameters['username'])
89
self.fp.write_string(parameters['userdn'])
90
self.fp.write_int32(code) # authc
91
self.fp.write_int32(constants.NSLCD_PAM_SUCCESS) # authz
92
self.fp.write_string(msg) # authzmsg
93
self.fp.write_int32(constants.NSLCD_RESULT_END)
95
def handle_request(self, parameters):
96
# if the username is blank and rootpwmoddn is configured, try to
97
# authenticate as administrator, otherwise validate request as usual
98
if not parameters['username'] and cfg.rootpwmoddn:
99
# authenticate as rootpwmoddn
100
userdn = cfg.rootpwmoddn
101
# if the caller is root we will allow the use of rootpwmodpw
102
if not parameters['password'] and self.calleruid == 0 and cfg.rootpwmodpw:
103
password = cfg.rootpwmodpw
105
self.validate_request(parameters)
106
userdn = parameters['userdn']
107
password = parameters['password']
110
try_bind(userdn, password)
111
logging.debug('bind successful')
112
self.write(parameters)
113
except ldap.INVALID_CREDENTIALS, e:
118
logging.debug('bind failed: %s', msg)
119
self.write(parameters, constants.NSLCD_PAM_AUTH_ERR, msg)
121
#class PAMAuthorisationRequest(PAMRequest):
123
# action = constants.NSLCD_ACTION_PAM_AUTHZ
125
# def handle_request(self):
128
#NSLCD_ACTION_PAM_SESS_O
129
#NSLCD_ACTION_PAM_SESS_C
130
#NSLCD_ACTION_PAM_PWMOD