]> andersk Git - openssh.git/blob - ssh-add.c
- markus@cvs.openbsd.org 2001/04/14 16:27:57
[openssh.git] / ssh-add.c
1 /*
2  * Author: Tatu Ylonen <ylo@cs.hut.fi>
3  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4  *                    All rights reserved
5  * Adds an identity to the authentication server, or removes an identity.
6  *
7  * As far as I am concerned, the code I have written for this software
8  * can be used freely for any purpose.  Any derived versions of this
9  * software must be clearly marked as such, and if the derived work is
10  * incompatible with the protocol description in the RFC file, it must be
11  * called by a name other than "ssh" or "Secure Shell".
12  *
13  * SSH2 implementation,
14  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
15  *
16  * Redistribution and use in source and binary forms, with or without
17  * modification, are permitted provided that the following conditions
18  * are met:
19  * 1. Redistributions of source code must retain the above copyright
20  *    notice, this list of conditions and the following disclaimer.
21  * 2. Redistributions in binary form must reproduce the above copyright
22  *    notice, this list of conditions and the following disclaimer in the
23  *    documentation and/or other materials provided with the distribution.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  */
36
37 #include "includes.h"
38 RCSID("$OpenBSD: ssh-add.c,v 1.35 2001/04/14 16:27:57 markus Exp $");
39
40 #include <openssl/evp.h>
41
42 #include "ssh.h"
43 #include "rsa.h"
44 #include "log.h"
45 #include "xmalloc.h"
46 #include "key.h"
47 #include "authfd.h"
48 #include "authfile.h"
49 #include "pathnames.h"
50 #include "readpass.h"
51
52 #ifdef HAVE___PROGNAME
53 extern char *__progname;
54 #else
55 char *__progname;
56 #endif
57
58 /* we keep a cache of one passphrases */
59 static char *pass = NULL;
60 void
61 clear_pass(void)
62 {
63         if (pass) {
64                 memset(pass, 0, strlen(pass));
65                 xfree(pass);
66                 pass = NULL;
67         }
68 }
69
70 void
71 delete_file(AuthenticationConnection *ac, const char *filename)
72 {
73         Key *public;
74         char *comment = NULL;
75
76         public = key_load_public(filename, &comment);
77         if (public == NULL) {
78                 printf("Bad key file %s\n", filename);
79                 return;
80         }
81         if (ssh_remove_identity(ac, public))
82                 fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment);
83         else
84                 fprintf(stderr, "Could not remove identity: %s\n", filename);
85         key_free(public);
86         xfree(comment);
87 }
88
89 /* Send a request to remove all identities. */
90 void
91 delete_all(AuthenticationConnection *ac)
92 {
93         int success = 1;
94
95         if (!ssh_remove_all_identities(ac, 1))
96                 success = 0;
97         /* ignore error-code for ssh2 */
98         ssh_remove_all_identities(ac, 2);
99
100         if (success)
101                 fprintf(stderr, "All identities removed.\n");
102         else
103                 fprintf(stderr, "Failed to remove all identities.\n");
104 }
105
106 char *
107 ssh_askpass(char *askpass, char *msg)
108 {
109         pid_t pid;
110         size_t len;
111         char *nl, *pass;
112         int p[2], status;
113         char buf[1024];
114
115         if (fflush(stdout) != 0)
116                 error("ssh_askpass: fflush: %s", strerror(errno));
117         if (askpass == NULL)
118                 fatal("internal error: askpass undefined");
119         if (pipe(p) < 0)
120                 fatal("ssh_askpass: pipe: %s", strerror(errno));
121         if ((pid = fork()) < 0)
122                 fatal("ssh_askpass: fork: %s", strerror(errno));
123         if (pid == 0) {
124                 close(p[0]);
125                 if (dup2(p[1], STDOUT_FILENO) < 0)
126                         fatal("ssh_askpass: dup2: %s", strerror(errno));
127                 execlp(askpass, askpass, msg, (char *) 0);
128                 fatal("ssh_askpass: exec(%s): %s", askpass, strerror(errno));
129         }
130         close(p[1]);
131         len = read(p[0], buf, sizeof buf);
132         close(p[0]);
133         while (waitpid(pid, &status, 0) < 0)
134                 if (errno != EINTR)
135                         break;
136         if (len <= 1)
137                 return xstrdup("");
138         nl = strchr(buf, '\n');
139         if (nl)
140                 *nl = '\0';
141         pass = xstrdup(buf);
142         memset(buf, 0, sizeof(buf));
143         return pass;
144 }
145
146 void
147 add_file(AuthenticationConnection *ac, const char *filename)
148 {
149         struct stat st;
150         Key *private;
151         char *comment = NULL, *askpass = NULL;
152         char buf[1024], msg[1024];
153         int interactive = isatty(STDIN_FILENO);
154
155         if (stat(filename, &st) < 0) {
156                 perror(filename);
157                 exit(1);
158         }
159         if (!interactive && getenv("DISPLAY")) {
160                 if (getenv(SSH_ASKPASS_ENV))
161                         askpass = getenv(SSH_ASKPASS_ENV);
162                 else
163                         askpass = _PATH_SSH_ASKPASS_DEFAULT;
164         }
165
166         /* At first, try empty passphrase */
167         private = key_load_private(filename, "", &comment);
168         if (comment == NULL)
169                 comment = xstrdup(filename);
170         /* try last */
171         if (private == NULL && pass != NULL)
172                 private = key_load_private(filename, pass, NULL);
173         if (private == NULL) {
174                 /* clear passphrase since it did not work */
175                 clear_pass();
176                 printf("Need passphrase for %.200s\n", filename);
177                 if (!interactive && askpass == NULL) {
178                         xfree(comment);
179                         return;
180                 }
181                 snprintf(msg, sizeof msg, "Enter passphrase for %.200s", comment);
182                 for (;;) {
183                         if (interactive) {
184                                 snprintf(buf, sizeof buf, "%s: ", msg);
185                                 pass = read_passphrase(buf, 1);
186                         } else {
187                                 pass = ssh_askpass(askpass, msg);
188                         }
189                         if (strcmp(pass, "") == 0) {
190                                 clear_pass();
191                                 xfree(comment);
192                                 return;
193                         }
194                         private = key_load_private(filename, pass, &comment);
195                         if (private != NULL)
196                                 break;
197                         clear_pass();
198                         strlcpy(msg, "Bad passphrase, try again", sizeof msg);
199                 }
200         }
201         if (ssh_add_identity(ac, private, comment))
202                 fprintf(stderr, "Identity added: %s (%s)\n", filename, comment);
203         else
204                 fprintf(stderr, "Could not add identity: %s\n", filename);
205         xfree(comment);
206         key_free(private);
207 }
208
209 void
210 list_identities(AuthenticationConnection *ac, int do_fp)
211 {
212         Key *key;
213         char *comment, *fp;
214         int had_identities = 0;
215         int version;
216
217         for (version = 1; version <= 2; version++) {
218                 for (key = ssh_get_first_identity(ac, &comment, version);
219                      key != NULL;
220                      key = ssh_get_next_identity(ac, &comment, version)) {
221                         had_identities = 1;
222                         if (do_fp) {
223                                 fp = key_fingerprint(key, SSH_FP_MD5,
224                                     SSH_FP_HEX);
225                                 printf("%d %s %s (%s)\n",
226                                     key_size(key), fp, comment, key_type(key));
227                                 xfree(fp);
228                         } else {
229                                 if (!key_write(key, stdout))
230                                         fprintf(stderr, "key_write failed");
231                                 fprintf(stdout, " %s\n", comment);
232                         }
233                         key_free(key);
234                         xfree(comment);
235                 }
236         }
237         if (!had_identities)
238                 printf("The agent has no identities.\n");
239 }
240
241 int
242 main(int argc, char **argv)
243 {
244         AuthenticationConnection *ac = NULL;
245         struct passwd *pw;
246         char buf[1024];
247         int no_files = 1;
248         int i;
249         int deleting = 0;
250
251         __progname = get_progname(argv[0]);
252         init_rng();
253
254         SSLeay_add_all_algorithms();
255
256         /* At first, get a connection to the authentication agent. */
257         ac = ssh_get_authentication_connection();
258         if (ac == NULL) {
259                 fprintf(stderr, "Could not open a connection to your authentication agent.\n");
260                 exit(1);
261         }
262         for (i = 1; i < argc; i++) {
263                 if ((strcmp(argv[i], "-l") == 0) ||
264                     (strcmp(argv[i], "-L") == 0)) {
265                         list_identities(ac, argv[i][1] == 'l' ? 1 : 0);
266                         /* Don't default-add/delete if -l. */
267                         no_files = 0;
268                         continue;
269                 }
270                 if (strcmp(argv[i], "-d") == 0) {
271                         deleting = 1;
272                         continue;
273                 }
274                 if (strcmp(argv[i], "-D") == 0) {
275                         delete_all(ac);
276                         no_files = 0;
277                         continue;
278                 }
279                 no_files = 0;
280                 if (deleting)
281                         delete_file(ac, argv[i]);
282                 else
283                         add_file(ac, argv[i]);
284         }
285         if (no_files) {
286                 pw = getpwuid(getuid());
287                 if (!pw) {
288                         fprintf(stderr, "No user found with uid %u\n",
289                             (u_int)getuid());
290                         ssh_close_authentication_connection(ac);
291                         exit(1);
292                 }
293                 snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, _PATH_SSH_CLIENT_IDENTITY);
294                 if (deleting)
295                         delete_file(ac, buf);
296                 else
297                         add_file(ac, buf);
298         }
299         clear_pass();
300         ssh_close_authentication_connection(ac);
301         exit(0);
302 }
This page took 0.067976 seconds and 5 git commands to generate.