#pike __REAL_VERSION__ |
|
|
#include "ldap_globals.h" |
|
import "."; |
|
|
|
|
|
|
constant LDAP_SUCCESS = 0x00; |
constant LDAP_OPERATIONS_ERROR = 0x01; |
constant LDAP_PROTOCOL_ERROR = 0x02; |
constant LDAP_TIMELIMIT_EXCEEDED = 0x03; |
constant LDAP_SIZELIMIT_EXCEEDED = 0x04; |
constant LDAP_COMPARE_FALSE = 0x05; |
constant LDAP_COMPARE_TRUE = 0x06; |
constant LDAP_AUTH_METHOD_NOT_SUPPORTED = 0x07; |
constant LDAP_STRONG_AUTH_NOT_SUPPORTED = LDAP_AUTH_METHOD_NOT_SUPPORTED; |
constant LDAP_STRONG_AUTH_REQUIRED = 0x08; |
constant LDAP_PARTIAL_RESULTS = 0x09; |
constant LDAP_REFERRAL = 0x0a; |
constant LDAP_ADMINLIMIT_EXCEEDED = 0x0b; |
constant LDAP_UNAVAILABLE_CRITICAL_EXTENSION = 0x0c; |
constant LDAP_CONFIDENTIALITY_REQUIRED = 0x0d; |
constant LDAP_SASL_BIND_IN_PROGRESS = 0x0e; |
constant LDAP_NO_SUCH_ATTRIBUTE = 0x10; |
constant LDAP_UNDEFINED_TYPE = 0x11; |
constant LDAP_INAPPROPRIATE_MATCHING = 0x12; |
constant LDAP_CONSTRAINT_VIOLATION = 0x13; |
constant LDAP_TYPE_OR_VALUE_EXISTS = 0x14; |
constant LDAP_INVALID_SYNTAX = 0x15; |
constant LDAP_NO_SUCH_OBJECT = 0x20; |
constant LDAP_ALIAS_PROBLEM = 0x21; |
constant LDAP_INVALID_DN_SYNTAX = 0x22; |
constant LDAP_IS_LEAF = 0x23; |
constant LDAP_ALIAS_DEREF_PROBLEM = 0x24; |
constant LDAP_INAPPROPRIATE_AUTH = 0x30; |
constant LDAP_INVALID_CREDENTIALS = 0x31; |
constant LDAP_INSUFFICIENT_ACCESS = 0x32; |
constant LDAP_BUSY = 0x33; |
constant LDAP_UNAVAILABLE = 0x34; |
constant LDAP_UNWILLING_TO_PERFORM = 0x35; |
constant LDAP_LOOP_DETECT = 0x36; |
constant LDAP_SORT_CONTROL_MISSING = 0x3C; |
constant LDAP_NAMING_VIOLATION = 0x40; |
constant LDAP_OBJECT_CLASS_VIOLATION = 0x41; |
constant LDAP_NOT_ALLOWED_ON_NONLEAF = 0x42; |
constant LDAP_NOT_ALLOWED_ON_RDN = 0x43; |
constant LDAP_ALREADY_EXISTS = 0x44; |
constant LDAP_NO_OBJECT_CLASS_MODS = 0x45; |
constant LDAP_RESULTS_TOO_LARGE = 0x46; |
constant LDAP_AFFECTS_MULTIPLE_DSAS = 0x47; |
constant LDAP_OTHER = 0x50; |
|
|
|
constant LDAP_SERVER_DOWN = 0x51; |
constant LDAP_LOCAL_ERROR = 0x52; |
constant LDAP_ENCODING_ERROR = 0x53; |
constant LDAP_DECODING_ERROR = 0x54; |
constant LDAP_TIMEOUT = 0x55; |
constant LDAP_AUTH_UNKNOWN = 0x56; |
constant LDAP_FILTER_ERROR = 0x57; |
constant LDAP_USER_CANCELLED = 0x58; |
constant LDAP_PARAM_ERROR = 0x59; |
constant LDAP_NO_MEMORY = 0x5a; |
|
constant LDAP_CONNECT_ERROR = 0x5b; |
constant LDAP_NOT_SUPPORTED = 0x5c; |
constant LDAP_CONTROL_NOT_FOUND = 0x5d; |
constant LDAP_NO_RESULTS_RETURNED = 0x5e; |
constant LDAP_MORE_RESULTS_TO_RETURN = 0x5f; |
constant LDAP_CLIENT_LOOP = 0x60; |
constant LDAP_REFERRAL_LIMIT_EXCEEDED = 0x61; |
constant LCUP_RESOURCES_EXHAUSTED = 0x71; |
constant LCUP_SECURITY_VIOLATION = 0x72; |
constant LCUP_INVALID_DATA = 0x73; |
constant LCUP_UNSUPPORTED_SCHEME = 0x74; |
constant LCUP_RELOAD_REQUIRED = 0x75; |
constant LDAP_CANCELED = 0x76; |
constant LDAP_NO_SUCH_OPERATION = 0x77; |
constant LDAP_TOO_LATE = 0x78; |
constant LDAP_CANNOT_CANCEL = 0x79; |
constant LDAP_ASSERTION_FAILED = 0x7a; |
constant LDAP_AUTHORIZATION_DENIED = 0x7b; |
|
|
constant ldap_error_strings = ([ |
LDAP_SUCCESS: "Success", |
LDAP_OPERATIONS_ERROR: "Operations error", |
LDAP_PROTOCOL_ERROR: "Protocol error", |
LDAP_TIMELIMIT_EXCEEDED: "Timelimit exceeded", |
LDAP_SIZELIMIT_EXCEEDED: "Sizelimit exceeded", |
LDAP_COMPARE_FALSE: "Compare false", |
LDAP_COMPARE_TRUE: "Compare true", |
LDAP_AUTH_METHOD_NOT_SUPPORTED: "Auth method not supported", |
LDAP_STRONG_AUTH_REQUIRED: "Strong auth required", |
LDAP_PARTIAL_RESULTS: "Partial results", |
LDAP_REFERRAL: "Referral", |
LDAP_ADMINLIMIT_EXCEEDED: "Adminlimit exceeded", |
LDAP_UNAVAILABLE_CRITICAL_EXTENSION: "Unavailable critical extension", |
LDAP_CONFIDENTIALITY_REQUIRED: "Confidentiality required", |
LDAP_SASL_BIND_IN_PROGRESS: "SASL bind in progress", |
|
LDAP_NO_SUCH_ATTRIBUTE: "No such attribute", |
LDAP_UNDEFINED_TYPE: "Undefined type", |
LDAP_INAPPROPRIATE_MATCHING: "Inappropriate matching", |
LDAP_CONSTRAINT_VIOLATION: "Constraint violation", |
LDAP_TYPE_OR_VALUE_EXISTS: "Type or value exists", |
LDAP_INVALID_SYNTAX: "Invalid syntax", |
|
LDAP_NO_SUCH_OBJECT: "No such object", |
LDAP_ALIAS_PROBLEM: "Alias problem", |
LDAP_INVALID_DN_SYNTAX: "Invalid DN syntax", |
LDAP_IS_LEAF: "Is leaf", |
LDAP_ALIAS_DEREF_PROBLEM: "Alias deref problem", |
|
LDAP_INAPPROPRIATE_AUTH: "Inappropriate auth", |
LDAP_INVALID_CREDENTIALS: "Invalid credentials", |
LDAP_INSUFFICIENT_ACCESS: "Insufficient access", |
LDAP_BUSY: "Busy", |
LDAP_UNAVAILABLE: "Unavailable", |
LDAP_UNWILLING_TO_PERFORM: "Unwilling to perform", |
LDAP_LOOP_DETECT: "Loop detect", |
|
LDAP_SORT_CONTROL_MISSING: "Sort control missing", |
|
LDAP_NAMING_VIOLATION: "Naming violation", |
LDAP_OBJECT_CLASS_VIOLATION: "Object class violation", |
LDAP_NOT_ALLOWED_ON_NONLEAF: "Not allowed on nonleaf", |
LDAP_NOT_ALLOWED_ON_RDN: "Not allowed on RDN", |
LDAP_ALREADY_EXISTS: "Already exists", |
LDAP_NO_OBJECT_CLASS_MODS: "No object class mods", |
LDAP_RESULTS_TOO_LARGE: "Results too large", |
LDAP_AFFECTS_MULTIPLE_DSAS: "Affects multiple DSAS", |
|
LDAP_OTHER: "Other str", |
LDAP_SERVER_DOWN: "Server is down", |
LDAP_LOCAL_ERROR: "Internal/local error", |
LDAP_ENCODING_ERROR: "Encoding error", |
LDAP_DECODING_ERROR: "Decoding error", |
LDAP_TIMEOUT: "Timeout", |
LDAP_AUTH_UNKNOWN: "Auth unknown", |
LDAP_FILTER_ERROR: "Filter error", |
LDAP_USER_CANCELLED: "User cancelled", |
LDAP_PARAM_ERROR: "Param error", |
LDAP_NO_MEMORY: "No memory", |
LDAP_CONNECT_ERROR: "Connect error", |
LDAP_NOT_SUPPORTED: "Not supported", |
LDAP_CONTROL_NOT_FOUND: "Control not found", |
LDAP_NO_RESULTS_RETURNED: "No results returned", |
LDAP_MORE_RESULTS_TO_RETURN: "More results to return", |
LDAP_CLIENT_LOOP: "Client loop", |
LDAP_REFERRAL_LIMIT_EXCEEDED: "Referral limit exceeded", |
]); |
|
constant SEARCH_LOWER_ATTRS = 1; |
constant SEARCH_MULTIVAL_ARRAYS_ONLY = 2; |
constant SEARCH_RETURN_DECODE_ERRORS = 4; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constant SCOPE_BASE = 0; |
constant SCOPE_ONE = 1; |
constant SCOPE_SUB = 2; |
|
|
|
|
|
|
|
|
|
|
|
|
|
constant MODIFY_ADD = 0; |
constant MODIFY_DELETE = 1; |
constant MODIFY_REPLACE = 2; |
|
|
|
string ldap_encode_string (string str) |
|
|
|
|
|
|
|
|
|
|
{ |
return replace (str, |
({"\0", "#", "$", "'", "(", ")", "*", "\\"}), |
({"\\00", "\\23", "\\24", "\\27", "\\28", "\\29", "\\2a", "\\5c"})); |
} |
|
string ldap_decode_string (string str) |
|
|
|
|
{ |
string rest = str, res = ""; |
while (1) { |
sscanf (rest, "%[^\\]%s", string val, rest); |
res += val; |
if (rest == "") break; |
|
if (sscanf (rest, "\\%1x%1x%s", int high, int low, rest) == 3) |
|
|
res += sprintf ("%c", (high << 4) + low); |
else { |
|
|
|
res += "\\"; |
rest = rest[1..]; |
} |
} |
return res; |
} |
|
string encode_dn_value (string str) |
|
|
|
|
|
|
|
|
{ |
str = replace (str, |
({",", "+", "\"", "\\", "<", ">", ";"}), |
({"\\,", "\\+", "\\\"", "\\\\", "\\<", "\\>", "\\;"})); |
if (has_suffix (str, " ")) |
str = str[..<1] + "\\ "; |
if (has_prefix (str, " ") || has_prefix (str, "#")) |
str = "\\" + str; |
return str; |
} |
|
string canonicalize_dn (string dn, void|int strict) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
string rest = dn, tmp_rest = rest, res = ""; |
array(string) last_rdn = ({}); |
|
parse_loop: |
while (1) { |
|
|
string attr; |
if (sscanf (tmp_rest, "%*[ ]%[-A-Za-z0-9.]%*[ ]=%*[ ]%s", attr, tmp_rest) != 5) |
break parse_loop; |
if (strict && attr == "") |
break parse_loop; |
attr = lower_case (attr); |
if (sscanf (attr, "oid.%*[0-9.]%*c") == 1) |
attr = attr[sizeof ("oid.")..]; |
|
|
|
string val; |
|
if (has_prefix (tmp_rest, "#")) { |
sscanf (tmp_rest, "#%[0-9A-Fa-f]%s", val, tmp_rest); |
if (strict && val == "") |
break parse_loop; |
|
last_rdn += ({attr + "=#" + lower_case (val)}); |
rest = tmp_rest; |
} |
|
else { |
string val_fmt; |
int quoted = has_prefix (tmp_rest, "\""); |
|
if (quoted) { |
val_fmt = "%[^\\\" ]%[ ]%s"; |
tmp_rest = tmp_rest[1..]; |
} |
else |
val_fmt = "%[^,=+<>#;\\\" ]%[ ]%s"; |
|
val = ""; |
string ws = ""; |
while (1) { |
sscanf (tmp_rest, val_fmt, string piece, ws, tmp_rest); |
val += piece; |
if (ws != "") |
while (1) { |
sscanf (tmp_rest, val_fmt, piece, string new_ws, tmp_rest); |
if (piece == "") break; |
val += ws + piece; |
ws = new_ws; |
} |
if (!has_prefix (tmp_rest, "\\")) break; |
val += ws; |
if (sscanf (tmp_rest, "\\%1x%1x%s", int high, int low, tmp_rest) == 3) |
|
|
val += sprintf ("%c", (high << 4) + low); |
else { |
string quoted; |
if (sscanf (tmp_rest, "\\%1s%s", quoted, tmp_rest) != 2) |
break parse_loop; |
if (strict && !(<",", "=", "+", "<", ">", "#", ";", "\\", "\"", " ">)[quoted]) |
break parse_loop; |
val += quoted; |
} |
} |
|
if (quoted) { |
if (has_prefix (tmp_rest, "\"")) { |
val += ws; |
sscanf (tmp_rest, "\"%*[ ]%s", tmp_rest); |
} |
else |
break parse_loop; |
} |
|
last_rdn += ({attr + "=" + encode_dn_value (val)}); |
rest = tmp_rest; |
} |
|
|
|
string sep = tmp_rest[..0]; |
|
if (sep == "," || sep == ";") { |
|
if (sizeof (last_rdn)) { |
sort (last_rdn); |
if (res != "") res += "," + (last_rdn * "+"); |
else res = last_rdn * "+"; |
last_rdn = ({}); |
} |
} |
|
else if (sep != "+") |
break; |
|
tmp_rest = tmp_rest[1..]; |
} |
|
if (sizeof (last_rdn)) { |
sort (last_rdn); |
if (res) res += "," + (last_rdn * "+"); |
else res = last_rdn * "+"; |
} |
|
if (rest != "") { |
if (strict) |
ERROR ("Syntax error at or after position %d in DN %O.\n", |
sizeof (dn) - sizeof (rest), dn); |
else |
res += rest; |
} |
|
|
return res; |
} |
|
|
|
|
|
|
constant LDAP_CONTROL_MANAGE_DSA_IT = "2.16.840.1.113730.3.4.2"; |
|
|
|
|
constant LDAP_CONTROL_VLVREQUEST = "2.16.840.1.113730.3.4.9"; |
|
|
|
|
constant LDAP_CONTROL_VLVRESPONSE = "2.16.840.1.113730.3.4.10"; |
|
|
|
|
constant LDAP_PAGED_RESULT_OID_STRING = "1.2.840.113556.1.4.319"; |
|
|
|
|
constant LDAP_SERVER_ASQ_OID = "1.2.840.113556.1.4.1504"; |
|
|
|
constant LDAP_SERVER_CROSSDOM_MOVE_TARGET_OID = "1.2.840.113556.1.4.521"; |
|
|
|
constant LDAP_SERVER_DIRSYNC_OID = "1.2.840.113556.1.4.841"; |
|
|
|
constant LDAP_SERVER_DOMAIN_SCOPE_OID = "1.2.840.113556.1.4.1339"; |
|
|
|
constant LDAP_SERVER_EXTENDED_DN_OID = "1.2.840.113556.1.4.529"; |
|
|
|
constant LDAP_SERVER_LAZY_COMMIT_OID = "1.2.840.113556.1.4.619"; |
|
|
|
|
|
constant LDAP_SERVER_NOTIFICATION_OID = "1.2.840.113556.1.4.528"; |
|
|
|
|
constant LDAP_SERVER_PERMISSIVE_MODIFY_OID = "1.2.840.113556.1.4.1413"; |
|
|
|
|
|
|
|
|
constant LDAP_SERVER_QUOTA_CONTROL_OID = "1.2.840.113556.1.4.1852"; |
|
|
|
|
constant LDAP_SERVER_RESP_SORT_OID = "1.2.840.113556.1.4.474"; |
|
|
|
|
constant LDAP_SERVER_SD_FLAGS_OID = "1.2.840.113556.1.4.801"; |
|
|
|
constant LDAP_SERVER_SEARCH_OPTIONS_OID = "1.2.840.113556.1.4.1340"; |
|
|
|
constant LDAP_SERVER_SHOW_DELETED_OID = "1.2.840.113556.1.4.417"; |
|
|
|
|
constant LDAP_SERVER_SORT_OID = "1.2.840.113556.1.4.473"; |
|
|
|
|
constant LDAP_SERVER_TREE_DELETE_OID = "1.2.840.113556.1.4.805"; |
|
|
|
constant LDAP_SERVER_VERIFY_NAME_OID = "1.2.840.113556.1.4.1338"; |
|
|
|
|
|
|
constant SYNTAX_ATTR_TYPE_DESCR = "1.3.6.1.4.1.1466.115.121.1.3"; |
constant SYNTAX_BINARY = "1.3.6.1.4.1.1466.115.121.1.5"; |
constant SYNTAX_BIT_STRING = "1.3.6.1.4.1.1466.115.121.1.6"; |
constant SYNTAX_BOOLEAN = "1.3.6.1.4.1.1466.115.121.1.7"; |
constant SYNTAX_CERT = "1.3.6.1.4.1.1466.115.121.1.8"; |
constant SYNTAX_CERT_LIST = "1.3.6.1.4.1.1466.115.121.1.9"; |
constant SYNTAX_CERT_PAIR = "1.3.6.1.4.1.1466.115.121.1.10"; |
constant SYNTAX_COUNTRY_STR = "1.3.6.1.4.1.1466.115.121.1.11"; |
constant SYNTAX_DN = "1.3.6.1.4.1.1466.115.121.1.12"; |
constant SYNTAX_DIRECTORY_STR = "1.3.6.1.4.1.1466.115.121.1.15"; |
constant SYNTAX_DIT_CONTENT_RULE_DESCR = "1.3.6.1.4.1.1466.115.121.1.16"; |
constant SYNTAX_FACSIMILE_PHONE_NUM = "1.3.6.1.4.1.1466.115.121.1.22"; |
constant SYNTAX_FAX = "1.3.6.1.4.1.1466.115.121.1.23"; |
constant SYNTAX_GENERALIZED_TIME = "1.3.6.1.4.1.1466.115.121.1.24"; |
constant SYNTAX_IA5_STR = "1.3.6.1.4.1.1466.115.121.1.26"; |
constant SYNTAX_INT = "1.3.6.1.4.1.1466.115.121.1.27"; |
constant SYNTAX_JPEG = "1.3.6.1.4.1.1466.115.121.1.28"; |
constant SYNTAX_MATCHING_RULE_DESCR = "1.3.6.1.4.1.1466.115.121.1.30"; |
constant SYNTAX_MATCHING_RULE_USE_DESCR = "1.3.6.1.4.1.1466.115.121.1.31"; |
constant SYNTAX_MHS_OR_ADDR = "1.3.6.1.4.1.1466.115.121.1.33"; |
constant SYNTAX_NAME_AND_OPTIONAL_UID = "1.3.6.1.4.1.1466.115.121.1.34"; |
constant SYNTAX_NAME_FORM_DESCR = "1.3.6.1.4.1.1466.115.121.1.35"; |
constant SYNTAX_NUMERIC_STRING = "1.3.6.1.4.1.1466.115.121.1.36"; |
constant SYNTAX_OBJECT_CLASS_DESCR = "1.3.6.1.4.1.1466.115.121.1.37"; |
constant SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.38"; |
constant SYNTAX_OTHER_MAILBOX = "1.3.6.1.4.1.1466.115.121.1.39"; |
constant SYNTAX_POSTAL_ADDR = "1.3.6.1.4.1.1466.115.121.1.41"; |
constant SYNTAX_PRESENTATION_ADDR = "1.3.6.1.4.1.1466.115.121.1.43"; |
constant SYNTAX_PRINTABLE_STR = "1.3.6.1.4.1.1466.115.121.1.44"; |
constant SYNTAX_PHONE_NUM = "1.3.6.1.4.1.1466.115.121.1.50"; |
constant SYNTAX_UTC_TIME = "1.3.6.1.4.1.1466.115.121.1.53"; |
constant SYNTAX_LDAP_SYNTAX_DESCR = "1.3.6.1.4.1.1466.115.121.1.54"; |
constant SYNTAX_DIT_STRUCTURE_RULE_DESCR = "1.3.6.1.4.1.1466.115.121.1.17"; |
|
|
constant SYNTAX_CASE_EXACT_STR = SYNTAX_DIRECTORY_STR; |
|
|
constant SYNTAX_DELIVERY_METHOD = "1.3.6.1.4.1.1466.115.121.1.14"; |
constant SYNTAX_ENHANCED_GUIDE = "1.3.6.1.4.1.1466.115.121.1.21"; |
constant SYNTAX_GUIDE = "1.3.6.1.4.1.1466.115.121.1.25"; |
constant SYNTAX_OCTET_STR = "1.3.6.1.4.1.1466.115.121.1.40"; |
constant SYNTAX_TELETEX_TERMINAL_ID = "1.3.6.1.4.1.1466.115.121.1.51"; |
constant SYNTAX_TELETEX_NUM = "1.3.6.1.4.1.1466.115.121.1.52"; |
constant SYNTAX_SUPPORTED_ALGORITHM = "1.3.6.1.4.1.1466.115.121.1.49"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constant SYNTAX_AD_DN_WITH_OCTET_STR = "1.2.840.113556.1.4.903"; |
constant SYNTAX_AD_DN_WITH_STR = "1.2.840.113556.1.4.904"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constant SYNTAX_AD_CASE_IGNORE_STR = "1.2.840.113556.1.4.905"; |
constant SYNTAX_AD_LARGE_INT = "1.2.840.113556.1.4.906"; |
constant SYNTAX_AD_OBJECT_SECURITY_DESCRIPTOR = "1.2.840.113556.1.4.907"; |
|
|
|
|
constant syntax_decode_fns = ([ |
SYNTAX_DN: utf8_to_string, |
SYNTAX_DIRECTORY_STR: utf8_to_string, |
SYNTAX_DIT_CONTENT_RULE_DESCR: utf8_to_string, |
SYNTAX_MATCHING_RULE_DESCR: utf8_to_string, |
SYNTAX_MATCHING_RULE_USE_DESCR: utf8_to_string, |
SYNTAX_NAME_AND_OPTIONAL_UID: utf8_to_string, |
SYNTAX_NAME_FORM_DESCR: utf8_to_string, |
SYNTAX_OBJECT_CLASS_DESCR: utf8_to_string, |
SYNTAX_POSTAL_ADDR: utf8_to_string, |
SYNTAX_LDAP_SYNTAX_DESCR: utf8_to_string, |
SYNTAX_DIT_STRUCTURE_RULE_DESCR: utf8_to_string, |
SYNTAX_AD_DN_WITH_OCTET_STR: utf8_to_string, |
SYNTAX_AD_DN_WITH_STR: utf8_to_string, |
]); |
|
|
|
|
|
|
|
|
|
|
|
constant syntax_encode_fns = ([]); |
|
|
|
|
|
|
|
|
constant ATD_createTimestamp = ([ |
"oid": "2.5.18.1", |
"NAME": ({"createTimestamp"}), |
"EQUALITY": "generalizedTimeMatch", |
"ORDERING": "generalizedTimeOrderingMatch", |
"syntax_oid": SYNTAX_GENERALIZED_TIME, |
"SINGLE-VALUE": 1, |
"NO-USER-MODIFICATION": 1, |
"USAGE": "directoryOperation", |
]); |
constant ATD_modifyTimestamp = ([ |
"oid": "2.5.18.2", |
"NAME": ({"modifyTimestamp"}), |
"EQUALITY": "generalizedTimeMatch", |
"ORDERING": "generalizedTimeOrderingMatch", |
"syntax_oid": SYNTAX_GENERALIZED_TIME, |
"SINGLE-VALUE": 1, |
"NO-USER-MODIFICATION": 1, |
"USAGE": "directoryOperation", |
]); |
constant ATD_creatorsName = ([ |
"oid": "2.5.18.3", |
"NAME": ({"creatorsName"}), |
"EQUALITY": "distinguishedNameMatch", |
"syntax_oid": SYNTAX_DN, |
"SINGLE-VALUE": 1, |
"NO-USER-MODIFICATION": 1, |
"USAGE": "directoryOperation", |
]); |
constant ATD_modifiersName = ([ |
"oid": "2.5.18.4", |
"NAME": ({"modifiersName"}), |
"EQUALITY": "distinguishedNameMatch", |
"syntax_oid": SYNTAX_DN, |
"SINGLE-VALUE": 1, |
"NO-USER-MODIFICATION": 1, |
"USAGE": "directoryOperation", |
]); |
constant ATD_subschemaSubentry = ([ |
"oid": "2.5.18.10", |
"NAME": ({"subschemaSubentry"}), |
"EQUALITY": "distinguishedNameMatch", |
"syntax_oid": SYNTAX_DN, |
"SINGLE-VALUE": 1, |
"NO-USER-MODIFICATION": 1, |
"USAGE": "directoryOperation", |
]); |
constant ATD_attributeTypes = ([ |
"oid": "2.5.21.5", |
"NAME": ({"attributeTypes"}), |
"EQUALITY": "objectIdentifierFirstComponentMatch", |
"syntax_oid": SYNTAX_ATTR_TYPE_DESCR, |
"USAGE": "directoryOperation", |
]); |
constant ATD_objectClasses = ([ |
"oid": "2.5.21.6", |
"NAME": ({"objectClasses"}), |
"EQUALITY": "objectIdentifierFirstComponentMatch", |
"syntax_oid": SYNTAX_OBJECT_CLASS_DESCR, |
"USAGE": "directoryOperation", |
]); |
constant ATD_matchingRules = ([ |
"oid": "2.5.21.4", |
"NAME": ({"matchingRules"}), |
"EQUALITY": "objectIdentifierFirstComponentMatch", |
"syntax_oid": SYNTAX_MATCHING_RULE_DESCR, |
"USAGE": "directoryOperation", |
]); |
constant ATD_matchingRuleUse = ([ |
"oid": "2.5.21.8", |
"NAME": ({"matchingRuleUse"}), |
"EQUALITY": "objectIdentifierFirstComponentMatch", |
"syntax_oid": SYNTAX_MATCHING_RULE_USE_DESCR, |
"USAGE": "directoryOperation", |
]); |
constant ATD_namingContexts = ([ |
"oid": "1.3.6.1.4.1.1466.101.120.5", |
"NAME": ({"namingContexts"}), |
"syntax_oid": SYNTAX_DN, |
"USAGE": "dSAOperation", |
]); |
constant ATD_altServer = ([ |
"oid": "1.3.6.1.4.1.1466.101.120.6", |
"NAME": ({"altServer"}), |
"syntax_oid": SYNTAX_IA5_STR, |
"USAGE": "dSAOperation", |
]); |
constant ATD_supportedExtension = ([ |
"oid": "1.3.6.1.4.1.1466.101.120.7", |
"NAME": ({"supportedExtension"}), |
"syntax_oid": SYNTAX_OID, |
"USAGE": "dSAOperation", |
]); |
constant ATD_supportedControl = ([ |
"oid": "1.3.6.1.4.1.1466.101.120.13", |
"NAME": ({"supportedControl"}), |
"syntax_oid": SYNTAX_OID, |
"USAGE": "dSAOperation", |
]); |
constant ATD_supportedSASLMechanisms = ([ |
"oid": "1.3.6.1.4.1.1466.101.120.14", |
"NAME": ({"supportedSASLMechanisms"}), |
"syntax_oid": SYNTAX_DIRECTORY_STR, |
"USAGE": "dSAOperation", |
]); |
constant ATD_supportedLDAPVersion = ([ |
"oid": "1.3.6.1.4.1.1466.101.120.15", |
"NAME": ({"supportedLDAPVersion"}), |
"syntax_oid": SYNTAX_INT, |
"USAGE": "dSAOperation", |
]); |
constant ATD_ldapSyntaxes = ([ |
"oid": "1.3.6.1.4.1.1466.101.120.16", |
"NAME": ({"ldapSyntaxes"}), |
"EQUALITY": "objectIdentifierFirstComponentMatch", |
"syntax_oid": SYNTAX_LDAP_SYNTAX_DESCR, |
"USAGE": "directoryOperation", |
]); |
constant ATD_dITStructureRules = ([ |
"oid": "2.5.21.1", |
"NAME": ({"dITStructureRules"}), |
"EQUALITY": "integerFirstComponentMatch", |
"syntax_oid": SYNTAX_DIT_STRUCTURE_RULE_DESCR, |
"USAGE": "directoryOperation", |
]); |
constant ATD_nameForms = ([ |
"oid": "2.5.21.7", |
"NAME": ({"nameForms"}), |
"EQUALITY": "objectIdentifierFirstComponentMatch", |
"syntax_oid": SYNTAX_NAME_FORM_DESCR, |
"USAGE": "directoryOperation", |
]); |
constant ATD_ditContentRules = ([ |
"oid": "2.5.21.2", |
"NAME": ({"dITContentRules"}), |
"EQUALITY": "objectIdentifierFirstComponentMatch", |
"syntax_oid": SYNTAX_DIT_CONTENT_RULE_DESCR, |
"USAGE": "directoryOperation", |
]); |
|
constant ATD_objectClass = ([ |
"oid": "2.5.4.0", |
"NAME": ({"objectClass"}), |
"EQUALITY": "objectIdentifierMatch", |
"syntax_oid": SYNTAX_OID, |
]); |
constant ATD_aliasedObjectName = ([ |
"oid": "2.5.4.1", |
"NAME": ({"aliasedObjectName"}), |
"EQUALITY": "distinguishedNameMatch", |
"syntax_oid": SYNTAX_DN, |
"SINGLE-VALUE": 1, |
]); |
constant ATD_knowledgeInformation = ([ |
"oid": "2.5.4.2", |
"NAME": ({"knowledgeInformation"}), |
"EQUALITY": "caseIgnoreMatch", |
"syntax_oid": SYNTAX_DIRECTORY_STR, |
"syntax_len": 32768, |
]); |
constant ATD_cn = ([ |
"oid": "2.5.4.3", |
"NAME": ({"cn"}), |
"SUP": "name", |
]); |
constant ATD_sn = ([ |
"oid": "2.5.4.4", |
"NAME": ({"sn"}), |
"SUP": "name", |
]); |
constant ATD_serialNumber = ([ |
"oid": "2.5.4.5", |
"NAME": ({"serialNumber"}), |
"EQUALITY": "caseIgnoreMatch", |
"SUBSTR": "caseIgnoreSubstringsMatch", |
"syntax_oid": SYNTAX_PRINTABLE_STR, |
"syntax_len": 64, |
]); |
constant ATD_c = ([ |
"oid": "2.5.4.6", |
"NAME": ({"c"}), |
"SUP": "name", |
"SINGLE-VALUE": 1, |
]); |
constant ATD_l = ([ |
"oid": "2.5.4.7", |
"NAME": ({"l"}), |
"SUP": "name", |
]); |
constant ATD_st = ([ |
"oid": "2.5.4.8", |
"NAME": ({"st"}), |
"SUP": "name", |
]); |
constant ATD_street = ([ |
"oid": "2.5.4.9", |
"NAME": ({"street"}), |
"EQUALITY": "caseIgnoreMatch", |
"SUBSTR": "caseIgnoreSubstringsMatch", |
"syntax_oid": SYNTAX_DIRECTORY_STR, |
"syntax_len": 128, |
]); |
constant ATD_o = ([ |
"oid": "2.5.4.10", |
"NAME": ({"o"}), |
"SUP": "name", |
]); |
constant ATD_ou = ([ |
"oid": "2.5.4.11", |
"NAME": ({"ou"}), |
"SUP": "name", |
]); |
constant ATD_title = ([ |
"oid": "2.5.4.12", |
"NAME": ({"title"}), |
"SUP": "name", |
]); |
constant ATD_description = ([ |
"oid": "2.5.4.13", |
"NAME": ({"description"}), |
"EQUALITY": "caseIgnoreMatch", |
"SUBSTR": "caseIgnoreSubstringsMatch", |
"syntax_oid": SYNTAX_DIRECTORY_STR, |
"syntax_len": 1024, |
]); |
constant ATD_searchGuide = ([ |
"oid": "2.5.4.14", |
"NAME": ({"searchGuide"}), |
"syntax_oid": SYNTAX_GUIDE, |
]); |
constant ATD_businessCategory = ([ |
"oid": "2.5.4.15", |
"NAME": ({"businessCategory"}), |
"EQUALITY": "caseIgnoreMatch", |
"SUBSTR": "caseIgnoreSubstringsMatch", |
"syntax_oid": SYNTAX_DIRECTORY_STR, |
"syntax_len": 128, |
]); |
constant ATD_postalAddress = ([ |
"oid": "2.5.4.16", |
"NAME": ({"postalAddress"}), |
"EQUALITY": "caseIgnoreListMatch", |
"SUBSTR": "caseIgnoreListSubstringsMatch", |
"syntax_oid": SYNTAX_POSTAL_ADDR, |
]); |
constant ATD_postalCode = ([ |
"oid": "2.5.4.17", |
"NAME": ({"postalCode"}), |
"EQUALITY": "caseIgnoreMatch", |
"SUBSTR": "caseIgnoreSubstringsMatch", |
"syntax_oid": SYNTAX_DIRECTORY_STR, |
"syntax_len": 40, |
]); |
constant ATD_postOfficeBox = ([ |
"oid": "2.5.4.18", |
"NAME": ({"postOfficeBox"}), |
"EQUALITY": "caseIgnoreMatch", |
"SUBSTR": "caseIgnoreSubstringsMatch", |
"syntax_oid": SYNTAX_DIRECTORY_STR, |
"syntax_len": 40, |
]); |
constant ATD_physicalDeliveryOfficeName = ([ |
"oid": "2.5.4.19", |
"NAME": ({"physicalDeliveryOfficeName"}), |
"EQUALITY": "caseIgnoreMatch", |
"SUBSTR": "caseIgnoreSubstringsMatch", |
"syntax_oid": SYNTAX_DIRECTORY_STR, |
"syntax_len": 128, |
]); |
constant ATD_telephoneNumber = ([ |
"oid": "2.5.4.20", |
"NAME": ({"telephoneNumber"}), |
"EQUALITY": "telephoneNumberMatch", |
"SUBSTR": "telephoneNumberSubstringsMatch", |
"syntax_oid": SYNTAX_PHONE_NUM, |
"syntax_len": 32, |
]); |
constant ATD_telexNumber = ([ |
"oid": "2.5.4.21", |
"NAME": ({"telexNumber"}), |
"syntax_oid": SYNTAX_TELETEX_NUM, |
]); |
constant ATD_teletexTerminalIdentifier = ([ |
"oid": "2.5.4.22", |
"NAME": ({"teletexTerminalIdentifier"}), |
"syntax_oid": SYNTAX_TELETEX_TERMINAL_ID, |
]); |
constant ATD_facsimileTelephoneNumber = ([ |
"oid": "2.5.4.23", |
"NAME": ({"facsimileTelephoneNumber"}), |
"syntax_oid": SYNTAX_FACSIMILE_PHONE_NUM, |
]); |
constant ATD_x121Address = ([ |
"oid": "2.5.4.24", |
"NAME": ({"x121Address"}), |
"EQUALITY": "numericStringMatch", |
"SUBSTR": "numericStringSubstringsMatch", |
"syntax_oid": SYNTAX_NUMERIC_STRING, |
"syntax_len": 15, |
]); |
constant ATD_internationaliSDNNumber = ([ |
"oid": "2.5.4.25", |
"NAME": ({"internationaliSDNNumber"}), |
"EQUALITY": "numericStringMatch", |
"SUBSTR": "numericStringSubstringsMatch", |
"syntax_oid": SYNTAX_NUMERIC_STRING, |
"syntax_len": 16, |
]); |
constant ATD_registeredAddress = ([ |
"oid": "2.5.4.26", |
"NAME": ({"registeredAddress"}), |
"SUP": "postalAddress", |
"syntax_oid": SYNTAX_POSTAL_ADDR, |
]); |
constant ATD_destinationIndicator = ([ |
"oid": "2.5.4.27", |
"NAME": ({"destinationIndicator"}), |
"EQUALITY": "caseIgnoreMatch", |
"SUBSTR": "caseIgnoreSubstringsMatch", |
"syntax_oid": SYNTAX_PRINTABLE_STR, |
"syntax_len": 128, |
]); |
constant ATD_preferredDeliveryMethod = ([ |
"oid": "2.5.4.28", |
"NAME": ({"preferredDeliveryMethod"}), |
"syntax_oid": SYNTAX_DELIVERY_METHOD, |
"SINGLE-VALUE": 1, |
]); |
constant ATD_presentationAddress = ([ |
"oid": "2.5.4.29", |
"NAME": ({"presentationAddress"}), |
"EQUALITY": "presentationAddressMatch", |
"syntax_oid": SYNTAX_PRESENTATION_ADDR, |
"SINGLE-VALUE": 1, |
]); |
constant ATD_supportedApplicationContext = ([ |
"oid": "2.5.4.30", |
"NAME": ({"supportedApplicationContext"}), |
"EQUALITY": "objectIdentifierMatch", |
"syntax_oid": SYNTAX_OID, |
]); |
constant ATD_member = ([ |
"oid": "2.5.4.31", |
"NAME": ({"member"}), |
"SUP": "distinguishedName", |
]); |
constant ATD_owner = ([ |
"oid": "2.5.4.32", |
"NAME": ({"owner"}), |
"SUP": "distinguishedName", |
]); |
constant ATD_roleOccupant = ([ |
"oid": "2.5.4.33", |
"NAME": ({"roleOccupant"}), |
"SUP": "distinguishedName", |
]); |
constant ATD_seeAlso = ([ |
"oid": "2.5.4.34", |
"NAME": ({"seeAlso"}), |
"SUP": "distinguishedName", |
]); |
constant ATD_userPassword = ([ |
"oid": "2.5.4.35", |
"NAME": ({"userPassword"}), |
"EQUALITY": "octetStringMatch", |
"syntax_oid": SYNTAX_OCTET_STR, |
"syntax_len": 128, |
]); |
constant ATD_userCertificate = ([ |
"oid": "2.5.4.36", |
"NAME": ({"userCertificate"}), |
"syntax_oid": SYNTAX_CERT, |
]); |
constant ATD_cACertificate = ([ |
"oid": "2.5.4.37", |
"NAME": ({"cACertificate"}), |
"syntax_oid": SYNTAX_CERT, |
]); |
constant ATD_authorityRevocationList = ([ |
"oid": "2.5.4.38", |
"NAME": ({"authorityRevocationList"}), |
"syntax_oid": SYNTAX_CERT_LIST, |
]); |
constant ATD_certificateRevocationList = ([ |
"oid": "2.5.4.39", |
"NAME": ({"certificateRevocationList"}), |
"syntax_oid": SYNTAX_CERT_LIST, |
]); |
constant ATD_crossCertificatePair = ([ |
"oid": "2.5.4.40", |
"NAME": ({"crossCertificatePair"}), |
"syntax_oid": SYNTAX_CERT_PAIR, |
]); |
constant ATD_name = ([ |
"oid": "2.5.4.41", |
"NAME": ({"name"}), |
"EQUALITY": "caseIgnoreMatch", |
"SUBSTR": "caseIgnoreSubstringsMatch", |
"syntax_oid": SYNTAX_DIRECTORY_STR, |
"syntax_len": 32768, |
]); |
constant ATD_givenName = ([ |
"oid": "2.5.4.42", |
"NAME": ({"givenName"}), |
"SUP": "name", |
]); |
constant ATD_initials = ([ |
"oid": "2.5.4.43", |
"NAME": ({"initials"}), |
"SUP": "name", |
]); |
constant ATD_generationQualifier = ([ |
"oid": "2.5.4.44", |
"NAME": ({"generationQualifier"}), |
"SUP": "name", |
]); |
constant ATD_x500UniqueIdentifier = ([ |
"oid": "2.5.4.45", |
"NAME": ({"x500UniqueIdentifier"}), |
"EQUALITY": "bitStringMatch", |
"syntax_oid": SYNTAX_BIT_STRING, |
]); |
constant ATD_dnQualifier = ([ |
"oid": "2.5.4.46", |
"NAME": ({"dnQualifier"}), |
"EQUALITY": "caseIgnoreMatch", |
"ORDERING": "caseIgnoreOrderingMatch", |
"SUBSTR": "caseIgnoreSubstringsMatch", |
"syntax_oid": SYNTAX_PRINTABLE_STR, |
]); |
constant ATD_enhancedSearchGuide = ([ |
"oid": "2.5.4.47", |
"NAME": ({"enhancedSearchGuide"}), |
"syntax_oid": SYNTAX_ENHANCED_GUIDE, |
]); |
constant ATD_protocolInformation = ([ |
"oid": "2.5.4.48", |
"NAME": ({"protocolInformation"}), |
"EQUALITY": "protocolInformationMatch", |
"syntax_oid": "1.3.6.1.4.1.1466.115.121.1.42", |
]); |
constant ATD_distinguishedName = ([ |
"oid": "2.5.4.49", |
"NAME": ({"distinguishedName"}), |
"EQUALITY": "distinguishedNameMatch", |
"syntax_oid": SYNTAX_DN, |
]); |
constant ATD_uniqueMember = ([ |
"oid": "2.5.4.50", |
"NAME": ({"uniqueMember"}), |
"EQUALITY": "uniqueMemberMatch", |
"syntax_oid": SYNTAX_NAME_AND_OPTIONAL_UID, |
]); |
constant ATD_houseIdentifier = ([ |
"oid": "2.5.4.51", |
"NAME": ({"houseIdentifier"}), |
"EQUALITY": "caseIgnoreMatch", |
"SUBSTR": "caseIgnoreSubstringsMatch", |
"syntax_oid": SYNTAX_DIRECTORY_STR, |
"syntax_len": 32768, |
]); |
constant ATD_supportedAlgorithms = ([ |
"oid": "2.5.4.52", |
"NAME": ({"supportedAlgorithms"}), |
"syntax_oid": SYNTAX_SUPPORTED_ALGORITHM, |
]); |
constant ATD_deltaRevocationList = ([ |
"oid": "2.5.4.53", |
"NAME": ({"deltaRevocationList"}), |
"syntax_oid": SYNTAX_CERT_LIST, |
]); |
constant ATD_dmdName = ([ |
"oid": "2.5.4.54", |
"NAME": ({"dmdName"}), |
"SUP": "name", |
]); |
|
constant ATD_labeledURI = ([ |
"oid": "1.3.6.1.4.1.250.1.57", |
"NAME": ({"labeledURI"}), |
"EQUALITY": "caseExactMatch", |
"syntax_oid": SYNTAX_CASE_EXACT_STR, |
]); |
|
constant ATD_supportedFeatures = ([ |
"oid": "1.3.6.1.4.1.4203.1.3.5", |
"NAME": ({"supportedFeatures"}), |
"EQUALITY": "objectIdentifierMatch", |
"syntax_oid": SYNTAX_OID, |
"USAGE": "dSAOperation", |
]); |
|
constant _standard_attr_type_descrs = ([]); |
|
|
|
|
|
|
|
|
constant GUID_USERS_CONTAINER = "a9d1ca15768811d1aded00c04fd8d5cd"; |
constant GUID_COMPUTERS_CONTAINER = "aa312825768811d1aded00c04fd8d5cd"; |
constant GUID_SYSTEMS_CONTAINER = "ab1d30f3768811d1aded00c04fd8d5cd"; |
constant GUID_DOMAIN_CONTROLLERS_CONTAINER = "a361b2ffffd211d1aa4b00c04fd7d83a"; |
constant GUID_INFRASTRUCTURE_CONTAINER = "2fbac1870ade11d297c400c04fd8d5cd"; |
constant GUID_DELETED_OBJECTS_CONTAINER = "18e2ea80684f11d2b9aa00c04f79f805"; |
constant GUID_LOSTANDFOUND_CONTAINER = "ab8153b7768811d1aded00c04fd8d5cd"; |
constant GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER = "22b70c67d56e4efb91e9300fca3dc1aa"; |
constant GUID_PROGRAM_DATA_CONTAINER = "09460c08ae1e4a4ea0f64aee7daa1e5a"; |
constant GUID_MICROSOFT_PROGRAM_DATA_CONTAINER = "f4be92a4c777485e878e9421d53087db"; |
constant GUID_NTDS_QUOTAS_CONTAINER = "6227f0af1fc2410d8e3bb10615bb5b0f"; |
|
|
|
protected mapping(mixed:string) constant_val_lookup; |
|
string get_constant_name (mixed val) |
|
|
{ |
if (!constant_val_lookup) { |
array(string) names = indices (this_program); |
array(mixed) vals = values (this_program); |
for (int i = 0; i < sizeof (names);) |
if (intp (vals[i]) || |
|
names[i] == "SYNTAX_CASE_EXACT_STR") { |
names = names[..i-1] + names[i+1..]; |
vals = vals[..i-1] + vals[i+1..]; |
} |
else |
i++; |
constant_val_lookup = mkmapping (vals, names); |
if (sizeof (constant_val_lookup) != sizeof (names)) |
error ("Found %d duplicate constant names.\n", |
sizeof (names) - sizeof (constant_val_lookup)); |
} |
return constant_val_lookup[val]; |
} |
|
protected void create() |
|
{ |
|
|
foreach (indices (syntax_decode_fns), string syntax) { |
function(string:string) encoder = ([ |
utf8_to_string: string_to_utf8, |
])[syntax_decode_fns[syntax]]; |
if (!encoder) |
error ("Don't know the encoder corresponding to %O.\n", |
syntax_decode_fns[syntax]); |
syntax_encode_fns[syntax] = encoder; |
} |
|
|
|
|
array(mapping(string:mixed)) incomplete = ({}); |
|
foreach (indices (this_program), string name) { |
if (has_prefix (name, "ATD_")) { |
mapping(string:mixed) descr = |
|
|
predef::`[] (this_program, name); |
if (_standard_attr_type_descrs[descr->oid]) |
error ("OID conflict between %O and %O.\n", |
_standard_attr_type_descrs[descr->oid], descr); |
if (descr->SUP) incomplete += ({descr}); |
_standard_attr_type_descrs[descr->oid] = descr; |
foreach (descr->NAME, string name) |
_standard_attr_type_descrs[lower_case (name)] = descr; |
} |
} |
|
void complete (mapping(string:mixed) descr) { |
mapping(string:mixed) sup_descr = |
_standard_attr_type_descrs[lower_case (descr->SUP)]; |
if (!sup_descr) |
error ("Got SUP reference to unknown attribute %O: %O\n", |
descr->SUP, descr); |
if (sup_descr->SUP) |
complete (sup_descr); |
foreach (indices (sup_descr), string term) |
if (!has_index (descr, term)) |
descr[term] = sup_descr[term]; |
}; |
foreach (incomplete, mapping(string:mixed) descr) |
complete (descr); |
|
#ifdef LDAP_DEBUG |
|
get_constant_name (0); |
#endif |
} |
|
protected constant supported_extensions = (<"bindname">); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mapping(string:mixed) parse_ldap_url (string ldap_url) |
{ |
array ar; |
mapping(string:mixed) res = (["url": ldap_url]); |
|
if (sscanf (ldap_url, "%[^:]://%s", res->scheme, ldap_url) != 2) |
ERROR ("Failed to parse scheme from ldap url.\n"); |
|
sscanf (ldap_url, "%[^/]/%s", string hostport, ldap_url); |
sscanf (hostport, "%[^:]:%s", res->host, string port); |
if (port) |
if (sscanf (port, "%d%*c", res->port) != 1) |
ERROR ("Failed to parse port number from %O.\n", port); |
|
ar = ldap_url / "?"; |
|
switch (sizeof(ar)) { |
case 5: if (sizeof(ar[4])) { |
mapping extensions = ([]); |
foreach(ar[4] / ",", string ext) { |
sscanf (ext, "%[^=]=%s", string extype, string exvalue); |
extype = _Roxen.http_decode_string (extype); |
if (has_prefix (extype, "!")) { |
extype = extype[1..]; |
if (!supported_extensions[extype[1..]]) |
ERROR ("Critical extension %s is not supported.\n", extype); |
} |
if (extype == "") |
ERROR ("Failed to parse extension type from %O.\n", ext); |
extensions[extype] = |
exvalue ? _Roxen.http_decode_string (exvalue) : 1; |
} |
res->ext = extensions; |
} |
case 4: res->filter = _Roxen.http_decode_string (ar[3]); |
case 3: res->scope = (["base": SCOPE_BASE, |
"one": SCOPE_ONE, |
"sub": SCOPE_SUB])[ar[2]]; |
case 2: if (sizeof(ar[1])) res->attributes = |
map (ar[1] / ",", _Roxen.http_decode_string); |
case 1: res->basedn = _Roxen.http_decode_string (ar[0]); |
break; |
default: res->basedn = ""; |
} |
|
return res; |
} |
|
class FilterError |
|
{ |
constant is_ldap_filter_error = 1; |
|
|
constant is_generic_error = 1; |
string error_message; |
array error_backtrace; |
string|array `[] (int i) {return i ? error_backtrace : error_message;} |
protected void create (string msg, mixed... args) |
{ |
if (sizeof (args)) msg = sprintf (msg, @args); |
error_message = msg; |
error_backtrace = backtrace(); |
error_backtrace = error_backtrace[..<1]; |
throw (this); |
} |
} |
|
object make_filter (string filter, void|int ldap_version) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
#define EXCERPT(STR) (sizeof (STR) > 30 ? (STR)[..27] + "..." : (STR)) |
|
if (!ldap_version) ldap_version = 3; |
if (ldap_version >= 3) |
filter = string_to_utf8 (filter); |
|
|
|
|
|
|
|
|
#define WS "%*[ \t\n\r]" |
|
string read_filter_value() |
|
|
{ |
string res = ""; |
|
while (1) { |
sscanf (filter, "%[^()*\\]%s", string val, filter); |
res += val; |
if (filter == "" || (<'(', ')', '*'>)[filter[0]]) break; |
|
if (sscanf (filter, "\\%1x%1x%s", int high, int low, filter) == 3) |
|
|
|
res += sprintf ("%c", (high << 4) + low); |
else { |
|
|
|
if (sscanf (filter, "\\%1[*()]%s", val, filter) == 2) |
res += val; |
else { |
res += filter[..1]; |
filter = filter[2..]; |
} |
} |
} |
|
return res; |
}; |
|
object make_filter_recur() |
{ |
string subfilter = filter; |
object res; |
|
|
|
if (sscanf (filter, WS"("WS"%s", filter) != 3) |
FilterError ("Expected opening parenthesis at the start of %O.\n", |
EXCERPT (subfilter)); |
if (filter == "") |
FilterError ("Unexpected end of filter expression.\n"); |
|
switch (filter[0]) { |
case '&': |
case '|': { |
int op = filter[0]; |
filter = filter[1..]; |
array(object) subs = ({}); |
do { |
subs += ({make_filter_recur()}); |
} while (has_prefix (filter, "(")); |
res = ASN1_CONTEXT_SET (op == '&' ? 0 : 1, subs); |
break; |
} |
|
case '!': { |
filter = filter[1..]; |
res = ASN1_CONTEXT_SEQUENCE (2, ({make_filter_recur()})); |
break; |
} |
|
default: { |
string attr; |
|
|
|
sscanf (filter, "%[-A-Za-z0-9.]"WS"%s", attr, filter); |
if (filter == "") |
FilterError ("Unexpected end of the filter expression starting at %O.\n", |
EXCERPT (subfilter)); |
|
string op; |
switch (filter[0]) { |
case ':': case '=': |
sscanf (filter, "%1s%s", op, filter); |
break; |
case '~': case '>': case '<': |
if (sscanf (filter, "%2s%s", op, filter) != 2 || op[1] != '=') |
FilterError ("Invalid filter type in the expression starting at %O.\n", |
EXCERPT (subfilter)); |
break; |
default: |
FilterError ("Invalid filter type in the expression starting at %O.\n", |
EXCERPT (subfilter)); |
} |
|
if (op == ":") { |
|
|
|
if (ldap_version < 3) |
FilterError ("Invalid filter type in the expression starting at %O.\n", |
EXCERPT (subfilter)); |
|
int dn_attrs = sscanf (filter, "dn"WS":"WS"%s", filter) == 3; |
string matching_rule; |
if (has_prefix (filter, "=")) { |
if (attr == "") |
FilterError ("Must specify either an attribute, " |
"a matching rule identifier or both " |
"in the expression starting at %O.\n", |
EXCERPT (subfilter)); |
filter = filter[1..]; |
} |
else { |
|
|
if (sscanf (filter, "%[-A-Za-z0-9.]"WS":=%s", matching_rule, filter) != 3 || |
matching_rule == "") |
FilterError ("Error parsing matching rule identifier " |
"in the expression starting at %O.\n", |
EXCERPT (subfilter)); |
} |
|
string val = read_filter_value(); |
|
res = ASN1_CONTEXT_SEQUENCE ( |
9, ((matching_rule ? |
({ASN1_CONTEXT_OCTET_STRING (1, matching_rule)}) : ({})) + |
(attr != "" ? |
({ASN1_CONTEXT_OCTET_STRING (2, attr)}) : ({})) + |
({ASN1_CONTEXT_OCTET_STRING (3, val), |
ASN1_CONTEXT_BOOLEAN (4, dn_attrs)}))); |
} |
|
else { |
if (attr == "") |
FilterError ("Expected attribute in the expression starting at %O.\n", |
EXCERPT (subfilter)); |
|
string|object val = read_filter_value(); |
|
if (op == "=" && has_prefix (filter, "*")) { |
array(string) parts = ({val}); |
do { |
filter = filter[1..]; |
val = read_filter_value(); |
parts += ({val}); |
} while (has_prefix (filter, "*")); |
|
array(object) subs = sizeof (parts[0]) ? |
({ASN1_CONTEXT_OCTET_STRING (0, parts[0])}) : ({}); |
foreach (parts[1..<1], string middle) |
subs += ({ASN1_CONTEXT_OCTET_STRING (1, middle)}); |
if (sizeof (parts) > 1 && sizeof (parts[-1])) |
subs += ({ASN1_CONTEXT_OCTET_STRING (2, parts[-1])}); |
|
if (!sizeof (subs)) |
res = ASN1_CONTEXT_OCTET_STRING (7, attr); |
else |
res = ASN1_CONTEXT_SEQUENCE ( |
4, ({Standards.ASN1.Types.OctetString (attr), |
Standards.ASN1.Types.Sequence (subs)})); |
} |
|
else { |
int op_number; |
switch (op) { |
case "=": op_number = 3; break; |
case ">=": op_number = 5; break; |
case "<=": op_number = 6; break; |
case "~=": op_number = 8; break; |
default: |
FilterError ("Invalid filter type in the expression " |
"starting at %O.\n", EXCERPT (subfilter)); |
} |
res = ASN1_CONTEXT_SEQUENCE ( |
op_number, ({Standards.ASN1.Types.OctetString (attr), |
Standards.ASN1.Types.OctetString (val)})); |
} |
} |
|
break; |
} |
} |
|
|
|
if (sscanf (filter, WS")"WS"%s", filter) != 3) |
FilterError ("Missing closing parenthesis in the expression " |
"starting at %O.\n", EXCERPT (subfilter)); |
return res; |
}; |
|
object res = make_filter_recur(); |
if (filter != "") |
FilterError ("Unexpected data beginning with %O " |
"after end of filter expression.\n", EXCERPT (filter)); |
return res; |
|
#undef WS |
#undef EXCERPT |
} |
|
protected mapping(string:array(object)) cached_filters = ([]); |
|
object get_cached_filter (string filter, void|int ldap_version) |
|
|
|
|
|
|
|
{ |
if (!ldap_version) ldap_version = 3; |
array(object) arr = cached_filters[filter] || ({}); |
if (object res = sizeof (arr) > ldap_version && arr[ldap_version]) |
return res; |
object res = make_filter (filter, ldap_version); |
if (sizeof (arr) <= ldap_version) |
arr = cached_filters[filter] = arr + allocate (ldap_version + 1 - sizeof (arr)); |
return arr[ldap_version] = res; |
} |
|
|
|
constant connection_idle_timeout = 30; |
|
|
|
|
|
constant connection_rebind_threshold = 4; |
|
|
|
constant connection_idle_garb_interval = 60; |
|
|
protected mapping(string:array(object)) idle_conns = ([]); |
protected Thread.Mutex idle_conns_mutex = Thread.Mutex(); |
protected mixed periodic_idle_conns_garb_call_out; |
|
protected void periodic_idle_conns_garb() |
{ |
Thread.MutexKey lock = idle_conns_mutex->lock(); |
DWRITE ("Periodic connection garb. Got %d urls.\n", sizeof (idle_conns)); |
|
int garb_time = time() - connection_idle_timeout; |
foreach (idle_conns; string ldap_url; array(object) conns) { |
int garbed = 0; |
foreach (conns; int i; object conn) |
if (conn->get_last_io_time() <= garb_time) { |
DWRITE ("Garbing connection to %O which has been idle for %d s.\n", |
ldap_url, time() - conn->get_last_io_time()); |
conns[i] = 0, garbed = 1; |
} |
if (garbed) { |
conns -= ({0}); |
if (sizeof (conns)) idle_conns[ldap_url] = conns; |
else m_delete (idle_conns, ldap_url); |
} |
} |
|
if (sizeof (idle_conns)) |
periodic_idle_conns_garb_call_out = |
call_out (periodic_idle_conns_garb, connection_idle_garb_interval); |
else { |
DWRITE ("No connections left - disabling periodic garb.\n"); |
periodic_idle_conns_garb_call_out = 0; |
} |
} |
|
|
|
|
|
|
protected mapping(string:array(int|string)) host_lookup = ([]); |
|
object get_connection (string ldap_url, void|string binddn, |
void|string password, void|int version) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
string pass = password; |
password = "CENSORED"; |
object conn; |
|
mapping(string:mixed) parsed_url = parse_ldap_url (ldap_url); |
if (string url_bindname = parsed_url->ext && parsed_url->ext->bindname) |
binddn = url_bindname; |
|
|
|
|
|
if (idle_conns[ldap_url]) { |
Thread.MutexKey lock = idle_conns_mutex->lock(); |
if (array(object) conns = idle_conns[ldap_url]) { |
find_connection: { |
int now = time(); |
object rebind_conn; |
string md5_pass; |
|
for (int i = 0; i < sizeof (conns);) { |
conn = conns[i]; |
int last_use = conn->get_last_io_time(); |
if (last_use <= now - connection_idle_timeout) { |
DWRITE ("Dropping old connection which has been idle for %d s.\n", |
now - last_use); |
conns = conns[..i-1] + conns[i+1..]; |
} |
else { |
if (!binddn || |
(conn->get_bound_dn() == binddn && |
(conn->get_bind_password_hash() == |
(md5_pass || |
(md5_pass = Crypto.MD5.hash (pass || "")))) && |
(!version || conn->get_protocol_version() == version))) { |
DWRITE ("Reusing connection which has been idle for %d s.\n", |
now - last_use); |
conns = conns[..i-1] + conns[i+1..]; |
lock = 0; |
break find_connection; |
} |
else if (!rebind_conn && conn->get_protocol_version() >= 3) { |
DWRITE ("Found differently bound connection " |
"which has been idle for %d s.\n", now - last_use); |
rebind_conn = conn; |
} |
i++; |
} |
} |
|
if (rebind_conn && sizeof (conns) >= connection_rebind_threshold) { |
conn = rebind_conn; |
conns -= ({rebind_conn}); |
DWRITE ("Reusing differently bound connection.\n"); |
} |
else |
conn = 0; |
} |
|
if (!sizeof (conns)) |
m_delete (idle_conns, ldap_url); |
else |
idle_conns[ldap_url] = conns; |
} |
lock = 0; |
} |
|
if (!sizeof (idle_conns) && periodic_idle_conns_garb_call_out) { |
DWRITE ("No connections left in pool - disabling periodic garb.\n"); |
remove_call_out (periodic_idle_conns_garb_call_out); |
periodic_idle_conns_garb_call_out = 0; |
} |
|
if (!conn) { |
DWRITE("Connecting to %O.\n", ldap_url); |
string host = parsed_url->host; |
if (host) { |
if (!host_lookup[host]) { |
array(string|array(string)) entry = |
Protocols.DNS.gethostbyname(host); |
if ((sizeof(entry) >= 2) && sizeof(entry[1])) { |
DWRITE("DNS lookup: %O.\n", entry[1]); |
host_lookup[host] = ({ random(sizeof(entry[1])) + 1 }) + entry[1]; |
} else { |
entry = gethostbyname(host); |
if ((sizeof(entry) >= 2) && sizeof(entry[1])) { |
DWRITE("Hosts lookup: %O.\n", entry[1]); |
host_lookup[host] = ({ random(sizeof(entry[1])) + 1 }) + entry[1]; |
} |
} |
} |
array(int|string) ips = host_lookup[host]; |
if (ips) { |
int i = ips[0]; |
for (int j = 1; j < sizeof(ips); j++) { |
mixed err = catch { |
DWRITE("Attempt #%d: %O.\n", j, ips[i]); |
parsed_url->host = ips[i]; |
conn = Protocols.LDAP["client"](parsed_url); |
ips[0] = i; |
break; |
}; |
if (!err) { |
break; |
} |
DWRITE("Failure: %s\n", describe_error(err)); |
if (++i >= sizeof(ips)) i = 1; |
} |
parsed_url->host = host; |
if (!conn) { |
m_delete(host_lookup, host); |
} |
} |
} |
} |
|
if (!conn) { |
conn = Protocols.LDAP["client"] (parsed_url); |
} |
|
if (!binddn) |
DWRITE ("Bound connection not requested.\n"); |
else { |
if (binddn == "") |
DWRITE ("Not binding - no bind DN set.\n"); |
else if (conn->get_bound_dn() == binddn && |
(!version || conn->get_protocol_version() == version)) |
DWRITE ("Not binding - already bound to %O using version %d.\n", |
binddn, conn->get_protocol_version()); |
else { |
conn->bind (binddn, pass, version); |
|
int err_num = conn->error_number(); |
if (err_num && !version && conn->get_protocol_version() >= 3) { |
string server_err_str = conn->server_error_string(); |
conn->bind (binddn, pass, 2); |
if (conn->error_number()) { |
DWRITE ("Bind attempt to %O using fallback version 2 failed: %s\n", |
binddn, conn->error_string()); |
|
|
conn->seterr (err_num, server_err_str); |
} |
} |
#ifdef DEBUG_PIKE_PROTOCOL_LDAP |
if (conn->error_number()) |
DWRITE ("Bind attempt to %O failed: %s\n", |
binddn, conn->error_string()); |
else |
DWRITE ("Bind to %O successful using version %d.\n", |
binddn, conn->get_protocol_version()); |
#endif |
} |
} |
|
return conn; |
} |
|
void return_connection (object conn) |
|
|
|
|
|
|
{ |
Thread.MutexKey lock = idle_conns_mutex->lock(); |
DWRITE ("Returning connection to %O to pool.\n", conn->get_parsed_url()->url); |
|
|
|
conn->reset_options(); |
idle_conns[conn->get_parsed_url()->url] += ({conn}); |
|
if (!periodic_idle_conns_garb_call_out) |
periodic_idle_conns_garb_call_out = |
call_out (periodic_idle_conns_garb, connection_idle_garb_interval); |
} |
|
int num_connections (string ldap_url) |
|
|
{ |
return sizeof (idle_conns[ldap_url] || ({})); |
} |
|
|