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 * Created: Thu Apr 6 00:52:24 1995 ylo 6 * Adds an identity to the authentication server, or removes an identity. 7 */ 8 9 #include "includes.h" 10 RCSID("$Id: ssh-add.c,v 1.15 1999/12/02 20:05:40 markus Exp $"); 11 12 #include "rsa.h" 13 #include "ssh.h" 14 #include "xmalloc.h" 15 #include "authfd.h" 16 #include "fingerprint.h" 17 18 void 19 delete_file(AuthenticationConnection *ac, const char *filename) 20 { 21 RSA *key; 22 char *comment; 23 24 key = RSA_new(); 25 if (!load_public_key(filename, key, &comment)) { 26 printf("Bad key file %s: %s\n", filename, strerror(errno)); 27 return; 28 } 29 if (ssh_remove_identity(ac, key)) 30 fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment); 31 else 32 fprintf(stderr, "Could not remove identity: %s\n", filename); 33 RSA_free(key); 34 xfree(comment); 35 } 36 37 void 38 delete_all(AuthenticationConnection *ac) 39 { 40 /* Send a request to remove all identities. */ 41 if (ssh_remove_all_identities(ac)) 42 fprintf(stderr, "All identities removed.\n"); 43 else 44 fprintf(stderr, "Failed to remove all identitities.\n"); 45 } 46 47 char * 48 ssh_askpass(char *askpass, char *msg) 49 { 50 pid_t pid; 51 size_t len; 52 char *nl, *pass; 53 int p[2], status; 54 char buf[1024]; 55 56 if (askpass == NULL) 57 fatal("internal error: askpass undefined"); 58 if (pipe(p) < 0) 59 fatal("ssh_askpass: pipe: %s", strerror(errno)); 60 if ((pid = fork()) < 0) 61 fatal("ssh_askpass: fork: %s", strerror(errno)); 62 if (pid == 0) { 63 close(p[0]); 64 if (dup2(p[1], STDOUT_FILENO) < 0) 65 fatal("ssh_askpass: dup2: %s", strerror(errno)); 66 execlp(askpass, askpass, msg, (char *) 0); 67 fatal("ssh_askpass: exec(%s): %s", askpass, strerror(errno)); 68 } 69 close(p[1]); 70 len = read(p[0], buf, sizeof buf); 71 close(p[0]); 72 while (waitpid(pid, &status, 0) < 0) 73 if (errno != EINTR) 74 break; 75 if (len <= 1) 76 return xstrdup(""); 77 nl = strchr(buf, '\n'); 78 if (nl) 79 *nl = '\0'; 80 pass = xstrdup(buf); 81 memset(buf, 0, sizeof(buf)); 82 return pass; 83 } 84 85 void 86 add_file(AuthenticationConnection *ac, const char *filename) 87 { 88 RSA *key; 89 RSA *public_key; 90 char *saved_comment, *comment, *askpass = NULL; 91 char buf[1024], msg[1024]; 92 int success; 93 int interactive = isatty(STDIN_FILENO); 94 95 key = RSA_new(); 96 public_key = RSA_new(); 97 if (!load_public_key(filename, public_key, &saved_comment)) { 98 printf("Bad key file %s: %s\n", filename, strerror(errno)); 99 return; 100 } 101 RSA_free(public_key); 102 103 if (!interactive && getenv("DISPLAY")) { 104 if (getenv(SSH_ASKPASS_ENV)) 105 askpass = getenv(SSH_ASKPASS_ENV); 106 else 107 askpass = SSH_ASKPASS_DEFAULT; 108 } 109 110 /* At first, try empty passphrase */ 111 success = load_private_key(filename, "", key, &comment); 112 if (!success) { 113 printf("Need passphrase for %.200s\n", filename); 114 if (!interactive && askpass == NULL) { 115 xfree(saved_comment); 116 return; 117 } 118 snprintf(msg, sizeof msg, "Enter passphrase for %.200s", saved_comment); 119 for (;;) { 120 char *pass; 121 if (interactive) { 122 snprintf(buf, sizeof buf, "%s: ", msg); 123 pass = read_passphrase(buf, 1); 124 } else { 125 pass = ssh_askpass(askpass, msg); 126 } 127 if (strcmp(pass, "") == 0) { 128 xfree(pass); 129 xfree(saved_comment); 130 return; 131 } 132 success = load_private_key(filename, pass, key, &comment); 133 memset(pass, 0, strlen(pass)); 134 xfree(pass); 135 if (success) 136 break; 137 strlcpy(msg, "Bad passphrase, try again", sizeof msg); 138 } 139 } 140 xfree(saved_comment); 141 142 if (ssh_add_identity(ac, key, comment)) 143 fprintf(stderr, "Identity added: %s (%s)\n", filename, comment); 144 else 145 fprintf(stderr, "Could not add identity: %s\n", filename); 146 RSA_free(key); 147 xfree(comment); 148 } 149 150 void 151 list_identities(AuthenticationConnection *ac, int fp) 152 { 153 BIGNUM *e, *n; 154 int status; 155 char *comment; 156 int had_identities; 157 158 e = BN_new(); 159 n = BN_new(); 160 had_identities = 0; 161 for (status = ssh_get_first_identity(ac, e, n, &comment); 162 status; 163 status = ssh_get_next_identity(ac, e, n, &comment)) { 164 unsigned int bits = BN_num_bits(n); 165 had_identities = 1; 166 if (fp) { 167 printf("%d %s %s\n", bits, fingerprint(e, n), comment); 168 } else { 169 char *ebuf, *nbuf; 170 ebuf = BN_bn2dec(e); 171 if (ebuf == NULL) { 172 error("list_identities: BN_bn2dec(e) failed."); 173 } else { 174 nbuf = BN_bn2dec(n); 175 if (nbuf == NULL) { 176 error("list_identities: BN_bn2dec(n) failed."); 177 } else { 178 printf("%d %s %s %s\n", bits, ebuf, nbuf, comment); 179 free(nbuf); 180 } 181 free(ebuf); 182 } 183 } 184 xfree(comment); 185 } 186 BN_clear_free(e); 187 BN_clear_free(n); 188 if (!had_identities) 189 printf("The agent has no identities.\n"); 190 } 191 192 int 193 main(int argc, char **argv) 194 { 195 AuthenticationConnection *ac = NULL; 196 struct passwd *pw; 197 char buf[1024]; 198 int no_files = 1; 199 int i; 200 int deleting = 0; 201 202 /* check if RSA support exists */ 203 if (rsa_alive() == 0) { 204 extern char *__progname; 205 206 fprintf(stderr, 207 "%s: no RSA support in libssl and libcrypto. See ssl(8).\n", 208 __progname); 209 exit(1); 210 } 211 /* At first, get a connection to the authentication agent. */ 212 ac = ssh_get_authentication_connection(); 213 if (ac == NULL) { 214 fprintf(stderr, "Could not open a connection to your authentication agent.\n"); 215 exit(1); 216 } 217 for (i = 1; i < argc; i++) { 218 if ((strcmp(argv[i], "-l") == 0) || 219 (strcmp(argv[i], "-L") == 0)) { 220 list_identities(ac, argv[i][1] == 'l' ? 1 : 0); 221 /* Don't default-add/delete if -l. */ 222 no_files = 0; 223 continue; 224 } 225 if (strcmp(argv[i], "-d") == 0) { 226 deleting = 1; 227 continue; 228 } 229 if (strcmp(argv[i], "-D") == 0) { 230 delete_all(ac); 231 no_files = 0; 232 continue; 233 } 234 no_files = 0; 235 if (deleting) 236 delete_file(ac, argv[i]); 237 else 238 add_file(ac, argv[i]); 239 } 240 if (no_files) { 241 pw = getpwuid(getuid()); 242 if (!pw) { 243 fprintf(stderr, "No user found with uid %d\n", (int) getuid()); 244 ssh_close_authentication_connection(ac); 245 exit(1); 246 } 247 snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, SSH_CLIENT_IDENTITY); 248 if (deleting) 249 delete_file(ac, buf); 250 else 251 add_file(ac, buf); 252 } 253 ssh_close_authentication_connection(ac); 254 exit(0); 255 } 256