PageRenderTime 45ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/external/openssh/ssh-add.c

https://gitlab.com/brian0218/rk3066_r-box_android4.2.2_sdk
C | 488 lines | 388 code | 46 blank | 54 comment | 99 complexity | cf7f6edfb9e00c7c70e52d53d83e7f0f MD5 | raw file
  1. /* $OpenBSD: ssh-add.c,v 1.101 2011/05/04 21:15:29 djm Exp $ */
  2. /*
  3. * Author: Tatu Ylonen <ylo@cs.hut.fi>
  4. * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
  5. * All rights reserved
  6. * Adds an identity to the authentication server, or removes an identity.
  7. *
  8. * As far as I am concerned, the code I have written for this software
  9. * can be used freely for any purpose. Any derived versions of this
  10. * software must be clearly marked as such, and if the derived work is
  11. * incompatible with the protocol description in the RFC file, it must be
  12. * called by a name other than "ssh" or "Secure Shell".
  13. *
  14. * SSH2 implementation,
  15. * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
  16. *
  17. * Redistribution and use in source and binary forms, with or without
  18. * modification, are permitted provided that the following conditions
  19. * are met:
  20. * 1. Redistributions of source code must retain the above copyright
  21. * notice, this list of conditions and the following disclaimer.
  22. * 2. Redistributions in binary form must reproduce the above copyright
  23. * notice, this list of conditions and the following disclaimer in the
  24. * documentation and/or other materials provided with the distribution.
  25. *
  26. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  27. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  28. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  29. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  30. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  31. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  32. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  33. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  34. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  35. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  36. */
  37. #include "includes.h"
  38. #include <sys/types.h>
  39. #include <sys/stat.h>
  40. #include <sys/param.h>
  41. #include <openssl/evp.h>
  42. #include "openbsd-compat/openssl-compat.h"
  43. #include <fcntl.h>
  44. #include <pwd.h>
  45. #include <stdarg.h>
  46. #include <stdio.h>
  47. #include <stdlib.h>
  48. #include <string.h>
  49. #include <unistd.h>
  50. #include "xmalloc.h"
  51. #include "ssh.h"
  52. #include "rsa.h"
  53. #include "log.h"
  54. #include "key.h"
  55. #include "buffer.h"
  56. #include "authfd.h"
  57. #include "authfile.h"
  58. #include "pathnames.h"
  59. #include "misc.h"
  60. /* argv0 */
  61. extern char *__progname;
  62. /* Default files to add */
  63. static char *default_files[] = {
  64. _PATH_SSH_CLIENT_ID_RSA,
  65. _PATH_SSH_CLIENT_ID_DSA,
  66. #ifdef OPENSSL_HAS_ECC
  67. _PATH_SSH_CLIENT_ID_ECDSA,
  68. #endif
  69. _PATH_SSH_CLIENT_IDENTITY,
  70. NULL
  71. };
  72. /* Default lifetime (0 == forever) */
  73. static int lifetime = 0;
  74. /* User has to confirm key use */
  75. static int confirm = 0;
  76. /* we keep a cache of one passphrases */
  77. static char *pass = NULL;
  78. static void
  79. clear_pass(void)
  80. {
  81. if (pass) {
  82. memset(pass, 0, strlen(pass));
  83. xfree(pass);
  84. pass = NULL;
  85. }
  86. }
  87. static int
  88. delete_file(AuthenticationConnection *ac, const char *filename)
  89. {
  90. Key *public;
  91. char *comment = NULL;
  92. int ret = -1;
  93. public = key_load_public(filename, &comment);
  94. if (public == NULL) {
  95. printf("Bad key file %s\n", filename);
  96. return -1;
  97. }
  98. if (ssh_remove_identity(ac, public)) {
  99. fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment);
  100. ret = 0;
  101. } else
  102. fprintf(stderr, "Could not remove identity: %s\n", filename);
  103. key_free(public);
  104. xfree(comment);
  105. return ret;
  106. }
  107. /* Send a request to remove all identities. */
  108. static int
  109. delete_all(AuthenticationConnection *ac)
  110. {
  111. int ret = -1;
  112. if (ssh_remove_all_identities(ac, 1))
  113. ret = 0;
  114. /* ignore error-code for ssh2 */
  115. ssh_remove_all_identities(ac, 2);
  116. if (ret == 0)
  117. fprintf(stderr, "All identities removed.\n");
  118. else
  119. fprintf(stderr, "Failed to remove all identities.\n");
  120. return ret;
  121. }
  122. static int
  123. add_file(AuthenticationConnection *ac, const char *filename)
  124. {
  125. Key *private, *cert;
  126. char *comment = NULL;
  127. char msg[1024], *certpath;
  128. int fd, perms_ok, ret = -1;
  129. Buffer keyblob;
  130. if (strcmp(filename, "-") == 0) {
  131. fd = STDIN_FILENO;
  132. filename = "(stdin)";
  133. } else if ((fd = open(filename, O_RDONLY)) < 0) {
  134. perror(filename);
  135. return -1;
  136. }
  137. /*
  138. * Since we'll try to load a keyfile multiple times, permission errors
  139. * will occur multiple times, so check perms first and bail if wrong.
  140. */
  141. if (fd != STDIN_FILENO) {
  142. perms_ok = key_perm_ok(fd, filename);
  143. if (!perms_ok) {
  144. close(fd);
  145. return -1;
  146. }
  147. }
  148. buffer_init(&keyblob);
  149. if (!key_load_file(fd, filename, &keyblob)) {
  150. buffer_free(&keyblob);
  151. close(fd);
  152. return -1;
  153. }
  154. close(fd);
  155. /* At first, try empty passphrase */
  156. private = key_parse_private(&keyblob, filename, "", &comment);
  157. if (comment == NULL)
  158. comment = xstrdup(filename);
  159. /* try last */
  160. if (private == NULL && pass != NULL)
  161. private = key_parse_private(&keyblob, filename, pass, NULL);
  162. if (private == NULL) {
  163. /* clear passphrase since it did not work */
  164. clear_pass();
  165. snprintf(msg, sizeof msg, "Enter passphrase for %.200s: ",
  166. comment);
  167. for (;;) {
  168. pass = read_passphrase(msg, RP_ALLOW_STDIN);
  169. if (strcmp(pass, "") == 0) {
  170. clear_pass();
  171. xfree(comment);
  172. buffer_free(&keyblob);
  173. return -1;
  174. }
  175. private = key_parse_private(&keyblob, filename, pass,
  176. &comment);
  177. if (private != NULL)
  178. break;
  179. clear_pass();
  180. snprintf(msg, sizeof msg,
  181. "Bad passphrase, try again for %.200s: ", comment);
  182. }
  183. }
  184. buffer_free(&keyblob);
  185. if (ssh_add_identity_constrained(ac, private, comment, lifetime,
  186. confirm)) {
  187. fprintf(stderr, "Identity added: %s (%s)\n", filename, comment);
  188. ret = 0;
  189. if (lifetime != 0)
  190. fprintf(stderr,
  191. "Lifetime set to %d seconds\n", lifetime);
  192. if (confirm != 0)
  193. fprintf(stderr,
  194. "The user must confirm each use of the key\n");
  195. } else {
  196. fprintf(stderr, "Could not add identity: %s\n", filename);
  197. }
  198. /* Now try to add the certificate flavour too */
  199. xasprintf(&certpath, "%s-cert.pub", filename);
  200. if ((cert = key_load_public(certpath, NULL)) == NULL)
  201. goto out;
  202. if (!key_equal_public(cert, private)) {
  203. error("Certificate %s does not match private key %s",
  204. certpath, filename);
  205. key_free(cert);
  206. goto out;
  207. }
  208. /* Graft with private bits */
  209. if (key_to_certified(private, key_cert_is_legacy(cert)) != 0) {
  210. error("%s: key_to_certified failed", __func__);
  211. key_free(cert);
  212. goto out;
  213. }
  214. key_cert_copy(cert, private);
  215. key_free(cert);
  216. if (!ssh_add_identity_constrained(ac, private, comment,
  217. lifetime, confirm)) {
  218. error("Certificate %s (%s) add failed", certpath,
  219. private->cert->key_id);
  220. }
  221. fprintf(stderr, "Certificate added: %s (%s)\n", certpath,
  222. private->cert->key_id);
  223. if (lifetime != 0)
  224. fprintf(stderr, "Lifetime set to %d seconds\n", lifetime);
  225. if (confirm != 0)
  226. fprintf(stderr, "The user must confirm each use of the key\n");
  227. out:
  228. xfree(certpath);
  229. xfree(comment);
  230. key_free(private);
  231. return ret;
  232. }
  233. static int
  234. update_card(AuthenticationConnection *ac, int add, const char *id)
  235. {
  236. char *pin;
  237. int ret = -1;
  238. pin = read_passphrase("Enter passphrase for PKCS#11: ", RP_ALLOW_STDIN);
  239. if (pin == NULL)
  240. return -1;
  241. if (ssh_update_card(ac, add, id, pin, lifetime, confirm)) {
  242. fprintf(stderr, "Card %s: %s\n",
  243. add ? "added" : "removed", id);
  244. ret = 0;
  245. } else {
  246. fprintf(stderr, "Could not %s card: %s\n",
  247. add ? "add" : "remove", id);
  248. ret = -1;
  249. }
  250. xfree(pin);
  251. return ret;
  252. }
  253. static int
  254. list_identities(AuthenticationConnection *ac, int do_fp)
  255. {
  256. Key *key;
  257. char *comment, *fp;
  258. int had_identities = 0;
  259. int version;
  260. for (version = 1; version <= 2; version++) {
  261. for (key = ssh_get_first_identity(ac, &comment, version);
  262. key != NULL;
  263. key = ssh_get_next_identity(ac, &comment, version)) {
  264. had_identities = 1;
  265. if (do_fp) {
  266. fp = key_fingerprint(key, SSH_FP_MD5,
  267. SSH_FP_HEX);
  268. printf("%d %s %s (%s)\n",
  269. key_size(key), fp, comment, key_type(key));
  270. xfree(fp);
  271. } else {
  272. if (!key_write(key, stdout))
  273. fprintf(stderr, "key_write failed");
  274. fprintf(stdout, " %s\n", comment);
  275. }
  276. key_free(key);
  277. xfree(comment);
  278. }
  279. }
  280. if (!had_identities) {
  281. printf("The agent has no identities.\n");
  282. return -1;
  283. }
  284. return 0;
  285. }
  286. static int
  287. lock_agent(AuthenticationConnection *ac, int lock)
  288. {
  289. char prompt[100], *p1, *p2;
  290. int passok = 1, ret = -1;
  291. strlcpy(prompt, "Enter lock password: ", sizeof(prompt));
  292. p1 = read_passphrase(prompt, RP_ALLOW_STDIN);
  293. if (lock) {
  294. strlcpy(prompt, "Again: ", sizeof prompt);
  295. p2 = read_passphrase(prompt, RP_ALLOW_STDIN);
  296. if (strcmp(p1, p2) != 0) {
  297. fprintf(stderr, "Passwords do not match.\n");
  298. passok = 0;
  299. }
  300. memset(p2, 0, strlen(p2));
  301. xfree(p2);
  302. }
  303. if (passok && ssh_lock_agent(ac, lock, p1)) {
  304. fprintf(stderr, "Agent %slocked.\n", lock ? "" : "un");
  305. ret = 0;
  306. } else
  307. fprintf(stderr, "Failed to %slock agent.\n", lock ? "" : "un");
  308. memset(p1, 0, strlen(p1));
  309. xfree(p1);
  310. return (ret);
  311. }
  312. static int
  313. do_file(AuthenticationConnection *ac, int deleting, char *file)
  314. {
  315. if (deleting) {
  316. if (delete_file(ac, file) == -1)
  317. return -1;
  318. } else {
  319. if (add_file(ac, file) == -1)
  320. return -1;
  321. }
  322. return 0;
  323. }
  324. static void
  325. usage(void)
  326. {
  327. fprintf(stderr, "usage: %s [options] [file ...]\n", __progname);
  328. fprintf(stderr, "Options:\n");
  329. fprintf(stderr, " -l List fingerprints of all identities.\n");
  330. fprintf(stderr, " -L List public key parameters of all identities.\n");
  331. fprintf(stderr, " -d Delete identity.\n");
  332. fprintf(stderr, " -D Delete all identities.\n");
  333. fprintf(stderr, " -x Lock agent.\n");
  334. fprintf(stderr, " -X Unlock agent.\n");
  335. fprintf(stderr, " -t life Set lifetime (in seconds) when adding identities.\n");
  336. fprintf(stderr, " -c Require confirmation to sign using identities\n");
  337. fprintf(stderr, " -s pkcs11 Add keys from PKCS#11 provider.\n");
  338. fprintf(stderr, " -e pkcs11 Remove keys provided by PKCS#11 provider.\n");
  339. }
  340. int
  341. main(int argc, char **argv)
  342. {
  343. extern char *optarg;
  344. extern int optind;
  345. AuthenticationConnection *ac = NULL;
  346. char *pkcs11provider = NULL;
  347. int i, ch, deleting = 0, ret = 0;
  348. /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
  349. sanitise_stdfd();
  350. __progname = ssh_get_progname(argv[0]);
  351. seed_rng();
  352. OpenSSL_add_all_algorithms();
  353. /* At first, get a connection to the authentication agent. */
  354. ac = ssh_get_authentication_connection();
  355. if (ac == NULL) {
  356. fprintf(stderr,
  357. "Could not open a connection to your authentication agent.\n");
  358. exit(2);
  359. }
  360. while ((ch = getopt(argc, argv, "lLcdDxXe:s:t:")) != -1) {
  361. switch (ch) {
  362. case 'l':
  363. case 'L':
  364. if (list_identities(ac, ch == 'l' ? 1 : 0) == -1)
  365. ret = 1;
  366. goto done;
  367. case 'x':
  368. case 'X':
  369. if (lock_agent(ac, ch == 'x' ? 1 : 0) == -1)
  370. ret = 1;
  371. goto done;
  372. case 'c':
  373. confirm = 1;
  374. break;
  375. case 'd':
  376. deleting = 1;
  377. break;
  378. case 'D':
  379. if (delete_all(ac) == -1)
  380. ret = 1;
  381. goto done;
  382. case 's':
  383. pkcs11provider = optarg;
  384. break;
  385. case 'e':
  386. deleting = 1;
  387. pkcs11provider = optarg;
  388. break;
  389. case 't':
  390. if ((lifetime = convtime(optarg)) == -1) {
  391. fprintf(stderr, "Invalid lifetime\n");
  392. ret = 1;
  393. goto done;
  394. }
  395. break;
  396. default:
  397. usage();
  398. ret = 1;
  399. goto done;
  400. }
  401. }
  402. argc -= optind;
  403. argv += optind;
  404. if (pkcs11provider != NULL) {
  405. if (update_card(ac, !deleting, pkcs11provider) == -1)
  406. ret = 1;
  407. goto done;
  408. }
  409. if (argc == 0) {
  410. char buf[MAXPATHLEN];
  411. struct passwd *pw;
  412. struct stat st;
  413. int count = 0;
  414. if ((pw = getpwuid(getuid())) == NULL) {
  415. fprintf(stderr, "No user found with uid %u\n",
  416. (u_int)getuid());
  417. ret = 1;
  418. goto done;
  419. }
  420. for (i = 0; default_files[i]; i++) {
  421. snprintf(buf, sizeof(buf), "%s/%s", pw->pw_dir,
  422. default_files[i]);
  423. if (stat(buf, &st) < 0)
  424. continue;
  425. if (do_file(ac, deleting, buf) == -1)
  426. ret = 1;
  427. else
  428. count++;
  429. }
  430. if (count == 0)
  431. ret = 1;
  432. } else {
  433. for (i = 0; i < argc; i++) {
  434. if (do_file(ac, deleting, argv[i]) == -1)
  435. ret = 1;
  436. }
  437. }
  438. clear_pass();
  439. done:
  440. ssh_close_authentication_connection(ac);
  441. return ret;
  442. }