Line data Source code
1 : /* See https://www.python-ldap.org/ for details. */
2 :
3 : #include "common.h"
4 : #include "constants.h"
5 : #include "LDAPObject.h"
6 : #include "ldapcontrol.h"
7 : #include "options.h"
8 :
9 : void
10 66 : set_timeval_from_double( struct timeval *tv, double d ) {
11 66 : tv->tv_usec = (long) ( fmod(d, 1.0) * 1000000.0 );
12 66 : tv->tv_sec = (long) floor(d);
13 66 : }
14 :
15 : /**
16 : * Converts a return code from ldap_set_option() or ldap_get_option()
17 : * into a python error, and returns NULL.
18 : */
19 : static PyObject *
20 1 : option_error(int res, const char *fn)
21 : {
22 1 : if (res == LDAP_OPT_ERROR)
23 1 : PyErr_SetString(PyExc_ValueError, "option error");
24 0 : else if (res == LDAP_PARAM_ERROR)
25 0 : PyErr_SetString(PyExc_ValueError, "parameter error");
26 0 : else if (res == LDAP_NO_MEMORY)
27 0 : PyErr_NoMemory();
28 : else
29 0 : PyErr_Format(PyExc_SystemError, "error %d from %s", res, fn);
30 1 : return NULL;
31 : }
32 :
33 : /**
34 : * Sets an LDAP option.
35 : * Returns 0 on failure, 1 on success
36 : */
37 : int
38 239 : LDAP_set_option(LDAPObject *self, int option, PyObject *value)
39 : {
40 : int res;
41 : int intval;
42 : double doubleval;
43 : char *strval;
44 : struct timeval tv;
45 : void *ptr;
46 : LDAP *ld;
47 239 : LDAPControl **controls = NULL;
48 :
49 239 : ld = self ? self->ldap : NULL;
50 :
51 239 : switch(option) {
52 2 : case LDAP_OPT_API_INFO:
53 : case LDAP_OPT_API_FEATURE_INFO:
54 : #ifdef HAVE_SASL
55 : case LDAP_OPT_X_SASL_SSF:
56 : #endif
57 : /* Read-only options */
58 2 : PyErr_SetString(PyExc_ValueError, "read-only option");
59 241 : return 0;
60 5 : case LDAP_OPT_REFERRALS:
61 : case LDAP_OPT_RESTART:
62 : #ifdef LDAP_OPT_X_SASL_NOCANON
63 : case LDAP_OPT_X_SASL_NOCANON:
64 : #endif
65 : #ifdef LDAP_OPT_CONNECT_ASYNC
66 : case LDAP_OPT_CONNECT_ASYNC:
67 : #endif
68 : /* Truth-value options */
69 5 : ptr = PyObject_IsTrue(value) ? LDAP_OPT_ON : LDAP_OPT_OFF;
70 5 : break;
71 :
72 165 : case LDAP_OPT_DEREF:
73 : case LDAP_OPT_SIZELIMIT:
74 : case LDAP_OPT_TIMELIMIT:
75 : case LDAP_OPT_PROTOCOL_VERSION:
76 : case LDAP_OPT_ERROR_NUMBER:
77 : case LDAP_OPT_DEBUG_LEVEL:
78 : #ifdef HAVE_TLS
79 : case LDAP_OPT_X_TLS:
80 : case LDAP_OPT_X_TLS_REQUIRE_CERT:
81 : #ifdef LDAP_OPT_X_TLS_CRLCHECK
82 : case LDAP_OPT_X_TLS_CRLCHECK:
83 : #endif
84 : #ifdef LDAP_OPT_X_TLS_NEWCTX
85 : case LDAP_OPT_X_TLS_NEWCTX:
86 : #endif
87 : #ifdef LDAP_OPT_X_TLS_PROTOCOL_MIN
88 : case LDAP_OPT_X_TLS_PROTOCOL_MIN:
89 : #endif
90 : #endif
91 : #ifdef HAVE_SASL
92 : case LDAP_OPT_X_SASL_SSF_MIN:
93 : case LDAP_OPT_X_SASL_SSF_MAX:
94 : #endif
95 : #ifdef LDAP_OPT_X_KEEPALIVE_IDLE
96 : case LDAP_OPT_X_KEEPALIVE_IDLE:
97 : #endif
98 : #ifdef LDAP_OPT_X_KEEPALIVE_PROBES
99 : case LDAP_OPT_X_KEEPALIVE_PROBES:
100 : #endif
101 : #ifdef LDAP_OPT_X_KEEPALIVE_INTERVAL
102 : case LDAP_OPT_X_KEEPALIVE_INTERVAL:
103 : #endif
104 :
105 : /* integer value options */
106 165 : if (!PyArg_Parse(value, "i:set_option", &intval))
107 1 : return 0;
108 164 : ptr = &intval;
109 164 : break;
110 13 : case LDAP_OPT_HOST_NAME:
111 : case LDAP_OPT_URI:
112 : #ifdef LDAP_OPT_DEFBASE
113 : case LDAP_OPT_DEFBASE:
114 : #endif
115 : case LDAP_OPT_ERROR_STRING:
116 : case LDAP_OPT_MATCHED_DN:
117 : #ifdef HAVE_TLS
118 : case LDAP_OPT_X_TLS_CACERTFILE:
119 : case LDAP_OPT_X_TLS_CACERTDIR:
120 : case LDAP_OPT_X_TLS_CERTFILE:
121 : case LDAP_OPT_X_TLS_KEYFILE:
122 : case LDAP_OPT_X_TLS_CIPHER_SUITE:
123 : case LDAP_OPT_X_TLS_RANDOM_FILE:
124 : case LDAP_OPT_X_TLS_DHFILE:
125 : #ifdef LDAP_OPT_X_TLS_CRLFILE
126 : case LDAP_OPT_X_TLS_CRLFILE:
127 : #endif
128 : #endif
129 : #ifdef HAVE_SASL
130 : case LDAP_OPT_X_SASL_SECPROPS:
131 : #endif
132 : /* String valued options */
133 13 : if (!PyArg_Parse(value, "s:set_option", &strval))
134 2 : return 0;
135 11 : ptr = strval;
136 11 : break;
137 28 : case LDAP_OPT_TIMEOUT:
138 : case LDAP_OPT_NETWORK_TIMEOUT:
139 : /* Float valued timeval options */
140 28 : if (!PyArg_Parse(value, "d:set_option", &doubleval))
141 4 : return 0;
142 24 : if (doubleval >= 0) {
143 8 : set_timeval_from_double( &tv, doubleval );
144 8 : ptr = &tv;
145 16 : } else if (doubleval == -1) {
146 : /* -1 is infinity timeout */
147 12 : tv.tv_sec = -1;
148 12 : tv.tv_usec = 0;
149 12 : ptr = &tv;
150 : } else {
151 4 : PyErr_Format(
152 : PyExc_ValueError,
153 : "timeout must be >= 0 or -1 for infinity, got %d",
154 : option
155 : );
156 4 : return 0;
157 : }
158 20 : break;
159 24 : case LDAP_OPT_SERVER_CONTROLS:
160 : case LDAP_OPT_CLIENT_CONTROLS:
161 24 : if (!LDAPControls_from_object(value, &controls))
162 6 : return 0;
163 18 : ptr = controls;
164 18 : break;
165 2 : default:
166 2 : PyErr_Format(PyExc_ValueError, "unknown option %d", option);
167 2 : return 0;
168 : }
169 :
170 218 : if (self) LDAP_BEGIN_ALLOW_THREADS(self);
171 218 : res = ldap_set_option(ld, option, ptr);
172 218 : if (self) LDAP_END_ALLOW_THREADS(self);
173 :
174 218 : if ((option == LDAP_OPT_SERVER_CONTROLS) || (option == LDAP_OPT_CLIENT_CONTROLS))
175 18 : LDAPControl_List_DEL(controls);
176 :
177 218 : if (res != LDAP_OPT_SUCCESS) {
178 0 : option_error(res, "ldap_set_option");
179 0 : return 0;
180 : }
181 :
182 218 : return 1;
183 : }
184 :
185 : PyObject *
186 80 : LDAP_get_option(LDAPObject *self, int option)
187 : {
188 : int res;
189 : int intval;
190 : struct timeval *tv;
191 : LDAPAPIInfo apiinfo;
192 : LDAPControl **lcs;
193 : char *strval;
194 : PyObject *extensions, *v;
195 : Py_ssize_t i, num_extensions;
196 : LDAP *ld;
197 :
198 80 : ld = self ? self->ldap : NULL;
199 :
200 80 : switch(option) {
201 3 : case LDAP_OPT_API_INFO:
202 3 : apiinfo.ldapai_info_version = LDAP_API_INFO_VERSION;
203 3 : if (self) LDAP_BEGIN_ALLOW_THREADS(self);
204 3 : res = ldap_get_option( ld, option, &apiinfo );
205 3 : if (self) LDAP_END_ALLOW_THREADS(self);
206 3 : if (res != LDAP_OPT_SUCCESS)
207 80 : return option_error(res, "ldap_get_option");
208 :
209 : /* put the extensions into tuple form */
210 3 : num_extensions = 0;
211 21 : while (apiinfo.ldapai_extensions[num_extensions])
212 15 : num_extensions++;
213 3 : extensions = PyTuple_New(num_extensions);
214 18 : for (i = 0; i < num_extensions; i++)
215 15 : PyTuple_SET_ITEM(extensions, i,
216 : PyUnicode_FromString(apiinfo.ldapai_extensions[i]));
217 :
218 : /* return api info as a dictionary */
219 3 : v = Py_BuildValue("{s:i, s:i, s:i, s:s, s:i, s:O}",
220 : "info_version", apiinfo.ldapai_info_version,
221 : "api_version", apiinfo.ldapai_api_version,
222 : "protocol_version", apiinfo.ldapai_protocol_version,
223 : "vendor_name", apiinfo.ldapai_vendor_name,
224 : "vendor_version", apiinfo.ldapai_vendor_version,
225 : "extensions", extensions);
226 :
227 3 : if (apiinfo.ldapai_vendor_name)
228 3 : ldap_memfree(apiinfo.ldapai_vendor_name);
229 18 : for (i = 0; i < num_extensions; i++)
230 15 : ldap_memfree(apiinfo.ldapai_extensions[i]);
231 3 : ldap_memfree(apiinfo.ldapai_extensions);
232 3 : Py_DECREF(extensions);
233 :
234 3 : return v;
235 :
236 : #ifdef HAVE_SASL
237 5 : case LDAP_OPT_X_SASL_SSF:
238 : #endif
239 : case LDAP_OPT_REFERRALS:
240 : case LDAP_OPT_RESTART:
241 : case LDAP_OPT_DEREF:
242 : case LDAP_OPT_SIZELIMIT:
243 : case LDAP_OPT_TIMELIMIT:
244 : case LDAP_OPT_PROTOCOL_VERSION:
245 : case LDAP_OPT_ERROR_NUMBER:
246 : case LDAP_OPT_DEBUG_LEVEL:
247 : case LDAP_OPT_DESC:
248 : #ifdef HAVE_TLS
249 : case LDAP_OPT_X_TLS:
250 : case LDAP_OPT_X_TLS_REQUIRE_CERT:
251 : #ifdef LDAP_OPT_X_TLS_CRLCHECK
252 : case LDAP_OPT_X_TLS_CRLCHECK:
253 : #endif
254 : #ifdef LDAP_OPT_X_TLS_PROTOCOL_MIN
255 : case LDAP_OPT_X_TLS_PROTOCOL_MIN:
256 : #endif
257 : #endif
258 : #ifdef HAVE_SASL
259 : case LDAP_OPT_X_SASL_SSF_MIN:
260 : case LDAP_OPT_X_SASL_SSF_MAX:
261 : #endif
262 : #ifdef LDAP_OPT_X_SASL_NOCANON
263 : case LDAP_OPT_X_SASL_NOCANON:
264 : #endif
265 : #ifdef LDAP_OPT_CONNECT_ASYNC
266 : case LDAP_OPT_CONNECT_ASYNC:
267 : #endif
268 : #ifdef LDAP_OPT_X_KEEPALIVE_IDLE
269 : case LDAP_OPT_X_KEEPALIVE_IDLE:
270 : #endif
271 : #ifdef LDAP_OPT_X_KEEPALIVE_PROBES
272 : case LDAP_OPT_X_KEEPALIVE_PROBES:
273 : #endif
274 : #ifdef LDAP_OPT_X_KEEPALIVE_INTERVAL
275 : case LDAP_OPT_X_KEEPALIVE_INTERVAL:
276 : #endif
277 : /* Integer-valued options */
278 5 : if (self) LDAP_BEGIN_ALLOW_THREADS(self);
279 5 : res = ldap_get_option(ld, option, &intval);
280 5 : if (self) LDAP_END_ALLOW_THREADS(self);
281 5 : if (res != LDAP_OPT_SUCCESS)
282 0 : return option_error(res, "ldap_get_option");
283 5 : return PyInt_FromLong(intval);
284 :
285 10 : case LDAP_OPT_HOST_NAME:
286 : case LDAP_OPT_URI:
287 : #ifdef LDAP_OPT_DEFBASE
288 : case LDAP_OPT_DEFBASE:
289 : #endif
290 : case LDAP_OPT_ERROR_STRING:
291 : case LDAP_OPT_MATCHED_DN:
292 : #ifdef HAVE_TLS
293 : case LDAP_OPT_X_TLS_CACERTFILE:
294 : case LDAP_OPT_X_TLS_CACERTDIR:
295 : case LDAP_OPT_X_TLS_CERTFILE:
296 : case LDAP_OPT_X_TLS_KEYFILE:
297 : case LDAP_OPT_X_TLS_CIPHER_SUITE:
298 : case LDAP_OPT_X_TLS_RANDOM_FILE:
299 : case LDAP_OPT_X_TLS_DHFILE:
300 : #ifdef LDAP_OPT_X_TLS_CRLFILE
301 : case LDAP_OPT_X_TLS_CRLFILE:
302 : #endif
303 : #ifdef LDAP_OPT_X_TLS_VERSION
304 : case LDAP_OPT_X_TLS_VERSION:
305 : #endif
306 : #ifdef LDAP_OPT_X_TLS_CIPHER
307 : case LDAP_OPT_X_TLS_CIPHER:
308 : #endif
309 : #ifdef LDAP_OPT_X_TLS_PACKAGE
310 : case LDAP_OPT_X_TLS_PACKAGE:
311 : #endif
312 : #endif
313 : #ifdef HAVE_SASL
314 : case LDAP_OPT_X_SASL_SECPROPS:
315 : case LDAP_OPT_X_SASL_MECH:
316 : case LDAP_OPT_X_SASL_REALM:
317 : case LDAP_OPT_X_SASL_AUTHCID:
318 : case LDAP_OPT_X_SASL_AUTHZID:
319 : #ifdef LDAP_OPT_X_SASL_USERNAME
320 : case LDAP_OPT_X_SASL_USERNAME:
321 : #endif
322 : #endif
323 : /* String-valued options */
324 10 : if (self) LDAP_BEGIN_ALLOW_THREADS(self);
325 10 : res = ldap_get_option(ld, option, &strval);
326 10 : if (self) LDAP_END_ALLOW_THREADS(self);
327 10 : if (res != LDAP_OPT_SUCCESS)
328 1 : return option_error(res, "ldap_get_option");
329 9 : if (strval == NULL) {
330 2 : Py_INCREF(Py_None);
331 2 : return Py_None;
332 : }
333 7 : v = PyUnicode_FromString(strval);
334 7 : ldap_memfree(strval);
335 7 : return v;
336 :
337 32 : case LDAP_OPT_TIMEOUT:
338 : case LDAP_OPT_NETWORK_TIMEOUT:
339 : /* Double-valued timeval options */
340 32 : if (self) LDAP_BEGIN_ALLOW_THREADS(self);
341 32 : res = ldap_get_option(ld, option, &tv);
342 32 : if (self) LDAP_END_ALLOW_THREADS(self);
343 32 : if (res != LDAP_OPT_SUCCESS)
344 0 : return option_error(res, "ldap_get_option");
345 32 : if (tv == NULL) {
346 24 : Py_INCREF(Py_None);
347 24 : return Py_None;
348 : }
349 8 : v = PyFloat_FromDouble(
350 8 : (double) tv->tv_sec + ( (double) tv->tv_usec / 1000000.0 )
351 : );
352 8 : ldap_memfree(tv);
353 8 : return v;
354 :
355 28 : case LDAP_OPT_SERVER_CONTROLS:
356 : case LDAP_OPT_CLIENT_CONTROLS:
357 28 : if (self) LDAP_BEGIN_ALLOW_THREADS(self);
358 28 : res = ldap_get_option(ld, option, &lcs);
359 28 : if (self) LDAP_END_ALLOW_THREADS(self);
360 :
361 28 : if (res != LDAP_OPT_SUCCESS)
362 0 : return option_error(res, "ldap_get_option");
363 :
364 28 : v = LDAPControls_to_List(lcs);
365 28 : ldap_controls_free(lcs);
366 28 : return v;
367 :
368 2 : default:
369 2 : PyErr_Format(PyExc_ValueError, "unknown option %d", option);
370 2 : return NULL;
371 : }
372 : }
|