1"""Definitions for constants exported by OpenLDAP
2
3This file lists all constants we know about, even those that aren't
4available in the OpenLDAP version python-ldap is compiled against.
5
6The information serves two purposes:
7
8- Generate a C header with the constants
9- Provide support for building documentation without compiling python-ldap
10
11"""
12
13# This module cannot import anything from ldap.
14# When building documentation, it is used to initialize ldap.__init__.
15
16
17class Constant:
18    """Base class for a definition of an OpenLDAP constant
19    """
20
21    def __init__(self, name, optional=False, requirements=(), doc=None):
22        self.name = name
23        if optional:
24            self_requirement = f'defined(LDAP_{self.name})'
25            requirements = list(requirements) + [self_requirement]
26        self.requirements = requirements
27        self.doc = self.__doc__ = doc
28
29
30class Error(Constant):
31    """Definition for an OpenLDAP error code
32
33    This is a constant at the C level; in Python errors are provided as
34    exception classes.
35    """
36
37    c_template = 'add_err({self.name});'
38
39
40class Int(Constant):
41    """Definition for an OpenLDAP integer constant"""
42
43    c_template = 'add_int({self.name});'
44
45
46class TLSInt(Int):
47    """Definition for a TLS integer constant -- requires HAVE_TLS"""
48
49    def __init__(self, *args, **kwargs):
50        requrements = list(kwargs.get('requirements', ()))
51        kwargs['requirements'] = ['HAVE_TLS'] + requrements
52        super().__init__(*args, **kwargs)
53
54
55class Feature(Constant):
56    """Definition for a feature: 0 or 1 based on a C #ifdef
57
58    """
59
60    c_template = '\n'.join([
61        '',
62        '#ifdef {self.c_feature}',
63        'if (PyModule_AddIntConstant(m, "{self.name}", 1) != 0) return -1;',
64        '#else',
65        'if (PyModule_AddIntConstant(m, "{self.name}", 0) != 0) return -1;',
66        '#endif',
67        '',
68    ])
69
70
71    def __init__(self, name, c_feature, **kwargs):
72        super().__init__(name, **kwargs)
73        self.c_feature = c_feature
74
75
76class Str(Constant):
77    c_template = 'add_string({self.name});'
78
79
80API_2004 = 'LDAP_API_VERSION >= 2004'
81
82CONSTANTS = (
83    Error('ADMINLIMIT_EXCEEDED'),
84    Error('AFFECTS_MULTIPLE_DSAS'),
85    Error('ALIAS_DEREF_PROBLEM'),
86    Error('ALIAS_PROBLEM'),
87    Error('ALREADY_EXISTS'),
88    Error('AUTH_METHOD_NOT_SUPPORTED'),
89    Error('AUTH_UNKNOWN'),
90    Error('BUSY'),
91    Error('CLIENT_LOOP'),
92    Error('COMPARE_FALSE'),
93    Error('COMPARE_TRUE'),
94    Error('CONFIDENTIALITY_REQUIRED'),
95    Error('CONNECT_ERROR'),
96    Error('CONSTRAINT_VIOLATION'),
97    Error('CONTROL_NOT_FOUND'),
98    Error('DECODING_ERROR'),
99    Error('ENCODING_ERROR'),
100    Error('FILTER_ERROR'),
101    Error('INAPPROPRIATE_AUTH'),
102    Error('INAPPROPRIATE_MATCHING'),
103    Error('INSUFFICIENT_ACCESS'),
104    Error('INVALID_CREDENTIALS'),
105    Error('INVALID_DN_SYNTAX'),
106    Error('INVALID_SYNTAX'),
107    Error('IS_LEAF'),
108    Error('LOCAL_ERROR'),
109    Error('LOOP_DETECT'),
110    Error('MORE_RESULTS_TO_RETURN'),
111    Error('NAMING_VIOLATION'),
112    Error('NO_MEMORY'),
113    Error('NO_OBJECT_CLASS_MODS'),
114    Error('NO_OBJECT_CLASS_MODS'),
115    Error('NO_RESULTS_RETURNED'),
116    Error('NO_SUCH_ATTRIBUTE'),
117    Error('NO_SUCH_OBJECT'),
118    Error('NOT_ALLOWED_ON_NONLEAF'),
119    Error('NOT_ALLOWED_ON_RDN'),
120    Error('NOT_SUPPORTED'),
121    Error('OBJECT_CLASS_VIOLATION'),
122    Error('OPERATIONS_ERROR'),
123    Error('OTHER'),
124    Error('PARAM_ERROR'),
125    Error('PARTIAL_RESULTS'),
126    Error('PROTOCOL_ERROR'),
127    Error('REFERRAL'),
128    Error('REFERRAL_LIMIT_EXCEEDED'),
129    Error('RESULTS_TOO_LARGE'),
130    Error('SASL_BIND_IN_PROGRESS'),
131    Error('SERVER_DOWN'),
132    Error('SIZELIMIT_EXCEEDED'),
133    Error('STRONG_AUTH_NOT_SUPPORTED'),
134    Error('STRONG_AUTH_REQUIRED'),
135    Error('SUCCESS'),
136    Error('TIMELIMIT_EXCEEDED'),
137    Error('TIMEOUT'),
138    Error('TYPE_OR_VALUE_EXISTS'),
139    Error('UNAVAILABLE'),
140    Error('UNAVAILABLE_CRITICAL_EXTENSION'),
141    Error('UNDEFINED_TYPE'),
142    Error('UNWILLING_TO_PERFORM'),
143    Error('USER_CANCELLED'),
144    Error('VLV_ERROR'),
145    Error('X_PROXY_AUTHZ_FAILURE'),
146
147    Error('CANCELLED', requirements=['defined(LDAP_API_FEATURE_CANCEL)']),
148    Error('NO_SUCH_OPERATION', requirements=['defined(LDAP_API_FEATURE_CANCEL)']),
149    Error('TOO_LATE', requirements=['defined(LDAP_API_FEATURE_CANCEL)']),
150    Error('CANNOT_CANCEL', requirements=['defined(LDAP_API_FEATURE_CANCEL)']),
151
152    Error('ASSERTION_FAILED', optional=True),
153
154    Error('PROXIED_AUTHORIZATION_DENIED', optional=True),
155
156    # simple constants
157
158    Int('API_VERSION'),
159    Int('VENDOR_VERSION'),
160
161    Int('PORT'),
162    Int('VERSION1'),
163    Int('VERSION2'),
164    Int('VERSION3'),
165    Int('VERSION_MIN'),
166    Int('VERSION'),
167    Int('VERSION_MAX'),
168    Int('TAG_MESSAGE'),
169    Int('TAG_MSGID'),
170
171    Int('REQ_BIND'),
172    Int('REQ_UNBIND'),
173    Int('REQ_SEARCH'),
174    Int('REQ_MODIFY'),
175    Int('REQ_ADD'),
176    Int('REQ_DELETE'),
177    Int('REQ_MODRDN'),
178    Int('REQ_COMPARE'),
179    Int('REQ_ABANDON'),
180
181    Int('TAG_LDAPDN'),
182    Int('TAG_LDAPCRED'),
183    Int('TAG_CONTROLS'),
184    Int('TAG_REFERRAL'),
185
186    Int('REQ_EXTENDED'),
187    Int('TAG_NEWSUPERIOR', requirements=[API_2004]),
188    Int('TAG_EXOP_REQ_OID', requirements=[API_2004]),
189    Int('TAG_EXOP_REQ_VALUE', requirements=[API_2004]),
190    Int('TAG_EXOP_RES_OID', requirements=[API_2004]),
191    Int('TAG_EXOP_RES_VALUE', requirements=[API_2004]),
192    Int('TAG_SASL_RES_CREDS', requirements=[API_2004, 'defined(HAVE_SASL)']),
193
194    Int('SASL_AUTOMATIC'),
195    Int('SASL_INTERACTIVE'),
196    Int('SASL_QUIET'),
197
198    # reversibles
199
200    Int('RES_BIND'),
201    Int('RES_SEARCH_ENTRY'),
202    Int('RES_SEARCH_RESULT'),
203    Int('RES_MODIFY'),
204    Int('RES_ADD'),
205    Int('RES_DELETE'),
206    Int('RES_MODRDN'),
207    Int('RES_COMPARE'),
208    Int('RES_ANY'),
209
210    Int('RES_SEARCH_REFERENCE'),
211    Int('RES_EXTENDED'),
212    Int('RES_UNSOLICITED'),
213
214    Int('RES_INTERMEDIATE'),
215
216    # non-reversibles
217
218    Int('AUTH_NONE'),
219    Int('AUTH_SIMPLE'),
220    Int('SCOPE_BASE'),
221    Int('SCOPE_ONELEVEL'),
222    Int('SCOPE_SUBTREE'),
223    Int('SCOPE_SUBORDINATE', optional=True),
224    Int('MOD_ADD'),
225    Int('MOD_DELETE'),
226    Int('MOD_REPLACE'),
227    Int('MOD_INCREMENT'),
228    Int('MOD_BVALUES'),
229
230    Int('MSG_ONE'),
231    Int('MSG_ALL'),
232    Int('MSG_RECEIVED'),
233
234    # (error constants handled above)
235
236    Int('DEREF_NEVER'),
237    Int('DEREF_SEARCHING'),
238    Int('DEREF_FINDING'),
239    Int('DEREF_ALWAYS'),
240    Int('NO_LIMIT'),
241
242    Int('OPT_API_INFO'),
243    Int('OPT_DEREF'),
244    Int('OPT_SIZELIMIT'),
245    Int('OPT_TIMELIMIT'),
246    Int('OPT_REFERRALS', optional=True),
247    Int('OPT_ERROR_NUMBER'),
248    Int('OPT_RESTART'),
249    Int('OPT_PROTOCOL_VERSION'),
250    Int('OPT_SERVER_CONTROLS'),
251    Int('OPT_CLIENT_CONTROLS'),
252    Int('OPT_API_FEATURE_INFO'),
253    Int('OPT_HOST_NAME'),
254
255    Int('OPT_DESC'),
256    Int('OPT_DIAGNOSTIC_MESSAGE'),
257
258    Int('OPT_ERROR_STRING'),
259    Int('OPT_MATCHED_DN'),
260    Int('OPT_DEBUG_LEVEL'),
261    Int('OPT_TIMEOUT'),
262    Int('OPT_REFHOPLIMIT'),
263    Int('OPT_NETWORK_TIMEOUT'),
264    Int('OPT_URI'),
265
266    Int('OPT_DEFBASE', optional=True),
267
268    TLSInt('OPT_X_TLS', optional=True),
269    TLSInt('OPT_X_TLS_CTX'),
270    TLSInt('OPT_X_TLS_CACERTFILE'),
271    TLSInt('OPT_X_TLS_CACERTDIR'),
272    TLSInt('OPT_X_TLS_CERTFILE'),
273    TLSInt('OPT_X_TLS_KEYFILE'),
274    TLSInt('OPT_X_TLS_REQUIRE_CERT'),
275    TLSInt('OPT_X_TLS_CIPHER_SUITE'),
276    TLSInt('OPT_X_TLS_RANDOM_FILE'),
277    TLSInt('OPT_X_TLS_DHFILE'),
278    TLSInt('OPT_X_TLS_NEVER'),
279    TLSInt('OPT_X_TLS_HARD'),
280    TLSInt('OPT_X_TLS_DEMAND'),
281    TLSInt('OPT_X_TLS_ALLOW'),
282    TLSInt('OPT_X_TLS_TRY'),
283
284    TLSInt('OPT_X_TLS_VERSION', optional=True),
285    TLSInt('OPT_X_TLS_CIPHER', optional=True),
286    TLSInt('OPT_X_TLS_PEERCERT', optional=True),
287
288    # only available if OpenSSL supports it => might cause
289    # backward compatibility problems
290    TLSInt('OPT_X_TLS_CRLCHECK', optional=True),
291
292    TLSInt('OPT_X_TLS_CRLFILE', optional=True),
293
294    TLSInt('OPT_X_TLS_CRL_NONE'),
295    TLSInt('OPT_X_TLS_CRL_PEER'),
296    TLSInt('OPT_X_TLS_CRL_ALL'),
297    TLSInt('OPT_X_TLS_NEWCTX', optional=True),
298    TLSInt('OPT_X_TLS_PROTOCOL_MIN', optional=True),
299    TLSInt('OPT_X_TLS_PACKAGE', optional=True),
300
301    # Added in OpenLDAP 2.4.52
302    TLSInt('OPT_X_TLS_REQUIRE_SAN', optional=True),
303
304    Int('OPT_X_SASL_MECH'),
305    Int('OPT_X_SASL_REALM'),
306    Int('OPT_X_SASL_AUTHCID'),
307    Int('OPT_X_SASL_AUTHZID'),
308    Int('OPT_X_SASL_SSF'),
309    Int('OPT_X_SASL_SSF_EXTERNAL'),
310    Int('OPT_X_SASL_SECPROPS'),
311    Int('OPT_X_SASL_SSF_MIN'),
312    Int('OPT_X_SASL_SSF_MAX'),
313    Int('OPT_X_SASL_NOCANON', optional=True),
314    Int('OPT_X_SASL_USERNAME', optional=True),
315    Int('OPT_CONNECT_ASYNC', optional=True),
316    Int('OPT_X_KEEPALIVE_IDLE', optional=True),
317    Int('OPT_X_KEEPALIVE_PROBES', optional=True),
318    Int('OPT_X_KEEPALIVE_INTERVAL', optional=True),
319
320    Int('DN_FORMAT_LDAP'),
321    Int('DN_FORMAT_LDAPV3'),
322    Int('DN_FORMAT_LDAPV2'),
323    Int('DN_FORMAT_DCE'),
324    Int('DN_FORMAT_UFN'),
325    Int('DN_FORMAT_AD_CANONICAL'),
326    # Int('DN_FORMAT_LBER'),  # for testing only
327    Int('DN_FORMAT_MASK'),
328    Int('DN_PRETTY'),
329    Int('DN_SKIP'),
330    Int('DN_P_NOLEADTRAILSPACES'),
331    Int('DN_P_NOSPACEAFTERRDN'),
332    Int('DN_PEDANTIC'),
333
334    Int('AVA_NULL'),
335    Int('AVA_STRING'),
336    Int('AVA_BINARY'),
337    Int('AVA_NONPRINTABLE'),
338
339    Int('OPT_SUCCESS'),
340
341    # XXX - these should be errors
342    Int('URL_ERR_BADSCOPE'),
343    Int('URL_ERR_MEM'),
344    # Int('LIBLDAP_R'),
345
346    Feature('LIBLDAP_R', 'HAVE_LIBLDAP_R'),
347    Feature('SASL_AVAIL', 'HAVE_SASL'),
348    Feature('TLS_AVAIL', 'HAVE_TLS'),
349    Feature('INIT_FD_AVAIL', 'HAVE_LDAP_INIT_FD'),
350
351    Str("CONTROL_MANAGEDSAIT"),
352    Str("CONTROL_PROXY_AUTHZ"),
353    Str("CONTROL_SUBENTRIES"),
354    Str("CONTROL_VALUESRETURNFILTER"),
355    Str("CONTROL_ASSERT"),
356    Str("CONTROL_PRE_READ"),
357    Str("CONTROL_POST_READ"),
358    Str("CONTROL_SORTREQUEST"),
359    Str("CONTROL_SORTRESPONSE"),
360    Str("CONTROL_PAGEDRESULTS"),
361    Str("CONTROL_SYNC"),
362    Str("CONTROL_SYNC_STATE"),
363    Str("CONTROL_SYNC_DONE"),
364    Str("SYNC_INFO"),
365    Str("CONTROL_PASSWORDPOLICYREQUEST"),
366    Str("CONTROL_PASSWORDPOLICYRESPONSE"),
367    Str("CONTROL_RELAX"),
368)
369
370
371def print_header():  # pragma: no cover
372    """Print the C header file to standard output"""
373
374    print('/*')
375    print(' * Generated with:')
376    print(' *   python Lib/ldap/constants.py > Modules/constants_generated.h')
377    print(' *')
378    print(' * Please do any modifications there, then re-generate this file')
379    print(' */')
380    print('')
381
382    current_requirements = []
383
384    def pop_requirement():
385        popped = current_requirements.pop()
386        print('#endif')
387        print()
388
389    for definition in CONSTANTS:
390        while not set(current_requirements).issubset(definition.requirements):
391            pop_requirement()
392
393        for requirement in definition.requirements:
394            if requirement not in current_requirements:
395                current_requirements.append(requirement)
396                print()
397                print(f'#if {requirement}')
398
399        print(definition.c_template.format(self=definition))
400
401    while current_requirements:
402        pop_requirement()
403
404
405if __name__ == '__main__':
406    print_header()
407