/* This file is in the public domain. */ #include #include extern const char *__progname; #include "pp.h" #include "bpp.h" #include "str.h" #include "errf.h" #include "msgs.h" #include "panic.h" #include "config.h" #include "nested.h" #include "escaped.h" #include "interact.h" #include "userauth.h" #include "pkt-util.h" typedef struct kipriv KIPRIV; typedef struct prompt PROMPT; struct prompt { unsigned int flags; #define PF_ECHO 0x00000001 #define PF_REPLIED 0x00000002 STR prompt; STR reply; } ; struct kipriv { CUASTATE *s; int state; #define KIS_USER 1 #define KIS_SERVER 2 PROMPT *prompt; int nprompt; int aprompt; } ; static int uac_kbdinter_canuse(BPP *b __attribute__((__unused__))) { return(!config_bool("no-interaction")); } static unsigned char *uac_kbdinter_start(CUASTATE *s) { KIPRIV *p; unsigned char *opp; p = malloc(sizeof(KIPRIV)); s->algpriv = p; p->s = s; p->state = KIS_SERVER; p->prompt = 0; p->nprompt = 0; p->aprompt = 0; opp = (*s->pkthead)(s); opp = put_string(opp,0,0); opp = put_string(opp,0,0); return(opp); } static int uac_kbdinter_partial(CUASTATE *s __attribute__((__unused__))) { fprintf(errf,"%s: server returned partial success to keyboard-interactive auth\n",__progname); exit(1); } static void clear_prompts(KIPRIV *kp) { PROMPT *p; while (kp->nprompt > 0) { p = &kp->prompt[--kp->nprompt]; free_str(p->prompt); if (p->flags & PF_REPLIED) free_str(p->reply); } } static int uac_kbdinter_run(CUASTATE *s) { BPP *b; KIPRIV *kp; STR name; STR instr; STR lang; unsigned int nprompt; PROMPT *p; STR ps; int echo; int i; unsigned char *opp; const void *rest; int restlen; char *resp; int resplen; NESTED void fail(const void *dataptr, const char *fmt, ...) { va_list ap; va_start(ap,fmt); pp_vfail(b,dataptr,fmt,ap); va_end(ap); } b = s->layer->b; kp = s->algpriv; switch (b->ipkt[0]) { case SSH_MSG_USERAUTH_INFO_REQUEST: switch (kp->state) { default: panic("bad state"); break; case KIS_SERVER: break; case KIS_USER: fprintf(errf,"%s: server didn't wait for keyboard-interactive authorization response\n",__progname); exit(1); break; } parse_packet(b,&pp_fail, PP_IGNORE(1), PP_STRING(&name), PP_STRING(&instr), PP_STRING(&lang), PP_UINT32(&nprompt), PP_REST(&rest,&restlen) ); clear_prompts(kp); if (nprompt > kp->aprompt) { kp->aprompt = nprompt; free(kp->prompt); kp->prompt = malloc(nprompt*sizeof(*kp->prompt)); } kp->nprompt = 0; while (nprompt > 0) { p = &kp->prompt[kp->nprompt]; parse_data(rest,restlen,&fail, PP_STRING(&ps), PP_BOOL(&echo), PP_REST(&rest,&restlen) ); p->flags = echo ? PF_ECHO : 0; p->prompt = ps; kp->nprompt ++; nprompt --; } parse_data(rest,restlen,&fail,PP_ENDSHERE); if (name.len) { print_escaped(stdout,name.data,name.len,name.len); if (name.data[name.len-1] != '\n') printf("\n"); } if (instr.len) { print_escaped(stdout,instr.data,instr.len,instr.len); if (instr.data[instr.len-1] != '\n') printf("\n"); } for (i=0;inprompt;i++) { p = &kp->prompt[i]; get_with_prompt( &resp, &resplen, GWP_DEV_TTY | GWP_ESC_BLK | ((p->flags & PF_ECHO) ? 0 : GWP_NO_ECHO), p->prompt.data, p->prompt.len ); p->reply = blk_to_str(resp,resplen); } opp = &b->opkt[0]; *opp++ = SSH_MSG_USERAUTH_INFO_RESPONSE; opp = put_uint32(opp,kp->nprompt); for (i=0;inprompt;i++) { p = &kp->prompt[i]; opp = put_string(opp,p->reply.data,p->reply.len); } b->oplen = opp - &b->opkt[0]; clear_prompts(kp); return(UA_SEND); break; default: fprintf(errf,"%s: keyboard-interactive authorization error: unexpected message (type %d)\n",__progname,b->ipkt[0]); exit(1); break; } } static int uac_kbdinter_retry(CUASTATE *s __attribute__((__unused__))) { /* * OpenSSH does this. :-( I'm not sure what else to do but write off * keyboard-interactive altogether.... */ return(UA_NEXT); } static void uac_kbdinter_done(CUASTATE *s) { KIPRIV *p; p = s->algpriv; clear_prompts(p); free(p); s->algpriv = 0; } static int uas_kbdinter_canuse(SUASTATE *s __attribute__((__unused__))) { return(0); } static int uas_kbdinter_request(SUASTATE *s, const void *rest, int restlen) { s=s;rest=rest;restlen=restlen; panic("impossible request"); } UAALG uaalg_keyboard_interactive = { "keyboard-interactive", 0, { &uac_kbdinter_canuse, &uac_kbdinter_start, &uac_kbdinter_partial, &uac_kbdinter_run, &uac_kbdinter_retry, &uac_kbdinter_done }, { &uas_kbdinter_canuse, &uas_kbdinter_request, 0 } };