/usr/lib/x86_64-linux-gnu/dirsrv/python/failedbinds.py is in 389-ds-base 1.3.7.10-1ubuntu1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | import re
import sys
import os, os.path
# regex that matches a BIND request line
regex_num = r'[-]?\d+' # matches numbers including negative
regex_new_conn = re.compile(r'^(\[.+\]) (conn=%s) (fd=%s) (slot=%s) (?:SSL )?connection from (\S+)' % (regex_num, regex_num, regex_num))
regex_sslinfo = re.compile(r'^\[.+\] (conn=%s) SSL (.+)$' % regex_num)
regex_bind_req = re.compile(r'^(\[.+\]) (conn=%s) (op=%s) BIND dn=(.+) method=(\S+) version=\d ?(?:mech=(\S+))?' % (regex_num, regex_num))
regex_bind_res = re.compile(r'^(\[.+\]) (conn=%s) (op=%s) RESULT err=(%s) tag=97 ' % (regex_num, regex_num, regex_num))
regex_unbind = re.compile(r'^\[.+\] (conn=%s) op=%s UNBIND' % (regex_num, regex_num))
regex_closed = re.compile(r'^(\[.+\]) (conn=%s) (op=%s) fd=%s closed' % (regex_num, regex_num, regex_num))
regex_ssl_map_fail = re.compile(r'^\[.+\] (conn=%s) (SSL failed to map client certificate.*)$' % regex_num)
# bind errors we can ignore
ignore_errors = {'0': 'Success',
'10': 'Referral',
'14': 'SASL Bind In Progress'
}
REQ = 0
RES = 1
class Conn:
def __init__(self, timestamp, conn, fd, slot, ip):
self.conn = conn
self.fd = fd
self.slot = slot
self.ip = ip
self.timestamp = timestamp
self.ops = {}
self.sslinfo = ''
def addssl(self, sslinfo):
if self.sslinfo and sslinfo:
self.sslinfo += ' '
self.sslinfo += sslinfo
def addreq(self, timestamp, opnum, dn, method, mech='SIMPLE'):
retval = None
if opnum in self.ops: # result came before request?
op = self.ops.pop(opnum) # grab the op and remove from list
if op[RES]['errnum'] in ignore_errors: # don't care about this op
return retval
if not mech: mech = "SIMPLE"
op[REQ] = {'dn': dn, 'method': method, 'timestamp': timestamp,
'mech': mech}
retval = self.logstr(opnum, op)
else: # store request until we get the result
op = [None, None] # new empty list
if not mech: mech = "SIMPLE"
op[REQ] = {'dn': dn, 'method': method, 'timestamp': timestamp,
'mech': mech}
self.ops[opnum] = op
return retval
def addres(self, timestamp, opnum, errnum):
retval = None
if opnum in self.ops:
op = self.ops.pop(opnum) # grab the op and remove from list
if errnum in ignore_errors: # don't care about this op
return retval
op[RES] = {'errnum': errnum, 'timestamp': timestamp}
retval = self.logstr(opnum, op)
else: # result came before request in access log - store until we find request
op = [None, None] # new empty list
op[RES] = {'errnum': errnum, 'timestamp': timestamp}
self.ops[opnum] = op
return retval
def logstr(self, opnum, op):
# timestamp connnum opnum err=X request timestamp dn=Y method=Z mech=W timestamp ip=ip
logstr = '%s %s %s err=%s REQUEST %s dn=%s method=%s mech=%s %s ip=%s extra=%s' % (
op[RES]['timestamp'], self.conn, opnum, op[RES]['errnum'],
op[REQ]['timestamp'], op[REQ]['dn'], op[REQ]['method'], op[REQ]['mech'],
self.timestamp, self.ip, self.sslinfo
)
return logstr
# key is conn=X
# val is ops hash
# key is op=Y
# value is list
# list[0] is BIND request
# list[1] is RESULT
conns = {}
# file to log failed binds to
logf = None
def pre(plgargs):
global logf
logfile = plgargs.get('logfile', None)
if not logfile:
print("Error: missing required argument failedbinds.logfile")
return False
needchmod = False
if not os.path.isfile(logfile): needchmod = True
if sys.version_info < (3, 0):
logf = open(logfile, 'a', 0) # 0 for unbuffered output
else:
logf = open(logfile, 'a')
if needchmod: os.chmod(logfile, 0o600)
return True
def post():
global logf
logf.close()
logf = None
def plugin(line):
# is this a new conn line?
match = regex_new_conn.match(line)
if match:
(timestamp, connid, fdid, slotid, ip) = match.groups()
if connid in conns: conns.pop(connid) # remove old one, if any
conn = Conn(timestamp, connid, fdid, slotid, ip)
conns[connid] = conn
return True
# is this an UNBIND line?
match = regex_unbind.match(line)
if match:
connid = match.group(1)
if connid in conns: conns.pop(connid) # remove it
return True
# is this a closed line?
match = regex_closed.match(line)
if match:
(timestamp, connid, opid) = match.groups()
if connid in conns: conns.pop(connid) # remove it
return True
# is this an SSL info line?
match = regex_sslinfo.match(line)
if match:
(connid, sslinfo) = match.groups()
if connid in conns:
conns[connid].addssl(sslinfo)
return True
# is this a line with extra SSL mapping info?
match = regex_ssl_map_fail.match(line)
if match:
(connid, sslinfo) = match.groups()
if connid in conns:
conns[connid].addssl(sslinfo)
return True
# is this a REQUEST line?
match = regex_bind_req.match(line)
if match:
(timestamp, connid, opnum, dn, method, mech) = match.groups()
# should have seen new conn line - if not, have to create a dummy one
conn = conns.get(connid, Conn('unknown', connid, '', '', 'unknown'))
logmsg = conn.addreq(timestamp, opnum, dn, method, mech)
if logmsg:
logf.write(logmsg + "\n")
logf.flush()
return True
# is this a RESULT line?
match = regex_bind_res.match(line)
if match:
(timestamp, connid, opnum, errnum) = match.groups()
# should have seen new conn line - if not, have to create a dummy one
conn = conns.get(connid, Conn('unknown', connid, '', '', 'unknown'))
logmsg = conn.addres(timestamp, opnum, errnum)
if logmsg:
logf.write(logmsg + "\n")
logf.flush()
return True
return True # no match
|