Annotation of src/usr.bin/ssh/sshconnect2.c, Revision 1.55
1.1 markus 1: /*
2: * Copyright (c) 2000 Markus Friedl. All rights reserved.
3: *
4: * Redistribution and use in source and binary forms, with or without
5: * modification, are permitted provided that the following conditions
6: * are met:
7: * 1. Redistributions of source code must retain the above copyright
8: * notice, this list of conditions and the following disclaimer.
9: * 2. Redistributions in binary form must reproduce the above copyright
10: * notice, this list of conditions and the following disclaimer in the
11: * documentation and/or other materials provided with the distribution.
12: *
13: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23: */
24:
25: #include "includes.h"
1.55 ! djm 26: RCSID("$OpenBSD: sshconnect2.c,v 1.54 2001/03/12 22:02:02 markus Exp $");
1.1 markus 27:
28: #include <openssl/bn.h>
29: #include <openssl/md5.h>
30: #include <openssl/dh.h>
31: #include <openssl/hmac.h>
32:
33: #include "ssh.h"
1.37 markus 34: #include "ssh2.h"
1.1 markus 35: #include "xmalloc.h"
36: #include "rsa.h"
37: #include "buffer.h"
38: #include "packet.h"
39: #include "uidswap.h"
40: #include "compat.h"
41: #include "bufaux.h"
1.37 markus 42: #include "cipher.h"
1.1 markus 43: #include "kex.h"
44: #include "myproposal.h"
45: #include "key.h"
46: #include "sshconnect.h"
47: #include "authfile.h"
1.23 markus 48: #include "cli.h"
1.20 markus 49: #include "dispatch.h"
1.17 markus 50: #include "authfd.h"
1.37 markus 51: #include "log.h"
52: #include "readconf.h"
53: #include "readpass.h"
1.53 markus 54: #include "match.h"
1.1 markus 55:
1.22 provos 56: void ssh_dh1_client(Kex *, char *, struct sockaddr *, Buffer *, Buffer *);
57: void ssh_dhgex_client(Kex *, char *, struct sockaddr *, Buffer *, Buffer *);
58:
1.1 markus 59: /* import */
60: extern char *client_version_string;
61: extern char *server_version_string;
62: extern Options options;
63:
64: /*
65: * SSH2 key exchange
66: */
67:
1.32 markus 68: u_char *session_id2 = NULL;
1.1 markus 69: int session_id2_len = 0;
70:
71: void
1.22 provos 72: ssh_kex2(char *host, struct sockaddr *hostaddr)
73: {
74: int i, plen;
75: Kex *kex;
76: Buffer *client_kexinit, *server_kexinit;
77: char *sprop[PROPOSAL_MAX];
78:
1.29 markus 79: if (options.ciphers == (char *)-1) {
80: log("No valid ciphers for protocol version 2 given, using defaults.");
81: options.ciphers = NULL;
1.24 markus 82: }
1.22 provos 83: if (options.ciphers != NULL) {
84: myproposal[PROPOSAL_ENC_ALGS_CTOS] =
85: myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
86: }
87: if (options.compression) {
1.47 markus 88: myproposal[PROPOSAL_COMP_ALGS_CTOS] =
1.22 provos 89: myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib";
90: } else {
1.47 markus 91: myproposal[PROPOSAL_COMP_ALGS_CTOS] =
1.22 provos 92: myproposal[PROPOSAL_COMP_ALGS_STOC] = "none";
1.47 markus 93: }
94: if (options.macs != NULL) {
95: myproposal[PROPOSAL_MAC_ALGS_CTOS] =
96: myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs;
1.22 provos 97: }
1.55 ! djm 98:
! 99: myproposal[PROPOSAL_ENC_ALGS_STOC] =
! 100: compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_STOC]);
1.22 provos 101:
102: /* buffers with raw kexinit messages */
103: server_kexinit = xmalloc(sizeof(*server_kexinit));
104: buffer_init(server_kexinit);
105: client_kexinit = kex_init(myproposal);
106:
107: /* algorithm negotiation */
108: kex_exchange_kexinit(client_kexinit, server_kexinit, sprop);
109: kex = kex_choose_conf(myproposal, sprop, 0);
110: for (i = 0; i < PROPOSAL_MAX; i++)
111: xfree(sprop[i]);
112:
113: /* server authentication and session key agreement */
114: switch(kex->kex_type) {
115: case DH_GRP1_SHA1:
116: ssh_dh1_client(kex, host, hostaddr,
117: client_kexinit, server_kexinit);
118: break;
119: case DH_GEX_SHA1:
120: ssh_dhgex_client(kex, host, hostaddr, client_kexinit,
121: server_kexinit);
122: break;
123: default:
124: fatal("Unsupported key exchange %d", kex->kex_type);
125: }
126:
127: buffer_free(client_kexinit);
128: buffer_free(server_kexinit);
129: xfree(client_kexinit);
130: xfree(server_kexinit);
131:
132: debug("Wait SSH2_MSG_NEWKEYS.");
133: packet_read_expect(&plen, SSH2_MSG_NEWKEYS);
134: packet_done();
135: debug("GOT SSH2_MSG_NEWKEYS.");
136:
137: debug("send SSH2_MSG_NEWKEYS.");
138: packet_start(SSH2_MSG_NEWKEYS);
139: packet_send();
140: packet_write_wait();
141: debug("done: send SSH2_MSG_NEWKEYS.");
142:
143: #ifdef DEBUG_KEXDH
144: /* send 1st encrypted/maced/compressed message */
145: packet_start(SSH2_MSG_IGNORE);
146: packet_put_cstring("markus");
147: packet_send();
148: packet_write_wait();
149: #endif
150: debug("done: KEX2.");
151: }
152:
153: /* diffie-hellman-group1-sha1 */
154:
155: void
1.41 stevesk 156: ssh_dh1_client(Kex *kex, char *host, struct sockaddr *hostaddr,
1.22 provos 157: Buffer *client_kexinit, Buffer *server_kexinit)
1.1 markus 158: {
1.19 markus 159: #ifdef DEBUG_KEXDH
160: int i;
161: #endif
1.11 markus 162: int plen, dlen;
1.32 markus 163: u_int klen, kout;
1.1 markus 164: char *signature = NULL;
1.32 markus 165: u_int slen;
1.1 markus 166: char *server_host_key_blob = NULL;
167: Key *server_host_key;
1.32 markus 168: u_int sbloblen;
1.1 markus 169: DH *dh;
170: BIGNUM *dh_server_pub = 0;
171: BIGNUM *shared_secret = 0;
1.32 markus 172: u_char *kbuf;
173: u_char *hash;
1.1 markus 174:
175: debug("Sending SSH2_MSG_KEXDH_INIT.");
176: /* generate and send 'e', client DH public key */
177: dh = dh_new_group1();
1.50 markus 178: dh_gen_key(dh, kex->we_need * 8);
1.1 markus 179: packet_start(SSH2_MSG_KEXDH_INIT);
180: packet_put_bignum2(dh->pub_key);
181: packet_send();
182: packet_write_wait();
183:
184: #ifdef DEBUG_KEXDH
185: fprintf(stderr, "\np= ");
1.19 markus 186: BN_print_fp(stderr, dh->p);
1.1 markus 187: fprintf(stderr, "\ng= ");
1.19 markus 188: BN_print_fp(stderr, dh->g);
1.1 markus 189: fprintf(stderr, "\npub= ");
1.19 markus 190: BN_print_fp(stderr, dh->pub_key);
1.1 markus 191: fprintf(stderr, "\n");
192: DHparams_print_fp(stderr, dh);
193: #endif
194:
195: debug("Wait SSH2_MSG_KEXDH_REPLY.");
196:
1.11 markus 197: packet_read_expect(&plen, SSH2_MSG_KEXDH_REPLY);
1.1 markus 198:
199: debug("Got SSH2_MSG_KEXDH_REPLY.");
200:
201: /* key, cert */
202: server_host_key_blob = packet_get_string(&sbloblen);
1.28 markus 203: server_host_key = key_from_blob(server_host_key_blob, sbloblen);
1.1 markus 204: if (server_host_key == NULL)
205: fatal("cannot decode server_host_key_blob");
206:
207: check_host_key(host, hostaddr, server_host_key,
1.22 provos 208: options.user_hostfile2, options.system_hostfile2);
1.1 markus 209:
210: /* DH paramter f, server public DH key */
211: dh_server_pub = BN_new();
212: if (dh_server_pub == NULL)
213: fatal("dh_server_pub == NULL");
214: packet_get_bignum2(dh_server_pub, &dlen);
215:
216: #ifdef DEBUG_KEXDH
217: fprintf(stderr, "\ndh_server_pub= ");
1.19 markus 218: BN_print_fp(stderr, dh_server_pub);
1.1 markus 219: fprintf(stderr, "\n");
220: debug("bits %d", BN_num_bits(dh_server_pub));
221: #endif
222:
223: /* signed H */
224: signature = packet_get_string(&slen);
225: packet_done();
226:
227: if (!dh_pub_is_valid(dh, dh_server_pub))
228: packet_disconnect("bad server public DH value");
229:
230: klen = DH_size(dh);
231: kbuf = xmalloc(klen);
232: kout = DH_compute_key(kbuf, dh_server_pub, dh);
233: #ifdef DEBUG_KEXDH
234: debug("shared secret: len %d/%d", klen, kout);
235: fprintf(stderr, "shared secret == ");
236: for (i = 0; i< kout; i++)
237: fprintf(stderr, "%02x", (kbuf[i])&0xff);
238: fprintf(stderr, "\n");
239: #endif
240: shared_secret = BN_new();
241:
242: BN_bin2bn(kbuf, kout, shared_secret);
243: memset(kbuf, 0, klen);
244: xfree(kbuf);
245:
246: /* calc and verify H */
247: hash = kex_hash(
248: client_version_string,
249: server_version_string,
250: buffer_ptr(client_kexinit), buffer_len(client_kexinit),
251: buffer_ptr(server_kexinit), buffer_len(server_kexinit),
252: server_host_key_blob, sbloblen,
253: dh->pub_key,
254: dh_server_pub,
255: shared_secret
256: );
1.3 markus 257: xfree(server_host_key_blob);
1.11 markus 258: DH_free(dh);
1.38 stevesk 259: BN_free(dh_server_pub);
1.1 markus 260: #ifdef DEBUG_KEXDH
261: fprintf(stderr, "hash == ");
262: for (i = 0; i< 20; i++)
263: fprintf(stderr, "%02x", (hash[i])&0xff);
264: fprintf(stderr, "\n");
265: #endif
1.32 markus 266: if (key_verify(server_host_key, (u_char *)signature, slen, hash, 20) != 1)
1.28 markus 267: fatal("key_verify failed for server_host_key");
1.1 markus 268: key_free(server_host_key);
1.38 stevesk 269: xfree(signature);
1.1 markus 270:
271: kex_derive_keys(kex, hash, shared_secret);
1.38 stevesk 272: BN_clear_free(shared_secret);
1.1 markus 273: packet_set_kex(kex);
274:
275: /* save session id */
276: session_id2_len = 20;
277: session_id2 = xmalloc(session_id2_len);
278: memcpy(session_id2, hash, session_id2_len);
1.11 markus 279: }
280:
1.22 provos 281: /* diffie-hellman-group-exchange-sha1 */
282:
283: /*
284: * Estimates the group order for a Diffie-Hellman group that has an
285: * attack complexity approximately the same as O(2**bits). Estimate
286: * with: O(exp(1.9223 * (ln q)^(1/3) (ln ln q)^(2/3)))
287: */
288:
289: int
290: dh_estimate(int bits)
291: {
1.41 stevesk 292:
1.22 provos 293: if (bits < 64)
294: return (512); /* O(2**63) */
295: if (bits < 128)
296: return (1024); /* O(2**86) */
297: if (bits < 192)
298: return (2048); /* O(2**116) */
299: return (4096); /* O(2**156) */
300: }
301:
1.11 markus 302: void
1.22 provos 303: ssh_dhgex_client(Kex *kex, char *host, struct sockaddr *hostaddr,
304: Buffer *client_kexinit, Buffer *server_kexinit)
1.11 markus 305: {
1.22 provos 306: #ifdef DEBUG_KEXDH
307: int i;
308: #endif
309: int plen, dlen;
1.32 markus 310: u_int klen, kout;
1.22 provos 311: char *signature = NULL;
1.32 markus 312: u_int slen, nbits;
1.22 provos 313: char *server_host_key_blob = NULL;
314: Key *server_host_key;
1.32 markus 315: u_int sbloblen;
1.22 provos 316: DH *dh;
317: BIGNUM *dh_server_pub = 0;
318: BIGNUM *shared_secret = 0;
319: BIGNUM *p = 0, *g = 0;
1.32 markus 320: u_char *kbuf;
321: u_char *hash;
1.22 provos 322:
1.50 markus 323: nbits = dh_estimate(kex->we_need * 8);
1.22 provos 324:
325: debug("Sending SSH2_MSG_KEX_DH_GEX_REQUEST.");
326: packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST);
327: packet_put_int(nbits);
328: packet_send();
329: packet_write_wait();
1.11 markus 330:
1.22 provos 331: #ifdef DEBUG_KEXDH
332: fprintf(stderr, "\nnbits = %d", nbits);
333: #endif
1.11 markus 334:
1.22 provos 335: debug("Wait SSH2_MSG_KEX_DH_GEX_GROUP.");
1.11 markus 336:
1.22 provos 337: packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_GROUP);
1.11 markus 338:
1.22 provos 339: debug("Got SSH2_MSG_KEX_DH_GEX_GROUP.");
1.11 markus 340:
1.22 provos 341: if ((p = BN_new()) == NULL)
342: fatal("BN_new");
343: packet_get_bignum2(p, &dlen);
344: if ((g = BN_new()) == NULL)
345: fatal("BN_new");
346: packet_get_bignum2(g, &dlen);
1.36 stevesk 347: dh = dh_new_group(g, p);
1.31 provos 348:
1.50 markus 349: dh_gen_key(dh, kex->we_need * 8);
1.1 markus 350:
1.22 provos 351: #ifdef DEBUG_KEXDH
352: fprintf(stderr, "\np= ");
353: BN_print_fp(stderr, dh->p);
354: fprintf(stderr, "\ng= ");
355: BN_print_fp(stderr, dh->g);
356: fprintf(stderr, "\npub= ");
357: BN_print_fp(stderr, dh->pub_key);
358: fprintf(stderr, "\n");
359: DHparams_print_fp(stderr, dh);
360: #endif
1.1 markus 361:
1.22 provos 362: debug("Sending SSH2_MSG_KEX_DH_GEX_INIT.");
363: /* generate and send 'e', client DH public key */
364: packet_start(SSH2_MSG_KEX_DH_GEX_INIT);
365: packet_put_bignum2(dh->pub_key);
1.1 markus 366: packet_send();
367: packet_write_wait();
368:
1.22 provos 369: debug("Wait SSH2_MSG_KEX_DH_GEX_REPLY.");
370:
371: packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_REPLY);
372:
373: debug("Got SSH2_MSG_KEXDH_REPLY.");
374:
375: /* key, cert */
376: server_host_key_blob = packet_get_string(&sbloblen);
1.28 markus 377: server_host_key = key_from_blob(server_host_key_blob, sbloblen);
1.22 provos 378: if (server_host_key == NULL)
379: fatal("cannot decode server_host_key_blob");
380:
381: check_host_key(host, hostaddr, server_host_key,
382: options.user_hostfile2, options.system_hostfile2);
383:
384: /* DH paramter f, server public DH key */
385: dh_server_pub = BN_new();
386: if (dh_server_pub == NULL)
387: fatal("dh_server_pub == NULL");
388: packet_get_bignum2(dh_server_pub, &dlen);
389:
390: #ifdef DEBUG_KEXDH
391: fprintf(stderr, "\ndh_server_pub= ");
392: BN_print_fp(stderr, dh_server_pub);
393: fprintf(stderr, "\n");
394: debug("bits %d", BN_num_bits(dh_server_pub));
395: #endif
396:
397: /* signed H */
398: signature = packet_get_string(&slen);
399: packet_done();
400:
401: if (!dh_pub_is_valid(dh, dh_server_pub))
402: packet_disconnect("bad server public DH value");
403:
404: klen = DH_size(dh);
405: kbuf = xmalloc(klen);
406: kout = DH_compute_key(kbuf, dh_server_pub, dh);
407: #ifdef DEBUG_KEXDH
408: debug("shared secret: len %d/%d", klen, kout);
409: fprintf(stderr, "shared secret == ");
410: for (i = 0; i< kout; i++)
411: fprintf(stderr, "%02x", (kbuf[i])&0xff);
412: fprintf(stderr, "\n");
413: #endif
414: shared_secret = BN_new();
415:
416: BN_bin2bn(kbuf, kout, shared_secret);
417: memset(kbuf, 0, klen);
418: xfree(kbuf);
419:
420: /* calc and verify H */
421: hash = kex_hash_gex(
422: client_version_string,
423: server_version_string,
424: buffer_ptr(client_kexinit), buffer_len(client_kexinit),
425: buffer_ptr(server_kexinit), buffer_len(server_kexinit),
426: server_host_key_blob, sbloblen,
1.41 stevesk 427: nbits, dh->p, dh->g,
1.22 provos 428: dh->pub_key,
429: dh_server_pub,
430: shared_secret
431: );
432: xfree(server_host_key_blob);
433: DH_free(dh);
1.38 stevesk 434: BN_free(dh_server_pub);
1.1 markus 435: #ifdef DEBUG_KEXDH
1.22 provos 436: fprintf(stderr, "hash == ");
437: for (i = 0; i< 20; i++)
438: fprintf(stderr, "%02x", (hash[i])&0xff);
439: fprintf(stderr, "\n");
1.1 markus 440: #endif
1.32 markus 441: if (key_verify(server_host_key, (u_char *)signature, slen, hash, 20) != 1)
1.28 markus 442: fatal("key_verify failed for server_host_key");
1.22 provos 443: key_free(server_host_key);
1.38 stevesk 444: xfree(signature);
1.22 provos 445:
446: kex_derive_keys(kex, hash, shared_secret);
1.38 stevesk 447: BN_clear_free(shared_secret);
1.22 provos 448: packet_set_kex(kex);
449:
450: /* save session id */
451: session_id2_len = 20;
452: session_id2 = xmalloc(session_id2_len);
453: memcpy(session_id2, hash, session_id2_len);
1.1 markus 454: }
1.11 markus 455:
1.1 markus 456: /*
457: * Authenticate user
458: */
1.20 markus 459:
460: typedef struct Authctxt Authctxt;
461: typedef struct Authmethod Authmethod;
462:
463: typedef int sign_cb_fn(
464: Authctxt *authctxt, Key *key,
1.32 markus 465: u_char **sigp, int *lenp, u_char *data, int datalen);
1.20 markus 466:
467: struct Authctxt {
468: const char *server_user;
469: const char *host;
470: const char *service;
471: AuthenticationConnection *agent;
1.23 markus 472: Authmethod *method;
1.20 markus 473: int success;
1.51 markus 474: char *authlist;
475: Key *last_key;
476: sign_cb_fn *last_key_sign;
477: int last_key_hint;
1.20 markus 478: };
479: struct Authmethod {
480: char *name; /* string to compare against server's list */
481: int (*userauth)(Authctxt *authctxt);
482: int *enabled; /* flag in option struct that enables method */
483: int *batch_flag; /* flag in option struct that disables method */
484: };
485:
486: void input_userauth_success(int type, int plen, void *ctxt);
487: void input_userauth_failure(int type, int plen, void *ctxt);
1.35 markus 488: void input_userauth_banner(int type, int plen, void *ctxt);
1.20 markus 489: void input_userauth_error(int type, int plen, void *ctxt);
1.23 markus 490: void input_userauth_info_req(int type, int plen, void *ctxt);
1.51 markus 491: void input_userauth_pk_ok(int type, int plen, void *ctxt);
1.23 markus 492:
493: int userauth_none(Authctxt *authctxt);
1.20 markus 494: int userauth_pubkey(Authctxt *authctxt);
495: int userauth_passwd(Authctxt *authctxt);
1.23 markus 496: int userauth_kbdint(Authctxt *authctxt);
1.20 markus 497:
1.51 markus 498: void userauth(Authctxt *authctxt, char *authlist);
499:
500: int
501: sign_and_send_pubkey(Authctxt *authctxt, Key *k,
502: sign_cb_fn *sign_callback);
503: void clear_auth_state(Authctxt *authctxt);
504:
1.23 markus 505: Authmethod *authmethod_get(char *authlist);
506: Authmethod *authmethod_lookup(const char *name);
1.53 markus 507: char *authmethods_get(void);
1.20 markus 508:
509: Authmethod authmethods[] = {
510: {"publickey",
511: userauth_pubkey,
1.28 markus 512: &options.pubkey_authentication,
1.20 markus 513: NULL},
514: {"password",
515: userauth_passwd,
516: &options.password_authentication,
517: &options.batch_mode},
1.23 markus 518: {"keyboard-interactive",
519: userauth_kbdint,
520: &options.kbd_interactive_authentication,
521: &options.batch_mode},
522: {"none",
523: userauth_none,
524: NULL,
525: NULL},
1.20 markus 526: {NULL, NULL, NULL, NULL}
527: };
528:
529: void
530: ssh_userauth2(const char *server_user, char *host)
531: {
532: Authctxt authctxt;
533: int type;
534: int plen;
1.39 markus 535:
536: if (options.challenge_reponse_authentication)
537: options.kbd_interactive_authentication = 1;
1.20 markus 538:
539: debug("send SSH2_MSG_SERVICE_REQUEST");
540: packet_start(SSH2_MSG_SERVICE_REQUEST);
541: packet_put_cstring("ssh-userauth");
542: packet_send();
543: packet_write_wait();
544: type = packet_read(&plen);
545: if (type != SSH2_MSG_SERVICE_ACCEPT) {
546: fatal("denied SSH2_MSG_SERVICE_ACCEPT: %d", type);
547: }
548: if (packet_remaining() > 0) {
549: char *reply = packet_get_string(&plen);
550: debug("service_accept: %s", reply);
551: xfree(reply);
552: } else {
553: debug("buggy server: service_accept w/o service");
554: }
555: packet_done();
556: debug("got SSH2_MSG_SERVICE_ACCEPT");
557:
1.53 markus 558: if (options.preferred_authentications == NULL)
559: options.preferred_authentications = authmethods_get();
560:
1.20 markus 561: /* setup authentication context */
562: authctxt.agent = ssh_get_authentication_connection();
563: authctxt.server_user = server_user;
564: authctxt.host = host;
565: authctxt.service = "ssh-connection"; /* service name */
566: authctxt.success = 0;
1.23 markus 567: authctxt.method = authmethod_lookup("none");
1.51 markus 568: authctxt.authlist = NULL;
1.23 markus 569: if (authctxt.method == NULL)
570: fatal("ssh_userauth2: internal error: cannot send userauth none request");
1.20 markus 571:
572: /* initial userauth request */
1.23 markus 573: userauth_none(&authctxt);
1.20 markus 574:
575: dispatch_init(&input_userauth_error);
576: dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success);
577: dispatch_set(SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure);
1.35 markus 578: dispatch_set(SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner);
1.20 markus 579: dispatch_run(DISPATCH_BLOCK, &authctxt.success, &authctxt); /* loop until success */
580:
581: if (authctxt.agent != NULL)
582: ssh_close_authentication_connection(authctxt.agent);
583:
1.34 markus 584: debug("ssh-userauth2 successful: method %s", authctxt.method->name);
1.20 markus 585: }
586: void
1.51 markus 587: userauth(Authctxt *authctxt, char *authlist)
588: {
589: if (authlist == NULL) {
590: authlist = authctxt->authlist;
591: } else {
592: if (authctxt->authlist)
593: xfree(authctxt->authlist);
594: authctxt->authlist = authlist;
595: }
596: for (;;) {
597: Authmethod *method = authmethod_get(authlist);
598: if (method == NULL)
599: fatal("Permission denied (%s).", authlist);
600: authctxt->method = method;
601: if (method->userauth(authctxt) != 0) {
602: debug2("we sent a %s packet, wait for reply", method->name);
603: break;
604: } else {
605: debug2("we did not send a packet, disable method");
606: method->enabled = NULL;
607: }
608: }
609: }
610: void
1.20 markus 611: input_userauth_error(int type, int plen, void *ctxt)
612: {
1.35 markus 613: fatal("input_userauth_error: bad message during authentication: "
614: "type %d", type);
615: }
616: void
617: input_userauth_banner(int type, int plen, void *ctxt)
618: {
619: char *msg, *lang;
620: debug3("input_userauth_banner");
621: msg = packet_get_string(NULL);
622: lang = packet_get_string(NULL);
623: fprintf(stderr, "%s", msg);
624: xfree(msg);
625: xfree(lang);
1.20 markus 626: }
627: void
628: input_userauth_success(int type, int plen, void *ctxt)
629: {
630: Authctxt *authctxt = ctxt;
631: if (authctxt == NULL)
632: fatal("input_userauth_success: no authentication context");
1.51 markus 633: if (authctxt->authlist)
634: xfree(authctxt->authlist);
635: clear_auth_state(authctxt);
1.20 markus 636: authctxt->success = 1; /* break out */
637: }
638: void
639: input_userauth_failure(int type, int plen, void *ctxt)
640: {
641: Authctxt *authctxt = ctxt;
642: char *authlist = NULL;
643: int partial;
644:
645: if (authctxt == NULL)
646: fatal("input_userauth_failure: no authentication context");
647:
1.23 markus 648: authlist = packet_get_string(NULL);
1.20 markus 649: partial = packet_get_char();
650: packet_done();
651:
652: if (partial != 0)
1.45 markus 653: log("Authenticated with partial success.");
1.20 markus 654: debug("authentications that can continue: %s", authlist);
655:
1.51 markus 656: clear_auth_state(authctxt);
657: userauth(authctxt, authlist);
658: }
659: void
660: input_userauth_pk_ok(int type, int plen, void *ctxt)
661: {
662: Authctxt *authctxt = ctxt;
663: Key *key = NULL;
664: Buffer b;
665: int alen, blen, pktype, sent = 0;
1.54 markus 666: char *pkalg, *pkblob, *fp;
1.51 markus 667:
668: if (authctxt == NULL)
669: fatal("input_userauth_pk_ok: no authentication context");
670: if (datafellows & SSH_BUG_PKOK) {
671: /* this is similar to SSH_BUG_PKAUTH */
672: debug2("input_userauth_pk_ok: SSH_BUG_PKOK");
673: pkblob = packet_get_string(&blen);
674: buffer_init(&b);
675: buffer_append(&b, pkblob, blen);
676: pkalg = buffer_get_string(&b, &alen);
677: buffer_free(&b);
678: } else {
679: pkalg = packet_get_string(&alen);
680: pkblob = packet_get_string(&blen);
681: }
682: packet_done();
683:
684: debug("input_userauth_pk_ok: pkalg %s blen %d lastkey %p hint %d",
685: pkalg, blen, authctxt->last_key, authctxt->last_key_hint);
686:
687: do {
688: if (authctxt->last_key == NULL ||
689: authctxt->last_key_sign == NULL) {
690: debug("no last key or no sign cb");
691: break;
692: }
693: if ((pktype = key_type_from_name(pkalg)) == KEY_UNSPEC) {
694: debug("unknown pkalg %s", pkalg);
695: break;
696: }
697: if ((key = key_from_blob(pkblob, blen)) == NULL) {
698: debug("no key from blob. pkalg %s", pkalg);
699: break;
700: }
1.54 markus 701: fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
702: debug2("input_userauth_pk_ok: fp %s", fp);
703: xfree(fp);
1.51 markus 704: if (!key_equal(key, authctxt->last_key)) {
705: debug("key != last_key");
1.20 markus 706: break;
707: }
1.51 markus 708: sent = sign_and_send_pubkey(authctxt, key,
709: authctxt->last_key_sign);
710: } while(0);
711:
712: if (key != NULL)
713: key_free(key);
714: xfree(pkalg);
715: xfree(pkblob);
716:
717: /* unregister */
718: clear_auth_state(authctxt);
719: dispatch_set(SSH2_MSG_USERAUTH_PK_OK, NULL);
720:
721: /* try another method if we did not send a packet*/
722: if (sent == 0)
723: userauth(authctxt, NULL);
724:
1.20 markus 725: }
726:
1.1 markus 727: int
1.23 markus 728: userauth_none(Authctxt *authctxt)
729: {
730: /* initial userauth request */
731: packet_start(SSH2_MSG_USERAUTH_REQUEST);
732: packet_put_cstring(authctxt->server_user);
733: packet_put_cstring(authctxt->service);
734: packet_put_cstring(authctxt->method->name);
735: packet_send();
736: return 1;
737: }
738:
739: int
1.20 markus 740: userauth_passwd(Authctxt *authctxt)
1.1 markus 741: {
1.6 markus 742: static int attempt = 0;
1.1 markus 743: char prompt[80];
744: char *password;
1.6 markus 745:
1.13 todd 746: if (attempt++ >= options.number_of_password_prompts)
1.6 markus 747: return 0;
1.13 todd 748:
749: if(attempt != 1)
750: error("Permission denied, please try again.");
1.1 markus 751:
1.43 itojun 752: snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ",
1.20 markus 753: authctxt->server_user, authctxt->host);
1.1 markus 754: password = read_passphrase(prompt, 0);
755: packet_start(SSH2_MSG_USERAUTH_REQUEST);
1.20 markus 756: packet_put_cstring(authctxt->server_user);
757: packet_put_cstring(authctxt->service);
1.23 markus 758: packet_put_cstring(authctxt->method->name);
1.1 markus 759: packet_put_char(0);
1.49 markus 760: packet_put_cstring(password);
1.1 markus 761: memset(password, 0, strlen(password));
762: xfree(password);
1.49 markus 763: packet_inject_ignore(64);
1.1 markus 764: packet_send();
765: return 1;
766: }
767:
1.51 markus 768: void
769: clear_auth_state(Authctxt *authctxt)
770: {
771: /* XXX clear authentication state */
772: if (authctxt->last_key != NULL && authctxt->last_key_hint == -1) {
773: debug3("clear_auth_state: key_free %p", authctxt->last_key);
774: key_free(authctxt->last_key);
775: }
776: authctxt->last_key = NULL;
777: authctxt->last_key_hint = -2;
778: authctxt->last_key_sign = NULL;
779: }
780:
1.17 markus 781: int
1.20 markus 782: sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
1.1 markus 783: {
784: Buffer b;
1.32 markus 785: u_char *blob, *signature;
1.1 markus 786: int bloblen, slen;
1.14 markus 787: int skip = 0;
1.17 markus 788: int ret = -1;
1.23 markus 789: int have_sig = 1;
1.1 markus 790:
1.30 markus 791: debug3("sign_and_send_pubkey");
1.51 markus 792:
1.28 markus 793: if (key_to_blob(k, &blob, &bloblen) == 0) {
794: /* we cannot handle this key */
1.30 markus 795: debug3("sign_and_send_pubkey: cannot handle key");
1.28 markus 796: return 0;
797: }
1.1 markus 798: /* data to be signed */
799: buffer_init(&b);
1.26 markus 800: if (datafellows & SSH_OLD_SESSIONID) {
801: buffer_append(&b, session_id2, session_id2_len);
1.41 stevesk 802: skip = session_id2_len;
1.26 markus 803: } else {
1.14 markus 804: buffer_put_string(&b, session_id2, session_id2_len);
805: skip = buffer_len(&b);
806: }
1.1 markus 807: buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
1.20 markus 808: buffer_put_cstring(&b, authctxt->server_user);
1.10 markus 809: buffer_put_cstring(&b,
1.30 markus 810: datafellows & SSH_BUG_PKSERVICE ?
1.10 markus 811: "ssh-userauth" :
1.20 markus 812: authctxt->service);
1.30 markus 813: if (datafellows & SSH_BUG_PKAUTH) {
814: buffer_put_char(&b, have_sig);
815: } else {
816: buffer_put_cstring(&b, authctxt->method->name);
817: buffer_put_char(&b, have_sig);
1.41 stevesk 818: buffer_put_cstring(&b, key_ssh_name(k));
1.30 markus 819: }
1.1 markus 820: buffer_put_string(&b, blob, bloblen);
821:
822: /* generate signature */
1.51 markus 823: ret = (*sign_callback)(authctxt, k, &signature, &slen,
824: buffer_ptr(&b), buffer_len(&b));
1.17 markus 825: if (ret == -1) {
826: xfree(blob);
827: buffer_free(&b);
828: return 0;
829: }
1.28 markus 830: #ifdef DEBUG_PK
1.1 markus 831: buffer_dump(&b);
832: #endif
1.30 markus 833: if (datafellows & SSH_BUG_PKSERVICE) {
1.10 markus 834: buffer_clear(&b);
835: buffer_append(&b, session_id2, session_id2_len);
1.51 markus 836: skip = session_id2_len;
1.10 markus 837: buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
1.20 markus 838: buffer_put_cstring(&b, authctxt->server_user);
839: buffer_put_cstring(&b, authctxt->service);
1.23 markus 840: buffer_put_cstring(&b, authctxt->method->name);
841: buffer_put_char(&b, have_sig);
1.30 markus 842: if (!(datafellows & SSH_BUG_PKAUTH))
1.41 stevesk 843: buffer_put_cstring(&b, key_ssh_name(k));
1.10 markus 844: buffer_put_string(&b, blob, bloblen);
845: }
846: xfree(blob);
1.51 markus 847:
1.1 markus 848: /* append signature */
849: buffer_put_string(&b, signature, slen);
850: xfree(signature);
851:
852: /* skip session id and packet type */
1.14 markus 853: if (buffer_len(&b) < skip + 1)
1.20 markus 854: fatal("userauth_pubkey: internal error");
1.14 markus 855: buffer_consume(&b, skip + 1);
1.1 markus 856:
857: /* put remaining data from buffer into packet */
858: packet_start(SSH2_MSG_USERAUTH_REQUEST);
859: packet_put_raw(buffer_ptr(&b), buffer_len(&b));
860: buffer_free(&b);
861: packet_send();
1.17 markus 862:
863: return 1;
1.16 markus 864: }
865:
1.51 markus 866: int
867: send_pubkey_test(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback,
868: int hint)
1.20 markus 869: {
1.51 markus 870: u_char *blob;
871: int bloblen, have_sig = 0;
1.20 markus 872:
1.51 markus 873: debug3("send_pubkey_test");
1.16 markus 874:
1.51 markus 875: if (key_to_blob(k, &blob, &bloblen) == 0) {
876: /* we cannot handle this key */
877: debug3("send_pubkey_test: cannot handle key");
1.16 markus 878: return 0;
879: }
1.51 markus 880: /* register callback for USERAUTH_PK_OK message */
881: authctxt->last_key_sign = sign_callback;
882: authctxt->last_key_hint = hint;
883: authctxt->last_key = k;
884: dispatch_set(SSH2_MSG_USERAUTH_PK_OK, &input_userauth_pk_ok);
885:
886: packet_start(SSH2_MSG_USERAUTH_REQUEST);
887: packet_put_cstring(authctxt->server_user);
888: packet_put_cstring(authctxt->service);
889: packet_put_cstring(authctxt->method->name);
890: packet_put_char(have_sig);
891: if (!(datafellows & SSH_BUG_PKAUTH))
892: packet_put_cstring(key_ssh_name(k));
893: packet_put_string(blob, bloblen);
894: xfree(blob);
895: packet_send();
896: return 1;
897: }
898:
899: Key *
900: load_identity_file(char *filename)
901: {
902: Key *private;
903: char prompt[300], *passphrase;
904: int success = 0, quit, i;
1.52 markus 905: struct stat st;
1.16 markus 906:
1.52 markus 907: if (stat(filename, &st) < 0) {
908: debug3("no such identity: %s", filename);
909: return NULL;
910: }
1.51 markus 911: private = key_new(KEY_UNSPEC);
912: if (!load_private_key(filename, "", private, NULL)) {
1.42 markus 913: if (options.batch_mode) {
1.51 markus 914: key_free(private);
915: return NULL;
1.42 markus 916: }
1.16 markus 917: snprintf(prompt, sizeof prompt,
1.28 markus 918: "Enter passphrase for key '%.100s': ", filename);
1.20 markus 919: for (i = 0; i < options.number_of_password_prompts; i++) {
920: passphrase = read_passphrase(prompt, 0);
921: if (strcmp(passphrase, "") != 0) {
1.51 markus 922: success = load_private_key(filename,
923: passphrase, private, NULL);
924: quit = 0;
1.20 markus 925: } else {
926: debug2("no passphrase given, try next key");
1.51 markus 927: quit = 1;
1.20 markus 928: }
929: memset(passphrase, 0, strlen(passphrase));
930: xfree(passphrase);
1.51 markus 931: if (success || quit)
1.20 markus 932: break;
933: debug2("bad passphrase given, try again...");
934: }
1.16 markus 935: if (!success) {
1.51 markus 936: key_free(private);
937: return NULL;
1.16 markus 938: }
939: }
1.51 markus 940: return private;
941: }
942:
943: int
944: identity_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp,
945: u_char *data, int datalen)
946: {
947: Key *private;
948: int idx, ret;
949:
950: idx = authctxt->last_key_hint;
951: if (idx < 0)
952: return -1;
953: private = load_identity_file(options.identity_files[idx]);
954: if (private == NULL)
955: return -1;
956: ret = key_sign(private, sigp, lenp, data, datalen);
957: key_free(private);
1.17 markus 958: return ret;
959: }
960:
1.32 markus 961: int agent_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp,
962: u_char *data, int datalen)
1.17 markus 963: {
1.20 markus 964: return ssh_agent_sign(authctxt->agent, key, sigp, lenp, data, datalen);
1.17 markus 965: }
966:
1.51 markus 967: int key_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp,
968: u_char *data, int datalen)
969: {
970: return key_sign(key, sigp, lenp, data, datalen);
971: }
972:
1.17 markus 973: int
1.20 markus 974: userauth_pubkey_agent(Authctxt *authctxt)
1.17 markus 975: {
976: static int called = 0;
1.28 markus 977: int ret = 0;
1.17 markus 978: char *comment;
979: Key *k;
980:
981: if (called == 0) {
1.28 markus 982: if (ssh_get_num_identities(authctxt->agent, 2) == 0)
983: debug2("userauth_pubkey_agent: no keys at all");
1.20 markus 984: called = 1;
1.17 markus 985: }
1.28 markus 986: k = ssh_get_next_identity(authctxt->agent, &comment, 2);
1.20 markus 987: if (k == NULL) {
1.28 markus 988: debug2("userauth_pubkey_agent: no more keys");
989: } else {
1.51 markus 990: debug("userauth_pubkey_agent: testing agent key %s", comment);
1.28 markus 991: xfree(comment);
1.51 markus 992: ret = send_pubkey_test(authctxt, k, agent_sign_cb, -1);
993: if (ret == 0)
994: key_free(k);
1.20 markus 995: }
1.28 markus 996: if (ret == 0)
997: debug2("userauth_pubkey_agent: no message sent");
1.17 markus 998: return ret;
1.1 markus 999: }
1000:
1.20 markus 1001: int
1002: userauth_pubkey(Authctxt *authctxt)
1003: {
1004: static int idx = 0;
1005: int sent = 0;
1.51 markus 1006: Key *key;
1007: char *filename;
1.20 markus 1008:
1.28 markus 1009: if (authctxt->agent != NULL) {
1010: do {
1011: sent = userauth_pubkey_agent(authctxt);
1012: } while(!sent && authctxt->agent->howmany > 0);
1013: }
1014: while (!sent && idx < options.num_identity_files) {
1.51 markus 1015: key = options.identity_keys[idx];
1016: filename = options.identity_files[idx];
1017: if (key == NULL) {
1018: debug("try privkey: %s", filename);
1019: key = load_identity_file(filename);
1020: if (key != NULL) {
1021: sent = sign_and_send_pubkey(authctxt, key,
1022: key_sign_cb);
1023: key_free(key);
1024: }
1025: } else if (key->type != KEY_RSA1) {
1026: debug("try pubkey: %s", filename);
1027: sent = send_pubkey_test(authctxt, key,
1028: identity_sign_cb, idx);
1029: }
1.28 markus 1030: idx++;
1031: }
1.20 markus 1032: return sent;
1033: }
1034:
1.23 markus 1035: /*
1036: * Send userauth request message specifying keyboard-interactive method.
1037: */
1038: int
1039: userauth_kbdint(Authctxt *authctxt)
1040: {
1041: static int attempt = 0;
1042:
1043: if (attempt++ >= options.number_of_password_prompts)
1044: return 0;
1045:
1046: debug2("userauth_kbdint");
1047: packet_start(SSH2_MSG_USERAUTH_REQUEST);
1048: packet_put_cstring(authctxt->server_user);
1049: packet_put_cstring(authctxt->service);
1050: packet_put_cstring(authctxt->method->name);
1051: packet_put_cstring(""); /* lang */
1052: packet_put_cstring(options.kbd_interactive_devices ?
1053: options.kbd_interactive_devices : "");
1054: packet_send();
1055:
1056: dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_info_req);
1057: return 1;
1058: }
1059:
1060: /*
1.46 markus 1061: * parse INFO_REQUEST, prompt user and send INFO_RESPONSE
1.23 markus 1062: */
1063: void
1064: input_userauth_info_req(int type, int plen, void *ctxt)
1065: {
1066: Authctxt *authctxt = ctxt;
1.46 markus 1067: char *name, *inst, *lang, *prompt, *response;
1.32 markus 1068: u_int num_prompts, i;
1.23 markus 1069: int echo = 0;
1070:
1071: debug2("input_userauth_info_req");
1072:
1073: if (authctxt == NULL)
1074: fatal("input_userauth_info_req: no authentication context");
1075:
1076: name = packet_get_string(NULL);
1077: inst = packet_get_string(NULL);
1078: lang = packet_get_string(NULL);
1079: if (strlen(name) > 0)
1080: cli_mesg(name);
1081: if (strlen(inst) > 0)
1082: cli_mesg(inst);
1.46 markus 1083: xfree(name);
1.23 markus 1084: xfree(inst);
1.46 markus 1085: xfree(lang);
1.23 markus 1086:
1087: num_prompts = packet_get_int();
1088: /*
1089: * Begin to build info response packet based on prompts requested.
1090: * We commit to providing the correct number of responses, so if
1091: * further on we run into a problem that prevents this, we have to
1092: * be sure and clean this up and send a correct error response.
1093: */
1094: packet_start(SSH2_MSG_USERAUTH_INFO_RESPONSE);
1095: packet_put_int(num_prompts);
1096:
1097: for (i = 0; i < num_prompts; i++) {
1098: prompt = packet_get_string(NULL);
1099: echo = packet_get_char();
1100:
1101: response = cli_prompt(prompt, echo);
1102:
1.49 markus 1103: packet_put_cstring(response);
1.23 markus 1104: memset(response, 0, strlen(response));
1105: xfree(response);
1106: xfree(prompt);
1107: }
1108: packet_done(); /* done with parsing incoming message. */
1109:
1.49 markus 1110: packet_inject_ignore(64);
1.23 markus 1111: packet_send();
1112: }
1.20 markus 1113:
1114: /* find auth method */
1115:
1116: /*
1117: * given auth method name, if configurable options permit this method fill
1118: * in auth_ident field and return true, otherwise return false.
1119: */
1120: int
1121: authmethod_is_enabled(Authmethod *method)
1122: {
1123: if (method == NULL)
1124: return 0;
1125: /* return false if options indicate this method is disabled */
1126: if (method->enabled == NULL || *method->enabled == 0)
1127: return 0;
1128: /* return false if batch mode is enabled but method needs interactive mode */
1129: if (method->batch_flag != NULL && *method->batch_flag != 0)
1130: return 0;
1131: return 1;
1132: }
1133:
1134: Authmethod *
1135: authmethod_lookup(const char *name)
1.1 markus 1136: {
1.20 markus 1137: Authmethod *method = NULL;
1138: if (name != NULL)
1139: for (method = authmethods; method->name != NULL; method++)
1140: if (strcmp(name, method->name) == 0)
1141: return method;
1142: debug2("Unrecognized authentication method name: %s", name ? name : "NULL");
1143: return NULL;
1144: }
1.1 markus 1145:
1.53 markus 1146: /* XXX internal state */
1147: static Authmethod *current = NULL;
1148: static char *supported = NULL;
1149: static char *preferred = NULL;
1.20 markus 1150: /*
1151: * Given the authentication method list sent by the server, return the
1152: * next method we should try. If the server initially sends a nil list,
1.53 markus 1153: * use a built-in default list.
1.41 stevesk 1154: */
1.20 markus 1155: Authmethod *
1156: authmethod_get(char *authlist)
1157: {
1.53 markus 1158:
1159: char *name = NULL;
1160: int next;
1.41 stevesk 1161:
1.20 markus 1162: /* Use a suitable default if we're passed a nil list. */
1163: if (authlist == NULL || strlen(authlist) == 0)
1.53 markus 1164: authlist = options.preferred_authentications;
1.20 markus 1165:
1.53 markus 1166: if (supported == NULL || strcmp(authlist, supported) != 0) {
1167: debug3("start over, passed a different list %s", authlist);
1168: if (supported != NULL)
1169: xfree(supported);
1170: supported = xstrdup(authlist);
1171: preferred = options.preferred_authentications;
1172: debug3("preferred %s", preferred);
1173: current = NULL;
1174: } else if (current != NULL && authmethod_is_enabled(current))
1175: return current;
1.20 markus 1176:
1.53 markus 1177: for (;;) {
1178: if ((name = match_list(preferred, supported, &next)) == NULL) {
1179: debug("no more auth methods to try");
1180: current = NULL;
1181: return NULL;
1182: }
1183: preferred += next;
1.23 markus 1184: debug3("authmethod_lookup %s", name);
1.53 markus 1185: debug3("remaining preferred: %s", preferred);
1186: if ((current = authmethod_lookup(name)) != NULL &&
1187: authmethod_is_enabled(current)) {
1.23 markus 1188: debug3("authmethod_is_enabled %s", name);
1.53 markus 1189: debug("next auth method to try is %s", name);
1190: return current;
1.23 markus 1191: }
1.1 markus 1192: }
1.53 markus 1193: }
1.1 markus 1194:
1.27 provos 1195:
1.53 markus 1196: #define DELIM ","
1197: char *
1198: authmethods_get(void)
1199: {
1200: Authmethod *method = NULL;
1201: char buf[1024];
1.27 provos 1202:
1.53 markus 1203: buf[0] = '\0';
1204: for (method = authmethods; method->name != NULL; method++) {
1205: if (authmethod_is_enabled(method)) {
1206: if (buf[0] != '\0')
1207: strlcat(buf, DELIM, sizeof buf);
1208: strlcat(buf, method->name, sizeof buf);
1209: }
1210: }
1211: return xstrdup(buf);
1.1 markus 1212: }