def check_samba_support(host, filt): ''' Check whether host supports Samba's NTLM authentication. ''' ok, msg = Report.PASS, [] if not host.object_class['sambaSamAccount']: msg.append('no object class \'sambaSamAccount\'') return False, {'messages': msg} # sambaDomain seems not necessary, but LDAP Account Manager (LAM) requires it. if host.object_class['sambaDomain']: res, err = ldapsearch(host, '(objectClass=sambaDomain)', 'sambaDomainName') if err or not len(res): msg.append('no \'sambaDomain\' found') else: msg.append('no object class \'sambaDomain\'') unix_users, err = ldapsearch(host, filt, 'dn') if err == 0x00: pass elif err == 0x04: ok = Report.FAIL msg.append('size limit exceeded, ' + str(len(unix_users)) + ' LDAP user(s) recognized') else: msg.append('failed to recognize LDAP user(s)') return False, {'messages': msg} samba_filt = filt if samba_filt[0] != '(': samba_filt = '(' + samba_filt + ')' samba_users, err = ldapsearch(host, '(&' + samba_filt + '(objectClass=sambaSamAccount))', 'dn', 'sambaNTPassword') if err == 0x00: pass elif err == 0x04: ok = Report.FAIL msg.append('size limit exceeded, ' + str(len(samba_users)) + ' Samba account(s) recognized') else: msg.append('failed to recognize Samba account(s)') return False, {'messages': msg} if len(unix_users) != len(samba_users): ok = Report.FAIL msg.append(str(len(unix_users)) + ' LDAP user(s) recognized but only ' + str(len(samba_users)) + ' Samba account(s)') flags = map(lambda x: 'sambaNTPassword' in x, samba_users) if (all(flags)): msg.append(str(len(samba_users)) + ' Samba account(s) recognized') return ok, {'messages': msg} msg.extend([ str(len(samba_users)) + ' Samba account(s) recognized but ' + str(flags.count(False)) + ' without \'sambaNTPassword\', maybe bind DN \'' + host.binddn + '\' does NOT have sufficient privilege' ]) return Report.FAIL, {'messages': msg}
def is_open_directory(host): if not isinstance(host, Host): raise TypeError('bad parameter') res, err = ldapsearch( host, '(&(objectClass=organizationalUnit)(ou=macosxodconfig))', 'dn') return True if err == 0 and len(res) else False
def validate_basedn(host): res, err = ldapsearch(host, '', 'namingContexts', basedn='', scope='base') if err: print >> sys.stderr, 'Error: ' + ldaperror(err) + '\n' return False candidates = [] if len(res) and 'namingContexts' in res[0]: candidates = res[0]['namingContexts'] if host.basedn: if host.basedn not in candidates: print >> sys.stderr, 'Warning: Given base DN \'' + host.basedn + '\' does not match any candidates.' else: if len(candidates) == 0: print >> sys.stderr, 'Error: No available base DN detected, please specify it via \'-b\' option.\n' return False if len(candidates) == 1: host.basedn = candidates[0] else: if not sys.stdin.isatty(): return False # Not in interactive mode. host.basedn = select_basedn(candidates) return True
def is_ibm_domino(host): if not isinstance(host, Host): raise TypeError('bad parameter') res, err = ldapsearch(host, '(objectClass=dominoOrganization)', 'dn', basedn='') return True if err == 0 and len(res) else False
def is_synology(host): if not isinstance(host, Host): raise TypeError('bad parameter') res, err = ldapsearch(host, '', 'dn', basedn='cn=synoconf,' + host.basedn, scope='base') return True if err == 0 and len(res) else False
def is_openldap(host): if not isinstance(host, Host): raise TypeError('bad parameter') res, err = ldapsearch(host, '', 'dn', 'objectClass', basedn='', scope='base') return True if err == 0 and len( res) and 'OpenLDAProotDSE' in res[0]['objectClass'] else False
def check_user_completeness(host, pfilter, sfilter): ok, is_sizelimit, msg = Report.FAIL, False, [] passwd, err = ldapsearch(host, pfilter, 'dn') if err == 0x00: pass elif err == 0x04: is_sizelimit = True else: msg.append('failed to recognize LDAP user(s)') return ok, {'messages': msg} passwd = set(x['dn'] for x in passwd) shadow, err = ldapsearch(host, sfilter, 'dn') if err == 0x00: pass elif err == 0x04: is_sizelimit = True else: msg.append('failed to recognize LDAP user(s)') return ok, {'messages': msg} shadow = set(x['dn'] for x in shadow) if is_sizelimit: msg.append('size limit exceeded') else: ok = Report.PASS if len(passwd - shadow): ok = Report.FAIL msg.append( str(len(passwd - shadow)) + ' potential LDAP user(s) do not match \'' + sfilter + '\'') if len(shadow - passwd): ok = Report.FAIL msg.append( str(len(shadow - passwd)) + ' potential LDAP user(s) do not match \'' + pfilter + '\'') return ok, {'messages': msg}
def check_user_completeness(host, pfilter, sfilter): ok, is_sizelimit, msg = Report.FAIL, False, [] passwd, err = ldapsearch(host, pfilter, 'dn') if err == 0x00: pass elif err == 0x04: is_sizelimit = True else: msg.append('failed to recognize LDAP user(s)') return ok, {'messages': msg} passwd = set(x['dn'] for x in passwd) shadow, err = ldapsearch(host, sfilter, 'dn') if err == 0x00: pass elif err == 0x04: is_sizelimit = True else: msg.append('failed to recognize LDAP user(s)') return ok, {'messages': msg} shadow = set(x['dn'] for x in shadow) if is_sizelimit: msg.append('size limit exceeded') else: ok = Report.PASS if len(passwd - shadow): ok = Report.FAIL msg.append(str(len(passwd - shadow)) + ' potential LDAP user(s) do not match \'' + sfilter + '\'') if len(shadow - passwd): ok = Report.FAIL msg.append(str(len(shadow - passwd)) + ' potential LDAP user(s) do not match \'' + pfilter + '\'') return ok, {'messages': msg}
def __recognize_entries(host, ugfilter, name, ugid, unit): ok, msg = Report.FAIL, [] res, err = ldapsearch(host, ugfilter, 'dn', name, ugid) if err == 0x00: ok = Report.PASS if len(res) else Report.WARN msg.append(str(len(res)) + ' ' + unit + ' recognized') elif err == 0x04: msg.append('size limit exceeded, ' + str(len(res)) + ' ' + unit + ' recognized') else: msg.append('failed to recognize ' + unit) return ok, {'messages': msg} try: if any(map(lambda x: not __is_name_valid(x[name][0]), res)): ok = Report.FAIL msg.append('name(s) of some ' + unit + ' are invalid') except KeyError: ok = Report.FAIL msg.append('some ' + unit + ' have no name(s)') try: if any(map(lambda x: not x[ugid][0].isdigit(), res)): ok = Report.FAIL msg.append('ID(s) of some ' + unit + ' are not numeric') except KeyError: ok = Report.FAIL msg.append('some ' + unit + ' have no numeric ID(s)') try: if len(res) != len(set([x[name][0] for x in res])): ok = Report.FAIL msg.append('name(s) of ' + unit + ' are not unique') if len(res) != len(set([x[ugid][0] for x in res])): ok = Report.FAIL msg.append('ID(s) of ' + unit + ' are not unique') except KeyError: pass # Missing attributes are handled in privious checks. return ok, {'messages': msg}
def __check_id_conflicts(host, ugfilter, ugid, local_ids, unit): ok, msg = Report.FAIL, [] res, err = ldapsearch(host, ugfilter, 'dn', ugid) if err != 0x00 and err != 0x04: msg.append('failed to recognize ' + unit) return ok, {'messages': msg} ok = Report.PASS ids = set(map(lambda x: int(x[ugid][0]), filter(lambda x: ugid in x and x[ugid][0].isdigit(), res))) if len(ids) != len(res): msg.append('some ' + unit + ' have no numeric ID(s)') if len(ids.intersection(local_ids)): ok = Report.FAIL msg.append('some ' + unit + ' have numeric ID conflict with local one(s)') return ok, {'messages': msg}
def __check_id_conflicts(host, ugfilter, ugid, local_ids, unit): ok, msg = Report.FAIL, [] res, err = ldapsearch(host, ugfilter, 'dn', ugid) if err != 0x00 and err != 0x04: msg.append('failed to recognize ' + unit) return ok, {'messages': msg} ok = Report.PASS ids = set( map(lambda x: int(x[ugid][0]), filter(lambda x: ugid in x and x[ugid][0].isdigit(), res))) if len(ids) != len(res): msg.append('some ' + unit + ' have no numeric ID(s)') if len(ids.intersection(local_ids)): ok = Report.FAIL msg.append('some ' + unit + ' have numeric ID conflict with local one(s)') return ok, {'messages': msg}
def is_ibm_domino(host): if not isinstance(host, Host): raise TypeError("bad parameter") res, err = ldapsearch(host, "(objectClass=dominoOrganization)", "dn", basedn="") return True if err == 0 and len(res) else False
def is_openldap(host): if not isinstance(host, Host): raise TypeError("bad parameter") res, err = ldapsearch(host, "", "dn", "objectClass", basedn="", scope="base") return True if err == 0 and len(res) and "OpenLDAProotDSE" in res[0]["objectClass"] else False
def is_open_directory(host): if not isinstance(host, Host): raise TypeError("bad parameter") res, err = ldapsearch(host, "(&(objectClass=organizationalUnit)(ou=macosxodconfig))", "dn") return True if err == 0 and len(res) else False
def is_synology(host): if not isinstance(host, Host): raise TypeError("bad parameter") res, err = ldapsearch(host, "", "dn", basedn="cn=synoconf," + host.basedn, scope="base") return True if err == 0 and len(res) else False
def check_samba_support(host, filt): ''' Check whether host supports Samba's NTLM authentication. ''' ok, msg = Report.PASS, [] if not host.object_class['sambaSamAccount']: msg.append('no object class \'sambaSamAccount\'') return False, {'messages': msg} # sambaDomain seems not necessary, but LDAP Account Manager (LAM) requires it. if host.object_class['sambaDomain']: res, err = ldapsearch(host, '(objectClass=sambaDomain)', 'sambaDomainName') if err or not len(res): msg.append('no \'sambaDomain\' found') else: msg.append('no object class \'sambaDomain\'') unix_users, err = ldapsearch(host, filt, 'dn') if err == 0x00: pass elif err == 0x04: ok = Report.FAIL msg.append('size limit exceeded, ' + str(len(unix_users)) + ' LDAP user(s) recognized') else: msg.append('failed to recognize LDAP user(s)') return False, {'messages': msg} samba_filt = filt if samba_filt[0] != '(': samba_filt = '(' + samba_filt + ')' samba_users, err = ldapsearch( host, '(&' + samba_filt + '(objectClass=sambaSamAccount))', 'dn', 'sambaNTPassword') if err == 0x00: pass elif err == 0x04: ok = Report.FAIL msg.append('size limit exceeded, ' + str(len(samba_users)) + ' Samba account(s) recognized') else: msg.append('failed to recognize Samba account(s)') return False, {'messages': msg} if len(unix_users) != len(samba_users): ok = Report.FAIL msg.append( str(len(unix_users)) + ' LDAP user(s) recognized but only ' + str(len(samba_users)) + ' Samba account(s)') flags = map(lambda x: 'sambaNTPassword' in x, samba_users) if (all(flags)): msg.append(str(len(samba_users)) + ' Samba account(s) recognized') return ok, {'messages': msg} msg.extend([ str(len(samba_users)) + ' Samba account(s) recognized but ' + str(flags.count(False)) + ' without \'sambaNTPassword\', maybe bind DN \'' + host.binddn + '\' does NOT have sufficient privilege' ]) return Report.FAIL, {'messages': msg}