auth-options.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894
  1. /* $OpenBSD: auth-options.c,v 1.93 2020/08/27 01:07:09 djm Exp $ */
  2. /*
  3. * Copyright (c) 2018 Damien Miller <djm@mindrot.org>
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #include "includes.h"
  18. #include <sys/types.h>
  19. #include <stdlib.h>
  20. #include <netdb.h>
  21. #include <pwd.h>
  22. #include <string.h>
  23. #include <stdio.h>
  24. #include <stdarg.h>
  25. #include <ctype.h>
  26. #include <limits.h>
  27. #include "openbsd-compat/sys-queue.h"
  28. #include "xmalloc.h"
  29. #include "ssherr.h"
  30. #include "log.h"
  31. #include "sshbuf.h"
  32. #include "misc.h"
  33. #include "sshkey.h"
  34. #include "match.h"
  35. #include "ssh2.h"
  36. #include "auth-options.h"
  37. static int
  38. dup_strings(char ***dstp, size_t *ndstp, char **src, size_t nsrc)
  39. {
  40. char **dst;
  41. size_t i, j;
  42. *dstp = NULL;
  43. *ndstp = 0;
  44. if (nsrc == 0)
  45. return 0;
  46. if ((dst = calloc(nsrc, sizeof(*src))) == NULL)
  47. return -1;
  48. for (i = 0; i < nsrc; i++) {
  49. if ((dst[i] = strdup(src[i])) == NULL) {
  50. for (j = 0; j < i; j++)
  51. free(dst[j]);
  52. free(dst);
  53. return -1;
  54. }
  55. }
  56. /* success */
  57. *dstp = dst;
  58. *ndstp = nsrc;
  59. return 0;
  60. }
  61. #define OPTIONS_CRITICAL 1
  62. #define OPTIONS_EXTENSIONS 2
  63. static int
  64. cert_option_list(struct sshauthopt *opts, struct sshbuf *oblob,
  65. u_int which, int crit)
  66. {
  67. char *command, *allowed;
  68. char *name = NULL;
  69. struct sshbuf *c = NULL, *data = NULL;
  70. int r, ret = -1, found;
  71. if ((c = sshbuf_fromb(oblob)) == NULL) {
  72. error("%s: sshbuf_fromb failed", __func__);
  73. goto out;
  74. }
  75. while (sshbuf_len(c) > 0) {
  76. sshbuf_free(data);
  77. data = NULL;
  78. if ((r = sshbuf_get_cstring(c, &name, NULL)) != 0 ||
  79. (r = sshbuf_froms(c, &data)) != 0) {
  80. error("Unable to parse certificate options: %s",
  81. ssh_err(r));
  82. goto out;
  83. }
  84. debug3("found certificate option \"%.100s\" len %zu",
  85. name, sshbuf_len(data));
  86. found = 0;
  87. if ((which & OPTIONS_EXTENSIONS) != 0) {
  88. if (strcmp(name, "no-touch-required") == 0) {
  89. opts->no_require_user_presence = 1;
  90. found = 1;
  91. } else if (strcmp(name, "permit-X11-forwarding") == 0) {
  92. opts->permit_x11_forwarding_flag = 1;
  93. found = 1;
  94. } else if (strcmp(name,
  95. "permit-agent-forwarding") == 0) {
  96. opts->permit_agent_forwarding_flag = 1;
  97. found = 1;
  98. } else if (strcmp(name,
  99. "permit-port-forwarding") == 0) {
  100. opts->permit_port_forwarding_flag = 1;
  101. found = 1;
  102. } else if (strcmp(name, "permit-pty") == 0) {
  103. opts->permit_pty_flag = 1;
  104. found = 1;
  105. } else if (strcmp(name, "permit-user-rc") == 0) {
  106. opts->permit_user_rc = 1;
  107. found = 1;
  108. }
  109. }
  110. if (!found && (which & OPTIONS_CRITICAL) != 0) {
  111. if (strcmp(name, "verify-required") == 0) {
  112. opts->require_verify = 1;
  113. found = 1;
  114. } else if (strcmp(name, "force-command") == 0) {
  115. if ((r = sshbuf_get_cstring(data, &command,
  116. NULL)) != 0) {
  117. error("Unable to parse \"%s\" "
  118. "section: %s", name, ssh_err(r));
  119. goto out;
  120. }
  121. if (opts->force_command != NULL) {
  122. error("Certificate has multiple "
  123. "force-command options");
  124. free(command);
  125. goto out;
  126. }
  127. opts->force_command = command;
  128. found = 1;
  129. } else if (strcmp(name, "source-address") == 0) {
  130. if ((r = sshbuf_get_cstring(data, &allowed,
  131. NULL)) != 0) {
  132. error("Unable to parse \"%s\" "
  133. "section: %s", name, ssh_err(r));
  134. goto out;
  135. }
  136. if (opts->required_from_host_cert != NULL) {
  137. error("Certificate has multiple "
  138. "source-address options");
  139. free(allowed);
  140. goto out;
  141. }
  142. /* Check syntax */
  143. if (addr_match_cidr_list(NULL, allowed) == -1) {
  144. error("Certificate source-address "
  145. "contents invalid");
  146. goto out;
  147. }
  148. opts->required_from_host_cert = allowed;
  149. found = 1;
  150. }
  151. }
  152. if (!found) {
  153. if (crit) {
  154. error("Certificate critical option \"%s\" "
  155. "is not supported", name);
  156. goto out;
  157. } else {
  158. logit("Certificate extension \"%s\" "
  159. "is not supported", name);
  160. }
  161. } else if (sshbuf_len(data) != 0) {
  162. error("Certificate option \"%s\" corrupt "
  163. "(extra data)", name);
  164. goto out;
  165. }
  166. free(name);
  167. name = NULL;
  168. }
  169. /* successfully parsed all options */
  170. ret = 0;
  171. out:
  172. free(name);
  173. sshbuf_free(data);
  174. sshbuf_free(c);
  175. return ret;
  176. }
  177. struct sshauthopt *
  178. sshauthopt_new(void)
  179. {
  180. struct sshauthopt *ret;
  181. if ((ret = calloc(1, sizeof(*ret))) == NULL)
  182. return NULL;
  183. ret->force_tun_device = -1;
  184. return ret;
  185. }
  186. void
  187. sshauthopt_free(struct sshauthopt *opts)
  188. {
  189. size_t i;
  190. if (opts == NULL)
  191. return;
  192. free(opts->cert_principals);
  193. free(opts->force_command);
  194. free(opts->required_from_host_cert);
  195. free(opts->required_from_host_keys);
  196. for (i = 0; i < opts->nenv; i++)
  197. free(opts->env[i]);
  198. free(opts->env);
  199. for (i = 0; i < opts->npermitopen; i++)
  200. free(opts->permitopen[i]);
  201. free(opts->permitopen);
  202. for (i = 0; i < opts->npermitlisten; i++)
  203. free(opts->permitlisten[i]);
  204. free(opts->permitlisten);
  205. freezero(opts, sizeof(*opts));
  206. }
  207. struct sshauthopt *
  208. sshauthopt_new_with_keys_defaults(void)
  209. {
  210. struct sshauthopt *ret = NULL;
  211. if ((ret = sshauthopt_new()) == NULL)
  212. return NULL;
  213. /* Defaults for authorized_keys flags */
  214. ret->permit_port_forwarding_flag = 1;
  215. ret->permit_agent_forwarding_flag = 1;
  216. ret->permit_x11_forwarding_flag = 1;
  217. ret->permit_pty_flag = 1;
  218. ret->permit_user_rc = 1;
  219. return ret;
  220. }
  221. /*
  222. * Parse and record a permitopen/permitlisten directive.
  223. * Return 0 on success. Return -1 on failure and sets *errstrp to error reason.
  224. */
  225. static int
  226. handle_permit(const char **optsp, int allow_bare_port,
  227. char ***permitsp, size_t *npermitsp, const char **errstrp)
  228. {
  229. char *opt, *tmp, *cp, *host, **permits = *permitsp;
  230. size_t npermits = *npermitsp;
  231. const char *errstr = "unknown error";
  232. if (npermits > SSH_AUTHOPT_PERMIT_MAX) {
  233. *errstrp = "too many permission directives";
  234. return -1;
  235. }
  236. if ((opt = opt_dequote(optsp, &errstr)) == NULL) {
  237. return -1;
  238. }
  239. if (allow_bare_port && strchr(opt, ':') == NULL) {
  240. /*
  241. * Allow a bare port number in permitlisten to indicate a
  242. * listen_host wildcard.
  243. */
  244. if (asprintf(&tmp, "*:%s", opt) == -1) {
  245. free(opt);
  246. *errstrp = "memory allocation failed";
  247. return -1;
  248. }
  249. free(opt);
  250. opt = tmp;
  251. }
  252. if ((tmp = strdup(opt)) == NULL) {
  253. free(opt);
  254. *errstrp = "memory allocation failed";
  255. return -1;
  256. }
  257. cp = tmp;
  258. /* validate syntax before recording it. */
  259. host = hpdelim(&cp);
  260. if (host == NULL || strlen(host) >= NI_MAXHOST) {
  261. free(tmp);
  262. free(opt);
  263. *errstrp = "invalid permission hostname";
  264. return -1;
  265. }
  266. /*
  267. * don't want to use permitopen_port to avoid
  268. * dependency on channels.[ch] here.
  269. */
  270. if (cp == NULL ||
  271. (strcmp(cp, "*") != 0 && a2port(cp) <= 0)) {
  272. free(tmp);
  273. free(opt);
  274. *errstrp = "invalid permission port";
  275. return -1;
  276. }
  277. /* XXX - add streamlocal support */
  278. free(tmp);
  279. /* Record it */
  280. if ((permits = recallocarray(permits, npermits, npermits + 1,
  281. sizeof(*permits))) == NULL) {
  282. free(opt);
  283. /* NB. don't update *permitsp if alloc fails */
  284. *errstrp = "memory allocation failed";
  285. return -1;
  286. }
  287. permits[npermits++] = opt;
  288. *permitsp = permits;
  289. *npermitsp = npermits;
  290. return 0;
  291. }
  292. struct sshauthopt *
  293. sshauthopt_parse(const char *opts, const char **errstrp)
  294. {
  295. char **oarray, *opt, *cp, *tmp;
  296. int r;
  297. struct sshauthopt *ret = NULL;
  298. const char *errstr = "unknown error";
  299. uint64_t valid_before;
  300. if (errstrp != NULL)
  301. *errstrp = NULL;
  302. if ((ret = sshauthopt_new_with_keys_defaults()) == NULL)
  303. goto alloc_fail;
  304. if (opts == NULL)
  305. return ret;
  306. while (*opts && *opts != ' ' && *opts != '\t') {
  307. /* flag options */
  308. if ((r = opt_flag("restrict", 0, &opts)) != -1) {
  309. ret->restricted = 1;
  310. ret->permit_port_forwarding_flag = 0;
  311. ret->permit_agent_forwarding_flag = 0;
  312. ret->permit_x11_forwarding_flag = 0;
  313. ret->permit_pty_flag = 0;
  314. ret->permit_user_rc = 0;
  315. } else if ((r = opt_flag("cert-authority", 0, &opts)) != -1) {
  316. ret->cert_authority = r;
  317. } else if ((r = opt_flag("port-forwarding", 1, &opts)) != -1) {
  318. ret->permit_port_forwarding_flag = r == 1;
  319. } else if ((r = opt_flag("agent-forwarding", 1, &opts)) != -1) {
  320. ret->permit_agent_forwarding_flag = r == 1;
  321. } else if ((r = opt_flag("x11-forwarding", 1, &opts)) != -1) {
  322. ret->permit_x11_forwarding_flag = r == 1;
  323. } else if ((r = opt_flag("touch-required", 1, &opts)) != -1) {
  324. ret->no_require_user_presence = r != 1; /* NB. flip */
  325. } else if ((r = opt_flag("verify-required", 1, &opts)) != -1) {
  326. ret->require_verify = r == 1;
  327. } else if ((r = opt_flag("pty", 1, &opts)) != -1) {
  328. ret->permit_pty_flag = r == 1;
  329. } else if ((r = opt_flag("user-rc", 1, &opts)) != -1) {
  330. ret->permit_user_rc = r == 1;
  331. } else if (opt_match(&opts, "command")) {
  332. if (ret->force_command != NULL) {
  333. errstr = "multiple \"command\" clauses";
  334. goto fail;
  335. }
  336. ret->force_command = opt_dequote(&opts, &errstr);
  337. if (ret->force_command == NULL)
  338. goto fail;
  339. } else if (opt_match(&opts, "principals")) {
  340. if (ret->cert_principals != NULL) {
  341. errstr = "multiple \"principals\" clauses";
  342. goto fail;
  343. }
  344. ret->cert_principals = opt_dequote(&opts, &errstr);
  345. if (ret->cert_principals == NULL)
  346. goto fail;
  347. } else if (opt_match(&opts, "from")) {
  348. if (ret->required_from_host_keys != NULL) {
  349. errstr = "multiple \"from\" clauses";
  350. goto fail;
  351. }
  352. ret->required_from_host_keys = opt_dequote(&opts,
  353. &errstr);
  354. if (ret->required_from_host_keys == NULL)
  355. goto fail;
  356. } else if (opt_match(&opts, "expiry-time")) {
  357. if ((opt = opt_dequote(&opts, &errstr)) == NULL)
  358. goto fail;
  359. if (parse_absolute_time(opt, &valid_before) != 0 ||
  360. valid_before == 0) {
  361. free(opt);
  362. errstr = "invalid expires time";
  363. goto fail;
  364. }
  365. free(opt);
  366. if (ret->valid_before == 0 ||
  367. valid_before < ret->valid_before)
  368. ret->valid_before = valid_before;
  369. } else if (opt_match(&opts, "environment")) {
  370. if (ret->nenv > INT_MAX) {
  371. errstr = "too many environment strings";
  372. goto fail;
  373. }
  374. if ((opt = opt_dequote(&opts, &errstr)) == NULL)
  375. goto fail;
  376. /* env name must be alphanumeric and followed by '=' */
  377. if ((tmp = strchr(opt, '=')) == NULL) {
  378. free(opt);
  379. errstr = "invalid environment string";
  380. goto fail;
  381. }
  382. if ((cp = strdup(opt)) == NULL)
  383. goto alloc_fail;
  384. cp[tmp - opt] = '\0'; /* truncate at '=' */
  385. if (!valid_env_name(cp)) {
  386. free(cp);
  387. free(opt);
  388. errstr = "invalid environment string";
  389. goto fail;
  390. }
  391. free(cp);
  392. /* Append it. */
  393. oarray = ret->env;
  394. if ((ret->env = recallocarray(ret->env, ret->nenv,
  395. ret->nenv + 1, sizeof(*ret->env))) == NULL) {
  396. free(opt);
  397. ret->env = oarray; /* put it back for cleanup */
  398. goto alloc_fail;
  399. }
  400. ret->env[ret->nenv++] = opt;
  401. } else if (opt_match(&opts, "permitopen")) {
  402. if (handle_permit(&opts, 0, &ret->permitopen,
  403. &ret->npermitopen, &errstr) != 0)
  404. goto fail;
  405. } else if (opt_match(&opts, "permitlisten")) {
  406. if (handle_permit(&opts, 1, &ret->permitlisten,
  407. &ret->npermitlisten, &errstr) != 0)
  408. goto fail;
  409. } else if (opt_match(&opts, "tunnel")) {
  410. if ((opt = opt_dequote(&opts, &errstr)) == NULL)
  411. goto fail;
  412. ret->force_tun_device = a2tun(opt, NULL);
  413. free(opt);
  414. if (ret->force_tun_device == SSH_TUNID_ERR) {
  415. errstr = "invalid tun device";
  416. goto fail;
  417. }
  418. }
  419. /*
  420. * Skip the comma, and move to the next option
  421. * (or break out if there are no more).
  422. */
  423. if (*opts == '\0' || *opts == ' ' || *opts == '\t')
  424. break; /* End of options. */
  425. /* Anything other than a comma is an unknown option */
  426. if (*opts != ',') {
  427. errstr = "unknown key option";
  428. goto fail;
  429. }
  430. opts++;
  431. if (*opts == '\0') {
  432. errstr = "unexpected end-of-options";
  433. goto fail;
  434. }
  435. }
  436. /* success */
  437. if (errstrp != NULL)
  438. *errstrp = NULL;
  439. return ret;
  440. alloc_fail:
  441. errstr = "memory allocation failed";
  442. fail:
  443. sshauthopt_free(ret);
  444. if (errstrp != NULL)
  445. *errstrp = errstr;
  446. return NULL;
  447. }
  448. struct sshauthopt *
  449. sshauthopt_from_cert(struct sshkey *k)
  450. {
  451. struct sshauthopt *ret;
  452. if (k == NULL || !sshkey_type_is_cert(k->type) || k->cert == NULL ||
  453. k->cert->type != SSH2_CERT_TYPE_USER)
  454. return NULL;
  455. if ((ret = sshauthopt_new()) == NULL)
  456. return NULL;
  457. /* Handle options and critical extensions separately */
  458. if (cert_option_list(ret, k->cert->critical,
  459. OPTIONS_CRITICAL, 1) == -1) {
  460. sshauthopt_free(ret);
  461. return NULL;
  462. }
  463. if (cert_option_list(ret, k->cert->extensions,
  464. OPTIONS_EXTENSIONS, 0) == -1) {
  465. sshauthopt_free(ret);
  466. return NULL;
  467. }
  468. /* success */
  469. return ret;
  470. }
  471. /*
  472. * Merges "additional" options to "primary" and returns the result.
  473. * NB. Some options from primary have primacy.
  474. */
  475. struct sshauthopt *
  476. sshauthopt_merge(const struct sshauthopt *primary,
  477. const struct sshauthopt *additional, const char **errstrp)
  478. {
  479. struct sshauthopt *ret;
  480. const char *errstr = "internal error";
  481. const char *tmp;
  482. if (errstrp != NULL)
  483. *errstrp = NULL;
  484. if ((ret = sshauthopt_new()) == NULL)
  485. goto alloc_fail;
  486. /* cert_authority and cert_principals are cleared in result */
  487. /* Prefer access lists from primary. */
  488. /* XXX err is both set and mismatch? */
  489. tmp = primary->required_from_host_cert;
  490. if (tmp == NULL)
  491. tmp = additional->required_from_host_cert;
  492. if (tmp != NULL && (ret->required_from_host_cert = strdup(tmp)) == NULL)
  493. goto alloc_fail;
  494. tmp = primary->required_from_host_keys;
  495. if (tmp == NULL)
  496. tmp = additional->required_from_host_keys;
  497. if (tmp != NULL && (ret->required_from_host_keys = strdup(tmp)) == NULL)
  498. goto alloc_fail;
  499. /*
  500. * force_tun_device, permitopen/permitlisten and environment all
  501. * prefer the primary.
  502. */
  503. ret->force_tun_device = primary->force_tun_device;
  504. if (ret->force_tun_device == -1)
  505. ret->force_tun_device = additional->force_tun_device;
  506. if (primary->nenv > 0) {
  507. if (dup_strings(&ret->env, &ret->nenv,
  508. primary->env, primary->nenv) != 0)
  509. goto alloc_fail;
  510. } else if (additional->nenv) {
  511. if (dup_strings(&ret->env, &ret->nenv,
  512. additional->env, additional->nenv) != 0)
  513. goto alloc_fail;
  514. }
  515. if (primary->npermitopen > 0) {
  516. if (dup_strings(&ret->permitopen, &ret->npermitopen,
  517. primary->permitopen, primary->npermitopen) != 0)
  518. goto alloc_fail;
  519. } else if (additional->npermitopen > 0) {
  520. if (dup_strings(&ret->permitopen, &ret->npermitopen,
  521. additional->permitopen, additional->npermitopen) != 0)
  522. goto alloc_fail;
  523. }
  524. if (primary->npermitlisten > 0) {
  525. if (dup_strings(&ret->permitlisten, &ret->npermitlisten,
  526. primary->permitlisten, primary->npermitlisten) != 0)
  527. goto alloc_fail;
  528. } else if (additional->npermitlisten > 0) {
  529. if (dup_strings(&ret->permitlisten, &ret->npermitlisten,
  530. additional->permitlisten, additional->npermitlisten) != 0)
  531. goto alloc_fail;
  532. }
  533. #define OPTFLAG_AND(x) ret->x = (primary->x == 1) && (additional->x == 1)
  534. #define OPTFLAG_OR(x) ret->x = (primary->x == 1) || (additional->x == 1)
  535. /* Permissive flags are logical-AND (i.e. must be set in both) */
  536. OPTFLAG_AND(permit_port_forwarding_flag);
  537. OPTFLAG_AND(permit_agent_forwarding_flag);
  538. OPTFLAG_AND(permit_x11_forwarding_flag);
  539. OPTFLAG_AND(permit_pty_flag);
  540. OPTFLAG_AND(permit_user_rc);
  541. OPTFLAG_AND(no_require_user_presence);
  542. /* Restrictive flags are logical-OR (i.e. must be set in either) */
  543. OPTFLAG_OR(require_verify);
  544. #undef OPTFLAG_AND
  545. /* Earliest expiry time should win */
  546. if (primary->valid_before != 0)
  547. ret->valid_before = primary->valid_before;
  548. if (additional->valid_before != 0 &&
  549. additional->valid_before < ret->valid_before)
  550. ret->valid_before = additional->valid_before;
  551. /*
  552. * When both multiple forced-command are specified, only
  553. * proceed if they are identical, otherwise fail.
  554. */
  555. if (primary->force_command != NULL &&
  556. additional->force_command != NULL) {
  557. if (strcmp(primary->force_command,
  558. additional->force_command) == 0) {
  559. /* ok */
  560. ret->force_command = strdup(primary->force_command);
  561. if (ret->force_command == NULL)
  562. goto alloc_fail;
  563. } else {
  564. errstr = "forced command options do not match";
  565. goto fail;
  566. }
  567. } else if (primary->force_command != NULL) {
  568. if ((ret->force_command = strdup(
  569. primary->force_command)) == NULL)
  570. goto alloc_fail;
  571. } else if (additional->force_command != NULL) {
  572. if ((ret->force_command = strdup(
  573. additional->force_command)) == NULL)
  574. goto alloc_fail;
  575. }
  576. /* success */
  577. if (errstrp != NULL)
  578. *errstrp = NULL;
  579. return ret;
  580. alloc_fail:
  581. errstr = "memory allocation failed";
  582. fail:
  583. if (errstrp != NULL)
  584. *errstrp = errstr;
  585. sshauthopt_free(ret);
  586. return NULL;
  587. }
  588. /*
  589. * Copy options
  590. */
  591. struct sshauthopt *
  592. sshauthopt_copy(const struct sshauthopt *orig)
  593. {
  594. struct sshauthopt *ret;
  595. if ((ret = sshauthopt_new()) == NULL)
  596. return NULL;
  597. #define OPTSCALAR(x) ret->x = orig->x
  598. OPTSCALAR(permit_port_forwarding_flag);
  599. OPTSCALAR(permit_agent_forwarding_flag);
  600. OPTSCALAR(permit_x11_forwarding_flag);
  601. OPTSCALAR(permit_pty_flag);
  602. OPTSCALAR(permit_user_rc);
  603. OPTSCALAR(restricted);
  604. OPTSCALAR(cert_authority);
  605. OPTSCALAR(force_tun_device);
  606. OPTSCALAR(valid_before);
  607. OPTSCALAR(no_require_user_presence);
  608. OPTSCALAR(require_verify);
  609. #undef OPTSCALAR
  610. #define OPTSTRING(x) \
  611. do { \
  612. if (orig->x != NULL && (ret->x = strdup(orig->x)) == NULL) { \
  613. sshauthopt_free(ret); \
  614. return NULL; \
  615. } \
  616. } while (0)
  617. OPTSTRING(cert_principals);
  618. OPTSTRING(force_command);
  619. OPTSTRING(required_from_host_cert);
  620. OPTSTRING(required_from_host_keys);
  621. #undef OPTSTRING
  622. if (dup_strings(&ret->env, &ret->nenv, orig->env, orig->nenv) != 0 ||
  623. dup_strings(&ret->permitopen, &ret->npermitopen,
  624. orig->permitopen, orig->npermitopen) != 0 ||
  625. dup_strings(&ret->permitlisten, &ret->npermitlisten,
  626. orig->permitlisten, orig->npermitlisten) != 0) {
  627. sshauthopt_free(ret);
  628. return NULL;
  629. }
  630. return ret;
  631. }
  632. static int
  633. serialise_array(struct sshbuf *m, char **a, size_t n)
  634. {
  635. struct sshbuf *b;
  636. size_t i;
  637. int r;
  638. if (n > INT_MAX)
  639. return SSH_ERR_INTERNAL_ERROR;
  640. if ((b = sshbuf_new()) == NULL) {
  641. return SSH_ERR_ALLOC_FAIL;
  642. }
  643. for (i = 0; i < n; i++) {
  644. if ((r = sshbuf_put_cstring(b, a[i])) != 0) {
  645. sshbuf_free(b);
  646. return r;
  647. }
  648. }
  649. if ((r = sshbuf_put_u32(m, n)) != 0 ||
  650. (r = sshbuf_put_stringb(m, b)) != 0) {
  651. sshbuf_free(b);
  652. return r;
  653. }
  654. /* success */
  655. return 0;
  656. }
  657. static int
  658. deserialise_array(struct sshbuf *m, char ***ap, size_t *np)
  659. {
  660. char **a = NULL;
  661. size_t i, n = 0;
  662. struct sshbuf *b = NULL;
  663. u_int tmp;
  664. int r = SSH_ERR_INTERNAL_ERROR;
  665. if ((r = sshbuf_get_u32(m, &tmp)) != 0 ||
  666. (r = sshbuf_froms(m, &b)) != 0)
  667. goto out;
  668. if (tmp > INT_MAX) {
  669. r = SSH_ERR_INVALID_FORMAT;
  670. goto out;
  671. }
  672. n = tmp;
  673. if (n > 0 && (a = calloc(n, sizeof(*a))) == NULL) {
  674. r = SSH_ERR_ALLOC_FAIL;
  675. goto out;
  676. }
  677. for (i = 0; i < n; i++) {
  678. if ((r = sshbuf_get_cstring(b, &a[i], NULL)) != 0)
  679. goto out;
  680. }
  681. /* success */
  682. r = 0;
  683. *ap = a;
  684. a = NULL;
  685. *np = n;
  686. n = 0;
  687. out:
  688. if (a != NULL) {
  689. for (i = 0; i < n; i++)
  690. free(a[i]);
  691. free(a);
  692. }
  693. sshbuf_free(b);
  694. return r;
  695. }
  696. static int
  697. serialise_nullable_string(struct sshbuf *m, const char *s)
  698. {
  699. int r;
  700. if ((r = sshbuf_put_u8(m, s == NULL)) != 0 ||
  701. (r = sshbuf_put_cstring(m, s)) != 0)
  702. return r;
  703. return 0;
  704. }
  705. static int
  706. deserialise_nullable_string(struct sshbuf *m, char **sp)
  707. {
  708. int r;
  709. u_char flag;
  710. *sp = NULL;
  711. if ((r = sshbuf_get_u8(m, &flag)) != 0 ||
  712. (r = sshbuf_get_cstring(m, flag ? NULL : sp, NULL)) != 0)
  713. return r;
  714. return 0;
  715. }
  716. int
  717. sshauthopt_serialise(const struct sshauthopt *opts, struct sshbuf *m,
  718. int untrusted)
  719. {
  720. int r = SSH_ERR_INTERNAL_ERROR;
  721. /* Flag options */
  722. if ((r = sshbuf_put_u8(m, opts->permit_port_forwarding_flag)) != 0 ||
  723. (r = sshbuf_put_u8(m, opts->permit_agent_forwarding_flag)) != 0 ||
  724. (r = sshbuf_put_u8(m, opts->permit_x11_forwarding_flag)) != 0 ||
  725. (r = sshbuf_put_u8(m, opts->permit_pty_flag)) != 0 ||
  726. (r = sshbuf_put_u8(m, opts->permit_user_rc)) != 0 ||
  727. (r = sshbuf_put_u8(m, opts->restricted)) != 0 ||
  728. (r = sshbuf_put_u8(m, opts->cert_authority)) != 0 ||
  729. (r = sshbuf_put_u8(m, opts->no_require_user_presence)) != 0 ||
  730. (r = sshbuf_put_u8(m, opts->require_verify)) != 0)
  731. return r;
  732. /* Simple integer options */
  733. if ((r = sshbuf_put_u64(m, opts->valid_before)) != 0)
  734. return r;
  735. /* tunnel number can be negative to indicate "unset" */
  736. if ((r = sshbuf_put_u8(m, opts->force_tun_device == -1)) != 0 ||
  737. (r = sshbuf_put_u32(m, (opts->force_tun_device < 0) ?
  738. 0 : (u_int)opts->force_tun_device)) != 0)
  739. return r;
  740. /* String options; these may be NULL */
  741. if ((r = serialise_nullable_string(m,
  742. untrusted ? "yes" : opts->cert_principals)) != 0 ||
  743. (r = serialise_nullable_string(m,
  744. untrusted ? "true" : opts->force_command)) != 0 ||
  745. (r = serialise_nullable_string(m,
  746. untrusted ? NULL : opts->required_from_host_cert)) != 0 ||
  747. (r = serialise_nullable_string(m,
  748. untrusted ? NULL : opts->required_from_host_keys)) != 0)
  749. return r;
  750. /* Array options */
  751. if ((r = serialise_array(m, opts->env,
  752. untrusted ? 0 : opts->nenv)) != 0 ||
  753. (r = serialise_array(m, opts->permitopen,
  754. untrusted ? 0 : opts->npermitopen)) != 0 ||
  755. (r = serialise_array(m, opts->permitlisten,
  756. untrusted ? 0 : opts->npermitlisten)) != 0)
  757. return r;
  758. /* success */
  759. return 0;
  760. }
  761. int
  762. sshauthopt_deserialise(struct sshbuf *m, struct sshauthopt **optsp)
  763. {
  764. struct sshauthopt *opts = NULL;
  765. int r = SSH_ERR_INTERNAL_ERROR;
  766. u_char f;
  767. u_int tmp;
  768. if ((opts = calloc(1, sizeof(*opts))) == NULL)
  769. return SSH_ERR_ALLOC_FAIL;
  770. /* Flag options */
  771. #define OPT_FLAG(x) \
  772. do { \
  773. if ((r = sshbuf_get_u8(m, &f)) != 0) \
  774. goto out; \
  775. opts->x = f; \
  776. } while (0)
  777. OPT_FLAG(permit_port_forwarding_flag);
  778. OPT_FLAG(permit_agent_forwarding_flag);
  779. OPT_FLAG(permit_x11_forwarding_flag);
  780. OPT_FLAG(permit_pty_flag);
  781. OPT_FLAG(permit_user_rc);
  782. OPT_FLAG(restricted);
  783. OPT_FLAG(cert_authority);
  784. OPT_FLAG(no_require_user_presence);
  785. OPT_FLAG(require_verify);
  786. #undef OPT_FLAG
  787. /* Simple integer options */
  788. if ((r = sshbuf_get_u64(m, &opts->valid_before)) != 0)
  789. goto out;
  790. /* tunnel number can be negative to indicate "unset" */
  791. if ((r = sshbuf_get_u8(m, &f)) != 0 ||
  792. (r = sshbuf_get_u32(m, &tmp)) != 0)
  793. goto out;
  794. opts->force_tun_device = f ? -1 : (int)tmp;
  795. /* String options may be NULL */
  796. if ((r = deserialise_nullable_string(m, &opts->cert_principals)) != 0 ||
  797. (r = deserialise_nullable_string(m, &opts->force_command)) != 0 ||
  798. (r = deserialise_nullable_string(m,
  799. &opts->required_from_host_cert)) != 0 ||
  800. (r = deserialise_nullable_string(m,
  801. &opts->required_from_host_keys)) != 0)
  802. goto out;
  803. /* Array options */
  804. if ((r = deserialise_array(m, &opts->env, &opts->nenv)) != 0 ||
  805. (r = deserialise_array(m,
  806. &opts->permitopen, &opts->npermitopen)) != 0 ||
  807. (r = deserialise_array(m,
  808. &opts->permitlisten, &opts->npermitlisten)) != 0)
  809. goto out;
  810. /* success */
  811. r = 0;
  812. *optsp = opts;
  813. opts = NULL;
  814. out:
  815. sshauthopt_free(opts);
  816. return r;
  817. }