Beispiel #1
0
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}
Beispiel #2
0
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
Beispiel #3
0
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
Beispiel #4
0
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
Beispiel #5
0
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
Beispiel #6
0
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
Beispiel #7
0
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
Beispiel #8
0
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}
Beispiel #9
0
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}
Beispiel #10
0
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}
Beispiel #11
0
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}
Beispiel #12
0
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}
Beispiel #13
0
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}
Beispiel #14
0
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
Beispiel #15
0
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
Beispiel #16
0
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
Beispiel #17
0
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
Beispiel #18
0
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}