blob: 661e1ffa92d7f2c623b4be8a1a9d007cbde1d6d1 [file] [log] [blame]
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001/*
Damien Miller95def091999-11-25 00:26:21 +11002 * Author: Tatu Ylonen <ylo@cs.hut.fi>
3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 * All rights reserved
5 * Created: Thu Apr 6 00:52:24 1995 ylo
6 * Adds an identity to the authentication server, or removes an identity.
7 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10008
9#include "includes.h"
Damien Miller6536c7d2000-06-22 21:32:31 +100010RCSID("$OpenBSD: ssh-add.c,v 1.17 2000/06/20 01:39:44 markus Exp $");
Damien Millereba71ba2000-04-29 23:57:08 +100011
12#include <openssl/rsa.h>
13#include <openssl/dsa.h>
Damien Millerd4a8b7e1999-10-27 13:42:43 +100014
15#include "rsa.h"
16#include "ssh.h"
17#include "xmalloc.h"
18#include "authfd.h"
Damien Miller10f6f6b1999-11-17 17:29:08 +110019#include "fingerprint.h"
Damien Millereba71ba2000-04-29 23:57:08 +100020#include "key.h"
21#include "authfile.h"
Damien Millerd4a8b7e1999-10-27 13:42:43 +100022
Damien Miller3f905871999-11-15 17:10:57 +110023#ifdef HAVE___PROGNAME
24extern char *__progname;
25#else /* HAVE___PROGNAME */
Damien Miller70fb6712000-05-01 20:59:50 +100026static const char *__progname = "ssh-add";
Damien Miller3f905871999-11-15 17:10:57 +110027#endif /* HAVE___PROGNAME */
28
Damien Millerd4a8b7e1999-10-27 13:42:43 +100029void
Damien Miller01ab4a21999-10-28 15:23:30 +100030delete_file(AuthenticationConnection *ac, const char *filename)
Damien Millerd4a8b7e1999-10-27 13:42:43 +100031{
Damien Millereba71ba2000-04-29 23:57:08 +100032 Key *public;
Damien Miller95def091999-11-25 00:26:21 +110033 char *comment;
Damien Millerd4a8b7e1999-10-27 13:42:43 +100034
Damien Millereba71ba2000-04-29 23:57:08 +100035 public = key_new(KEY_RSA);
36 if (!load_public_key(filename, public, &comment)) {
Damien Miller95def091999-11-25 00:26:21 +110037 printf("Bad key file %s: %s\n", filename, strerror(errno));
38 return;
39 }
Damien Millereba71ba2000-04-29 23:57:08 +100040 if (ssh_remove_identity(ac, public->rsa))
Damien Miller95def091999-11-25 00:26:21 +110041 fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment);
42 else
43 fprintf(stderr, "Could not remove identity: %s\n", filename);
Damien Millereba71ba2000-04-29 23:57:08 +100044 key_free(public);
Damien Miller95def091999-11-25 00:26:21 +110045 xfree(comment);
Damien Millerd4a8b7e1999-10-27 13:42:43 +100046}
47
48void
Damien Miller01ab4a21999-10-28 15:23:30 +100049delete_all(AuthenticationConnection *ac)
Damien Millerd4a8b7e1999-10-27 13:42:43 +100050{
Damien Miller95def091999-11-25 00:26:21 +110051 /* Send a request to remove all identities. */
52 if (ssh_remove_all_identities(ac))
53 fprintf(stderr, "All identities removed.\n");
54 else
55 fprintf(stderr, "Failed to remove all identitities.\n");
Damien Millerd4a8b7e1999-10-27 13:42:43 +100056}
57
Damien Miller5428f641999-11-25 11:54:57 +110058char *
59ssh_askpass(char *askpass, char *msg)
60{
61 pid_t pid;
62 size_t len;
63 char *nl, *pass;
64 int p[2], status;
65 char buf[1024];
66
67 if (askpass == NULL)
68 fatal("internal error: askpass undefined");
69 if (pipe(p) < 0)
70 fatal("ssh_askpass: pipe: %s", strerror(errno));
71 if ((pid = fork()) < 0)
72 fatal("ssh_askpass: fork: %s", strerror(errno));
73 if (pid == 0) {
74 close(p[0]);
75 if (dup2(p[1], STDOUT_FILENO) < 0)
76 fatal("ssh_askpass: dup2: %s", strerror(errno));
77 execlp(askpass, askpass, msg, (char *) 0);
78 fatal("ssh_askpass: exec(%s): %s", askpass, strerror(errno));
79 }
80 close(p[1]);
81 len = read(p[0], buf, sizeof buf);
82 close(p[0]);
83 while (waitpid(pid, &status, 0) < 0)
84 if (errno != EINTR)
85 break;
86 if (len <= 1)
87 return xstrdup("");
88 nl = strchr(buf, '\n');
89 if (nl)
90 *nl = '\0';
91 pass = xstrdup(buf);
92 memset(buf, 0, sizeof(buf));
93 return pass;
94}
95
Damien Millerd4a8b7e1999-10-27 13:42:43 +100096void
Damien Miller01ab4a21999-10-28 15:23:30 +100097add_file(AuthenticationConnection *ac, const char *filename)
Damien Millerd4a8b7e1999-10-27 13:42:43 +100098{
Damien Millereba71ba2000-04-29 23:57:08 +100099 Key *public;
100 Key *private;
Damien Miller5428f641999-11-25 11:54:57 +1100101 char *saved_comment, *comment, *askpass = NULL;
102 char buf[1024], msg[1024];
Damien Miller95def091999-11-25 00:26:21 +1100103 int success;
Damien Miller5428f641999-11-25 11:54:57 +1100104 int interactive = isatty(STDIN_FILENO);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000105
Damien Millereba71ba2000-04-29 23:57:08 +1000106 public = key_new(KEY_RSA);
107 if (!load_public_key(filename, public, &saved_comment)) {
Damien Miller95def091999-11-25 00:26:21 +1100108 printf("Bad key file %s: %s\n", filename, strerror(errno));
109 return;
110 }
Damien Millereba71ba2000-04-29 23:57:08 +1000111 key_free(public);
Damien Miller95def091999-11-25 00:26:21 +1100112
Damien Milleraae6c611999-12-06 11:47:28 +1100113 if (!interactive && getenv("DISPLAY")) {
114 if (getenv(SSH_ASKPASS_ENV))
115 askpass = getenv(SSH_ASKPASS_ENV);
116 else
117 askpass = SSH_ASKPASS_DEFAULT;
118 }
Damien Miller5428f641999-11-25 11:54:57 +1100119
Damien Miller95def091999-11-25 00:26:21 +1100120 /* At first, try empty passphrase */
Damien Millereba71ba2000-04-29 23:57:08 +1000121 private = key_new(KEY_RSA);
122 success = load_private_key(filename, "", private, &comment);
Damien Miller95def091999-11-25 00:26:21 +1100123 if (!success) {
Damien Miller5428f641999-11-25 11:54:57 +1100124 printf("Need passphrase for %.200s\n", filename);
125 if (!interactive && askpass == NULL) {
126 xfree(saved_comment);
127 return;
Damien Miller95def091999-11-25 00:26:21 +1100128 }
Damien Miller5428f641999-11-25 11:54:57 +1100129 snprintf(msg, sizeof msg, "Enter passphrase for %.200s", saved_comment);
130 for (;;) {
131 char *pass;
132 if (interactive) {
133 snprintf(buf, sizeof buf, "%s: ", msg);
134 pass = read_passphrase(buf, 1);
135 } else {
136 pass = ssh_askpass(askpass, msg);
137 }
Damien Miller95def091999-11-25 00:26:21 +1100138 if (strcmp(pass, "") == 0) {
139 xfree(pass);
140 xfree(saved_comment);
141 return;
142 }
Damien Millereba71ba2000-04-29 23:57:08 +1000143 success = load_private_key(filename, pass, private, &comment);
Damien Miller95def091999-11-25 00:26:21 +1100144 memset(pass, 0, strlen(pass));
145 xfree(pass);
146 if (success)
147 break;
Damien Miller5428f641999-11-25 11:54:57 +1100148 strlcpy(msg, "Bad passphrase, try again", sizeof msg);
Damien Miller95def091999-11-25 00:26:21 +1100149 }
150 }
151 xfree(saved_comment);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000152
Damien Millereba71ba2000-04-29 23:57:08 +1000153 if (ssh_add_identity(ac, private->rsa, comment))
Damien Miller95def091999-11-25 00:26:21 +1100154 fprintf(stderr, "Identity added: %s (%s)\n", filename, comment);
155 else
156 fprintf(stderr, "Could not add identity: %s\n", filename);
Damien Millereba71ba2000-04-29 23:57:08 +1000157 key_free(private);
Damien Miller95def091999-11-25 00:26:21 +1100158 xfree(comment);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000159}
160
161void
Damien Miller10f6f6b1999-11-17 17:29:08 +1100162list_identities(AuthenticationConnection *ac, int fp)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000163{
Damien Miller95def091999-11-25 00:26:21 +1100164 BIGNUM *e, *n;
165 int status;
166 char *comment;
167 int had_identities;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000168
Damien Miller95def091999-11-25 00:26:21 +1100169 e = BN_new();
170 n = BN_new();
171 had_identities = 0;
172 for (status = ssh_get_first_identity(ac, e, n, &comment);
173 status;
174 status = ssh_get_next_identity(ac, e, n, &comment)) {
175 unsigned int bits = BN_num_bits(n);
176 had_identities = 1;
177 if (fp) {
178 printf("%d %s %s\n", bits, fingerprint(e, n), comment);
179 } else {
180 char *ebuf, *nbuf;
181 ebuf = BN_bn2dec(e);
182 if (ebuf == NULL) {
183 error("list_identities: BN_bn2dec(e) failed.");
184 } else {
185 nbuf = BN_bn2dec(n);
186 if (nbuf == NULL) {
187 error("list_identities: BN_bn2dec(n) failed.");
188 } else {
189 printf("%d %s %s %s\n", bits, ebuf, nbuf, comment);
190 free(nbuf);
191 }
192 free(ebuf);
193 }
194 }
195 xfree(comment);
Damien Miller10f6f6b1999-11-17 17:29:08 +1100196 }
Damien Miller95def091999-11-25 00:26:21 +1100197 BN_clear_free(e);
198 BN_clear_free(n);
199 if (!had_identities)
200 printf("The agent has no identities.\n");
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000201}
202
203int
Damien Miller01ab4a21999-10-28 15:23:30 +1000204main(int argc, char **argv)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000205{
Damien Miller95def091999-11-25 00:26:21 +1100206 AuthenticationConnection *ac = NULL;
207 struct passwd *pw;
208 char buf[1024];
209 int no_files = 1;
210 int i;
211 int deleting = 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000212
Damien Miller95def091999-11-25 00:26:21 +1100213 /* check if RSA support exists */
214 if (rsa_alive() == 0) {
Damien Miller95def091999-11-25 00:26:21 +1100215 fprintf(stderr,
216 "%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
217 __progname);
218 exit(1);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000219 }
Damien Miller95def091999-11-25 00:26:21 +1100220 /* At first, get a connection to the authentication agent. */
221 ac = ssh_get_authentication_connection();
222 if (ac == NULL) {
223 fprintf(stderr, "Could not open a connection to your authentication agent.\n");
224 exit(1);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000225 }
Damien Miller95def091999-11-25 00:26:21 +1100226 for (i = 1; i < argc; i++) {
227 if ((strcmp(argv[i], "-l") == 0) ||
228 (strcmp(argv[i], "-L") == 0)) {
229 list_identities(ac, argv[i][1] == 'l' ? 1 : 0);
230 /* Don't default-add/delete if -l. */
231 no_files = 0;
232 continue;
233 }
234 if (strcmp(argv[i], "-d") == 0) {
235 deleting = 1;
236 continue;
237 }
238 if (strcmp(argv[i], "-D") == 0) {
239 delete_all(ac);
240 no_files = 0;
241 continue;
242 }
243 no_files = 0;
244 if (deleting)
245 delete_file(ac, argv[i]);
246 else
247 add_file(ac, argv[i]);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000248 }
Damien Miller95def091999-11-25 00:26:21 +1100249 if (no_files) {
250 pw = getpwuid(getuid());
251 if (!pw) {
252 fprintf(stderr, "No user found with uid %d\n", (int) getuid());
253 ssh_close_authentication_connection(ac);
254 exit(1);
255 }
256 snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, SSH_CLIENT_IDENTITY);
257 if (deleting)
258 delete_file(ac, buf);
259 else
260 add_file(ac, buf);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000261 }
Damien Miller95def091999-11-25 00:26:21 +1100262 ssh_close_authentication_connection(ac);
263 exit(0);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000264}