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("$FreeBSD$"); 39 RCSID("$OpenBSD: ssh-add.c,v 1.36 2001/04/18 21:57:42 markus Exp $"); 40 41 #include <openssl/evp.h> 42 43 #include "ssh.h" 44 #include "rsa.h" 45 #include "log.h" 46 #include "xmalloc.h" 47 #include "key.h" 48 #include "authfd.h" 49 #include "authfile.h" 50 #include "pathnames.h" 51 #include "readpass.h" 52 53 /* we keep a cache of one passphrases */ 54 static char *pass = NULL; 55 void 56 clear_pass(void) 57 { 58 if (pass) { 59 memset(pass, 0, strlen(pass)); 60 xfree(pass); 61 pass = NULL; 62 } 63 } 64 65 void 66 delete_file(AuthenticationConnection *ac, const char *filename) 67 { 68 Key *public; 69 char *comment = NULL; 70 71 public = key_load_public(filename, &comment); 72 if (public == NULL) { 73 printf("Bad key file %s\n", filename); 74 return; 75 } 76 if (ssh_remove_identity(ac, public)) 77 fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment); 78 else 79 fprintf(stderr, "Could not remove identity: %s\n", filename); 80 key_free(public); 81 xfree(comment); 82 } 83 84 /* Send a request to remove all identities. */ 85 void 86 delete_all(AuthenticationConnection *ac) 87 { 88 int success = 1; 89 90 if (!ssh_remove_all_identities(ac, 1)) 91 success = 0; 92 /* ignore error-code for ssh2 */ 93 ssh_remove_all_identities(ac, 2); 94 95 if (success) 96 fprintf(stderr, "All identities removed.\n"); 97 else 98 fprintf(stderr, "Failed to remove all identities.\n"); 99 } 100 101 void 102 add_file(AuthenticationConnection *ac, const char *filename) 103 { 104 struct stat st; 105 Key *private; 106 char *comment = NULL; 107 char msg[1024]; 108 109 if (stat(filename, &st) < 0) { 110 perror(filename); 111 exit(1); 112 } 113 /* At first, try empty passphrase */ 114 private = key_load_private(filename, "", &comment); 115 if (comment == NULL) 116 comment = xstrdup(filename); 117 /* try last */ 118 if (private == NULL && pass != NULL) 119 private = key_load_private(filename, pass, NULL); 120 if (private == NULL) { 121 /* clear passphrase since it did not work */ 122 clear_pass(); 123 printf("Need passphrase for %.200s\n", filename); 124 snprintf(msg, sizeof msg, "Enter passphrase for %.200s: ", 125 comment); 126 for (;;) { 127 pass = read_passphrase(msg, 1); 128 if (strcmp(pass, "") == 0) { 129 clear_pass(); 130 xfree(comment); 131 return; 132 } 133 private = key_load_private(filename, pass, &comment); 134 if (private != NULL) 135 break; 136 clear_pass(); 137 strlcpy(msg, "Bad passphrase, try again: ", sizeof msg); 138 } 139 } 140 if (ssh_add_identity(ac, private, comment)) 141 fprintf(stderr, "Identity added: %s (%s)\n", filename, comment); 142 else 143 fprintf(stderr, "Could not add identity: %s\n", filename); 144 xfree(comment); 145 key_free(private); 146 } 147 148 void 149 list_identities(AuthenticationConnection *ac, int do_fp) 150 { 151 Key *key; 152 char *comment, *fp; 153 int had_identities = 0; 154 int version; 155 156 for (version = 1; version <= 2; version++) { 157 for (key = ssh_get_first_identity(ac, &comment, version); 158 key != NULL; 159 key = ssh_get_next_identity(ac, &comment, version)) { 160 had_identities = 1; 161 if (do_fp) { 162 fp = key_fingerprint(key, SSH_FP_MD5, 163 SSH_FP_HEX); 164 printf("%d %s %s (%s)\n", 165 key_size(key), fp, comment, key_type(key)); 166 xfree(fp); 167 } else { 168 if (!key_write(key, stdout)) 169 fprintf(stderr, "key_write failed"); 170 fprintf(stdout, " %s\n", comment); 171 } 172 key_free(key); 173 xfree(comment); 174 } 175 } 176 if (!had_identities) 177 printf("The agent has no identities.\n"); 178 } 179 180 int 181 main(int argc, char **argv) 182 { 183 AuthenticationConnection *ac = NULL; 184 struct passwd *pw; 185 char buf[1024]; 186 int no_files = 1; 187 int i; 188 int deleting = 0; 189 190 SSLeay_add_all_algorithms(); 191 192 /* At first, get a connection to the authentication agent. */ 193 ac = ssh_get_authentication_connection(); 194 if (ac == NULL) { 195 fprintf(stderr, "Could not open a connection to your authentication agent.\n"); 196 exit(1); 197 } 198 for (i = 1; i < argc; i++) { 199 if ((strcmp(argv[i], "-l") == 0) || 200 (strcmp(argv[i], "-L") == 0)) { 201 list_identities(ac, argv[i][1] == 'l' ? 1 : 0); 202 /* Don't default-add/delete if -l. */ 203 no_files = 0; 204 continue; 205 } 206 if (strcmp(argv[i], "-d") == 0) { 207 deleting = 1; 208 continue; 209 } 210 if (strcmp(argv[i], "-D") == 0) { 211 delete_all(ac); 212 no_files = 0; 213 continue; 214 } 215 no_files = 0; 216 if (deleting) 217 delete_file(ac, argv[i]); 218 else 219 add_file(ac, argv[i]); 220 } 221 if (no_files) { 222 pw = getpwuid(getuid()); 223 if (!pw) { 224 fprintf(stderr, "No user found with uid %u\n", 225 (u_int)getuid()); 226 ssh_close_authentication_connection(ac); 227 exit(1); 228 } 229 snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, _PATH_SSH_CLIENT_IDENTITY); 230 if (deleting) 231 delete_file(ac, buf); 232 else 233 add_file(ac, buf); 234 } 235 clear_pass(); 236 ssh_close_authentication_connection(ac); 237 exit(0); 238 } 239