diff options
Diffstat (limited to 'ssh-agent.c')
-rw-r--r-- | ssh-agent.c | 1124 |
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> | |
5 | ssh-agent.c | 5 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
6 | 6 | * All rights reserved | |
7 | Author: Tatu Ylonen <ylo@cs.hut.fi> | 7 | * Created: Wed Mar 29 03:46:59 1995 ylo |
8 | 8 | * The authentication agent program. | |
9 | Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 9 | */ |
10 | All rights reserved | ||
11 | |||
12 | Created: Wed Mar 29 03:46:59 1995 ylo | ||
13 | |||
14 | The authentication agent program. | ||
15 | |||
16 | */ | ||
17 | 10 | ||
18 | #include "includes.h" | 11 | #include "includes.h" |
19 | RCSID("$OpenBSD: ssh-agent.c,v 1.20 1999/11/19 10:20:51 markus Exp $"); | 12 | RCSID("$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 | 31 | typedef struct { |
39 | extern char *__progname; | 32 | int fd; |
40 | #else /* HAVE___PROGNAME */ | 33 | enum { |
41 | const char *__progname = "ssh-agent"; | 34 | AUTH_UNUSED, AUTH_SOCKET, AUTH_CONNECTION |
42 | #endif /* HAVE___PROGNAME */ | 35 | } type; |
43 | 36 | Buffer input; | |
44 | typedef 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 | ||
52 | unsigned int sockets_alloc = 0; | 40 | unsigned int sockets_alloc = 0; |
53 | SocketEntry *sockets = NULL; | 41 | SocketEntry *sockets = NULL; |
54 | 42 | ||
55 | typedef struct | 43 | typedef struct { |
56 | { | 44 | RSA *key; |
57 | RSA *key; | 45 | char *comment; |
58 | char *comment; | ||
59 | } Identity; | 46 | } Identity; |
60 | 47 | ||
61 | unsigned int num_identities = 0; | 48 | unsigned int num_identities = 0; |
@@ -70,640 +57,601 @@ int parent_pid = -1; | |||
70 | char socket_name[1024]; | 57 | char socket_name[1024]; |
71 | char socket_dir[1024]; | 58 | char socket_dir[1024]; |
72 | 59 | ||
60 | #ifdef HAVE___PROGNAME | ||
61 | extern char *__progname; | ||
62 | #else /* HAVE___PROGNAME */ | ||
63 | const char *__progname = "ssh-agent"; | ||
64 | #endif /* HAVE___PROGNAME */ | ||
65 | |||
73 | void | 66 | void |
74 | process_request_identity(SocketEntry *e) | 67 | process_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 | ||
95 | void | 87 | void |
96 | process_authentication_challenge(SocketEntry *e) | 88 | process_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]); | 160 | send: |
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 | ||
184 | void | 170 | void |
185 | process_remove_identity(SocketEntry *e) | 171 | process_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 | */ | ||
234 | void | 221 | void |
235 | process_remove_all_identities(SocketEntry *e) | 222 | process_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 | ||
257 | void | 232 | /* Mark that there are no identities. */ |
258 | process_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. */ | 244 | void |
323 | buffer_put_int(&e->output, 1); | 245 | process_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 | ||
327 | void | 312 | void |
328 | process_message(SocketEntry *e) | 313 | process_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 | ||
376 | void | 359 | void |
377 | new_socket(int type, int fd) | 360 | new_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 | ||
409 | void | 391 | void |
410 | prepare_select(fd_set *readset, fd_set *writeset) | 392 | prepare_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 | ||
430 | void after_select(fd_set *readset, fd_set *writeset) | 411 | void |
412 | after_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 | ||
489 | void | 464 | void |
490 | check_parent_exists(int sig) | 465 | check_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 | ||
501 | void | 475 | void |
502 | cleanup_socket(void) | 476 | cleanup_socket(void) |
503 | { | 477 | { |
504 | remove(socket_name); | 478 | remove(socket_name); |
505 | rmdir(socket_dir); | 479 | rmdir(socket_dir); |
506 | } | 480 | } |
507 | 481 | ||
508 | void | 482 | void |
509 | cleanup_exit(int i) | 483 | cleanup_exit(int i) |
510 | { | 484 | { |
511 | cleanup_socket(); | 485 | cleanup_socket(); |
512 | exit(i); | 486 | exit(i); |
513 | } | 487 | } |
514 | 488 | ||
515 | void | 489 | void |
516 | usage() | 490 | usage() |
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 | ||
524 | int | 498 | int |
525 | main(int ac, char **av) | 499 | main(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 | } |