PageRenderTime 51ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/hdb/common.c

https://github.com/asankah/heimdal
C | 487 lines | 360 code | 59 blank | 68 comment | 111 complexity | 5386c03928e871a1811836c2bf29875b MD5 | raw file
Possible License(s): BSD-3-Clause
  1. /*
  2. * Copyright (c) 1997-2002 Kungliga Tekniska Högskolan
  3. * (Royal Institute of Technology, Stockholm, Sweden).
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. *
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. *
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. *
  17. * 3. Neither the name of the Institute nor the names of its contributors
  18. * may be used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
  22. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24. * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
  25. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. */
  33. #include "krb5_locl.h"
  34. #include "hdb_locl.h"
  35. int
  36. hdb_principal2key(krb5_context context, krb5_const_principal p, krb5_data *key)
  37. {
  38. Principal new;
  39. size_t len = 0;
  40. int ret;
  41. ret = copy_Principal(p, &new);
  42. if(ret)
  43. return ret;
  44. new.name.name_type = 0;
  45. ASN1_MALLOC_ENCODE(Principal, key->data, key->length, &new, &len, ret);
  46. if (ret == 0 && key->length != len)
  47. krb5_abortx(context, "internal asn.1 encoder error");
  48. free_Principal(&new);
  49. return ret;
  50. }
  51. int
  52. hdb_key2principal(krb5_context context, krb5_data *key, krb5_principal p)
  53. {
  54. return decode_Principal(key->data, key->length, p, NULL);
  55. }
  56. int
  57. hdb_entry2value(krb5_context context, const hdb_entry *ent, krb5_data *value)
  58. {
  59. size_t len = 0;
  60. int ret;
  61. ASN1_MALLOC_ENCODE(hdb_entry, value->data, value->length, ent, &len, ret);
  62. if (ret == 0 && value->length != len)
  63. krb5_abortx(context, "internal asn.1 encoder error");
  64. return ret;
  65. }
  66. int
  67. hdb_value2entry(krb5_context context, krb5_data *value, hdb_entry *ent)
  68. {
  69. return decode_hdb_entry(value->data, value->length, ent, NULL);
  70. }
  71. int
  72. hdb_entry_alias2value(krb5_context context,
  73. const hdb_entry_alias *alias,
  74. krb5_data *value)
  75. {
  76. size_t len = 0;
  77. int ret;
  78. ASN1_MALLOC_ENCODE(hdb_entry_alias, value->data, value->length,
  79. alias, &len, ret);
  80. if (ret == 0 && value->length != len)
  81. krb5_abortx(context, "internal asn.1 encoder error");
  82. return ret;
  83. }
  84. int
  85. hdb_value2entry_alias(krb5_context context, krb5_data *value,
  86. hdb_entry_alias *ent)
  87. {
  88. return decode_hdb_entry_alias(value->data, value->length, ent, NULL);
  89. }
  90. /*
  91. * Some old databases may not have stored the salt with each key, which will
  92. * break clients when aliases or canonicalization are used. Generate a
  93. * default salt based on the real principal name in the entry to handle
  94. * this case.
  95. */
  96. static krb5_error_code
  97. add_default_salts(krb5_context context, HDB *db, hdb_entry *entry)
  98. {
  99. krb5_error_code ret;
  100. size_t i;
  101. krb5_salt pwsalt;
  102. ret = krb5_get_pw_salt(context, entry->principal, &pwsalt);
  103. if (ret)
  104. return ret;
  105. for (i = 0; i < entry->keys.len; i++) {
  106. Key *key = &entry->keys.val[i];
  107. if (key->salt != NULL ||
  108. _krb5_enctype_requires_random_salt(context, key->key.keytype))
  109. continue;
  110. key->salt = calloc(1, sizeof(*key->salt));
  111. if (key->salt == NULL) {
  112. ret = krb5_enomem(context);
  113. break;
  114. }
  115. key->salt->type = KRB5_PADATA_PW_SALT;
  116. ret = krb5_data_copy(&key->salt->salt,
  117. pwsalt.saltvalue.data,
  118. pwsalt.saltvalue.length);
  119. if (ret)
  120. break;
  121. }
  122. krb5_free_salt(context, pwsalt);
  123. return ret;
  124. }
  125. krb5_error_code
  126. _hdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal,
  127. unsigned flags, krb5_kvno kvno, hdb_entry_ex *entry)
  128. {
  129. krb5_principal enterprise_principal = NULL;
  130. krb5_data key, value;
  131. krb5_error_code ret;
  132. if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
  133. if (principal->name.name_string.len != 1) {
  134. ret = KRB5_PARSE_MALFORMED;
  135. krb5_set_error_message(context, ret, "malformed principal: "
  136. "enterprise name with %d name components",
  137. principal->name.name_string.len);
  138. return ret;
  139. }
  140. ret = krb5_parse_name(context, principal->name.name_string.val[0],
  141. &enterprise_principal);
  142. if (ret)
  143. return ret;
  144. principal = enterprise_principal;
  145. }
  146. hdb_principal2key(context, principal, &key);
  147. if (enterprise_principal)
  148. krb5_free_principal(context, enterprise_principal);
  149. ret = db->hdb__get(context, db, key, &value);
  150. krb5_data_free(&key);
  151. if(ret)
  152. return ret;
  153. ret = hdb_value2entry(context, &value, &entry->entry);
  154. /* HDB_F_GET_ANY indicates request originated from KDC (not kadmin) */
  155. if (ret == ASN1_BAD_ID && (flags & (HDB_F_CANON|HDB_F_GET_ANY)) == 0) {
  156. krb5_data_free(&value);
  157. return HDB_ERR_NOENTRY;
  158. } else if (ret == ASN1_BAD_ID) {
  159. hdb_entry_alias alias;
  160. ret = hdb_value2entry_alias(context, &value, &alias);
  161. if (ret) {
  162. krb5_data_free(&value);
  163. return ret;
  164. }
  165. hdb_principal2key(context, alias.principal, &key);
  166. krb5_data_free(&value);
  167. free_hdb_entry_alias(&alias);
  168. ret = db->hdb__get(context, db, key, &value);
  169. krb5_data_free(&key);
  170. if (ret)
  171. return ret;
  172. ret = hdb_value2entry(context, &value, &entry->entry);
  173. if (ret) {
  174. krb5_data_free(&value);
  175. return ret;
  176. }
  177. }
  178. krb5_data_free(&value);
  179. if ((flags & HDB_F_DECRYPT) && (flags & HDB_F_ALL_KVNOS)) {
  180. /* Decrypt the current keys */
  181. ret = hdb_unseal_keys(context, db, &entry->entry);
  182. if (ret) {
  183. hdb_free_entry(context, entry);
  184. return ret;
  185. }
  186. /* Decrypt the key history too */
  187. ret = hdb_unseal_keys_kvno(context, db, 0, flags, &entry->entry);
  188. if (ret) {
  189. hdb_free_entry(context, entry);
  190. return ret;
  191. }
  192. } else if ((flags & HDB_F_DECRYPT)) {
  193. if ((flags & HDB_F_KVNO_SPECIFIED) == 0 || kvno == entry->entry.kvno) {
  194. /* Decrypt the current keys */
  195. ret = hdb_unseal_keys(context, db, &entry->entry);
  196. if (ret) {
  197. hdb_free_entry(context, entry);
  198. return ret;
  199. }
  200. } else {
  201. if ((flags & HDB_F_ALL_KVNOS))
  202. kvno = 0;
  203. /*
  204. * Find and decrypt the keys from the history that we want,
  205. * and swap them with the current keys
  206. */
  207. ret = hdb_unseal_keys_kvno(context, db, kvno, flags, &entry->entry);
  208. if (ret) {
  209. hdb_free_entry(context, entry);
  210. return ret;
  211. }
  212. }
  213. }
  214. if ((flags & HDB_F_FOR_AS_REQ) && (flags & HDB_F_GET_CLIENT)) {
  215. /*
  216. * Generate default salt for any principals missing one; note such
  217. * principals could include those for which a random (non-password)
  218. * key was generated, but given the salt will be ignored by a keytab
  219. * client it doesn't hurt to include the default salt.
  220. */
  221. ret = add_default_salts(context, db, &entry->entry);
  222. if (ret) {
  223. hdb_free_entry(context, entry);
  224. return ret;
  225. }
  226. }
  227. if (enterprise_principal) {
  228. /*
  229. * Whilst Windows does not canonicalize enterprise principal names if
  230. * the canonicalize flag is unset, the original specification in
  231. * draft-ietf-krb-wg-kerberos-referrals-03.txt says we should.
  232. */
  233. entry->entry.flags.force_canonicalize = 1;
  234. }
  235. return 0;
  236. }
  237. static krb5_error_code
  238. hdb_remove_aliases(krb5_context context, HDB *db, krb5_data *key)
  239. {
  240. const HDB_Ext_Aliases *aliases;
  241. krb5_error_code code;
  242. hdb_entry oldentry;
  243. krb5_data value;
  244. size_t i;
  245. code = db->hdb__get(context, db, *key, &value);
  246. if (code == HDB_ERR_NOENTRY)
  247. return 0;
  248. else if (code)
  249. return code;
  250. code = hdb_value2entry(context, &value, &oldentry);
  251. krb5_data_free(&value);
  252. if (code)
  253. return code;
  254. code = hdb_entry_get_aliases(&oldentry, &aliases);
  255. if (code || aliases == NULL) {
  256. free_hdb_entry(&oldentry);
  257. return code;
  258. }
  259. for (i = 0; i < aliases->aliases.len; i++) {
  260. krb5_data akey;
  261. code = hdb_principal2key(context, &aliases->aliases.val[i], &akey);
  262. if (code == 0) {
  263. code = db->hdb__del(context, db, akey);
  264. krb5_data_free(&akey);
  265. }
  266. if (code) {
  267. free_hdb_entry(&oldentry);
  268. return code;
  269. }
  270. }
  271. free_hdb_entry(&oldentry);
  272. return 0;
  273. }
  274. static krb5_error_code
  275. hdb_add_aliases(krb5_context context, HDB *db,
  276. unsigned flags, hdb_entry_ex *entry)
  277. {
  278. const HDB_Ext_Aliases *aliases;
  279. krb5_error_code code;
  280. krb5_data key, value;
  281. size_t i;
  282. code = hdb_entry_get_aliases(&entry->entry, &aliases);
  283. if (code || aliases == NULL)
  284. return code;
  285. for (i = 0; i < aliases->aliases.len; i++) {
  286. hdb_entry_alias entryalias;
  287. entryalias.principal = entry->entry.principal;
  288. code = hdb_entry_alias2value(context, &entryalias, &value);
  289. if (code)
  290. return code;
  291. code = hdb_principal2key(context, &aliases->aliases.val[i], &key);
  292. if (code == 0) {
  293. code = db->hdb__put(context, db, flags, key, value);
  294. krb5_data_free(&key);
  295. }
  296. krb5_data_free(&value);
  297. if (code)
  298. return code;
  299. }
  300. return 0;
  301. }
  302. static krb5_error_code
  303. hdb_check_aliases(krb5_context context, HDB *db, hdb_entry_ex *entry)
  304. {
  305. const HDB_Ext_Aliases *aliases;
  306. int code;
  307. size_t i;
  308. /* check if new aliases already is used */
  309. code = hdb_entry_get_aliases(&entry->entry, &aliases);
  310. if (code)
  311. return code;
  312. for (i = 0; aliases && i < aliases->aliases.len; i++) {
  313. hdb_entry_alias alias;
  314. krb5_data akey, value;
  315. code = hdb_principal2key(context, &aliases->aliases.val[i], &akey);
  316. if (code == 0) {
  317. code = db->hdb__get(context, db, akey, &value);
  318. krb5_data_free(&akey);
  319. }
  320. if (code == HDB_ERR_NOENTRY)
  321. continue;
  322. else if (code)
  323. return code;
  324. code = hdb_value2entry_alias(context, &value, &alias);
  325. krb5_data_free(&value);
  326. if (code == ASN1_BAD_ID)
  327. return HDB_ERR_EXISTS;
  328. else if (code)
  329. return code;
  330. code = krb5_principal_compare(context, alias.principal,
  331. entry->entry.principal);
  332. free_hdb_entry_alias(&alias);
  333. if (code == 0)
  334. return HDB_ERR_EXISTS;
  335. }
  336. return 0;
  337. }
  338. krb5_error_code
  339. _hdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
  340. {
  341. krb5_data key, value;
  342. int code;
  343. if (entry->entry.flags.do_not_store ||
  344. entry->entry.flags.force_canonicalize)
  345. return HDB_ERR_MISUSE;
  346. /* check if new aliases already is used */
  347. code = hdb_check_aliases(context, db, entry);
  348. if (code)
  349. return code;
  350. if ((flags & HDB_F_PRECHECK) && (flags & HDB_F_REPLACE))
  351. return 0;
  352. if ((flags & HDB_F_PRECHECK)) {
  353. code = hdb_principal2key(context, entry->entry.principal, &key);
  354. if (code)
  355. return code;
  356. code = db->hdb__get(context, db, key, &value);
  357. krb5_data_free(&key);
  358. if (code == 0)
  359. krb5_data_free(&value);
  360. if (code == HDB_ERR_NOENTRY)
  361. return 0;
  362. return code ? code : HDB_ERR_EXISTS;
  363. }
  364. if(entry->entry.generation == NULL) {
  365. struct timeval t;
  366. entry->entry.generation = malloc(sizeof(*entry->entry.generation));
  367. if(entry->entry.generation == NULL) {
  368. krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
  369. return ENOMEM;
  370. }
  371. gettimeofday(&t, NULL);
  372. entry->entry.generation->time = t.tv_sec;
  373. entry->entry.generation->usec = t.tv_usec;
  374. entry->entry.generation->gen = 0;
  375. } else
  376. entry->entry.generation->gen++;
  377. code = hdb_seal_keys(context, db, &entry->entry);
  378. if (code)
  379. return code;
  380. hdb_principal2key(context, entry->entry.principal, &key);
  381. /* remove aliases */
  382. code = hdb_remove_aliases(context, db, &key);
  383. if (code) {
  384. krb5_data_free(&key);
  385. return code;
  386. }
  387. hdb_entry2value(context, &entry->entry, &value);
  388. code = db->hdb__put(context, db, flags & HDB_F_REPLACE, key, value);
  389. krb5_data_free(&value);
  390. krb5_data_free(&key);
  391. if (code)
  392. return code;
  393. code = hdb_add_aliases(context, db, flags, entry);
  394. return code;
  395. }
  396. krb5_error_code
  397. _hdb_remove(krb5_context context, HDB *db,
  398. unsigned flags, krb5_const_principal principal)
  399. {
  400. krb5_data key, value;
  401. int code;
  402. hdb_principal2key(context, principal, &key);
  403. if ((flags & HDB_F_PRECHECK)) {
  404. /*
  405. * We don't check that we can delete the aliases because we
  406. * assume that the DB is consistent. If we did check for alias
  407. * consistency we'd also have to provide a way to fsck the DB,
  408. * otherwise admins would have no way to recover -- papering
  409. * over this here is less work, but we really ought to provide
  410. * an HDB fsck.
  411. */
  412. code = db->hdb__get(context, db, key, &value);
  413. krb5_data_free(&key);
  414. if (code == 0) {
  415. krb5_data_free(&value);
  416. return 0;
  417. }
  418. return code;
  419. }
  420. code = hdb_remove_aliases(context, db, &key);
  421. if (code) {
  422. krb5_data_free(&key);
  423. return code;
  424. }
  425. code = db->hdb__del(context, db, key);
  426. krb5_data_free(&key);
  427. return code;
  428. }