source: trunk/third/openssh/sshconnect2.c @ 19998

Revision 19998, 35.9 KB checked in by zacheiss, 21 years ago (diff)
Be compatible with error code sent by OpenSSH 3.6p1 + GSSAPI patches from a server that offers GSSAPI auth but has no keytab. Report error in verbose mode, and otherwise just proceed to next available auth type.
Line 
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"
26RCSID("$OpenBSD: sshconnect2.c,v 1.107 2002/07/01 19:48:46 markus Exp $");
27
28#include "ssh.h"
29#include "ssh2.h"
30#include "xmalloc.h"
31#include "buffer.h"
32#include "packet.h"
33#include "compat.h"
34#include "bufaux.h"
35#include "cipher.h"
36#include "kex.h"
37#include "myproposal.h"
38#include "sshconnect.h"
39#include "authfile.h"
40#include "dh.h"
41#include "authfd.h"
42#include "log.h"
43#include "readconf.h"
44#include "readpass.h"
45#include "match.h"
46#include "dispatch.h"
47#include "canohost.h"
48#include "msg.h"
49#include "pathnames.h"
50
51#ifdef GSSAPI
52#include "ssh-gss.h"
53#endif
54
55/* import */
56extern char *client_version_string;
57extern char *server_version_string;
58extern Options options;
59
60/*
61 * SSH2 key exchange
62 */
63
64u_char *session_id2 = NULL;
65int session_id2_len = 0;
66
67char *xxx_host;
68struct sockaddr *xxx_hostaddr;
69
70Kex *xxx_kex = NULL;
71
72static int
73verify_host_key_callback(Key *hostkey)
74{
75        if (verify_host_key(xxx_host, xxx_hostaddr, hostkey) == -1)
76                fatal("Host key verification failed.");
77        return 0;
78}
79
80void
81ssh_kex2(char *host, struct sockaddr *hostaddr)
82{
83        Kex *kex;
84#ifdef GSSAPI
85        char *orig, *gss;
86        int len;
87#endif
88
89        xxx_host = host;
90        xxx_hostaddr = hostaddr;
91
92#ifdef GSSAPI
93        /* Add the GSSAPI mechanisms currently supported on this client to
94         * the key exchange algorithm proposal */
95        orig = myproposal[PROPOSAL_KEX_ALGS];
96        gss = ssh_gssapi_mechanisms(0,host);
97        if (gss) {
98           len = strlen(orig)+strlen(gss)+2;
99           myproposal[PROPOSAL_KEX_ALGS]=xmalloc(len);
100           snprintf(myproposal[PROPOSAL_KEX_ALGS],len,"%s,%s",gss,orig);
101        }
102#endif
103
104        if (options.ciphers == (char *)-1) {
105                log("No valid ciphers for protocol version 2 given, using defaults.");
106                options.ciphers = NULL;
107        }
108        if (options.ciphers != NULL) {
109                myproposal[PROPOSAL_ENC_ALGS_CTOS] =
110                myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
111        }
112        myproposal[PROPOSAL_ENC_ALGS_CTOS] =
113            compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]);
114        myproposal[PROPOSAL_ENC_ALGS_STOC] =
115            compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_STOC]);
116        if (options.compression) {
117                myproposal[PROPOSAL_COMP_ALGS_CTOS] =
118                myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib,none";
119        } else {
120                myproposal[PROPOSAL_COMP_ALGS_CTOS] =
121                myproposal[PROPOSAL_COMP_ALGS_STOC] = "none,zlib";
122        }
123        if (options.macs != NULL) {
124                myproposal[PROPOSAL_MAC_ALGS_CTOS] =
125                myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs;
126        }
127        if (options.hostkeyalgorithms != NULL)
128                myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
129                    options.hostkeyalgorithms;
130
131#ifdef GSSAPI
132        /* If we've got GSSAPI algorithms, then we also support the
133         * 'null' hostkey, as a last resort */
134        if (gss) {
135                orig=myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
136                len = strlen(orig)+sizeof(",null");
137                myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]=xmalloc(len);
138                snprintf(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],len,"%s,null",orig); 
139        }
140#endif
141
142        /* start key exchange */
143        kex = kex_setup(myproposal);
144        kex->client_version_string=client_version_string;
145        kex->server_version_string=server_version_string;
146        kex->verify_host_key=&verify_host_key_callback;
147        kex->host=host;
148
149#ifdef GSSAPI
150        kex->options.gss_deleg_creds=options.gss_deleg_creds;
151#endif
152
153        xxx_kex = kex;
154
155        dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
156
157        session_id2 = kex->session_id;
158        session_id2_len = kex->session_id_len;
159
160#ifdef DEBUG_KEXDH
161        /* send 1st encrypted/maced/compressed message */
162        packet_start(SSH2_MSG_IGNORE);
163        packet_put_cstring("markus");
164        packet_send();
165        packet_write_wait();
166#endif
167        debug("done: ssh_kex2.");
168}
169
170/*
171 * Authenticate user
172 */
173
174typedef struct Authctxt Authctxt;
175typedef struct Authmethod Authmethod;
176
177typedef int sign_cb_fn(
178    Authctxt *authctxt, Key *key,
179    u_char **sigp, u_int *lenp, u_char *data, u_int datalen);
180
181struct Authctxt {
182        const char *server_user;
183        const char *local_user;
184        const char *host;
185        const char *service;
186        Authmethod *method;
187        int success;
188        char *authlist;
189        /* pubkey */
190        Key *last_key;
191        sign_cb_fn *last_key_sign;
192        int last_key_hint;
193        AuthenticationConnection *agent;
194        /* hostbased */
195        Sensitive *sensitive;
196        /* kbd-interactive */
197        int info_req_seen;
198        /* generic */
199        void *methoddata;
200};
201struct Authmethod {
202        char    *name;          /* string to compare against server's list */
203        int     (*userauth)(Authctxt *authctxt);
204        int     *enabled;       /* flag in option struct that enables method */
205        int     *batch_flag;    /* flag in option struct that disables method */
206};
207
208void    input_userauth_success(int, u_int32_t, void *);
209void    input_userauth_failure(int, u_int32_t, void *);
210void    input_userauth_banner(int, u_int32_t, void *);
211void    input_userauth_error(int, u_int32_t, void *);
212void    input_userauth_info_req(int, u_int32_t, void *);
213void    input_userauth_pk_ok(int, u_int32_t, void *);
214void    input_userauth_passwd_changereq(int, u_int32_t, void *);
215
216int     userauth_none(Authctxt *);
217int     userauth_pubkey(Authctxt *);
218int     userauth_passwd(Authctxt *);
219int     userauth_kbdint(Authctxt *);
220int     userauth_hostbased(Authctxt *);
221
222#ifdef GSSAPI
223int     userauth_external(Authctxt *authctxt);
224int     userauth_gssapi(Authctxt *authctxt);
225void    input_gssapi_response(int type, u_int32_t plen, void *ctxt);
226void    input_gssapi_token(int type, u_int32_t plen, void *ctxt);
227void    input_gssapi_error(int type, u_int32_t plen, void *ctxt);
228void    input_gssapi_hash(int type, u_int32_t plen, void *ctxt);
229#endif
230
231void    userauth(Authctxt *, char *);
232
233static int sign_and_send_pubkey(Authctxt *, Key *, sign_cb_fn *);
234static void clear_auth_state(Authctxt *);
235
236static Authmethod *authmethod_get(char *authlist);
237static Authmethod *authmethod_lookup(const char *name);
238static char *authmethods_get(void);
239
240Authmethod authmethods[] = {
241#ifdef GSSAPI
242        {"external-keyx",
243                userauth_external,
244                &options.gss_authentication,
245                NULL},
246        {"gssapi",
247                userauth_gssapi,
248                &options.gss_authentication,
249                NULL},
250#endif
251        {"hostbased",
252                userauth_hostbased,
253                &options.hostbased_authentication,
254                NULL},
255        {"publickey",
256                userauth_pubkey,
257                &options.pubkey_authentication,
258                NULL},
259        {"keyboard-interactive",
260                userauth_kbdint,
261                &options.kbd_interactive_authentication,
262                &options.batch_mode},
263        {"password",
264                userauth_passwd,
265                &options.password_authentication,
266                &options.batch_mode},
267        {"none",
268                userauth_none,
269                NULL,
270                NULL},
271        {NULL, NULL, NULL, NULL}
272};
273
274void
275ssh_userauth2(const char *local_user, const char *server_user, char *host,
276    Sensitive *sensitive)
277{
278        Authctxt authctxt;
279        int type;
280
281        if (options.challenge_response_authentication)
282                options.kbd_interactive_authentication = 1;
283
284        debug("send SSH2_MSG_SERVICE_REQUEST");
285        packet_start(SSH2_MSG_SERVICE_REQUEST);
286        packet_put_cstring("ssh-userauth");
287        packet_send();
288        packet_write_wait();
289        type = packet_read();
290        if (type != SSH2_MSG_SERVICE_ACCEPT) {
291                fatal("denied SSH2_MSG_SERVICE_ACCEPT: %d", type);
292        }
293        if (packet_remaining() > 0) {
294                char *reply = packet_get_string(NULL);
295                debug("service_accept: %s", reply);
296                xfree(reply);
297        } else {
298                debug("buggy server: service_accept w/o service");
299        }
300        packet_check_eom();
301        debug("got SSH2_MSG_SERVICE_ACCEPT");
302
303        if (options.preferred_authentications == NULL)
304                options.preferred_authentications = authmethods_get();
305
306        /* setup authentication context */
307        memset(&authctxt, 0, sizeof(authctxt));
308        authctxt.agent = ssh_get_authentication_connection();
309        authctxt.server_user = server_user;
310        authctxt.local_user = local_user;
311        authctxt.host = host;
312        authctxt.service = "ssh-connection";            /* service name */
313        authctxt.success = 0;
314        authctxt.method = authmethod_lookup("none");
315        authctxt.authlist = NULL;
316        authctxt.methoddata = NULL;
317        authctxt.sensitive = sensitive;
318        authctxt.info_req_seen = 0;
319        if (authctxt.method == NULL)
320                fatal("ssh_userauth2: internal error: cannot send userauth none request");
321
322        /* initial userauth request */
323        userauth_none(&authctxt);
324
325        dispatch_init(&input_userauth_error);
326        dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success);
327        dispatch_set(SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure);
328        dispatch_set(SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner);
329        dispatch_run(DISPATCH_BLOCK, &authctxt.success, &authctxt);     /* loop until success */
330
331        if (authctxt.agent != NULL)
332                ssh_close_authentication_connection(authctxt.agent);
333
334        debug("ssh-userauth2 successful: method %s", authctxt.method->name);
335}
336void
337userauth(Authctxt *authctxt, char *authlist)
338{
339        if (authctxt->methoddata!=NULL) {
340                xfree(authctxt->methoddata);
341                authctxt->methoddata=NULL;
342        }
343           
344        if (authlist == NULL) {
345                authlist = authctxt->authlist;
346        } else {
347                if (authctxt->authlist)
348                        xfree(authctxt->authlist);
349                authctxt->authlist = authlist;
350        }
351        for (;;) {
352                Authmethod *method = authmethod_get(authlist);
353                if (method == NULL)
354                        fatal("Permission denied (%s).", authlist);
355                authctxt->method = method;
356                if (method->userauth(authctxt) != 0) {
357                        debug2("we sent a %s packet, wait for reply", method->name);
358                        break;
359                } else {
360                        debug2("we did not send a packet, disable method");
361                        method->enabled = NULL;
362                }
363        }
364}
365
366void
367input_userauth_error(int type, u_int32_t seq, void *ctxt)
368{
369        fatal("input_userauth_error: bad message during authentication: "
370           "type %d", type);
371}
372
373void
374input_userauth_banner(int type, u_int32_t seq, void *ctxt)
375{
376        char *msg, *lang;
377        debug3("input_userauth_banner");
378        msg = packet_get_string(NULL);
379        lang = packet_get_string(NULL);
380        fprintf(stderr, "%s", msg);
381        xfree(msg);
382        xfree(lang);
383}
384
385void
386input_userauth_success(int type, u_int32_t seq, void *ctxt)
387{
388        Authctxt *authctxt = ctxt;
389        if (authctxt == NULL)
390                fatal("input_userauth_success: no authentication context");
391        if (authctxt->authlist)
392                xfree(authctxt->authlist);
393        if (authctxt->methoddata)
394                xfree(authctxt->methoddata);
395        clear_auth_state(authctxt);
396        authctxt->success = 1;                  /* break out */
397}
398
399void
400input_userauth_failure(int type, u_int32_t seq, void *ctxt)
401{
402        Authctxt *authctxt = ctxt;
403        char *authlist = NULL;
404        int partial;
405
406        if (authctxt == NULL)
407                fatal("input_userauth_failure: no authentication context");
408
409        authlist = packet_get_string(NULL);
410        partial = packet_get_char();
411        packet_check_eom();
412
413        if (partial != 0)
414                log("Authenticated with partial success.");
415        debug("authentications that can continue: %s", authlist);
416
417        clear_auth_state(authctxt);
418        userauth(authctxt, authlist);
419}
420void
421input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt)
422{
423        Authctxt *authctxt = ctxt;
424        Key *key = NULL;
425        Buffer b;
426        int pktype, sent = 0;
427        u_int alen, blen;
428        char *pkalg, *fp;
429        u_char *pkblob;
430
431        if (authctxt == NULL)
432                fatal("input_userauth_pk_ok: no authentication context");
433        if (datafellows & SSH_BUG_PKOK) {
434                /* this is similar to SSH_BUG_PKAUTH */
435                debug2("input_userauth_pk_ok: SSH_BUG_PKOK");
436                pkblob = packet_get_string(&blen);
437                buffer_init(&b);
438                buffer_append(&b, pkblob, blen);
439                pkalg = buffer_get_string(&b, &alen);
440                buffer_free(&b);
441        } else {
442                pkalg = packet_get_string(&alen);
443                pkblob = packet_get_string(&blen);
444        }
445        packet_check_eom();
446
447        debug("input_userauth_pk_ok: pkalg %s blen %u lastkey %p hint %d",
448            pkalg, blen, authctxt->last_key, authctxt->last_key_hint);
449
450        do {
451                if (authctxt->last_key == NULL ||
452                    authctxt->last_key_sign == NULL) {
453                        debug("no last key or no sign cb");
454                        break;
455                }
456                if ((pktype = key_type_from_name(pkalg)) == KEY_UNSPEC) {
457                        debug("unknown pkalg %s", pkalg);
458                        break;
459                }
460                if ((key = key_from_blob(pkblob, blen)) == NULL) {
461                        debug("no key from blob. pkalg %s", pkalg);
462                        break;
463                }
464                if (key->type != pktype) {
465                        error("input_userauth_pk_ok: type mismatch "
466                            "for decoded key (received %d, expected %d)",
467                            key->type, pktype);
468                        break;
469                }
470                fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
471                debug2("input_userauth_pk_ok: fp %s", fp);
472                xfree(fp);
473                if (!key_equal(key, authctxt->last_key)) {
474                        debug("key != last_key");
475                        break;
476                }
477                sent = sign_and_send_pubkey(authctxt, key,
478                   authctxt->last_key_sign);
479        } while (0);
480
481        if (key != NULL)
482                key_free(key);
483        xfree(pkalg);
484        xfree(pkblob);
485
486        /* unregister */
487        clear_auth_state(authctxt);
488        dispatch_set(SSH2_MSG_USERAUTH_PK_OK, NULL);
489
490        /* try another method if we did not send a packet */
491        if (sent == 0)
492                userauth(authctxt, NULL);
493
494}
495
496#ifdef GSSAPI
497int
498userauth_gssapi(Authctxt *authctxt)
499{
500        int i;
501        Gssctxt *gssctxt;
502        static int tries=0;
503
504        /* For now, we only make one attempt at this. We could try offering
505         * the server different GSSAPI OIDs until we get bored, I suppose.
506         */     
507        if (tries++>0) return 0;
508
509        if (datafellows & SSH_OLD_GSSAPI) return 0;
510       
511        /* Initialise as much of our context as we can, so failures can be
512         * trapped before sending any packets.
513         */
514        ssh_gssapi_build_ctx(&gssctxt);
515
516        if (ssh_gssapi_import_name(gssctxt,authctxt->host)) {
517                return(0);
518        }
519       
520        authctxt->methoddata=(void *)gssctxt;
521               
522        packet_start(SSH2_MSG_USERAUTH_REQUEST);
523        packet_put_cstring(authctxt->server_user);
524        packet_put_cstring(authctxt->service);
525        packet_put_cstring(authctxt->method->name);
526
527        /* FIXME: This assumes that our current GSSAPI implementation
528         * supports all of the mechanisms listed in supported_mechs.
529         * This may not be the case - we should use something along
530         * the lines of the code in gss_genr to remove the ones that
531         * aren't supported */
532        packet_put_int(GSS_LAST_ENTRY);
533        for (i=0;i<GSS_LAST_ENTRY;i++) {
534                packet_put_string(supported_mechs[i].oid.elements,
535                                  supported_mechs[i].oid.length);
536        }
537        packet_send();
538        packet_write_wait();
539
540        dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE,&input_gssapi_response);
541        dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,&input_gssapi_token);
542        dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERROR, &input_gssapi_error);
543       
544        return 1;
545}
546
547void
548input_gssapi_response(int type, u_int32_t plen, void *ctxt)
549{
550        Authctxt *authctxt = ctxt;
551        Gssctxt *gssctxt;
552        OM_uint32 status,ms;
553        int oidlen;
554        char *oidv;
555        gss_buffer_desc send_tok;
556       
557        if (authctxt == NULL)
558                fatal("input_gssapi_response: no authentication context");
559        gssctxt = authctxt->methoddata;
560       
561        /* Setup our OID */
562        oidv=packet_get_string(&oidlen);
563        ssh_gssapi_set_oid_data(gssctxt,oidv,oidlen);
564       
565        packet_check_eom();
566       
567        status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
568                                     GSS_C_NO_BUFFER, &send_tok,
569                                     NULL);
570        if (GSS_ERROR(status)) {
571                /* Start again with next method on list */
572                debug("Trying to start again");
573                userauth(authctxt,NULL);
574                return;
575        }
576
577        /* We must have data to send */                                 
578        packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
579        packet_put_string(send_tok.value,send_tok.length);
580        packet_send();
581        packet_write_wait();
582        gss_release_buffer(&ms, &send_tok);
583}
584
585void
586input_gssapi_token(int type, u_int32_t plen, void *ctxt)
587{
588        Authctxt *authctxt = ctxt;
589        Gssctxt *gssctxt;
590        gss_buffer_desc send_tok,recv_tok;
591        OM_uint32 status;
592       
593        if (authctxt == NULL)
594                fatal("input_gssapi_response: no authentication context");
595        gssctxt = authctxt->methoddata;
596       
597        recv_tok.value=packet_get_string(&recv_tok.length);
598
599        status=ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
600                                   &recv_tok, &send_tok, NULL);
601
602        packet_check_eom();
603       
604        if (GSS_ERROR(status)) {
605                /* Start again with the next method in the list */
606                userauth(authctxt,NULL);
607                return;
608        }
609       
610        if (send_tok.length>0) {
611                packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
612                packet_put_string(send_tok.value,send_tok.length);
613                packet_send();
614                packet_write_wait();
615        }
616       
617        if (status == GSS_S_COMPLETE) {
618                /* If that succeeded, send a exchange complete message */
619                packet_start(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE);
620                packet_send();
621                packet_write_wait();
622        }
623}
624
625void
626input_gssapi_error(int type, u_int32_t plen, void *ctxt)
627{
628        OM_uint32 maj,min;
629        char *msg;
630        char *lang;
631
632        maj=packet_get_int();
633        min=packet_get_int();
634        msg=packet_get_string(NULL);
635        lang=packet_get_string(NULL);
636
637        packet_check_eom();
638
639        verbose("Server GSSAPI Error: %s", msg);
640        xfree(msg);
641        xfree(lang);
642}
643
644int
645userauth_external(Authctxt *authctxt)
646{
647        static int attempt =0;
648       
649        if (attempt++ >= 1)
650                return 0;
651                               
652        debug2("userauth_external");
653        packet_start(SSH2_MSG_USERAUTH_REQUEST);
654        packet_put_cstring(authctxt->server_user);
655        packet_put_cstring(authctxt->service);
656        packet_put_cstring(authctxt->method->name);
657        packet_send();
658        packet_write_wait();
659        return 1;
660}                                                                                               
661#endif /* GSSAPI */
662
663int
664userauth_none(Authctxt *authctxt)
665{
666        /* initial userauth request */
667        packet_start(SSH2_MSG_USERAUTH_REQUEST);
668        packet_put_cstring(authctxt->server_user);
669        packet_put_cstring(authctxt->service);
670        packet_put_cstring(authctxt->method->name);
671        packet_send();
672        return 1;
673
674}
675
676int
677userauth_passwd(Authctxt *authctxt)
678{
679        static int attempt = 0;
680        char prompt[150];
681        char *password;
682
683        if (attempt++ >= options.number_of_password_prompts)
684                return 0;
685
686        if (attempt != 1)
687                error("Permission denied, please try again.");
688
689        snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ",
690            authctxt->server_user, authctxt->host);
691        password = read_passphrase(prompt, 0);
692        packet_start(SSH2_MSG_USERAUTH_REQUEST);
693        packet_put_cstring(authctxt->server_user);
694        packet_put_cstring(authctxt->service);
695        packet_put_cstring(authctxt->method->name);
696        packet_put_char(0);
697        packet_put_cstring(password);
698        memset(password, 0, strlen(password));
699        xfree(password);
700        packet_add_padding(64);
701        packet_send();
702
703        dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ,
704            &input_userauth_passwd_changereq);
705
706        return 1;
707}
708/*
709 * parse PASSWD_CHANGEREQ, prompt user and send SSH2_MSG_USERAUTH_REQUEST
710 */
711void
712input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt)
713{
714        Authctxt *authctxt = ctxt;
715        char *info, *lang, *password = NULL, *retype = NULL;
716        char prompt[150];
717
718        debug2("input_userauth_passwd_changereq");
719
720        if (authctxt == NULL)
721                fatal("input_userauth_passwd_changereq: "
722                    "no authentication context");
723
724        info = packet_get_string(NULL);
725        lang = packet_get_string(NULL);
726        if (strlen(info) > 0)
727                log("%s", info);
728        xfree(info);
729        xfree(lang);
730        packet_start(SSH2_MSG_USERAUTH_REQUEST);
731        packet_put_cstring(authctxt->server_user);
732        packet_put_cstring(authctxt->service);
733        packet_put_cstring(authctxt->method->name);
734        packet_put_char(1);                     /* additional info */
735        snprintf(prompt, sizeof(prompt),
736            "Enter %.30s@%.128s's old password: ",
737            authctxt->server_user, authctxt->host);
738        password = read_passphrase(prompt, 0);
739        packet_put_cstring(password);
740        memset(password, 0, strlen(password));
741        xfree(password);
742        password = NULL;
743        while (password == NULL) {
744                snprintf(prompt, sizeof(prompt),
745                    "Enter %.30s@%.128s's new password: ",
746                    authctxt->server_user, authctxt->host);
747                password = read_passphrase(prompt, RP_ALLOW_EOF);
748                if (password == NULL) {
749                        /* bail out */
750                        return;
751                }
752                snprintf(prompt, sizeof(prompt),
753                    "Retype %.30s@%.128s's new password: ",
754                    authctxt->server_user, authctxt->host);
755                retype = read_passphrase(prompt, 0);
756                if (strcmp(password, retype) != 0) {
757                        memset(password, 0, strlen(password));
758                        xfree(password);
759                        log("Mismatch; try again, EOF to quit.");
760                        password = NULL;
761                }
762                memset(retype, 0, strlen(retype));
763                xfree(retype);
764        }
765        packet_put_cstring(password);
766        memset(password, 0, strlen(password));
767        xfree(password);
768        packet_add_padding(64);
769        packet_send();
770
771        dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ,
772            &input_userauth_passwd_changereq);
773}
774
775static void
776clear_auth_state(Authctxt *authctxt)
777{
778        /* XXX clear authentication state */
779        dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, NULL);
780
781        if (authctxt->last_key != NULL && authctxt->last_key_hint == -1) {
782                debug3("clear_auth_state: key_free %p", authctxt->last_key);
783                key_free(authctxt->last_key);
784        }
785        authctxt->last_key = NULL;
786        authctxt->last_key_hint = -2;
787        authctxt->last_key_sign = NULL;
788}
789
790static int
791sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
792{
793        Buffer b;
794        u_char *blob, *signature;
795        u_int bloblen, slen;
796        int skip = 0;
797        int ret = -1;
798        int have_sig = 1;
799
800        debug3("sign_and_send_pubkey");
801
802        if (key_to_blob(k, &blob, &bloblen) == 0) {
803                /* we cannot handle this key */
804                debug3("sign_and_send_pubkey: cannot handle key");
805                return 0;
806        }
807        /* data to be signed */
808        buffer_init(&b);
809        if (datafellows & SSH_OLD_SESSIONID) {
810                buffer_append(&b, session_id2, session_id2_len);
811                skip = session_id2_len;
812        } else {
813                buffer_put_string(&b, session_id2, session_id2_len);
814                skip = buffer_len(&b);
815        }
816        buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
817        buffer_put_cstring(&b, authctxt->server_user);
818        buffer_put_cstring(&b,
819            datafellows & SSH_BUG_PKSERVICE ?
820            "ssh-userauth" :
821            authctxt->service);
822        if (datafellows & SSH_BUG_PKAUTH) {
823                buffer_put_char(&b, have_sig);
824        } else {
825                buffer_put_cstring(&b, authctxt->method->name);
826                buffer_put_char(&b, have_sig);
827                buffer_put_cstring(&b, key_ssh_name(k));
828        }
829        buffer_put_string(&b, blob, bloblen);
830
831        /* generate signature */
832        ret = (*sign_callback)(authctxt, k, &signature, &slen,
833            buffer_ptr(&b), buffer_len(&b));
834        if (ret == -1) {
835                xfree(blob);
836                buffer_free(&b);
837                return 0;
838        }
839#ifdef DEBUG_PK
840        buffer_dump(&b);
841#endif
842        if (datafellows & SSH_BUG_PKSERVICE) {
843                buffer_clear(&b);
844                buffer_append(&b, session_id2, session_id2_len);
845                skip = session_id2_len;
846                buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
847                buffer_put_cstring(&b, authctxt->server_user);
848                buffer_put_cstring(&b, authctxt->service);
849                buffer_put_cstring(&b, authctxt->method->name);
850                buffer_put_char(&b, have_sig);
851                if (!(datafellows & SSH_BUG_PKAUTH))
852                        buffer_put_cstring(&b, key_ssh_name(k));
853                buffer_put_string(&b, blob, bloblen);
854        }
855        xfree(blob);
856
857        /* append signature */
858        buffer_put_string(&b, signature, slen);
859        xfree(signature);
860
861        /* skip session id and packet type */
862        if (buffer_len(&b) < skip + 1)
863                fatal("userauth_pubkey: internal error");
864        buffer_consume(&b, skip + 1);
865
866        /* put remaining data from buffer into packet */
867        packet_start(SSH2_MSG_USERAUTH_REQUEST);
868        packet_put_raw(buffer_ptr(&b), buffer_len(&b));
869        buffer_free(&b);
870        packet_send();
871
872        return 1;
873}
874
875static int
876send_pubkey_test(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback,
877    int hint)
878{
879        u_char *blob;
880        u_int bloblen, have_sig = 0;
881
882        debug3("send_pubkey_test");
883
884        if (key_to_blob(k, &blob, &bloblen) == 0) {
885                /* we cannot handle this key */
886                debug3("send_pubkey_test: cannot handle key");
887                return 0;
888        }
889        /* register callback for USERAUTH_PK_OK message */
890        authctxt->last_key_sign = sign_callback;
891        authctxt->last_key_hint = hint;
892        authctxt->last_key = k;
893        dispatch_set(SSH2_MSG_USERAUTH_PK_OK, &input_userauth_pk_ok);
894
895        packet_start(SSH2_MSG_USERAUTH_REQUEST);
896        packet_put_cstring(authctxt->server_user);
897        packet_put_cstring(authctxt->service);
898        packet_put_cstring(authctxt->method->name);
899        packet_put_char(have_sig);
900        if (!(datafellows & SSH_BUG_PKAUTH))
901                packet_put_cstring(key_ssh_name(k));
902        packet_put_string(blob, bloblen);
903        xfree(blob);
904        packet_send();
905        return 1;
906}
907
908static Key *
909load_identity_file(char *filename)
910{
911        Key *private;
912        char prompt[300], *passphrase;
913        int quit, i;
914        struct stat st;
915
916        if (stat(filename, &st) < 0) {
917                debug3("no such identity: %s", filename);
918                return NULL;
919        }
920        private = key_load_private_type(KEY_UNSPEC, filename, "", NULL);
921        if (private == NULL) {
922                if (options.batch_mode)
923                        return NULL;
924                snprintf(prompt, sizeof prompt,
925                    "Enter passphrase for key '%.100s': ", filename);
926                for (i = 0; i < options.number_of_password_prompts; i++) {
927                        passphrase = read_passphrase(prompt, 0);
928                        if (strcmp(passphrase, "") != 0) {
929                                private = key_load_private_type(KEY_UNSPEC, filename,
930                                    passphrase, NULL);
931                                quit = 0;
932                        } else {
933                                debug2("no passphrase given, try next key");
934                                quit = 1;
935                        }
936                        memset(passphrase, 0, strlen(passphrase));
937                        xfree(passphrase);
938                        if (private != NULL || quit)
939                                break;
940                        debug2("bad passphrase given, try again...");
941                }
942        }
943        return private;
944}
945
946static int
947identity_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp,
948    u_char *data, u_int datalen)
949{
950        Key *private;
951        int idx, ret;
952
953        idx = authctxt->last_key_hint;
954        if (idx < 0)
955                return -1;
956
957        /* private key is stored in external hardware */
958        if (options.identity_keys[idx]->flags & KEY_FLAG_EXT)
959                return key_sign(options.identity_keys[idx], sigp, lenp, data, datalen);
960
961        private = load_identity_file(options.identity_files[idx]);
962        if (private == NULL)
963                return -1;
964        ret = key_sign(private, sigp, lenp, data, datalen);
965        key_free(private);
966        return ret;
967}
968
969static int
970agent_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp,
971    u_char *data, u_int datalen)
972{
973        return ssh_agent_sign(authctxt->agent, key, sigp, lenp, data, datalen);
974}
975
976static int
977key_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp,
978    u_char *data, u_int datalen)
979{
980        return key_sign(key, sigp, lenp, data, datalen);
981}
982
983static int
984userauth_pubkey_agent(Authctxt *authctxt)
985{
986        static int called = 0;
987        int ret = 0;
988        char *comment;
989        Key *k;
990
991        if (called == 0) {
992                if (ssh_get_num_identities(authctxt->agent, 2) == 0)
993                        debug2("userauth_pubkey_agent: no keys at all");
994                called = 1;
995        }
996        k = ssh_get_next_identity(authctxt->agent, &comment, 2);
997        if (k == NULL) {
998                debug2("userauth_pubkey_agent: no more keys");
999        } else {
1000                debug("userauth_pubkey_agent: testing agent key %s", comment);
1001                xfree(comment);
1002                ret = send_pubkey_test(authctxt, k, agent_sign_cb, -1);
1003                if (ret == 0)
1004                        key_free(k);
1005        }
1006        if (ret == 0)
1007                debug2("userauth_pubkey_agent: no message sent");
1008        return ret;
1009}
1010
1011int
1012userauth_pubkey(Authctxt *authctxt)
1013{
1014        static int idx = 0;
1015        int sent = 0;
1016        Key *key;
1017        char *filename;
1018
1019        if (authctxt->agent != NULL) {
1020                do {
1021                        sent = userauth_pubkey_agent(authctxt);
1022                } while (!sent && authctxt->agent->howmany > 0);
1023        }
1024        while (!sent && idx < options.num_identity_files) {
1025                key = options.identity_keys[idx];
1026                filename = options.identity_files[idx];
1027                if (key == NULL) {
1028                        debug("try privkey: %s", filename);
1029                        key = load_identity_file(filename);
1030                        if (key != NULL) {
1031                                sent = sign_and_send_pubkey(authctxt, key,
1032                                    key_sign_cb);
1033                                key_free(key);
1034                        }
1035                } else if (key->type != KEY_RSA1) {
1036                        debug("try pubkey: %s", filename);
1037                        sent = send_pubkey_test(authctxt, key,
1038                            identity_sign_cb, idx);
1039                }
1040                idx++;
1041        }
1042        return sent;
1043}
1044
1045/*
1046 * Send userauth request message specifying keyboard-interactive method.
1047 */
1048int
1049userauth_kbdint(Authctxt *authctxt)
1050{
1051        static int attempt = 0;
1052
1053        if (attempt++ >= options.number_of_password_prompts)
1054                return 0;
1055        /* disable if no SSH2_MSG_USERAUTH_INFO_REQUEST has been seen */
1056        if (attempt > 1 && !authctxt->info_req_seen) {
1057                debug3("userauth_kbdint: disable: no info_req_seen");
1058                dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, NULL);
1059                return 0;
1060        }
1061
1062        debug2("userauth_kbdint");
1063        packet_start(SSH2_MSG_USERAUTH_REQUEST);
1064        packet_put_cstring(authctxt->server_user);
1065        packet_put_cstring(authctxt->service);
1066        packet_put_cstring(authctxt->method->name);
1067        packet_put_cstring("");                                 /* lang */
1068        packet_put_cstring(options.kbd_interactive_devices ?
1069            options.kbd_interactive_devices : "");
1070        packet_send();
1071
1072        dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_info_req);
1073        return 1;
1074}
1075
1076/*
1077 * parse INFO_REQUEST, prompt user and send INFO_RESPONSE
1078 */
1079void
1080input_userauth_info_req(int type, u_int32_t seq, void *ctxt)
1081{
1082        Authctxt *authctxt = ctxt;
1083        char *name, *inst, *lang, *prompt, *response;
1084        u_int num_prompts, i;
1085        int echo = 0;
1086
1087        debug2("input_userauth_info_req");
1088
1089        if (authctxt == NULL)
1090                fatal("input_userauth_info_req: no authentication context");
1091
1092        authctxt->info_req_seen = 1;
1093
1094        name = packet_get_string(NULL);
1095        inst = packet_get_string(NULL);
1096        lang = packet_get_string(NULL);
1097        if (strlen(name) > 0)
1098                log("%s", name);
1099        if (strlen(inst) > 0)
1100                log("%s", inst);
1101        xfree(name);
1102        xfree(inst);
1103        xfree(lang);
1104
1105        num_prompts = packet_get_int();
1106        /*
1107         * Begin to build info response packet based on prompts requested.
1108         * We commit to providing the correct number of responses, so if
1109         * further on we run into a problem that prevents this, we have to
1110         * be sure and clean this up and send a correct error response.
1111         */
1112        packet_start(SSH2_MSG_USERAUTH_INFO_RESPONSE);
1113        packet_put_int(num_prompts);
1114
1115        debug2("input_userauth_info_req: num_prompts %d", num_prompts);
1116        for (i = 0; i < num_prompts; i++) {
1117                prompt = packet_get_string(NULL);
1118                echo = packet_get_char();
1119
1120                response = read_passphrase(prompt, echo ? RP_ECHO : 0);
1121
1122                packet_put_cstring(response);
1123                memset(response, 0, strlen(response));
1124                xfree(response);
1125                xfree(prompt);
1126        }
1127        packet_check_eom(); /* done with parsing incoming message. */
1128
1129        packet_add_padding(64);
1130        packet_send();
1131}
1132
1133static int
1134ssh_keysign(Key *key, u_char **sigp, u_int *lenp,
1135    u_char *data, u_int datalen)
1136{
1137        Buffer b;
1138        struct stat st;
1139        pid_t pid;
1140        int to[2], from[2], status, version = 2;
1141
1142        debug("ssh_keysign called");
1143
1144        if (stat(_PATH_SSH_KEY_SIGN, &st) < 0) {
1145                error("ssh_keysign: no installed: %s", strerror(errno));
1146                return -1;
1147        }
1148        if (fflush(stdout) != 0)
1149                error("ssh_keysign: fflush: %s", strerror(errno));
1150        if (pipe(to) < 0) {
1151                error("ssh_keysign: pipe: %s", strerror(errno));
1152                return -1;
1153        }
1154        if (pipe(from) < 0) {
1155                error("ssh_keysign: pipe: %s", strerror(errno));
1156                return -1;
1157        }
1158        if ((pid = fork()) < 0) {
1159                error("ssh_keysign: fork: %s", strerror(errno));
1160                return -1;
1161        }
1162        if (pid == 0) {
1163                seteuid(getuid());
1164                setuid(getuid());
1165                close(from[0]);
1166                if (dup2(from[1], STDOUT_FILENO) < 0)
1167                        fatal("ssh_keysign: dup2: %s", strerror(errno));
1168                close(to[1]);
1169                if (dup2(to[0], STDIN_FILENO) < 0)
1170                        fatal("ssh_keysign: dup2: %s", strerror(errno));
1171                close(from[1]);
1172                close(to[0]);
1173                execl(_PATH_SSH_KEY_SIGN, _PATH_SSH_KEY_SIGN, (char *) 0);
1174                fatal("ssh_keysign: exec(%s): %s", _PATH_SSH_KEY_SIGN,
1175                    strerror(errno));
1176        }
1177        close(from[1]);
1178        close(to[0]);
1179
1180        buffer_init(&b);
1181        buffer_put_int(&b, packet_get_connection_in()); /* send # of socket */
1182        buffer_put_string(&b, data, datalen);
1183        ssh_msg_send(to[1], version, &b);
1184
1185        if (ssh_msg_recv(from[0], &b) < 0) {
1186                error("ssh_keysign: no reply");
1187                buffer_clear(&b);
1188                return -1;
1189        }
1190        close(from[0]);
1191        close(to[1]);
1192
1193        while (waitpid(pid, &status, 0) < 0)
1194                if (errno != EINTR)
1195                        break;
1196
1197        if (buffer_get_char(&b) != version) {
1198                error("ssh_keysign: bad version");
1199                buffer_clear(&b);
1200                return -1;
1201        }
1202        *sigp = buffer_get_string(&b, lenp);
1203        buffer_clear(&b);
1204
1205        return 0;
1206}
1207
1208int
1209userauth_hostbased(Authctxt *authctxt)
1210{
1211        Key *private = NULL;
1212        Sensitive *sensitive = authctxt->sensitive;
1213        Buffer b;
1214        u_char *signature, *blob;
1215        char *chost, *pkalg, *p;
1216        const char *service;
1217        u_int blen, slen;
1218        int ok, i, len, found = 0;
1219
1220        /* check for a useful key */
1221        for (i = 0; i < sensitive->nkeys; i++) {
1222                private = sensitive->keys[i];
1223                if (private && private->type != KEY_RSA1) {
1224                        found = 1;
1225                        /* we take and free the key */
1226                        sensitive->keys[i] = NULL;
1227                        break;
1228                }
1229        }
1230        if (!found) {
1231                debug("userauth_hostbased: no more client hostkeys");
1232                return 0;
1233        }
1234        if (key_to_blob(private, &blob, &blen) == 0) {
1235                key_free(private);
1236                return 0;
1237        }
1238        /* figure out a name for the client host */
1239        p = get_local_name(packet_get_connection_in());
1240        if (p == NULL) {
1241                error("userauth_hostbased: cannot get local ipaddr/name");
1242                key_free(private);
1243                return 0;
1244        }
1245        len = strlen(p) + 2;
1246        chost = xmalloc(len);
1247        strlcpy(chost, p, len);
1248        strlcat(chost, ".", len);
1249        debug2("userauth_hostbased: chost %s", chost);
1250
1251        service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" :
1252            authctxt->service;
1253        pkalg = xstrdup(key_ssh_name(private));
1254        buffer_init(&b);
1255        /* construct data */
1256        buffer_put_string(&b, session_id2, session_id2_len);
1257        buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
1258        buffer_put_cstring(&b, authctxt->server_user);
1259        buffer_put_cstring(&b, service);
1260        buffer_put_cstring(&b, authctxt->method->name);
1261        buffer_put_cstring(&b, pkalg);
1262        buffer_put_string(&b, blob, blen);
1263        buffer_put_cstring(&b, chost);
1264        buffer_put_cstring(&b, authctxt->local_user);
1265#ifdef DEBUG_PK
1266        buffer_dump(&b);
1267#endif
1268        if (sensitive->external_keysign)
1269                ok = ssh_keysign(private, &signature, &slen,
1270                    buffer_ptr(&b), buffer_len(&b));
1271        else
1272                ok = key_sign(private, &signature, &slen,
1273                    buffer_ptr(&b), buffer_len(&b));
1274        key_free(private);
1275        buffer_free(&b);
1276        if (ok != 0) {
1277                error("key_sign failed");
1278                xfree(chost);
1279                xfree(pkalg);
1280                return 0;
1281        }
1282        packet_start(SSH2_MSG_USERAUTH_REQUEST);
1283        packet_put_cstring(authctxt->server_user);
1284        packet_put_cstring(authctxt->service);
1285        packet_put_cstring(authctxt->method->name);
1286        packet_put_cstring(pkalg);
1287        packet_put_string(blob, blen);
1288        packet_put_cstring(chost);
1289        packet_put_cstring(authctxt->local_user);
1290        packet_put_string(signature, slen);
1291        memset(signature, 's', slen);
1292        xfree(signature);
1293        xfree(chost);
1294        xfree(pkalg);
1295
1296        packet_send();
1297        return 1;
1298}
1299
1300/* find auth method */
1301
1302/*
1303 * given auth method name, if configurable options permit this method fill
1304 * in auth_ident field and return true, otherwise return false.
1305 */
1306static int
1307authmethod_is_enabled(Authmethod *method)
1308{
1309        if (method == NULL)
1310                return 0;
1311        /* return false if options indicate this method is disabled */
1312        if  (method->enabled == NULL || *method->enabled == 0)
1313                return 0;
1314        /* return false if batch mode is enabled but method needs interactive mode */
1315        if  (method->batch_flag != NULL && *method->batch_flag != 0)
1316                return 0;
1317        return 1;
1318}
1319
1320static Authmethod *
1321authmethod_lookup(const char *name)
1322{
1323        Authmethod *method = NULL;
1324        if (name != NULL)
1325                for (method = authmethods; method->name != NULL; method++)
1326                        if (strcmp(name, method->name) == 0)
1327                                return method;
1328        debug2("Unrecognized authentication method name: %s", name ? name : "NULL");
1329        return NULL;
1330}
1331
1332/* XXX internal state */
1333static Authmethod *current = NULL;
1334static char *supported = NULL;
1335static char *preferred = NULL;
1336
1337/*
1338 * Given the authentication method list sent by the server, return the
1339 * next method we should try.  If the server initially sends a nil list,
1340 * use a built-in default list.
1341 */
1342static Authmethod *
1343authmethod_get(char *authlist)
1344{
1345
1346        char *name = NULL;
1347        u_int next;
1348
1349        /* Use a suitable default if we're passed a nil list.  */
1350        if (authlist == NULL || strlen(authlist) == 0)
1351                authlist = options.preferred_authentications;
1352
1353        if (supported == NULL || strcmp(authlist, supported) != 0) {
1354                debug3("start over, passed a different list %s", authlist);
1355                if (supported != NULL)
1356                        xfree(supported);
1357                supported = xstrdup(authlist);
1358                preferred = options.preferred_authentications;
1359                debug3("preferred %s", preferred);
1360                current = NULL;
1361        } else if (current != NULL && authmethod_is_enabled(current))
1362                return current;
1363
1364        for (;;) {
1365                if ((name = match_list(preferred, supported, &next)) == NULL) {
1366                        debug("no more auth methods to try");
1367                        current = NULL;
1368                        return NULL;
1369                }
1370                preferred += next;
1371                debug3("authmethod_lookup %s", name);
1372                debug3("remaining preferred: %s", preferred);
1373                if ((current = authmethod_lookup(name)) != NULL &&
1374                    authmethod_is_enabled(current)) {
1375                        debug3("authmethod_is_enabled %s", name);
1376                        debug("next auth method to try is %s", name);
1377                        return current;
1378                }
1379        }
1380}
1381
1382static char *
1383authmethods_get(void)
1384{
1385        Authmethod *method = NULL;
1386        Buffer b;
1387        char *list;
1388
1389        buffer_init(&b);
1390        for (method = authmethods; method->name != NULL; method++) {
1391                if (authmethod_is_enabled(method)) {
1392                        if (buffer_len(&b) > 0)
1393                                buffer_append(&b, ",", 1);
1394                        buffer_append(&b, method->name, strlen(method->name));
1395                }
1396        }
1397        buffer_append(&b, "\0", 1);
1398        list = xstrdup(buffer_ptr(&b));
1399        buffer_free(&b);
1400        return list;
1401}
Note: See TracBrowser for help on using the repository browser.