static int match_principals_file(char *file, struct passwd *pw, struct sshkey_cert *cert) { FILE *f; char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts; u_long linenum = 0; u_int i; temporarily_use_uid(pw); debug("trying authorized principals file %s", file); if ((f = auth_openprincipals(file, pw, options.strict_modes)) == NULL) { restore_uid(); return 0; } while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { /* Skip leading whitespace. */ for (cp = line; *cp == ' ' || *cp == '\t'; cp++) ; /* Skip blank and comment lines. */ if ((ep = strchr(cp, '#')) != NULL) *ep = '\0'; if (!*cp || *cp == '\n') continue; /* Trim trailing whitespace. */ ep = cp + strlen(cp) - 1; while (ep > cp && (*ep == '\n' || *ep == ' ' || *ep == '\t')) *ep-- = '\0'; /* * If the line has internal whitespace then assume it has * key options. */ line_opts = NULL; if ((ep = strrchr(cp, ' ')) != NULL || (ep = strrchr(cp, '\t')) != NULL) { for (; *ep == ' ' || *ep == '\t'; ep++) ; line_opts = cp; cp = ep; } for (i = 0; i < cert->nprincipals; i++) { if (strcmp(cp, cert->principals[i]) == 0) { debug3("matched principal \"%.100s\" " "from file \"%s\" on line %lu", cert->principals[i], file, linenum); if (auth_parse_options(pw, line_opts, file, linenum) != 1) continue; fclose(f); restore_uid(); return 1; } } } fclose(f); restore_uid(); return 0; }
static int process_principals(FILE *f, char *file, struct passwd *pw, const struct sshkey_cert *cert) { char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts; u_long linenum = 0; u_int i, found_principal = 0; while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { /* Always consume entire input */ if (found_principal) continue; /* Skip leading whitespace. */ for (cp = line; *cp == ' ' || *cp == '\t'; cp++) ; /* Skip blank and comment lines. */ if ((ep = strchr(cp, '#')) != NULL) *ep = '\0'; if (!*cp || *cp == '\n') continue; /* Trim trailing whitespace. */ ep = cp + strlen(cp) - 1; while (ep > cp && (*ep == '\n' || *ep == ' ' || *ep == '\t')) *ep-- = '\0'; /* * If the line has internal whitespace then assume it has * key options. */ line_opts = NULL; if ((ep = strrchr(cp, ' ')) != NULL || (ep = strrchr(cp, '\t')) != NULL) { for (; *ep == ' ' || *ep == '\t'; ep++) ; line_opts = cp; cp = ep; } for (i = 0; i < cert->nprincipals; i++) { if (strcmp(cp, cert->principals[i]) == 0) { debug3("%s:%lu: matched principal \"%.100s\"", file == NULL ? "(command)" : file, linenum, cert->principals[i]); if (auth_parse_options(pw, line_opts, file, linenum) != 1) continue; found_principal = 1; continue; } } } return found_principal; }
/* check to see if the script specified by file can authorize the key * * the script will have the key written to STDIN, which is identical * to the normal public key format. * * the script must exit with either 0 for success or 1 for failure. * the script can print login options (if any) to STDOUT. No whitepace should be added * to the output. * * Use with caution: the script can hang sshd. It is recommended you code the script * with a timeout set if it cannot determine authenication quickly. */ static int user_key_found_by_script(struct passwd *pw, Key *key, char *file) { pid_t pid; char line[SSH_MAX_PUBKEY_BYTES]; int pipe_in[2]; int pipe_out[2]; int exit_code = 1; int success = 0; FILE *f; //mysig_t oldsig; pipe(pipe_in); pipe(pipe_out); //oldsig = signal(SIGCHLD, SIG_IGN); temporarily_use_uid(pw); debug3("user_key_found_by_script: executing %s", file); switch ((pid = fork())) { case -1: error("fork(): %s", strerror(errno)); restore_uid(); return (-1); case 0: /* setup input pipe */ close(pipe_in[1]); dup2(pipe_in[0], 0); close(pipe_in[0]); /* setup output pipe */ close(pipe_out[0]); dup2(pipe_out[1], 1); close(pipe_out[1]); execl(file, file, NULL); /* exec failed */ error("execl(): %s", strerror(errno)); _exit(1); default: debug3("user_key_found_by_script: script pid %d", pid); close(pipe_in[0]); close(pipe_out[1]); f = fdopen(pipe_in[1], "w"); key_write(key, f); fclose(f); while(waitpid(pid, &exit_code, 0) < 0) { switch(errno) { case EINTR: debug3("user_key_found_by_script: waitpid() EINTR, continuing"); continue; default: error("waitpid(): %s", strerror(errno)); goto waitpid_error; } } if (WIFEXITED(exit_code) && WEXITSTATUS(exit_code) == 0) { int amt_read = read(pipe_out[0], line, sizeof(line) - 1); line[amt_read] = ' '; line[amt_read + 1] = 0; debug3("user_key_found_by_script: options: %s", line); if (auth_parse_options(pw, line, file, 0) == 1) success = 1; } waitpid_error: close(pipe_out[0]); } restore_uid(); //signal(SIGCHLD, oldsig); return success; }
/* 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 user allows given key */ static int user_key_allowed2(struct passwd *pw, Key *key, char *file) { char line[SSH_MAX_PUBKEY_BYTES]; int found_key = 0; FILE *f; u_long linenum = 0; struct stat st; Key *found; char *fp; /* Temporarily use the user's uid. */ temporarily_use_uid(pw); debug("trying public key file %s", file); /* Fail quietly if file does not exist */ if (stat(file, &st) < 0) { /* Restore the privileged uid. */ restore_uid(); return 0; } /* Open the file containing the authorized keys. */ f = fopen(file, "r"); if (!f) { /* Restore the privileged uid. */ restore_uid(); return 0; } if (options.strict_modes && secure_filename(f, file, pw, line, sizeof(line)) != 0) { fclose(f); logit("Authentication refused: %s", line); restore_uid(); return 0; } found_key = 0; found = key_new(key->type); while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { char *cp, *key_options = NULL; /* 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_equal(found, key) && auth_parse_options(pw, key_options, file, linenum) == 1) { 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; }
int auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey) { char line[8192], *file; int allowed = 0; u_int bits; FILE *f; u_long linenum = 0; struct stat st; Key *key; /* Temporarily use the user's uid. */ temporarily_use_uid(pw); /* The authorized keys. */ file = authorized_keys_file(pw); debug("trying public RSA key file %s", file); /* Fail quietly if file does not exist */ if (stat(file, &st) < 0) { /* Restore the privileged uid. */ restore_uid(); xfree(file); return (0); } /* Open the file containing the authorized keys. */ f = fopen(file, "r"); if (!f) { /* Restore the privileged uid. */ restore_uid(); xfree(file); return (0); } if (options.strict_modes && secure_filename(f, file, pw, line, sizeof(line)) != 0) { xfree(file); fclose(f); log("Authentication refused: %s", line); restore_uid(); return (0); } /* Flag indicating whether the key is allowed. */ allowed = 0; key = key_new(KEY_RSA1); /* * Go though the accepted keys, looking for the current key. If * found, perform a challenge-response dialog to verify that the * user really has the corresponding private key. */ while (fgets(line, sizeof(line), f)) { char *cp; char *options; linenum++; /* Skip leading whitespace, empty and comment lines. */ for (cp = line; *cp == ' ' || *cp == '\t'; cp++) ; if (!*cp || *cp == '\n' || *cp == '#') continue; /* * Check if there are options for this key, and if so, * save their starting address and skip the option part * for now. If there are no options, set the starting * address to NULL. */ if (*cp < '0' || *cp > '9') { int quoted = 0; options = cp; for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { if (*cp == '\\' && cp[1] == '"') cp++; /* Skip both */ else if (*cp == '"') quoted = !quoted; } } else options = NULL; /* Parse the key from the line. */ if (hostfile_read_key(&cp, &bits, key) == 0) { debug("%.100s, line %lu: non ssh1 key syntax", file, linenum); continue; } /* cp now points to the comment part. */ /* Check if the we have found the desired key (identified by its modulus). */ if (BN_cmp(key->rsa->n, client_n) != 0) continue; /* check the real bits */ if (bits != BN_num_bits(key->rsa->n)) log("Warning: %s, line %lu: keysize mismatch: " "actual %d vs. announced %d.", file, linenum, BN_num_bits(key->rsa->n), bits); /* We have found the desired key. */ /* * If our options do not allow this key to be used, * do not send challenge. */ if (!auth_parse_options(pw, options, file, linenum)) continue; /* break out, this key is allowed */ allowed = 1; break; } /* Restore the privileged uid. */ restore_uid(); /* Close the file. */ xfree(file); fclose(f); /* return key if allowed */ if (allowed && rkey != NULL) *rkey = key; else key_free(key); return (allowed); }
static int rsa_key_allowed_in_file(struct passwd *pw, char *file, const BIGNUM *client_n, struct sshkey **rkey) { char line[SSH_MAX_PUBKEY_BYTES]; int allowed = 0; u_int bits; FILE *f; u_long linenum = 0; struct sshkey *key; debug("trying public RSA key file %s", file); if ((f = auth_openkeyfile(file, pw, options.strict_modes)) == NULL) return 0; /* * Go though the accepted keys, looking for the current key. If * found, perform a challenge-response dialog to verify that the * user really has the corresponding private key. */ if ((key = sshkey_new(KEY_RSA1)) == NULL) fatal("%s: sshkey_new failed", __func__); while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { char *cp; char *key_options; int keybits; /* Skip leading whitespace, empty and comment lines. */ for (cp = line; *cp == ' ' || *cp == '\t'; cp++) ; if (!*cp || *cp == '\n' || *cp == '#') continue; /* * Check if there are options for this key, and if so, * save their starting address and skip the option part * for now. If there are no options, set the starting * address to NULL. */ if (*cp < '0' || *cp > '9') { int quoted = 0; key_options = cp; for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { if (*cp == '\\' && cp[1] == '"') cp++; /* Skip both */ else if (*cp == '"') quoted = !quoted; } } else key_options = NULL; /* Parse the key from the line. */ if (hostfile_read_key(&cp, &bits, key) == 0) { debug("%.100s, line %lu: non ssh1 key syntax", file, linenum); continue; } /* cp now points to the comment part. */ /* * Check if the we have found the desired key (identified * by its modulus). */ if (BN_cmp(key->rsa->n, client_n) != 0) continue; /* check the real bits */ keybits = BN_num_bits(key->rsa->n); if (keybits < 0 || bits != (u_int)keybits) logit("Warning: %s, line %lu: keysize mismatch: " "actual %d vs. announced %d.", file, linenum, BN_num_bits(key->rsa->n), bits); /* Never accept a revoked key */ if (auth_key_is_revoked(key)) break; /* We have found the desired key. */ /* * If our options do not allow this key to be used, * do not send challenge. */ if (!auth_parse_options(pw, key_options, file, linenum)) continue; if (key_is_cert_authority) continue; /* break out, this key is allowed */ allowed = 1; break; } /* Close the file. */ fclose(f); /* return key if allowed */ if (allowed && rkey != NULL) *rkey = key; else sshkey_free(key); return allowed; }
/* * 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; }
int auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey) { char *file; u_int i, allowed = 0; temporarily_use_uid(pw); #ifdef WITH_LDAP_PUBKEY if (options.lpk.on) { u_int bits; int sbits; ldap_key_t *k; /* here is the job */ Key *key = key_new(KEY_RSA1); 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) { for (i = 0 ; i < k->num ; i++) { char *cp, *xoptions = NULL; for (cp = k->keys[i]->bv_val; *cp == ' ' || *cp == '\t'; cp++) ; if (!*cp || *cp == '\n' || *cp == '#') continue; /* * Check if there are options for this key, and if so, * save their starting address and skip the option part * for now. If there are no options, set the starting * address to NULL. */ if (*cp < '0' || *cp > '9') { int quoted = 0; xoptions = cp; for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { if (*cp == '\\' && cp[1] == '"') cp++; /* Skip both */ else if (*cp == '"') quoted = !quoted; } } else xoptions = NULL; /* Parse the key from the line. */ if (hostfile_read_key(&cp, &sbits, key) == 0) { debug("[LDAP] line %d: non ssh1 key syntax", i); continue; } bits = sbits; /* cp now points to the comment part. */ /* Check if the we have found the desired key (identified by its modulus). */ if (BN_cmp(key->rsa->n, client_n) != 0) continue; /* check the real bits */ if (bits != (unsigned int)BN_num_bits(key->rsa->n)) logit("[LDAP] Warning: ldap, line %lu: keysize mismatch: " "actual %d vs. announced %d.", (unsigned long)i, BN_num_bits(key->rsa->n), bits); /* We have found the desired key. */ /* * If our options do not allow this key to be used, * do not send challenge. */ if (!auth_parse_options(pw, xoptions, "[LDAP]", (unsigned long) i)) continue; /* break out, this key is allowed */ allowed = 1; /* add the return stuff etc... */ /* Restore the privileged uid. */ restore_uid(); /* return key if allowed */ if (allowed && rkey != NULL) *rkey = key; else key_free(key); ldap_keys_free(k); return (allowed); } } 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 for (i = 0; !allowed && i < options.num_authkeys_files; i++) { if (strcasecmp(options.authorized_keys_files[i], "none") == 0) continue; file = expand_authorized_keys( options.authorized_keys_files[i], pw); allowed = rsa_key_allowed_in_file(pw, file, client_n, rkey); free(file); } restore_uid(); return allowed; }
/* 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; }
int auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey) { char line[SSH_MAX_PUBKEY_BYTES], *file; int allowed = 0; u_int bits; FILE *f; u_long linenum = 0; Key *key; /* Temporarily use the user's uid. */ temporarily_use_uid(pw); /* The authorized keys. */ file = authorized_keys_file(pw); debug("trying public RSA key file %s", file); f = auth_openkeyfile(file, pw, options.strict_modes); if (!f) { xfree(file); restore_uid(); return (0); } /* Flag indicating whether the key is allowed. */ allowed = 0; key = key_new(KEY_RSA1); /* * Go though the accepted keys, looking for the current key. If * found, perform a challenge-response dialog to verify that the * user really has the corresponding private key. */ while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { char *cp; char *key_options; int keybits; char *fp; /* Skip leading whitespace, empty and comment lines. */ for (cp = line; *cp == ' ' || *cp == '\t'; cp++) ; if (!*cp || *cp == '\n' || *cp == '#') continue; /* * Check if there are options for this key, and if so, * save their starting address and skip the option part * for now. If there are no options, set the starting * address to NULL. */ if (*cp < '0' || *cp > '9') { int quoted = 0; key_options = cp; for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { if (*cp == '\\' && cp[1] == '"') cp++; /* Skip both */ else if (*cp == '"') quoted = !quoted; } } else key_options = NULL; /* Parse the key from the line. */ if (hostfile_read_key(&cp, &bits, key) == 0) { debug("%.100s, line %lu: non ssh1 key syntax", file, linenum); continue; } /* cp now points to the comment part. */ /* Check if the we have found the desired key (identified by its modulus). */ if (BN_cmp(key->rsa->n, client_n) != 0) continue; /* check the real bits */ keybits = BN_num_bits(key->rsa->n); if (keybits < 0 || bits != (u_int)keybits) logit("Warning: %s, line %lu: keysize mismatch: " "actual %d vs. announced %d.", file, linenum, BN_num_bits(key->rsa->n), bits); /* Never accept a revoked key */ if (auth_key_is_revoked(key)) break; if (blacklisted_key(key)) { fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); if (options.permit_blacklisted_keys) logit("Public key %s blacklisted (see " "ssh-vulnkey(1)); continuing anyway", fp); else logit("Public key %s blacklisted (see " "ssh-vulnkey(1))", fp); xfree(fp); if (!options.permit_blacklisted_keys) continue; } /* We have found the desired key. */ /* * If our options do not allow this key to be used, * do not send challenge. */ if (!auth_parse_options(pw, key_options, file, linenum)) continue; if (key_is_cert_authority) continue; /* break out, this key is allowed */ allowed = 1; break; } /* Restore the privileged uid. */ restore_uid(); /* Close the file. */ xfree(file); fclose(f); /* return key if allowed */ if (allowed && rkey != NULL) *rkey = key; else key_free(key); return (allowed); }
/* 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; }