/crypto/heimdal/kadmin/util.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 674 lines · 458 code · 89 blank · 127 comment · 151 complexity · 2f246e89034159550cedd8f83b4f2ce1 MD5 · raw file

  1. /*
  2. * Copyright (c) 1997 - 2006 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 "kadmin_locl.h"
  34. #include <parse_units.h>
  35. /*
  36. * util.c - functions for parsing, unparsing, and editing different
  37. * types of data used in kadmin.
  38. */
  39. static int
  40. get_response(const char *prompt, const char *def, char *buf, size_t len);
  41. /*
  42. * attributes
  43. */
  44. struct units kdb_attrs[] = {
  45. { "allow-digest", KRB5_KDB_ALLOW_DIGEST },
  46. { "allow-kerberos4", KRB5_KDB_ALLOW_KERBEROS4 },
  47. { "trusted-for-delegation", KRB5_KDB_TRUSTED_FOR_DELEGATION },
  48. { "ok-as-delegate", KRB5_KDB_OK_AS_DELEGATE },
  49. { "new-princ", KRB5_KDB_NEW_PRINC },
  50. { "support-desmd5", KRB5_KDB_SUPPORT_DESMD5 },
  51. { "pwchange-service", KRB5_KDB_PWCHANGE_SERVICE },
  52. { "disallow-svr", KRB5_KDB_DISALLOW_SVR },
  53. { "requires-pw-change", KRB5_KDB_REQUIRES_PWCHANGE },
  54. { "requires-hw-auth", KRB5_KDB_REQUIRES_HW_AUTH },
  55. { "requires-pre-auth", KRB5_KDB_REQUIRES_PRE_AUTH },
  56. { "disallow-all-tix", KRB5_KDB_DISALLOW_ALL_TIX },
  57. { "disallow-dup-skey", KRB5_KDB_DISALLOW_DUP_SKEY },
  58. { "disallow-proxiable", KRB5_KDB_DISALLOW_PROXIABLE },
  59. { "disallow-renewable", KRB5_KDB_DISALLOW_RENEWABLE },
  60. { "disallow-tgt-based", KRB5_KDB_DISALLOW_TGT_BASED },
  61. { "disallow-forwardable", KRB5_KDB_DISALLOW_FORWARDABLE },
  62. { "disallow-postdated", KRB5_KDB_DISALLOW_POSTDATED },
  63. { NULL, 0 }
  64. };
  65. /*
  66. * convert the attributes in `attributes' into a printable string
  67. * in `str, len'
  68. */
  69. void
  70. attributes2str(krb5_flags attributes, char *str, size_t len)
  71. {
  72. unparse_flags (attributes, kdb_attrs, str, len);
  73. }
  74. /*
  75. * convert the string in `str' into attributes in `flags'
  76. * return 0 if parsed ok, else -1.
  77. */
  78. int
  79. str2attributes(const char *str, krb5_flags *flags)
  80. {
  81. int res;
  82. res = parse_flags (str, kdb_attrs, *flags);
  83. if (res < 0)
  84. return res;
  85. else {
  86. *flags = res;
  87. return 0;
  88. }
  89. }
  90. /*
  91. * try to parse the string `resp' into attributes in `attr', also
  92. * setting the `bit' in `mask' if attributes are given and valid.
  93. */
  94. int
  95. parse_attributes (const char *resp, krb5_flags *attr, int *mask, int bit)
  96. {
  97. krb5_flags tmp = *attr;
  98. if (str2attributes(resp, &tmp) == 0) {
  99. *attr = tmp;
  100. if (mask)
  101. *mask |= bit;
  102. return 0;
  103. } else if(*resp == '?') {
  104. print_flags_table (kdb_attrs, stderr);
  105. } else {
  106. fprintf (stderr, "Unable to parse \"%s\"\n", resp);
  107. }
  108. return -1;
  109. }
  110. /*
  111. * allow the user to edit the attributes in `attr', prompting with `prompt'
  112. */
  113. int
  114. edit_attributes (const char *prompt, krb5_flags *attr, int *mask, int bit)
  115. {
  116. char buf[1024], resp[1024];
  117. if (mask && (*mask & bit))
  118. return 0;
  119. attributes2str(*attr, buf, sizeof(buf));
  120. for (;;) {
  121. if(get_response("Attributes", buf, resp, sizeof(resp)) != 0)
  122. return 1;
  123. if (resp[0] == '\0')
  124. break;
  125. if (parse_attributes (resp, attr, mask, bit) == 0)
  126. break;
  127. }
  128. return 0;
  129. }
  130. /*
  131. * time_t
  132. * the special value 0 means ``never''
  133. */
  134. /*
  135. * Convert the time `t' to a string representation in `str' (of max
  136. * size `len'). If include_time also include time, otherwise just
  137. * date.
  138. */
  139. void
  140. time_t2str(time_t t, char *str, size_t len, int include_time)
  141. {
  142. if(t) {
  143. if(include_time)
  144. strftime(str, len, "%Y-%m-%d %H:%M:%S UTC", gmtime(&t));
  145. else
  146. strftime(str, len, "%Y-%m-%d", gmtime(&t));
  147. } else
  148. snprintf(str, len, "never");
  149. }
  150. /*
  151. * Convert the time representation in `str' to a time in `time'.
  152. * Return 0 if succesful, else -1.
  153. */
  154. int
  155. str2time_t (const char *str, time_t *t)
  156. {
  157. const char *p;
  158. struct tm tm, tm2;
  159. memset (&tm, 0, sizeof (tm));
  160. memset (&tm2, 0, sizeof (tm2));
  161. while(isspace((unsigned char)*str))
  162. str++;
  163. if (str[0] == '+') {
  164. str++;
  165. *t = parse_time(str, "month");
  166. if (*t < 0)
  167. return -1;
  168. *t += time(NULL);
  169. return 0;
  170. }
  171. if(strcasecmp(str, "never") == 0) {
  172. *t = 0;
  173. return 0;
  174. }
  175. if(strcasecmp(str, "now") == 0) {
  176. *t = time(NULL);
  177. return 0;
  178. }
  179. p = strptime (str, "%Y-%m-%d", &tm);
  180. if (p == NULL)
  181. return -1;
  182. while(isspace((unsigned char)*p))
  183. p++;
  184. /* XXX this is really a bit optimistic, we should really complain
  185. if there was a problem parsing the time */
  186. if(p[0] != '\0' && strptime (p, "%H:%M:%S", &tm2) != NULL) {
  187. tm.tm_hour = tm2.tm_hour;
  188. tm.tm_min = tm2.tm_min;
  189. tm.tm_sec = tm2.tm_sec;
  190. } else {
  191. /* Do it on the end of the day */
  192. tm.tm_hour = 23;
  193. tm.tm_min = 59;
  194. tm.tm_sec = 59;
  195. }
  196. *t = tm2time (tm, 0);
  197. return 0;
  198. }
  199. /*
  200. * try to parse the time in `resp' storing it in `value'
  201. */
  202. int
  203. parse_timet (const char *resp, krb5_timestamp *value, int *mask, int bit)
  204. {
  205. time_t tmp;
  206. if (str2time_t(resp, &tmp) == 0) {
  207. *value = tmp;
  208. if(mask)
  209. *mask |= bit;
  210. return 0;
  211. }
  212. if(*resp != '?')
  213. fprintf (stderr, "Unable to parse time \"%s\"\n", resp);
  214. fprintf (stderr, "Print date on format YYYY-mm-dd [hh:mm:ss]\n");
  215. return -1;
  216. }
  217. /*
  218. * allow the user to edit the time in `value'
  219. */
  220. int
  221. edit_timet (const char *prompt, krb5_timestamp *value, int *mask, int bit)
  222. {
  223. char buf[1024], resp[1024];
  224. if (mask && (*mask & bit))
  225. return 0;
  226. time_t2str (*value, buf, sizeof (buf), 0);
  227. for (;;) {
  228. if(get_response(prompt, buf, resp, sizeof(resp)) != 0)
  229. return 1;
  230. if (parse_timet (resp, value, mask, bit) == 0)
  231. break;
  232. }
  233. return 0;
  234. }
  235. /*
  236. * deltat
  237. * the special value 0 means ``unlimited''
  238. */
  239. /*
  240. * convert the delta_t value in `t' into a printable form in `str, len'
  241. */
  242. void
  243. deltat2str(unsigned t, char *str, size_t len)
  244. {
  245. if(t == 0 || t == INT_MAX)
  246. snprintf(str, len, "unlimited");
  247. else
  248. unparse_time(t, str, len);
  249. }
  250. /*
  251. * parse the delta value in `str', storing result in `*delta'
  252. * return 0 if ok, else -1
  253. */
  254. int
  255. str2deltat(const char *str, krb5_deltat *delta)
  256. {
  257. int res;
  258. if(strcasecmp(str, "unlimited") == 0) {
  259. *delta = 0;
  260. return 0;
  261. }
  262. res = parse_time(str, "day");
  263. if (res < 0)
  264. return res;
  265. else {
  266. *delta = res;
  267. return 0;
  268. }
  269. }
  270. /*
  271. * try to parse the string in `resp' into a deltad in `value'
  272. * `mask' will get the bit `bit' set if a value was given.
  273. */
  274. int
  275. parse_deltat (const char *resp, krb5_deltat *value, int *mask, int bit)
  276. {
  277. krb5_deltat tmp;
  278. if (str2deltat(resp, &tmp) == 0) {
  279. *value = tmp;
  280. if (mask)
  281. *mask |= bit;
  282. return 0;
  283. } else if(*resp == '?') {
  284. print_time_table (stderr);
  285. } else {
  286. fprintf (stderr, "Unable to parse time \"%s\"\n", resp);
  287. }
  288. return -1;
  289. }
  290. /*
  291. * allow the user to edit the deltat in `value'
  292. */
  293. int
  294. edit_deltat (const char *prompt, krb5_deltat *value, int *mask, int bit)
  295. {
  296. char buf[1024], resp[1024];
  297. if (mask && (*mask & bit))
  298. return 0;
  299. deltat2str(*value, buf, sizeof(buf));
  300. for (;;) {
  301. if(get_response(prompt, buf, resp, sizeof(resp)) != 0)
  302. return 1;
  303. if (parse_deltat (resp, value, mask, bit) == 0)
  304. break;
  305. }
  306. return 0;
  307. }
  308. /*
  309. * allow the user to edit `ent'
  310. */
  311. void
  312. set_defaults(kadm5_principal_ent_t ent, int *mask,
  313. kadm5_principal_ent_t default_ent, int default_mask)
  314. {
  315. if (default_ent
  316. && (default_mask & KADM5_MAX_LIFE)
  317. && !(*mask & KADM5_MAX_LIFE))
  318. ent->max_life = default_ent->max_life;
  319. if (default_ent
  320. && (default_mask & KADM5_MAX_RLIFE)
  321. && !(*mask & KADM5_MAX_RLIFE))
  322. ent->max_renewable_life = default_ent->max_renewable_life;
  323. if (default_ent
  324. && (default_mask & KADM5_PRINC_EXPIRE_TIME)
  325. && !(*mask & KADM5_PRINC_EXPIRE_TIME))
  326. ent->princ_expire_time = default_ent->princ_expire_time;
  327. if (default_ent
  328. && (default_mask & KADM5_PW_EXPIRATION)
  329. && !(*mask & KADM5_PW_EXPIRATION))
  330. ent->pw_expiration = default_ent->pw_expiration;
  331. if (default_ent
  332. && (default_mask & KADM5_ATTRIBUTES)
  333. && !(*mask & KADM5_ATTRIBUTES))
  334. ent->attributes = default_ent->attributes & ~KRB5_KDB_DISALLOW_ALL_TIX;
  335. }
  336. int
  337. edit_entry(kadm5_principal_ent_t ent, int *mask,
  338. kadm5_principal_ent_t default_ent, int default_mask)
  339. {
  340. set_defaults(ent, mask, default_ent, default_mask);
  341. if(edit_deltat ("Max ticket life", &ent->max_life, mask,
  342. KADM5_MAX_LIFE) != 0)
  343. return 1;
  344. if(edit_deltat ("Max renewable life", &ent->max_renewable_life, mask,
  345. KADM5_MAX_RLIFE) != 0)
  346. return 1;
  347. if(edit_timet ("Principal expiration time", &ent->princ_expire_time, mask,
  348. KADM5_PRINC_EXPIRE_TIME) != 0)
  349. return 1;
  350. if(edit_timet ("Password expiration time", &ent->pw_expiration, mask,
  351. KADM5_PW_EXPIRATION) != 0)
  352. return 1;
  353. if(edit_attributes ("Attributes", &ent->attributes, mask,
  354. KADM5_ATTRIBUTES) != 0)
  355. return 1;
  356. return 0;
  357. }
  358. /*
  359. * Parse the arguments, set the fields in `ent' and the `mask' for the
  360. * entries having been set.
  361. * Return 1 on failure and 0 on success.
  362. */
  363. int
  364. set_entry(krb5_context contextp,
  365. kadm5_principal_ent_t ent,
  366. int *mask,
  367. const char *max_ticket_life,
  368. const char *max_renewable_life,
  369. const char *expiration,
  370. const char *pw_expiration,
  371. const char *attributes)
  372. {
  373. if (max_ticket_life != NULL) {
  374. if (parse_deltat (max_ticket_life, &ent->max_life,
  375. mask, KADM5_MAX_LIFE)) {
  376. krb5_warnx (contextp, "unable to parse `%s'", max_ticket_life);
  377. return 1;
  378. }
  379. }
  380. if (max_renewable_life != NULL) {
  381. if (parse_deltat (max_renewable_life, &ent->max_renewable_life,
  382. mask, KADM5_MAX_RLIFE)) {
  383. krb5_warnx (contextp, "unable to parse `%s'", max_renewable_life);
  384. return 1;
  385. }
  386. }
  387. if (expiration) {
  388. if (parse_timet (expiration, &ent->princ_expire_time,
  389. mask, KADM5_PRINC_EXPIRE_TIME)) {
  390. krb5_warnx (contextp, "unable to parse `%s'", expiration);
  391. return 1;
  392. }
  393. }
  394. if (pw_expiration) {
  395. if (parse_timet (pw_expiration, &ent->pw_expiration,
  396. mask, KADM5_PW_EXPIRATION)) {
  397. krb5_warnx (contextp, "unable to parse `%s'", pw_expiration);
  398. return 1;
  399. }
  400. }
  401. if (attributes != NULL) {
  402. if (parse_attributes (attributes, &ent->attributes,
  403. mask, KADM5_ATTRIBUTES)) {
  404. krb5_warnx (contextp, "unable to parse `%s'", attributes);
  405. return 1;
  406. }
  407. }
  408. return 0;
  409. }
  410. /*
  411. * Does `string' contain any globing characters?
  412. */
  413. static int
  414. is_expression(const char *string)
  415. {
  416. const char *p;
  417. int quote = 0;
  418. for(p = string; *p; p++) {
  419. if(quote) {
  420. quote = 0;
  421. continue;
  422. }
  423. if(*p == '\\')
  424. quote++;
  425. else if(strchr("[]*?", *p) != NULL)
  426. return 1;
  427. }
  428. return 0;
  429. }
  430. /*
  431. * Loop over all principals matching exp. If any of calls to `func'
  432. * failes, the first error is returned when all principals are
  433. * processed.
  434. */
  435. int
  436. foreach_principal(const char *exp_str,
  437. int (*func)(krb5_principal, void*),
  438. const char *funcname,
  439. void *data)
  440. {
  441. char **princs = NULL;
  442. int num_princs = 0;
  443. int i;
  444. krb5_error_code saved_ret = 0, ret = 0;
  445. krb5_principal princ_ent;
  446. int is_expr;
  447. /* if this isn't an expression, there is no point in wading
  448. through the whole database looking for matches */
  449. is_expr = is_expression(exp_str);
  450. if(is_expr)
  451. ret = kadm5_get_principals(kadm_handle, exp_str, &princs, &num_princs);
  452. if(!is_expr || ret == KADM5_AUTH_LIST) {
  453. /* we might be able to perform the requested opreration even
  454. if we're not allowed to list principals */
  455. num_princs = 1;
  456. princs = malloc(sizeof(*princs));
  457. if(princs == NULL)
  458. return ENOMEM;
  459. princs[0] = strdup(exp_str);
  460. if(princs[0] == NULL){
  461. free(princs);
  462. return ENOMEM;
  463. }
  464. } else if(ret) {
  465. krb5_warn(context, ret, "kadm5_get_principals");
  466. return ret;
  467. }
  468. for(i = 0; i < num_princs; i++) {
  469. ret = krb5_parse_name(context, princs[i], &princ_ent);
  470. if(ret){
  471. krb5_warn(context, ret, "krb5_parse_name(%s)", princs[i]);
  472. continue;
  473. }
  474. ret = (*func)(princ_ent, data);
  475. if(ret) {
  476. krb5_clear_error_message(context);
  477. krb5_warn(context, ret, "%s %s", funcname, princs[i]);
  478. if (saved_ret == 0)
  479. saved_ret = ret;
  480. }
  481. krb5_free_principal(context, princ_ent);
  482. }
  483. if (ret == 0 && saved_ret != 0)
  484. ret = saved_ret;
  485. kadm5_free_name_list(kadm_handle, princs, &num_princs);
  486. return ret;
  487. }
  488. /*
  489. * prompt with `prompt' and default value `def', and store the reply
  490. * in `buf, len'
  491. */
  492. #include <setjmp.h>
  493. static jmp_buf jmpbuf;
  494. static void
  495. interrupt(int sig)
  496. {
  497. longjmp(jmpbuf, 1);
  498. }
  499. static int
  500. get_response(const char *prompt, const char *def, char *buf, size_t len)
  501. {
  502. char *p;
  503. void (*osig)(int);
  504. osig = signal(SIGINT, interrupt);
  505. if(setjmp(jmpbuf)) {
  506. signal(SIGINT, osig);
  507. fprintf(stderr, "\n");
  508. return 1;
  509. }
  510. fprintf(stderr, "%s [%s]:", prompt, def);
  511. if(fgets(buf, len, stdin) == NULL) {
  512. int save_errno = errno;
  513. if(ferror(stdin))
  514. krb5_err(context, 1, save_errno, "<stdin>");
  515. signal(SIGINT, osig);
  516. return 1;
  517. }
  518. p = strchr(buf, '\n');
  519. if(p)
  520. *p = '\0';
  521. if(strcmp(buf, "") == 0)
  522. strlcpy(buf, def, len);
  523. signal(SIGINT, osig);
  524. return 0;
  525. }
  526. /*
  527. * return [0, 16) or -1
  528. */
  529. static int
  530. hex2n (char c)
  531. {
  532. static char hexdigits[] = "0123456789abcdef";
  533. const char *p;
  534. p = strchr (hexdigits, tolower((unsigned char)c));
  535. if (p == NULL)
  536. return -1;
  537. else
  538. return p - hexdigits;
  539. }
  540. /*
  541. * convert a key in a readable format into a keyblock.
  542. * return 0 iff succesful, otherwise `err' should point to an error message
  543. */
  544. int
  545. parse_des_key (const char *key_string, krb5_key_data *key_data,
  546. const char **error)
  547. {
  548. const char *p = key_string;
  549. unsigned char bits[8];
  550. int i;
  551. if (strlen (key_string) != 16) {
  552. *error = "bad length, should be 16 for DES key";
  553. return 1;
  554. }
  555. for (i = 0; i < 8; ++i) {
  556. int d1, d2;
  557. d1 = hex2n(p[2 * i]);
  558. d2 = hex2n(p[2 * i + 1]);
  559. if (d1 < 0 || d2 < 0) {
  560. *error = "non-hex character";
  561. return 1;
  562. }
  563. bits[i] = (d1 << 4) | d2;
  564. }
  565. for (i = 0; i < 3; ++i) {
  566. key_data[i].key_data_ver = 2;
  567. key_data[i].key_data_kvno = 0;
  568. /* key */
  569. key_data[i].key_data_type[0] = ETYPE_DES_CBC_CRC;
  570. key_data[i].key_data_length[0] = 8;
  571. key_data[i].key_data_contents[0] = malloc(8);
  572. if (key_data[i].key_data_contents[0] == NULL) {
  573. *error = "malloc";
  574. return ENOMEM;
  575. }
  576. memcpy (key_data[i].key_data_contents[0], bits, 8);
  577. /* salt */
  578. key_data[i].key_data_type[1] = KRB5_PW_SALT;
  579. key_data[i].key_data_length[1] = 0;
  580. key_data[i].key_data_contents[1] = NULL;
  581. }
  582. key_data[0].key_data_type[0] = ETYPE_DES_CBC_MD5;
  583. key_data[1].key_data_type[0] = ETYPE_DES_CBC_MD4;
  584. return 0;
  585. }