source: trunk/third/openssh/ssh-add.c @ 18759

Revision 18759, 9.8 KB checked in by zacheiss, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18758, which included commits to RCS files with non-trunk default branches.
Line 
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, 2001 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"
38RCSID("$OpenBSD: ssh-add.c,v 1.63 2002/09/19 15:51:23 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#include "misc.h"
52
53#ifdef HAVE___PROGNAME
54extern char *__progname;
55#else
56char *__progname;
57#endif
58
59/* argv0 */
60extern char *__progname;
61
62/* Default files to add */
63static char *default_files[] = {
64        _PATH_SSH_CLIENT_ID_RSA,
65        _PATH_SSH_CLIENT_ID_DSA,
66        _PATH_SSH_CLIENT_IDENTITY,
67        NULL
68};
69
70/* Default lifetime (0 == forever) */
71static int lifetime = 0;
72
73/* we keep a cache of one passphrases */
74static char *pass = NULL;
75static void
76clear_pass(void)
77{
78        if (pass) {
79                memset(pass, 0, strlen(pass));
80                xfree(pass);
81                pass = NULL;
82        }
83}
84
85static int
86delete_file(AuthenticationConnection *ac, const char *filename)
87{
88        Key *public;
89        char *comment = NULL;
90        int ret = -1;
91
92        public = key_load_public(filename, &comment);
93        if (public == NULL) {
94                printf("Bad key file %s\n", filename);
95                return -1;
96        }
97        if (ssh_remove_identity(ac, public)) {
98                fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment);
99                ret = 0;
100        } else
101                fprintf(stderr, "Could not remove identity: %s\n", filename);
102
103        key_free(public);
104        xfree(comment);
105
106        return ret;
107}
108
109/* Send a request to remove all identities. */
110static int
111delete_all(AuthenticationConnection *ac)
112{
113        int ret = -1;
114
115        if (ssh_remove_all_identities(ac, 1))
116                ret = 0;
117        /* ignore error-code for ssh2 */
118        ssh_remove_all_identities(ac, 2);
119
120        if (ret == 0)
121                fprintf(stderr, "All identities removed.\n");
122        else
123                fprintf(stderr, "Failed to remove all identities.\n");
124
125        return ret;
126}
127
128static int
129add_file(AuthenticationConnection *ac, const char *filename)
130{
131        struct stat st;
132        Key *private;
133        char *comment = NULL;
134        char msg[1024];
135        int ret = -1;
136
137        if (stat(filename, &st) < 0) {
138                perror(filename);
139                return -1;
140        }
141        /* At first, try empty passphrase */
142        private = key_load_private(filename, "", &comment);
143        if (comment == NULL)
144                comment = xstrdup(filename);
145        /* try last */
146        if (private == NULL && pass != NULL)
147                private = key_load_private(filename, pass, NULL);
148        if (private == NULL) {
149                /* clear passphrase since it did not work */
150                clear_pass();
151                snprintf(msg, sizeof msg, "Enter passphrase for %.200s: ",
152                   comment);
153                for (;;) {
154                        pass = read_passphrase(msg, RP_ALLOW_STDIN);
155                        if (strcmp(pass, "") == 0) {
156                                clear_pass();
157                                xfree(comment);
158                                return -1;
159                        }
160                        private = key_load_private(filename, pass, &comment);
161                        if (private != NULL)
162                                break;
163                        clear_pass();
164                        strlcpy(msg, "Bad passphrase, try again: ", sizeof msg);
165                }
166        }
167
168        if (ssh_add_identity_constrained(ac, private, comment, lifetime)) {
169                fprintf(stderr, "Identity added: %s (%s)\n", filename, comment);
170                ret = 0;
171                if (lifetime != 0)
172                        fprintf(stderr,
173                            "Lifetime set to %d seconds\n", lifetime);
174        } else if (ssh_add_identity(ac, private, comment)) {
175                fprintf(stderr, "Identity added: %s (%s)\n", filename, comment);
176                ret = 0;
177        } else {
178                fprintf(stderr, "Could not add identity: %s\n", filename);
179        }
180
181        xfree(comment);
182        key_free(private);
183
184        return ret;
185}
186
187static int
188update_card(AuthenticationConnection *ac, int add, const char *id)
189{
190        char *pin;
191
192        pin = read_passphrase("Enter passphrase for smartcard: ", RP_ALLOW_STDIN);
193        if (pin == NULL)
194                return -1;
195
196        if (ssh_update_card(ac, add, id, pin)) {
197                fprintf(stderr, "Card %s: %s\n",
198                    add ? "added" : "removed", id);
199                return 0;
200        } else {
201                fprintf(stderr, "Could not %s card: %s\n",
202                    add ? "add" : "remove", id);
203                return -1;
204        }
205}
206
207static int
208list_identities(AuthenticationConnection *ac, int do_fp)
209{
210        Key *key;
211        char *comment, *fp;
212        int had_identities = 0;
213        int version;
214
215        for (version = 1; version <= 2; version++) {
216                for (key = ssh_get_first_identity(ac, &comment, version);
217                    key != NULL;
218                    key = ssh_get_next_identity(ac, &comment, version)) {
219                        had_identities = 1;
220                        if (do_fp) {
221                                fp = key_fingerprint(key, SSH_FP_MD5,
222                                    SSH_FP_HEX);
223                                printf("%d %s %s (%s)\n",
224                                    key_size(key), fp, comment, key_type(key));
225                                xfree(fp);
226                        } else {
227                                if (!key_write(key, stdout))
228                                        fprintf(stderr, "key_write failed");
229                                fprintf(stdout, " %s\n", comment);
230                        }
231                        key_free(key);
232                        xfree(comment);
233                }
234        }
235        if (!had_identities) {
236                printf("The agent has no identities.\n");
237                return -1;
238        }
239        return 0;
240}
241
242static int
243lock_agent(AuthenticationConnection *ac, int lock)
244{
245        char prompt[100], *p1, *p2;
246        int passok = 1, ret = -1;
247
248        strlcpy(prompt, "Enter lock password: ", sizeof(prompt));
249        p1 = read_passphrase(prompt, RP_ALLOW_STDIN);
250        if (lock) {
251                strlcpy(prompt, "Again: ", sizeof prompt);
252                p2 = read_passphrase(prompt, RP_ALLOW_STDIN);
253                if (strcmp(p1, p2) != 0) {
254                        fprintf(stderr, "Passwords do not match.\n");
255                        passok = 0;
256                }
257                memset(p2, 0, strlen(p2));
258                xfree(p2);
259        }
260        if (passok && ssh_lock_agent(ac, lock, p1)) {
261                fprintf(stderr, "Agent %slocked.\n", lock ? "" : "un");
262                ret = 0;
263        } else
264                fprintf(stderr, "Failed to %slock agent.\n", lock ? "" : "un");
265        memset(p1, 0, strlen(p1));
266        xfree(p1);
267        return (ret);
268}
269
270static int
271do_file(AuthenticationConnection *ac, int deleting, char *file)
272{
273        if (deleting) {
274                if (delete_file(ac, file) == -1)
275                        return -1;
276        } else {
277                if (add_file(ac, file) == -1)
278                        return -1;
279        }
280        return 0;
281}
282
283static void
284usage(void)
285{
286        fprintf(stderr, "Usage: %s [options]\n", __progname);
287        fprintf(stderr, "Options:\n");
288        fprintf(stderr, "  -l          List fingerprints of all identities.\n");
289        fprintf(stderr, "  -L          List public key parameters of all identities.\n");
290        fprintf(stderr, "  -d          Delete identity.\n");
291        fprintf(stderr, "  -D          Delete all identities.\n");
292        fprintf(stderr, "  -x          Lock agent.\n");
293        fprintf(stderr, "  -X          Unlock agent.\n");
294        fprintf(stderr, "  -t life     Set lifetime (in seconds) when adding identities.\n");
295#ifdef SMARTCARD
296        fprintf(stderr, "  -s reader   Add key in smartcard reader.\n");
297        fprintf(stderr, "  -e reader   Remove key in smartcard reader.\n");
298#endif
299}
300
301int
302main(int argc, char **argv)
303{
304        extern char *optarg;
305        extern int optind;
306        AuthenticationConnection *ac = NULL;
307        char *sc_reader_id = NULL;
308        int i, ch, deleting = 0, ret = 0;
309
310        __progname = get_progname(argv[0]);
311        init_rng();
312        seed_rng();
313
314        SSLeay_add_all_algorithms();
315
316        /* At first, get a connection to the authentication agent. */
317        ac = ssh_get_authentication_connection();
318        if (ac == NULL) {
319                fprintf(stderr, "Could not open a connection to your authentication agent.\n");
320                exit(2);
321        }
322        while ((ch = getopt(argc, argv, "lLdDxXe:s:t:")) != -1) {
323                switch (ch) {
324                case 'l':
325                case 'L':
326                        if (list_identities(ac, ch == 'l' ? 1 : 0) == -1)
327                                ret = 1;
328                        goto done;
329                        break;
330                case 'x':
331                case 'X':
332                        if (lock_agent(ac, ch == 'x' ? 1 : 0) == -1)
333                                ret = 1;
334                        goto done;
335                        break;
336                case 'd':
337                        deleting = 1;
338                        break;
339                case 'D':
340                        if (delete_all(ac) == -1)
341                                ret = 1;
342                        goto done;
343                        break;
344                case 's':
345                        sc_reader_id = optarg;
346                        break;
347                case 'e':
348                        deleting = 1;
349                        sc_reader_id = optarg;
350                        break;
351                case 't':
352                        if ((lifetime = convtime(optarg)) == -1) {
353                                fprintf(stderr, "Invalid lifetime\n");
354                                ret = 1;
355                                goto done;
356                        }
357                        break;
358                default:
359                        usage();
360                        ret = 1;
361                        goto done;
362                }
363        }
364        argc -= optind;
365        argv += optind;
366        if (sc_reader_id != NULL) {
367                if (update_card(ac, !deleting, sc_reader_id) == -1)
368                        ret = 1;
369                goto done;
370        }
371        if (argc == 0) {
372                char buf[MAXPATHLEN];
373                struct passwd *pw;
374                struct stat st;
375                int count = 0;
376
377                if ((pw = getpwuid(getuid())) == NULL) {
378                        fprintf(stderr, "No user found with uid %u\n",
379                            (u_int)getuid());
380                        ret = 1;
381                        goto done;
382                }
383
384                for(i = 0; default_files[i]; i++) {
385                        snprintf(buf, sizeof(buf), "%s/%s", pw->pw_dir,
386                            default_files[i]);
387                        if (stat(buf, &st) < 0)
388                                continue;
389                        if (do_file(ac, deleting, buf) == -1)
390                                ret = 1;
391                        else
392                                count++;
393                }
394                if (count == 0)
395                        ret = 1;
396        } else {
397                for(i = 0; i < argc; i++) {
398                        if (do_file(ac, deleting, argv[i]) == -1)
399                                ret = 1;
400                }
401        }
402        clear_pass();
403
404done:
405        ssh_close_authentication_connection(ac);
406        return ret;
407}
Note: See TracBrowser for help on using the repository browser.