PageRenderTime 25ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/freeipa-3.0.0.pre1/daemons/ipa-kdb/ipa_kdb_common.c

#
C | 533 lines | 418 code | 83 blank | 32 comment | 64 complexity | b80ede3b7ddc477ea49ff27d8b0e14c3 MD5 | raw file
Possible License(s): GPL-3.0
  1. /*
  2. * MIT Kerberos KDC database backend for FreeIPA
  3. *
  4. * Authors: Simo Sorce <ssorce@redhat.com>
  5. *
  6. * Copyright (C) 2011 Simo Sorce, Red Hat
  7. * see file 'COPYING' for use and warranty information
  8. *
  9. * This program is free software you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation, either version 3 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. */
  22. #include "ipa_kdb.h"
  23. static struct timeval std_timeout = {300, 0};
  24. char *ipadb_filter_escape(const char *input, bool star)
  25. {
  26. char *output;
  27. size_t i = 0;
  28. size_t j = 0;
  29. /* Assume the worst-case. */
  30. output = malloc(strlen(input) * 3 + 1);
  31. if (!output) {
  32. return NULL;
  33. }
  34. while (input[i]) {
  35. switch(input[i]) {
  36. case '*':
  37. if (star) {
  38. output[j++] = '\\';
  39. output[j++] = '2';
  40. output[j++] = 'a';
  41. } else {
  42. output[j++] = '*';
  43. }
  44. break;
  45. case '(':
  46. output[j++] = '\\';
  47. output[j++] = '2';
  48. output[j++] = '8';
  49. break;
  50. case ')':
  51. output[j++] = '\\';
  52. output[j++] = '2';
  53. output[j++] = '9';
  54. break;
  55. case '\\':
  56. output[j++] = '\\';
  57. output[j++] = '5';
  58. output[j++] = 'c';
  59. break;
  60. default:
  61. output[j++] = input[i];
  62. }
  63. i++;
  64. }
  65. output[j] = '\0';
  66. return output;
  67. }
  68. static krb5_error_code ipadb_simple_ldap_to_kerr(int ldap_error)
  69. {
  70. switch (ldap_error) {
  71. case LDAP_SUCCESS:
  72. return 0;
  73. case LDAP_NO_SUCH_OBJECT:
  74. case LDAP_NO_SUCH_ATTRIBUTE:
  75. return KRB5_KDB_NOENTRY;
  76. case LDAP_ALIAS_PROBLEM:
  77. case LDAP_INVALID_DN_SYNTAX:
  78. case LDAP_ALIAS_DEREF_PROBLEM:
  79. case LDAP_UNDEFINED_TYPE:
  80. case LDAP_INAPPROPRIATE_MATCHING:
  81. case LDAP_INVALID_SYNTAX:
  82. case LDAP_NAMING_VIOLATION:
  83. case LDAP_OBJECT_CLASS_VIOLATION:
  84. case LDAP_NO_OBJECT_CLASS_MODS:
  85. return KRB5_KDB_INTERNAL_ERROR;
  86. case LDAP_ALREADY_EXISTS:
  87. case LDAP_NOT_ALLOWED_ON_NONLEAF:
  88. case LDAP_NOT_ALLOWED_ON_RDN:
  89. case LDAP_TIMELIMIT_EXCEEDED:
  90. case LDAP_SIZELIMIT_EXCEEDED:
  91. case LDAP_ADMINLIMIT_EXCEEDED:
  92. case LDAP_STRONG_AUTH_REQUIRED:
  93. case LDAP_CONFIDENTIALITY_REQUIRED:
  94. case LDAP_INAPPROPRIATE_AUTH:
  95. case LDAP_INVALID_CREDENTIALS:
  96. case LDAP_INSUFFICIENT_ACCESS:
  97. case LDAP_BUSY:
  98. case LDAP_UNAVAILABLE:
  99. case LDAP_UNWILLING_TO_PERFORM:
  100. case LDAP_CONSTRAINT_VIOLATION:
  101. case LDAP_TYPE_OR_VALUE_EXISTS:
  102. return KRB5_KDB_CONSTRAINT_VIOLATION;
  103. }
  104. return KRB5_KDB_SERVER_INTERNAL_ERR;
  105. }
  106. static bool ipadb_need_retry(struct ipadb_context *ipactx, int error)
  107. {
  108. switch(error) {
  109. /* connection errors */
  110. case LDAP_SERVER_DOWN:
  111. case LDAP_LOCAL_ERROR:
  112. case LDAP_ENCODING_ERROR:
  113. case LDAP_DECODING_ERROR:
  114. case LDAP_TIMEOUT:
  115. case LDAP_USER_CANCELLED:
  116. case LDAP_PARAM_ERROR:
  117. case LDAP_NO_MEMORY:
  118. case LDAP_CONNECT_ERROR:
  119. case LDAP_NOT_SUPPORTED:
  120. case LDAP_CLIENT_LOOP:
  121. case LDAP_X_CONNECTING:
  122. /* server returned errors */
  123. case LDAP_PROTOCOL_ERROR:
  124. case LDAP_BUSY:
  125. case LDAP_UNAVAILABLE:
  126. case LDAP_UNWILLING_TO_PERFORM:
  127. case LDAP_LOOP_DETECT:
  128. /* prob connection error, try to reconnect */
  129. error = ipadb_get_connection(ipactx);
  130. if (error == 0) {
  131. return true;
  132. }
  133. /* fall through */
  134. default:
  135. break;
  136. }
  137. return false;
  138. }
  139. krb5_error_code ipadb_simple_search(struct ipadb_context *ipactx,
  140. char *basedn, int scope,
  141. char *filter, char **attrs,
  142. LDAPMessage **res)
  143. {
  144. int ret;
  145. ret = ldap_search_ext_s(ipactx->lcontext, basedn, scope,
  146. filter, attrs, 0, NULL, NULL,
  147. &std_timeout, LDAP_NO_LIMIT,
  148. res);
  149. /* first test if we need to retry to connect */
  150. if (ret != 0 &&
  151. ipadb_need_retry(ipactx, ret)) {
  152. ret = ldap_search_ext_s(ipactx->lcontext, basedn, scope,
  153. filter, attrs, 0, NULL, NULL,
  154. &std_timeout, LDAP_NO_LIMIT,
  155. res);
  156. }
  157. return ipadb_simple_ldap_to_kerr(ret);
  158. }
  159. krb5_error_code ipadb_simple_delete(struct ipadb_context *ipactx, char *dn)
  160. {
  161. int ret;
  162. ret = ldap_delete_ext_s(ipactx->lcontext, dn, NULL, NULL);
  163. /* first test if we need to retry to connect */
  164. if (ret != 0 &&
  165. ipadb_need_retry(ipactx, ret)) {
  166. ret = ldap_delete_ext_s(ipactx->lcontext, dn, NULL, NULL);
  167. }
  168. return ipadb_simple_ldap_to_kerr(ret);
  169. }
  170. krb5_error_code ipadb_simple_add(struct ipadb_context *ipactx,
  171. char *dn, LDAPMod **mods)
  172. {
  173. int ret;
  174. ret = ldap_add_ext_s(ipactx->lcontext, dn, mods, NULL, NULL);
  175. /* first test if we need to retry to connect */
  176. if (ret != 0 &&
  177. ipadb_need_retry(ipactx, ret)) {
  178. ret = ldap_add_ext_s(ipactx->lcontext, dn, mods, NULL, NULL);
  179. }
  180. return ipadb_simple_ldap_to_kerr(ret);
  181. }
  182. krb5_error_code ipadb_simple_modify(struct ipadb_context *ipactx,
  183. char *dn, LDAPMod **mods)
  184. {
  185. int ret;
  186. ret = ldap_modify_ext_s(ipactx->lcontext, dn, mods, NULL, NULL);
  187. /* first test if we need to retry to connect */
  188. if (ret != 0 &&
  189. ipadb_need_retry(ipactx, ret)) {
  190. ret = ldap_modify_ext_s(ipactx->lcontext, dn, mods, NULL, NULL);
  191. }
  192. return ipadb_simple_ldap_to_kerr(ret);
  193. }
  194. krb5_error_code ipadb_simple_delete_val(struct ipadb_context *ipactx,
  195. char *dn, char *attr, char *value)
  196. {
  197. krb5_error_code kerr;
  198. LDAPMod *mods[2];
  199. mods[0] = calloc(1, sizeof(LDAPMod));
  200. if (!mods[0]) {
  201. return ENOMEM;
  202. }
  203. mods[1] = NULL;
  204. mods[0]->mod_op = LDAP_MOD_DELETE;
  205. mods[0]->mod_type = strdup(attr);
  206. if (!mods[0]->mod_type) {
  207. kerr = ENOMEM;
  208. goto done;
  209. }
  210. mods[0]->mod_values = calloc(2, sizeof(char *));
  211. if (!mods[0]->mod_values) {
  212. kerr = ENOMEM;
  213. goto done;
  214. }
  215. mods[0]->mod_values[0] = strdup(value);
  216. if (!mods[0]->mod_values[0]) {
  217. kerr = ENOMEM;
  218. goto done;
  219. }
  220. kerr = ipadb_simple_modify(ipactx, dn, mods);
  221. done:
  222. ldap_mods_free(mods, 0);
  223. return kerr;
  224. }
  225. krb5_error_code ipadb_deref_search(struct ipadb_context *ipactx,
  226. char *base_dn, int scope,
  227. char *filter,
  228. char **entry_attrs,
  229. char **deref_attr_names,
  230. char **deref_attrs,
  231. LDAPMessage **res)
  232. {
  233. struct berval derefval = { 0, NULL };
  234. LDAPControl *ctrl[2] = { NULL, NULL };
  235. LDAPDerefSpec *ds;
  236. krb5_error_code kerr;
  237. int times;
  238. int ret;
  239. int c;
  240. for (c = 0; deref_attr_names[c]; c++) {
  241. /* count */ ;
  242. }
  243. ds = calloc(c, sizeof(LDAPDerefSpec));
  244. if (!ds) {
  245. return ENOMEM;
  246. }
  247. for (c = 0; deref_attr_names[c]; c++) {
  248. ds[c].derefAttr = deref_attr_names[c];
  249. ds[c].attributes = deref_attrs;
  250. }
  251. ret = ldap_create_deref_control_value(ipactx->lcontext, ds, &derefval);
  252. if (ret != LDAP_SUCCESS) {
  253. kerr = ENOMEM;
  254. goto done;
  255. }
  256. ret = ldap_control_create(LDAP_CONTROL_X_DEREF,
  257. 1, &derefval, 1, &ctrl[0]);
  258. if (ret != LDAP_SUCCESS) {
  259. kerr = ENOMEM;
  260. goto done;
  261. }
  262. /* retry once if connection errors (tot. max. 2 tries) */
  263. times = 2;
  264. ret = LDAP_SUCCESS;
  265. while (!ipadb_need_retry(ipactx, ret) && times > 0) {
  266. times--;
  267. ret = ldap_search_ext_s(ipactx->lcontext, base_dn,
  268. scope, filter,
  269. entry_attrs, 0,
  270. ctrl, NULL,
  271. &std_timeout, LDAP_NO_LIMIT,
  272. res);
  273. }
  274. kerr = ipadb_simple_ldap_to_kerr(ret);
  275. done:
  276. ldap_memfree(derefval.bv_val);
  277. free(ds);
  278. return kerr;
  279. }
  280. /* result extraction */
  281. int ipadb_ldap_attr_to_int(LDAP *lcontext, LDAPMessage *le,
  282. char *attrname, int *result)
  283. {
  284. struct berval **vals;
  285. int ret = ENOENT;
  286. vals = ldap_get_values_len(lcontext, le, attrname);
  287. if (vals) {
  288. *result = atoi(vals[0]->bv_val);
  289. ret = 0;
  290. ldap_value_free_len(vals);
  291. }
  292. return ret;
  293. }
  294. int ipadb_ldap_attr_to_uint32(LDAP *lcontext, LDAPMessage *le,
  295. char *attrname, uint32_t *result)
  296. {
  297. struct berval **vals;
  298. long r;
  299. int ret = ENOENT;
  300. vals = ldap_get_values_len(lcontext, le, attrname);
  301. if (vals) {
  302. r = atol(vals[0]->bv_val);
  303. if (r < 0 || r > (uint32_t)-1) {
  304. ret = EINVAL;
  305. } else {
  306. *result = r;
  307. ret = 0;
  308. }
  309. ldap_value_free_len(vals);
  310. }
  311. return ret;
  312. }
  313. int ipadb_ldap_attr_to_str(LDAP *lcontext, LDAPMessage *le,
  314. char *attrname, char **result)
  315. {
  316. struct berval **vals;
  317. int ret = ENOENT;
  318. vals = ldap_get_values_len(lcontext, le, attrname);
  319. if (vals) {
  320. *result = strndup(vals[0]->bv_val, vals[0]->bv_len);
  321. if (!*result) {
  322. ret = ENOMEM;
  323. } else {
  324. ret = 0;
  325. }
  326. ldap_value_free_len(vals);
  327. }
  328. return ret;
  329. }
  330. int ipadb_ldap_attr_to_strlist(LDAP *lcontext, LDAPMessage *le,
  331. char *attrname, char ***result)
  332. {
  333. struct berval **vals = NULL;
  334. char **strlist = NULL;
  335. int ret;
  336. int i;
  337. vals = ldap_get_values_len(lcontext, le, attrname);
  338. if (!vals) {
  339. return ENOENT;
  340. }
  341. for (i = 0; vals[i]; i++) /* count */ ;
  342. strlist = calloc(i + 1, sizeof(char *));
  343. if (!strlist) {
  344. ret = ENOMEM;
  345. goto fail;
  346. }
  347. for (i = 0; vals[i]; i++) {
  348. strlist[i] = strndup(vals[i]->bv_val, vals[i]->bv_len);
  349. if (!strlist[i]) {
  350. ret = ENOMEM;
  351. goto fail;
  352. }
  353. }
  354. ldap_value_free_len(vals);
  355. *result = strlist;
  356. return 0;
  357. fail:
  358. ldap_value_free_len(vals);
  359. for (i = 0; strlist && strlist[i]; i++) {
  360. free(strlist[i]);
  361. }
  362. free(strlist);
  363. return ret;
  364. }
  365. int ipadb_ldap_attr_to_bool(LDAP *lcontext, LDAPMessage *le,
  366. char *attrname, bool *result)
  367. {
  368. struct berval **vals;
  369. int ret = ENOENT;
  370. vals = ldap_get_values_len(lcontext, le, attrname);
  371. if (vals) {
  372. if (strcasecmp("TRUE", vals[0]->bv_val) == 0) {
  373. *result = true;
  374. ret = 0;
  375. } else if (strcasecmp("FALSE", vals[0]->bv_val) == 0) {
  376. *result = false;
  377. ret = 0;
  378. } else {
  379. ret = EINVAL;
  380. }
  381. ldap_value_free_len(vals);
  382. }
  383. return ret;
  384. }
  385. int ipadb_ldap_attr_to_time_t(LDAP *lcontext, LDAPMessage *le,
  386. char *attrname, time_t *result)
  387. {
  388. struct berval **vals;
  389. char *p;
  390. struct tm stm = { 0 };
  391. int ret = ENOENT;
  392. vals = ldap_get_values_len(lcontext, le, attrname);
  393. if (vals) {
  394. p = strptime(vals[0]->bv_val, "%Y%m%d%H%M%SZ", &stm);
  395. if (p && *p == '\0') {
  396. *result = timegm(&stm);
  397. ret = 0;
  398. } else {
  399. ret = EINVAL;
  400. }
  401. ldap_value_free_len(vals);
  402. }
  403. return ret;
  404. }
  405. int ipadb_ldap_attr_has_value(LDAP *lcontext, LDAPMessage *le,
  406. char *attrname, char *value)
  407. {
  408. struct berval **vals;
  409. int ret = ENOENT;
  410. int i;
  411. vals = ldap_get_values_len(lcontext, le, attrname);
  412. if (vals) {
  413. for (i = 0; vals[i]; i++) {
  414. if (strcasecmp(vals[i]->bv_val, value) == 0) {
  415. ret = 0;
  416. break;
  417. }
  418. }
  419. ldap_value_free_len(vals);
  420. }
  421. return ret;
  422. }
  423. int ipadb_ldap_deref_results(LDAP *lcontext, LDAPMessage *le,
  424. LDAPDerefRes **results)
  425. {
  426. LDAPControl **ctrls = NULL;
  427. LDAPControl *derefctrl = NULL;
  428. int ret;
  429. ret = ldap_get_entry_controls(lcontext, le, &ctrls);
  430. if (ret != LDAP_SUCCESS) {
  431. return EINVAL;
  432. }
  433. if (!ctrls) {
  434. return ENOENT;
  435. }
  436. derefctrl = ldap_control_find(LDAP_CONTROL_X_DEREF, ctrls, NULL);
  437. if (!derefctrl) {
  438. ret = ENOENT;
  439. goto done;
  440. }
  441. ret = ldap_parse_derefresponse_control(lcontext, derefctrl, results);
  442. if (ret) {
  443. ret = EINVAL;
  444. goto done;
  445. }
  446. ret = 0;
  447. done:
  448. ldap_controls_free(ctrls);
  449. return ret;
  450. }