summaryrefslogtreecommitdiff
path: root/ssh-agent.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>1999-11-25 00:26:21 +1100
committerDamien Miller <djm@mindrot.org>1999-11-25 00:26:21 +1100
commit95def09838fc61b37b6ea7cd5c234a465b4b129b (patch)
tree042744f76f40a326b873cb1c3690a6d7d966bc3e /ssh-agent.c
parent4d2f15f895f4c795afc008aeff3fd2ceffbc44f4 (diff)
- Merged very large OpenBSD source code reformat
- OpenBSD CVS updates - [channels.c cipher.c compat.c log-client.c scp.c serverloop.c] [ssh.h sshd.8 sshd.c] syslog changes: * Unified Logmessage for all auth-types, for success and for failed * Standard connections get only ONE line in the LOG when level==LOG: Auth-attempts are logged only, if authentication is: a) successfull or b) with passwd or c) we had more than AUTH_FAIL_LOG failues * many log() became verbose() * old behaviour with level=VERBOSE - [readconf.c readconf.h ssh.1 ssh.h sshconnect.c sshd.c] tranfer s/key challenge/response data in SSH_SMSG_AUTH_TIS_CHALLENGE messages. allows use of s/key in windows (ttssh, securecrt) and ssh-1.2.27 clients without 'ssh -v', ok: niels@ - [sshd.8] -V, for fallback to openssh in SSH2 compatibility mode - [sshd.c] fix sigchld race; cjc5@po.cwru.edu
Diffstat (limited to 'ssh-agent.c')
-rw-r--r--ssh-agent.c1124
1 files changed, 536 insertions, 588 deletions
diff --git a/ssh-agent.c b/ssh-agent.c
index f1ceb5692..70c2a7f65 100644
--- a/ssh-agent.c
+++ b/ssh-agent.c
@@ -1,22 +1,15 @@
1/* $OpenBSD: ssh-agent.c,v 1.20 1999/11/19 10:20:51 markus Exp $ */ 1/* $OpenBSD: ssh-agent.c,v 1.22 1999/11/24 00:26:03 deraadt Exp $ */
2 2
3/* 3/*
4 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
5ssh-agent.c 5 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
6 6 * All rights reserved
7Author: Tatu Ylonen <ylo@cs.hut.fi> 7 * Created: Wed Mar 29 03:46:59 1995 ylo
8 8 * The authentication agent program.
9Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 9 */
10 All rights reserved
11
12Created: Wed Mar 29 03:46:59 1995 ylo
13
14The authentication agent program.
15
16*/
17 10
18#include "includes.h" 11#include "includes.h"
19RCSID("$OpenBSD: ssh-agent.c,v 1.20 1999/11/19 10:20:51 markus Exp $"); 12RCSID("$OpenBSD: ssh-agent.c,v 1.22 1999/11/24 00:26:03 deraadt Exp $");
20 13
21#include "ssh.h" 14#include "ssh.h"
22#include "rsa.h" 15#include "rsa.h"
@@ -35,27 +28,21 @@ RCSID("$OpenBSD: ssh-agent.c,v 1.20 1999/11/19 10:20:51 markus Exp $");
35#include <ssl/md5.h> 28#include <ssl/md5.h>
36#endif 29#endif
37 30
38#ifdef HAVE___PROGNAME 31typedef struct {
39extern char *__progname; 32 int fd;
40#else /* HAVE___PROGNAME */ 33 enum {
41const char *__progname = "ssh-agent"; 34 AUTH_UNUSED, AUTH_SOCKET, AUTH_CONNECTION
42#endif /* HAVE___PROGNAME */ 35 } type;
43 36 Buffer input;
44typedef struct 37 Buffer output;
45{
46 int fd;
47 enum { AUTH_UNUSED, AUTH_SOCKET, AUTH_CONNECTION } type;
48 Buffer input;
49 Buffer output;
50} SocketEntry; 38} SocketEntry;
51 39
52unsigned int sockets_alloc = 0; 40unsigned int sockets_alloc = 0;
53SocketEntry *sockets = NULL; 41SocketEntry *sockets = NULL;
54 42
55typedef struct 43typedef struct {
56{ 44 RSA *key;
57 RSA *key; 45 char *comment;
58 char *comment;
59} Identity; 46} Identity;
60 47
61unsigned int num_identities = 0; 48unsigned int num_identities = 0;
@@ -70,640 +57,601 @@ int parent_pid = -1;
70char socket_name[1024]; 57char socket_name[1024];
71char socket_dir[1024]; 58char socket_dir[1024];
72 59
60#ifdef HAVE___PROGNAME
61extern char *__progname;
62#else /* HAVE___PROGNAME */
63const char *__progname = "ssh-agent";
64#endif /* HAVE___PROGNAME */
65
73void 66void
74process_request_identity(SocketEntry *e) 67process_request_identity(SocketEntry *e)
75{ 68{
76 Buffer msg; 69 Buffer msg;
77 int i; 70 int i;
78 71
79 buffer_init(&msg); 72 buffer_init(&msg);
80 buffer_put_char(&msg, SSH_AGENT_RSA_IDENTITIES_ANSWER); 73 buffer_put_char(&msg, SSH_AGENT_RSA_IDENTITIES_ANSWER);
81 buffer_put_int(&msg, num_identities); 74 buffer_put_int(&msg, num_identities);
82 for (i = 0; i < num_identities; i++) 75 for (i = 0; i < num_identities; i++) {
83 { 76 buffer_put_int(&msg, BN_num_bits(identities[i].key->n));
84 buffer_put_int(&msg, BN_num_bits(identities[i].key->n)); 77 buffer_put_bignum(&msg, identities[i].key->e);
85 buffer_put_bignum(&msg, identities[i].key->e); 78 buffer_put_bignum(&msg, identities[i].key->n);
86 buffer_put_bignum(&msg, identities[i].key->n); 79 buffer_put_string(&msg, identities[i].comment,
87 buffer_put_string(&msg, identities[i].comment, 80 strlen(identities[i].comment));
88 strlen(identities[i].comment)); 81 }
89 } 82 buffer_put_int(&e->output, buffer_len(&msg));
90 buffer_put_int(&e->output, buffer_len(&msg)); 83 buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
91 buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg)); 84 buffer_free(&msg);
92 buffer_free(&msg);
93} 85}
94 86
95void 87void
96process_authentication_challenge(SocketEntry *e) 88process_authentication_challenge(SocketEntry *e)
97{ 89{
98 int i, pub_bits, len; 90 int i, pub_bits, len;
99 BIGNUM *pub_e, *pub_n, *challenge; 91 BIGNUM *pub_e, *pub_n, *challenge;
100 Buffer msg; 92 Buffer msg;
101 MD5_CTX md; 93 MD5_CTX md;
102 unsigned char buf[32], mdbuf[16], session_id[16]; 94 unsigned char buf[32], mdbuf[16], session_id[16];
103 unsigned int response_type; 95 unsigned int response_type;
104 96
105 buffer_init(&msg); 97 buffer_init(&msg);
106 pub_e = BN_new(); 98 pub_e = BN_new();
107 pub_n = BN_new(); 99 pub_n = BN_new();
108 challenge = BN_new(); 100 challenge = BN_new();
109 pub_bits = buffer_get_int(&e->input); 101 pub_bits = buffer_get_int(&e->input);
110 buffer_get_bignum(&e->input, pub_e); 102 buffer_get_bignum(&e->input, pub_e);
111 buffer_get_bignum(&e->input, pub_n); 103 buffer_get_bignum(&e->input, pub_n);
112 buffer_get_bignum(&e->input, challenge); 104 buffer_get_bignum(&e->input, challenge);
113 if (buffer_len(&e->input) == 0) 105 if (buffer_len(&e->input) == 0) {
114 { 106 /* Compatibility code for old servers. */
115 /* Compatibility code for old servers. */ 107 memset(session_id, 0, 16);
116 memset(session_id, 0, 16); 108 response_type = 0;
117 response_type = 0; 109 } else {
118 } 110 /* New code. */
119 else 111 buffer_get(&e->input, (char *) session_id, 16);
120 { 112 response_type = buffer_get_int(&e->input);
121 /* New code. */ 113 }
122 buffer_get(&e->input, (char *)session_id, 16); 114 for (i = 0; i < num_identities; i++)
123 response_type = buffer_get_int(&e->input); 115 if (pub_bits == BN_num_bits(identities[i].key->n) &&
124 } 116 BN_cmp(pub_e, identities[i].key->e) == 0 &&
125 for (i = 0; i < num_identities; i++) 117 BN_cmp(pub_n, identities[i].key->n) == 0) {
126 if (pub_bits == BN_num_bits(identities[i].key->n) && 118 /* Decrypt the challenge using the private key. */
127 BN_cmp(pub_e, identities[i].key->e) == 0 && 119 rsa_private_decrypt(challenge, challenge, identities[i].key);
128 BN_cmp(pub_n, identities[i].key->n) == 0) 120
129 { 121 /* Compute the desired response. */
130 /* Decrypt the challenge using the private key. */ 122 switch (response_type) {
131 rsa_private_decrypt(challenge, challenge, identities[i].key); 123 case 0:/* As of protocol 1.0 */
132 124 /* This response type is no longer supported. */
133 /* Compute the desired response. */ 125 log("Compatibility with ssh protocol 1.0 no longer supported.");
134 switch (response_type) 126 buffer_put_char(&msg, SSH_AGENT_FAILURE);
135 { 127 goto send;
136 case 0: /* As of protocol 1.0 */ 128
137 /* This response type is no longer supported. */ 129 case 1:/* As of protocol 1.1 */
138 log("Compatibility with ssh protocol 1.0 no longer supported."); 130 /* The response is MD5 of decrypted challenge plus session id. */
139 buffer_put_char(&msg, SSH_AGENT_FAILURE); 131 len = BN_num_bytes(challenge);
140 goto send; 132
141 133 if (len <= 0 || len > 32) {
142 case 1: /* As of protocol 1.1 */ 134 fatal("process_authentication_challenge: "
143 /* The response is MD5 of decrypted challenge plus session id. */ 135 "bad challenge length %d", len);
144 len = BN_num_bytes(challenge); 136 }
145 137 memset(buf, 0, 32);
146 if (len <= 0 || len > 32) { 138 BN_bn2bin(challenge, buf + 32 - len);
147 fatal("process_authentication_challenge: " 139 MD5_Init(&md);
148 "bad challenge length %d", len); 140 MD5_Update(&md, buf, 32);
149 } 141 MD5_Update(&md, session_id, 16);
150 142 MD5_Final(mdbuf, &md);
151 memset(buf, 0, 32); 143 break;
152 BN_bn2bin(challenge, buf + 32 - len); 144
153 MD5_Init(&md); 145 default:
154 MD5_Update(&md, buf, 32); 146 fatal("process_authentication_challenge: bad response_type %d",
155 MD5_Update(&md, session_id, 16); 147 response_type);
156 MD5_Final(mdbuf, &md); 148 break;
157 break; 149 }
158 150
159 default: 151 /* Send the response. */
160 fatal("process_authentication_challenge: bad response_type %d", 152 buffer_put_char(&msg, SSH_AGENT_RSA_RESPONSE);
161 response_type); 153 for (i = 0; i < 16; i++)
162 break; 154 buffer_put_char(&msg, mdbuf[i]);
163 } 155
164 156 goto send;
165 /* Send the response. */ 157 }
166 buffer_put_char(&msg, SSH_AGENT_RSA_RESPONSE); 158 /* Unknown identity. Send failure. */
167 for (i = 0; i < 16; i++) 159 buffer_put_char(&msg, SSH_AGENT_FAILURE);
168 buffer_put_char(&msg, mdbuf[i]); 160send:
169 161 buffer_put_int(&e->output, buffer_len(&msg));
170 goto send; 162 buffer_append(&e->output, buffer_ptr(&msg),
171 } 163 buffer_len(&msg));
172 /* Unknown identity. Send failure. */ 164 buffer_free(&msg);
173 buffer_put_char(&msg, SSH_AGENT_FAILURE); 165 BN_clear_free(pub_e);
174 send: 166 BN_clear_free(pub_n);
175 buffer_put_int(&e->output, buffer_len(&msg)); 167 BN_clear_free(challenge);
176 buffer_append(&e->output, buffer_ptr(&msg),
177 buffer_len(&msg));
178 buffer_free(&msg);
179 BN_clear_free(pub_e);
180 BN_clear_free(pub_n);
181 BN_clear_free(challenge);
182} 168}
183 169
184void 170void
185process_remove_identity(SocketEntry *e) 171process_remove_identity(SocketEntry *e)
186{ 172{
187 unsigned int bits; 173 unsigned int bits;
188 unsigned int i; 174 unsigned int i;
189 BIGNUM *dummy, *n; 175 BIGNUM *dummy, *n;
190 176
191 dummy = BN_new(); 177 dummy = BN_new();
192 n = BN_new(); 178 n = BN_new();
193 179
194 /* Get the key from the packet. */ 180 /* Get the key from the packet. */
195 bits = buffer_get_int(&e->input); 181 bits = buffer_get_int(&e->input);
196 buffer_get_bignum(&e->input, dummy); 182 buffer_get_bignum(&e->input, dummy);
197 buffer_get_bignum(&e->input, n); 183 buffer_get_bignum(&e->input, n);
198 184
199 if (bits != BN_num_bits(n)) 185 if (bits != BN_num_bits(n))
200 error("Warning: keysize mismatch: actual %d, announced %d", 186 error("Warning: keysize mismatch: actual %d, announced %d",
201 BN_num_bits(n), bits); 187 BN_num_bits(n), bits);
202 188
203 /* Check if we have the key. */ 189 /* Check if we have the key. */
204 for (i = 0; i < num_identities; i++) 190 for (i = 0; i < num_identities; i++)
205 if (BN_cmp(identities[i].key->n, n) == 0) 191 if (BN_cmp(identities[i].key->n, n) == 0) {
206 { 192 /* We have this key. Free the old key. Since we
207 /* We have this key. Free the old key. Since we don\'t want to leave 193 don\'t want to leave empty slots in the middle
208 empty slots in the middle of the array, we actually free the 194 of the array, we actually free the key there
209 key there and copy data from the last entry. */ 195 and copy data from the last entry. */
210 RSA_free(identities[i].key); 196 RSA_free(identities[i].key);
211 xfree(identities[i].comment); 197 xfree(identities[i].comment);
212 if (i < num_identities - 1) 198 if (i < num_identities - 1)
213 identities[i] = identities[num_identities - 1]; 199 identities[i] = identities[num_identities - 1];
214 num_identities--; 200 num_identities--;
215 BN_clear_free(dummy); 201 BN_clear_free(dummy);
216 BN_clear_free(n); 202 BN_clear_free(n);
217 203
218 /* Send success. */ 204 /* Send success. */
205 buffer_put_int(&e->output, 1);
206 buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
207 return;
208 }
209 /* We did not have the key. */
210 BN_clear(dummy);
211 BN_clear(n);
212
213 /* Send failure. */
219 buffer_put_int(&e->output, 1); 214 buffer_put_int(&e->output, 1);
220 buffer_put_char(&e->output, SSH_AGENT_SUCCESS); 215 buffer_put_char(&e->output, SSH_AGENT_FAILURE);
221 return;
222 }
223 /* We did not have the key. */
224 BN_clear(dummy);
225 BN_clear(n);
226
227 /* Send failure. */
228 buffer_put_int(&e->output, 1);
229 buffer_put_char(&e->output, SSH_AGENT_FAILURE);
230} 216}
231 217
232/* Removes all identities from the agent. */ 218/*
233 219 * Removes all identities from the agent.
220 */
234void 221void
235process_remove_all_identities(SocketEntry *e) 222process_remove_all_identities(SocketEntry *e)
236{ 223{
237 unsigned int i; 224 unsigned int i;
238
239 /* Loop over all identities and clear the keys. */
240 for (i = 0; i < num_identities; i++)
241 {
242 RSA_free(identities[i].key);
243 xfree(identities[i].comment);
244 }
245
246 /* Mark that there are no identities. */
247 num_identities = 0;
248
249 /* Send success. */
250 buffer_put_int(&e->output, 1);
251 buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
252 return;
253}
254 225
255/* Adds an identity to the agent. */ 226 /* Loop over all identities and clear the keys. */
227 for (i = 0; i < num_identities; i++) {
228 RSA_free(identities[i].key);
229 xfree(identities[i].comment);
230 }
256 231
257void 232 /* Mark that there are no identities. */
258process_add_identity(SocketEntry *e) 233 num_identities = 0;
259{
260 RSA *k;
261 int i;
262 BIGNUM *aux;
263 BN_CTX *ctx;
264
265 if (num_identities == 0)
266 identities = xmalloc(sizeof(Identity));
267 else
268 identities = xrealloc(identities, (num_identities + 1) * sizeof(Identity));
269
270 identities[num_identities].key = RSA_new();
271 k = identities[num_identities].key;
272 buffer_get_int(&e->input); /* bits */
273 k->n = BN_new();
274 buffer_get_bignum(&e->input, k->n);
275 k->e = BN_new();
276 buffer_get_bignum(&e->input, k->e);
277 k->d = BN_new();
278 buffer_get_bignum(&e->input, k->d);
279 k->iqmp = BN_new();
280 buffer_get_bignum(&e->input, k->iqmp);
281 /* SSH and SSL have p and q swapped */
282 k->q = BN_new();
283 buffer_get_bignum(&e->input, k->q); /* p */
284 k->p = BN_new();
285 buffer_get_bignum(&e->input, k->p); /* q */
286
287 /* Generate additional parameters */
288 aux = BN_new();
289 ctx = BN_CTX_new();
290
291 BN_sub(aux, k->q, BN_value_one());
292 k->dmq1 = BN_new();
293 BN_mod(k->dmq1, k->d, aux, ctx);
294
295 BN_sub(aux, k->p, BN_value_one());
296 k->dmp1 = BN_new();
297 BN_mod(k->dmp1, k->d, aux, ctx);
298
299 BN_clear_free(aux);
300 BN_CTX_free(ctx);
301
302 identities[num_identities].comment = buffer_get_string(&e->input, NULL);
303
304 /* Check if we already have the key. */
305 for (i = 0; i < num_identities; i++)
306 if (BN_cmp(identities[i].key->n, k->n) == 0)
307 {
308 /* We already have this key. Clear and free the new data and
309 return success. */
310 RSA_free(k);
311 xfree(identities[num_identities].comment);
312 234
313 /* Send success. */ 235 /* Send success. */
314 buffer_put_int(&e->output, 1); 236 buffer_put_int(&e->output, 1);
315 buffer_put_char(&e->output, SSH_AGENT_SUCCESS); 237 buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
316 return; 238 return;
317 } 239}
318 240
319 /* Increment the number of identities. */ 241/*
320 num_identities++; 242 * Adds an identity to the agent.
321 243 */
322 /* Send a success message. */ 244void
323 buffer_put_int(&e->output, 1); 245process_add_identity(SocketEntry *e)
324 buffer_put_char(&e->output, SSH_AGENT_SUCCESS); 246{
247 RSA *k;
248 int i;
249 BIGNUM *aux;
250 BN_CTX *ctx;
251
252 if (num_identities == 0)
253 identities = xmalloc(sizeof(Identity));
254 else
255 identities = xrealloc(identities, (num_identities + 1) * sizeof(Identity));
256
257 identities[num_identities].key = RSA_new();
258 k = identities[num_identities].key;
259 buffer_get_int(&e->input); /* bits */
260 k->n = BN_new();
261 buffer_get_bignum(&e->input, k->n);
262 k->e = BN_new();
263 buffer_get_bignum(&e->input, k->e);
264 k->d = BN_new();
265 buffer_get_bignum(&e->input, k->d);
266 k->iqmp = BN_new();
267 buffer_get_bignum(&e->input, k->iqmp);
268 /* SSH and SSL have p and q swapped */
269 k->q = BN_new();
270 buffer_get_bignum(&e->input, k->q); /* p */
271 k->p = BN_new();
272 buffer_get_bignum(&e->input, k->p); /* q */
273
274 /* Generate additional parameters */
275 aux = BN_new();
276 ctx = BN_CTX_new();
277
278 BN_sub(aux, k->q, BN_value_one());
279 k->dmq1 = BN_new();
280 BN_mod(k->dmq1, k->d, aux, ctx);
281
282 BN_sub(aux, k->p, BN_value_one());
283 k->dmp1 = BN_new();
284 BN_mod(k->dmp1, k->d, aux, ctx);
285
286 BN_clear_free(aux);
287 BN_CTX_free(ctx);
288
289 identities[num_identities].comment = buffer_get_string(&e->input, NULL);
290
291 /* Check if we already have the key. */
292 for (i = 0; i < num_identities; i++)
293 if (BN_cmp(identities[i].key->n, k->n) == 0) {
294 /* We already have this key. Clear and free the
295 new data and return success. */
296 RSA_free(k);
297 xfree(identities[num_identities].comment);
298
299 /* Send success. */
300 buffer_put_int(&e->output, 1);
301 buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
302 return;
303 }
304 /* Increment the number of identities. */
305 num_identities++;
306
307 /* Send a success message. */
308 buffer_put_int(&e->output, 1);
309 buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
325} 310}
326 311
327void 312void
328process_message(SocketEntry *e) 313process_message(SocketEntry *e)
329{ 314{
330 unsigned int msg_len; 315 unsigned int msg_len;
331 unsigned int type; 316 unsigned int type;
332 unsigned char *cp; 317 unsigned char *cp;
333 if (buffer_len(&e->input) < 5) 318 if (buffer_len(&e->input) < 5)
334 return; /* Incomplete message. */ 319 return; /* Incomplete message. */
335 cp = (unsigned char *)buffer_ptr(&e->input); 320 cp = (unsigned char *) buffer_ptr(&e->input);
336 msg_len = GET_32BIT(cp); 321 msg_len = GET_32BIT(cp);
337 if (msg_len > 256 * 1024) 322 if (msg_len > 256 * 1024) {
338 { 323 shutdown(e->fd, SHUT_RDWR);
339 shutdown(e->fd, SHUT_RDWR); 324 close(e->fd);
340 close(e->fd); 325 e->type = AUTH_UNUSED;
341 e->type = AUTH_UNUSED; 326 return;
342 return; 327 }
343 } 328 if (buffer_len(&e->input) < msg_len + 4)
344 if (buffer_len(&e->input) < msg_len + 4) 329 return;
345 return; 330 buffer_consume(&e->input, 4);
346 buffer_consume(&e->input, 4); 331 type = buffer_get_char(&e->input);
347 type = buffer_get_char(&e->input); 332
348 333 switch (type) {
349 switch (type) 334 case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
350 { 335 process_request_identity(e);
351 case SSH_AGENTC_REQUEST_RSA_IDENTITIES: 336 break;
352 process_request_identity(e); 337 case SSH_AGENTC_RSA_CHALLENGE:
353 break; 338 process_authentication_challenge(e);
354 case SSH_AGENTC_RSA_CHALLENGE: 339 break;
355 process_authentication_challenge(e); 340 case SSH_AGENTC_ADD_RSA_IDENTITY:
356 break; 341 process_add_identity(e);
357 case SSH_AGENTC_ADD_RSA_IDENTITY: 342 break;
358 process_add_identity(e); 343 case SSH_AGENTC_REMOVE_RSA_IDENTITY:
359 break; 344 process_remove_identity(e);
360 case SSH_AGENTC_REMOVE_RSA_IDENTITY: 345 break;
361 process_remove_identity(e); 346 case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
362 break; 347 process_remove_all_identities(e);
363 case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES: 348 break;
364 process_remove_all_identities(e); 349 default:
365 break; 350 /* Unknown message. Respond with failure. */
366 default: 351 error("Unknown message %d", type);
367 /* Unknown message. Respond with failure. */ 352 buffer_clear(&e->input);
368 error("Unknown message %d", type); 353 buffer_put_int(&e->output, 1);
369 buffer_clear(&e->input); 354 buffer_put_char(&e->output, SSH_AGENT_FAILURE);
370 buffer_put_int(&e->output, 1); 355 break;
371 buffer_put_char(&e->output, SSH_AGENT_FAILURE); 356 }
372 break;
373 }
374} 357}
375 358
376void 359void
377new_socket(int type, int fd) 360new_socket(int type, int fd)
378{ 361{
379 unsigned int i, old_alloc; 362 unsigned int i, old_alloc;
380 if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) 363 if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
381 error("fcntl O_NONBLOCK: %s", strerror(errno)); 364 error("fcntl O_NONBLOCK: %s", strerror(errno));
382 365
383 if (fd > max_fd) 366 if (fd > max_fd)
384 max_fd = fd; 367 max_fd = fd;
385 368
386 for (i = 0; i < sockets_alloc; i++) 369 for (i = 0; i < sockets_alloc; i++)
387 if (sockets[i].type == AUTH_UNUSED) 370 if (sockets[i].type == AUTH_UNUSED) {
388 { 371 sockets[i].fd = fd;
389 sockets[i].fd = fd; 372 sockets[i].type = type;
390 sockets[i].type = type; 373 buffer_init(&sockets[i].input);
391 buffer_init(&sockets[i].input); 374 buffer_init(&sockets[i].output);
392 buffer_init(&sockets[i].output); 375 return;
393 return; 376 }
394 } 377 old_alloc = sockets_alloc;
395 old_alloc = sockets_alloc; 378 sockets_alloc += 10;
396 sockets_alloc += 10; 379 if (sockets)
397 if (sockets) 380 sockets = xrealloc(sockets, sockets_alloc * sizeof(sockets[0]));
398 sockets = xrealloc(sockets, sockets_alloc * sizeof(sockets[0])); 381 else
399 else 382 sockets = xmalloc(sockets_alloc * sizeof(sockets[0]));
400 sockets = xmalloc(sockets_alloc * sizeof(sockets[0])); 383 for (i = old_alloc; i < sockets_alloc; i++)
401 for (i = old_alloc; i < sockets_alloc; i++) 384 sockets[i].type = AUTH_UNUSED;
402 sockets[i].type = AUTH_UNUSED; 385 sockets[old_alloc].type = type;
403 sockets[old_alloc].type = type; 386 sockets[old_alloc].fd = fd;
404 sockets[old_alloc].fd = fd; 387 buffer_init(&sockets[old_alloc].input);
405 buffer_init(&sockets[old_alloc].input); 388 buffer_init(&sockets[old_alloc].output);
406 buffer_init(&sockets[old_alloc].output);
407} 389}
408 390
409void 391void
410prepare_select(fd_set *readset, fd_set *writeset) 392prepare_select(fd_set *readset, fd_set *writeset)
411{ 393{
412 unsigned int i; 394 unsigned int i;
413 for (i = 0; i < sockets_alloc; i++) 395 for (i = 0; i < sockets_alloc; i++)
414 switch (sockets[i].type) 396 switch (sockets[i].type) {
415 { 397 case AUTH_SOCKET:
416 case AUTH_SOCKET: 398 case AUTH_CONNECTION:
417 case AUTH_CONNECTION: 399 FD_SET(sockets[i].fd, readset);
418 FD_SET(sockets[i].fd, readset); 400 if (buffer_len(&sockets[i].output) > 0)
419 if (buffer_len(&sockets[i].output) > 0) 401 FD_SET(sockets[i].fd, writeset);
420 FD_SET(sockets[i].fd, writeset); 402 break;
421 break; 403 case AUTH_UNUSED:
422 case AUTH_UNUSED: 404 break;
423 break; 405 default:
424 default: 406 fatal("Unknown socket type %d", sockets[i].type);
425 fatal("Unknown socket type %d", sockets[i].type); 407 break;
426 break; 408 }
427 }
428} 409}
429 410
430void after_select(fd_set *readset, fd_set *writeset) 411void
412after_select(fd_set *readset, fd_set *writeset)
431{ 413{
432 unsigned int i; 414 unsigned int i;
433 int len, sock; 415 int len, sock;
434 char buf[1024]; 416 char buf[1024];
435 struct sockaddr_un sunaddr; 417 struct sockaddr_un sunaddr;
436 418
437 for (i = 0; i < sockets_alloc; i++) 419 for (i = 0; i < sockets_alloc; i++)
438 switch (sockets[i].type) 420 switch (sockets[i].type) {
439 { 421 case AUTH_UNUSED:
440 case AUTH_UNUSED: 422 break;
441 break; 423 case AUTH_SOCKET:
442 case AUTH_SOCKET: 424 if (FD_ISSET(sockets[i].fd, readset)) {
443 if (FD_ISSET(sockets[i].fd, readset)) 425 len = sizeof(sunaddr);
444 { 426 sock = accept(sockets[i].fd, (struct sockaddr *) & sunaddr, &len);
445 len = sizeof(sunaddr); 427 if (sock < 0) {
446 sock = accept(sockets[i].fd, (struct sockaddr *)&sunaddr, &len); 428 perror("accept from AUTH_SOCKET");
447 if (sock < 0) 429 break;
448 { 430 }
449 perror("accept from AUTH_SOCKET"); 431 new_socket(AUTH_CONNECTION, sock);
450 break; 432 }
451 } 433 break;
452 new_socket(AUTH_CONNECTION, sock); 434 case AUTH_CONNECTION:
453 } 435 if (buffer_len(&sockets[i].output) > 0 &&
454 break; 436 FD_ISSET(sockets[i].fd, writeset)) {
455 case AUTH_CONNECTION: 437 len = write(sockets[i].fd, buffer_ptr(&sockets[i].output),
456 if (buffer_len(&sockets[i].output) > 0 && 438 buffer_len(&sockets[i].output));
457 FD_ISSET(sockets[i].fd, writeset)) 439 if (len <= 0) {
458 { 440 shutdown(sockets[i].fd, SHUT_RDWR);
459 len = write(sockets[i].fd, buffer_ptr(&sockets[i].output), 441 close(sockets[i].fd);
460 buffer_len(&sockets[i].output)); 442 sockets[i].type = AUTH_UNUSED;
461 if (len <= 0) 443 break;
462 { 444 }
463 shutdown(sockets[i].fd, SHUT_RDWR); 445 buffer_consume(&sockets[i].output, len);
464 close(sockets[i].fd); 446 }
465 sockets[i].type = AUTH_UNUSED; 447 if (FD_ISSET(sockets[i].fd, readset)) {
466 break; 448 len = read(sockets[i].fd, buf, sizeof(buf));
467 } 449 if (len <= 0) {
468 buffer_consume(&sockets[i].output, len); 450 shutdown(sockets[i].fd, SHUT_RDWR);
469 } 451 close(sockets[i].fd);
470 if (FD_ISSET(sockets[i].fd, readset)) 452 sockets[i].type = AUTH_UNUSED;
471 { 453 break;
472 len = read(sockets[i].fd, buf, sizeof(buf)); 454 }
473 if (len <= 0) 455 buffer_append(&sockets[i].input, buf, len);
474 { 456 process_message(&sockets[i]);
475 shutdown(sockets[i].fd, SHUT_RDWR); 457 }
476 close(sockets[i].fd); 458 break;
477 sockets[i].type = AUTH_UNUSED; 459 default:
478 break; 460 fatal("Unknown type %d", sockets[i].type);
479 } 461 }
480 buffer_append(&sockets[i].input, buf, len);
481 process_message(&sockets[i]);
482 }
483 break;
484 default:
485 fatal("Unknown type %d", sockets[i].type);
486 }
487} 462}
488 463
489void 464void
490check_parent_exists(int sig) 465check_parent_exists(int sig)
491{ 466{
492 if (kill(parent_pid, 0) < 0) 467 if (kill(parent_pid, 0) < 0) {
493 { 468 /* printf("Parent has died - Authentication agent exiting.\n"); */
494 /* printf("Parent has died - Authentication agent exiting.\n"); */ 469 exit(1);
495 exit(1); 470 }
496 } 471 signal(SIGALRM, check_parent_exists);
497 signal(SIGALRM, check_parent_exists); 472 alarm(10);
498 alarm(10);
499} 473}
500 474
501void 475void
502cleanup_socket(void) 476cleanup_socket(void)
503{ 477{
504 remove(socket_name); 478 remove(socket_name);
505 rmdir(socket_dir); 479 rmdir(socket_dir);
506} 480}
507 481
508void 482void
509cleanup_exit(int i) 483cleanup_exit(int i)
510{ 484{
511 cleanup_socket(); 485 cleanup_socket();
512 exit(i); 486 exit(i);
513} 487}
514 488
515void 489void
516usage() 490usage()
517{ 491{
518 fprintf(stderr, "ssh-agent version %s\n", SSH_VERSION); 492 fprintf(stderr, "ssh-agent version %s\n", SSH_VERSION);
519 fprintf(stderr, "Usage: %s [-c | -s] [-k] [command {args...]]\n", 493 fprintf(stderr, "Usage: %s [-c | -s] [-k] [command {args...]]\n",
520 __progname); 494 __progname);
521 exit(1); 495 exit(1);
522} 496}
523 497
524int 498int
525main(int ac, char **av) 499main(int ac, char **av)
526{ 500{
527 fd_set readset, writeset; 501 fd_set readset, writeset;
528 int sock, c_flag = 0, k_flag = 0, s_flag = 0, ch; 502 int sock, c_flag = 0, k_flag = 0, s_flag = 0, ch;
529 struct sockaddr_un sunaddr; 503 struct sockaddr_un sunaddr;
530 pid_t pid; 504 pid_t pid;
531 char *shell, *format, *pidstr, pidstrbuf[1 + 3 * sizeof pid]; 505 char *shell, *format, *pidstr, pidstrbuf[1 + 3 * sizeof pid];
532 506
533 /* check if RSA support exists */ 507 /* check if RSA support exists */
534 if (rsa_alive() == 0) { 508 if (rsa_alive() == 0) {
535 fprintf(stderr, 509 fprintf(stderr,
536 "%s: no RSA support in libssl and libcrypto. See ssl(8).\n", 510 "%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
537 __progname); 511 __progname);
538 exit(1); 512 exit(1);
539 } 513 }
540
541#if defined(__GNU_LIBRARY__) 514#if defined(__GNU_LIBRARY__)
542 while ((ch = getopt(ac, av, "+cks")) != -1) 515 while ((ch = getopt(ac, av, "+cks")) != -1) {
543#else 516#else
544 while ((ch = getopt(ac, av, "cks")) != -1) 517 while ((ch = getopt(ac, av, "cks")) != -1) {
545#endif /* defined(__GNU_LIBRARY__) */ 518#endif /* defined(__GNU_LIBRARY__) */
546 { 519 switch (ch) {
547 switch (ch) 520 case 'c':
548 { 521 if (s_flag)
549 case 'c': 522 usage();
550 if (s_flag) 523 c_flag++;
551 usage(); 524 break;
552 c_flag++; 525 case 'k':
553 break; 526 k_flag++;
554 case 'k': 527 break;
555 k_flag++; 528 case 's':
556 break; 529 if (c_flag)
557 case 's': 530 usage();
558 if (c_flag) 531 s_flag++;
559 usage(); 532 break;
560 s_flag++; 533 default:
561 break; 534 usage();
562 default: 535 }
563 usage();
564 } 536 }
565 } 537 ac -= optind;
566 ac -= optind; 538 av += optind;
567 av += optind; 539
568 540 if (ac > 0 && (c_flag || k_flag || s_flag))
569 if (ac > 0 && (c_flag || k_flag || s_flag)) 541 usage();
570 usage(); 542
571 543 if (ac == 0 && !c_flag && !k_flag && !s_flag) {
572 if (ac == 0 && !c_flag && !k_flag && !s_flag) 544 shell = getenv("SHELL");
573 { 545 if (shell != NULL && strncmp(shell + strlen(shell) - 3, "csh", 3) == 0)
574 shell = getenv("SHELL"); 546 c_flag = 1;
575 if (shell != NULL && strncmp(shell + strlen(shell) - 3, "csh", 3) == 0)
576 c_flag = 1;
577 }
578
579 if (k_flag)
580 {
581 pidstr = getenv(SSH_AGENTPID_ENV_NAME);
582 if (pidstr == NULL)
583 {
584 fprintf(stderr, "%s not set, cannot kill agent\n",
585 SSH_AGENTPID_ENV_NAME);
586 exit(1);
587 } 547 }
588 pid = atoi(pidstr); 548 if (k_flag) {
589 if (pid < 1) /* XXX PID_MAX check too */ 549 pidstr = getenv(SSH_AGENTPID_ENV_NAME);
590 { 550 if (pidstr == NULL) {
591 fprintf(stderr, "%s=\"%s\", which is not a good PID\n", 551 fprintf(stderr, "%s not set, cannot kill agent\n",
592 SSH_AGENTPID_ENV_NAME, pidstr); 552 SSH_AGENTPID_ENV_NAME);
593 exit(1); 553 exit(1);
554 }
555 pid = atoi(pidstr);
556 if (pid < 1) { /* XXX PID_MAX check too */
557 fprintf(stderr, "%s=\"%s\", which is not a good PID\n",
558 SSH_AGENTPID_ENV_NAME, pidstr);
559 exit(1);
560 }
561 if (kill(pid, SIGTERM) == -1) {
562 perror("kill");
563 exit(1);
564 }
565 format = c_flag ? "unsetenv %s;\n" : "unset %s;\n";
566 printf(format, SSH_AUTHSOCKET_ENV_NAME);
567 printf(format, SSH_AGENTPID_ENV_NAME);
568 printf("echo Agent pid %d killed;\n", pid);
569 exit(0);
594 } 570 }
595 if (kill(pid, SIGTERM) == -1) 571 parent_pid = getpid();
596 { 572
597 perror("kill"); 573 /* Create private directory for agent socket */
598 exit(1); 574 strlcpy(socket_dir, "/tmp/ssh-XXXXXXXX", sizeof socket_dir);
575 if (mkdtemp(socket_dir) == NULL) {
576 perror("mkdtemp: private socket dir");
577 exit(1);
578 }
579 snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir,
580 parent_pid);
581
582 /* Create socket early so it will exist before command gets run
583 from the parent. */
584 sock = socket(AF_UNIX, SOCK_STREAM, 0);
585 if (sock < 0) {
586 perror("socket");
587 cleanup_exit(1);
588 }
589 memset(&sunaddr, 0, sizeof(sunaddr));
590 sunaddr.sun_family = AF_UNIX;
591 strlcpy(sunaddr.sun_path, socket_name, sizeof(sunaddr.sun_path));
592 if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) {
593 perror("bind");
594 cleanup_exit(1);
595 }
596 if (listen(sock, 5) < 0) {
597 perror("listen");
598 cleanup_exit(1);
599 } 599 }
600 format = c_flag ? "unsetenv %s;\n" : "unset %s;\n"; 600 /* Fork, and have the parent execute the command, if any, or
601 printf(format, SSH_AUTHSOCKET_ENV_NAME); 601 present the socket data. The child continues as the
602 printf(format, SSH_AGENTPID_ENV_NAME); 602 authentication agent. */
603 printf("echo Agent pid %d killed;\n", pid); 603 pid = fork();
604 exit(0); 604 if (pid == -1) {
605 } 605 perror("fork");
606 606 exit(1);
607 parent_pid = getpid();
608
609 /* Create private directory for agent socket */
610 strlcpy(socket_dir, "/tmp/ssh-XXXXXXXX", sizeof socket_dir);
611 if (mkdtemp(socket_dir) == NULL) {
612 perror("mkdtemp: private socket dir");
613 exit(1);
614 }
615 snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir,
616 parent_pid);
617
618 /* Create socket early so it will exist before command gets run from
619 the parent. */
620 sock = socket(AF_UNIX, SOCK_STREAM, 0);
621 if (sock < 0)
622 {
623 perror("socket");
624 cleanup_exit(1);
625 }
626 memset(&sunaddr, 0, sizeof(sunaddr));
627 sunaddr.sun_family = AF_UNIX;
628 strlcpy(sunaddr.sun_path, socket_name, sizeof(sunaddr.sun_path));
629 if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0)
630 {
631 perror("bind");
632 cleanup_exit(1);
633 }
634 if (listen(sock, 5) < 0)
635 {
636 perror("listen");
637 cleanup_exit(1);
638 }
639
640 /* Fork, and have the parent execute the command, if any, or present the
641 socket data. The child continues as the authentication agent. */
642 pid = fork();
643 if (pid == -1)
644 {
645 perror("fork");
646 exit(1);
647 }
648 if (pid != 0)
649 { /* Parent - execute the given command. */
650 close(sock);
651 snprintf(pidstrbuf, sizeof pidstrbuf, "%d", pid);
652 if (ac == 0)
653 {
654 format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
655 printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
656 SSH_AUTHSOCKET_ENV_NAME);
657 printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf,
658 SSH_AGENTPID_ENV_NAME);
659 printf("echo Agent pid %d;\n", pid);
660 exit(0);
661 } 607 }
608 if (pid != 0) { /* Parent - execute the given command. */
609 close(sock);
610 snprintf(pidstrbuf, sizeof pidstrbuf, "%d", pid);
611 if (ac == 0) {
612 format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
613 printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
614 SSH_AUTHSOCKET_ENV_NAME);
615 printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf,
616 SSH_AGENTPID_ENV_NAME);
617 printf("echo Agent pid %d;\n", pid);
618 exit(0);
619 }
620 setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1);
621 setenv(SSH_AGENTPID_ENV_NAME, pidstrbuf, 1);
622 execvp(av[0], av);
623 perror(av[0]);
624 exit(1);
625 }
626 close(0);
627 close(1);
628 close(2);
662 629
663 setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1); 630 if (setsid() == -1) {
664 setenv(SSH_AGENTPID_ENV_NAME, pidstrbuf, 1); 631 perror("setsid");
665 execvp(av[0], av); 632 cleanup_exit(1);
666 perror(av[0]); 633 }
667 exit(1); 634 if (atexit(cleanup_socket) < 0) {
668 } 635 perror("atexit");
669 636 cleanup_exit(1);
670 close(0); 637 }
671 close(1); 638 new_socket(AUTH_SOCKET, sock);
672 close(2); 639 if (ac > 0) {
673 640 signal(SIGALRM, check_parent_exists);
674 if (setsid() == -1) 641 alarm(10);
675 { 642 }
676 perror("setsid"); 643 signal(SIGINT, SIG_IGN);
677 cleanup_exit(1); 644 signal(SIGPIPE, SIG_IGN);
678 } 645 while (1) {
679 646 FD_ZERO(&readset);
680 if (atexit(cleanup_socket) < 0) 647 FD_ZERO(&writeset);
681 { 648 prepare_select(&readset, &writeset);
682 perror("atexit"); 649 if (select(max_fd + 1, &readset, &writeset, NULL, NULL) < 0) {
683 cleanup_exit(1); 650 if (errno == EINTR)
684 } 651 continue;
685 652 exit(1);
686 new_socket(AUTH_SOCKET, sock); 653 }
687 if (ac > 0) 654 after_select(&readset, &writeset);
688 {
689 signal(SIGALRM, check_parent_exists);
690 alarm(10);
691 }
692
693 signal(SIGINT, SIG_IGN);
694 signal(SIGPIPE, SIG_IGN);
695 while (1)
696 {
697 FD_ZERO(&readset);
698 FD_ZERO(&writeset);
699 prepare_select(&readset, &writeset);
700 if (select(max_fd + 1, &readset, &writeset, NULL, NULL) < 0)
701 {
702 if (errno == EINTR)
703 continue;
704 exit(1);
705 } 655 }
706 after_select(&readset, &writeset); 656 /* NOTREACHED */
707 }
708 /*NOTREACHED*/
709} 657}