1ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman/* $OpenBSD: auth2-pubkey.c,v 1.53 2015/06/15 18:44:22 jsing Exp $ */ 2bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* 3bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Copyright (c) 2000 Markus Friedl. All rights reserved. 4bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * 5bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Redistribution and use in source and binary forms, with or without 6bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * modification, are permitted provided that the following conditions 7bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * are met: 8bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * 1. Redistributions of source code must retain the above copyright 9bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * notice, this list of conditions and the following disclaimer. 10bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * 2. Redistributions in binary form must reproduce the above copyright 11bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * notice, this list of conditions and the following disclaimer in the 12bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * documentation and/or other materials provided with the distribution. 13bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * 14bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 25bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 26bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "includes.h" 27bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 28bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <sys/types.h> 29bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <sys/stat.h> 30d059297112922cabb0c674840589be8db821fd9aAdam Langley#include <sys/wait.h> 31bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 32d059297112922cabb0c674840589be8db821fd9aAdam Langley#include <errno.h> 33bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <fcntl.h> 34d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef HAVE_PATHS_H 35d059297112922cabb0c674840589be8db821fd9aAdam Langley# include <paths.h> 36d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif 37bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <pwd.h> 38d059297112922cabb0c674840589be8db821fd9aAdam Langley#include <signal.h> 39bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <stdio.h> 40bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <stdarg.h> 41bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <string.h> 42bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <time.h> 43bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <unistd.h> 44d059297112922cabb0c674840589be8db821fd9aAdam Langley#include <limits.h> 45bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 46bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "xmalloc.h" 47bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "ssh.h" 48bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "ssh2.h" 49bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "packet.h" 50bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "buffer.h" 51bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "log.h" 52d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "misc.h" 53bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "servconf.h" 54bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "compat.h" 55bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "key.h" 56bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "hostfile.h" 57bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "auth.h" 58bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "pathnames.h" 59bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "uidswap.h" 60bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "auth-options.h" 61bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "canohost.h" 62bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef GSSAPI 63bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "ssh-gss.h" 64bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif 65bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "monitor_wrap.h" 66bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "authfile.h" 67bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "match.h" 68ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman#include "ssherr.h" 69ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman#include "channels.h" /* XXX for session.h */ 70ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman#include "session.h" /* XXX for child_set_env(); refactor? */ 71bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 72bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* import */ 73bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanextern ServerOptions options; 74bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanextern u_char *session_id2; 75bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanextern u_int session_id2_len; 76bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 77bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic int 78bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanuserauth_pubkey(Authctxt *authctxt) 79bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 80bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman Buffer b; 81bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman Key *key = NULL; 82d059297112922cabb0c674840589be8db821fd9aAdam Langley char *pkalg, *userstyle; 83bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman u_char *pkblob, *sig; 84bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman u_int alen, blen, slen; 85bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman int have_sig, pktype; 86bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman int authenticated = 0; 87bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 88bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (!authctxt->valid) { 89bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug2("userauth_pubkey: disabled because of invalid user"); 90bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return 0; 91bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 92bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman have_sig = packet_get_char(); 93bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (datafellows & SSH_BUG_PKAUTH) { 94bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug2("userauth_pubkey: SSH_BUG_PKAUTH"); 95bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* no explicit pkalg given */ 96bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman pkblob = packet_get_string(&blen); 97bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman buffer_init(&b); 98bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman buffer_append(&b, pkblob, blen); 99bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* so we have to extract the pkalg from the pkblob */ 100bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman pkalg = buffer_get_string(&b, &alen); 101bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman buffer_free(&b); 102bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } else { 103bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman pkalg = packet_get_string(&alen); 104bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman pkblob = packet_get_string(&blen); 105bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 106bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman pktype = key_type_from_name(pkalg); 107bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (pktype == KEY_UNSPEC) { 108bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* this is perfectly legal */ 109bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman logit("userauth_pubkey: unsupported public key algorithm: %s", 110bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman pkalg); 111bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman goto done; 112bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 113bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman key = key_from_blob(pkblob, blen); 114bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (key == NULL) { 115bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("userauth_pubkey: cannot decode key: %s", pkalg); 116bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman goto done; 117bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 118bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (key->type != pktype) { 119bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("userauth_pubkey: type mismatch for decoded key " 120bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "(received %d, expected %d)", key->type, pktype); 121bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman goto done; 122bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 123d059297112922cabb0c674840589be8db821fd9aAdam Langley if (key_type_plain(key->type) == KEY_RSA && 124d059297112922cabb0c674840589be8db821fd9aAdam Langley (datafellows & SSH_BUG_RSASIGMD5) != 0) { 125d059297112922cabb0c674840589be8db821fd9aAdam Langley logit("Refusing RSA key because client uses unsafe " 126d059297112922cabb0c674840589be8db821fd9aAdam Langley "signature scheme"); 127d059297112922cabb0c674840589be8db821fd9aAdam Langley goto done; 128d059297112922cabb0c674840589be8db821fd9aAdam Langley } 129d059297112922cabb0c674840589be8db821fd9aAdam Langley if (auth2_userkey_already_used(authctxt, key)) { 130d059297112922cabb0c674840589be8db821fd9aAdam Langley logit("refusing previously-used %s key", key_type(key)); 131d059297112922cabb0c674840589be8db821fd9aAdam Langley goto done; 132d059297112922cabb0c674840589be8db821fd9aAdam Langley } 133ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (match_pattern_list(sshkey_ssh_name(key), 134ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman options.pubkey_key_types, 0) != 1) { 135d059297112922cabb0c674840589be8db821fd9aAdam Langley logit("%s: key type %s not in PubkeyAcceptedKeyTypes", 136d059297112922cabb0c674840589be8db821fd9aAdam Langley __func__, sshkey_ssh_name(key)); 137d059297112922cabb0c674840589be8db821fd9aAdam Langley goto done; 138d059297112922cabb0c674840589be8db821fd9aAdam Langley } 139d059297112922cabb0c674840589be8db821fd9aAdam Langley 140bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (have_sig) { 141bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman sig = packet_get_string(&slen); 142bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman packet_check_eom(); 143bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman buffer_init(&b); 144bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (datafellows & SSH_OLD_SESSIONID) { 145bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman buffer_append(&b, session_id2, session_id2_len); 146bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } else { 147bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman buffer_put_string(&b, session_id2, session_id2_len); 148bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 149bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* reconstruct packet */ 150bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); 151d059297112922cabb0c674840589be8db821fd9aAdam Langley xasprintf(&userstyle, "%s%s%s", authctxt->user, 152d059297112922cabb0c674840589be8db821fd9aAdam Langley authctxt->style ? ":" : "", 153d059297112922cabb0c674840589be8db821fd9aAdam Langley authctxt->style ? authctxt->style : ""); 154d059297112922cabb0c674840589be8db821fd9aAdam Langley buffer_put_cstring(&b, userstyle); 155d059297112922cabb0c674840589be8db821fd9aAdam Langley free(userstyle); 156bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman buffer_put_cstring(&b, 157bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman datafellows & SSH_BUG_PKSERVICE ? 158bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "ssh-userauth" : 159bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman authctxt->service); 160bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (datafellows & SSH_BUG_PKAUTH) { 161bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman buffer_put_char(&b, have_sig); 162bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } else { 163bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman buffer_put_cstring(&b, "publickey"); 164bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman buffer_put_char(&b, have_sig); 165bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman buffer_put_cstring(&b, pkalg); 166bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 167bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman buffer_put_string(&b, pkblob, blen); 168bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef DEBUG_PK 169bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman buffer_dump(&b); 170bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif 171d059297112922cabb0c674840589be8db821fd9aAdam Langley pubkey_auth_info(authctxt, key, NULL); 172d059297112922cabb0c674840589be8db821fd9aAdam Langley 173bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* test for correct signature */ 174bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman authenticated = 0; 175ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (PRIVSEP(user_key_allowed(authctxt->pw, key, 1)) && 176bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), 177d059297112922cabb0c674840589be8db821fd9aAdam Langley buffer_len(&b))) == 1) { 178bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman authenticated = 1; 179d059297112922cabb0c674840589be8db821fd9aAdam Langley /* Record the successful key to prevent reuse */ 180d059297112922cabb0c674840589be8db821fd9aAdam Langley auth2_record_userkey(authctxt, key); 181d059297112922cabb0c674840589be8db821fd9aAdam Langley key = NULL; /* Don't free below */ 182d059297112922cabb0c674840589be8db821fd9aAdam Langley } 183bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman buffer_free(&b); 184d059297112922cabb0c674840589be8db821fd9aAdam Langley free(sig); 185bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } else { 186bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug("test whether pkalg/pkblob are acceptable"); 187bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman packet_check_eom(); 188bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 189bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* XXX fake reply and always send PK_OK ? */ 190bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* 191bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * XXX this allows testing whether a user is allowed 192bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * to login: if you happen to have a valid pubkey this 193bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * message is sent. the message is NEVER sent at all 194bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * if a user is not allowed to login. is this an 195bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * issue? -markus 196bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 197ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (PRIVSEP(user_key_allowed(authctxt->pw, key, 0))) { 198bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman packet_start(SSH2_MSG_USERAUTH_PK_OK); 199bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman packet_put_string(pkalg, alen); 200bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman packet_put_string(pkblob, blen); 201bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman packet_send(); 202bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman packet_write_wait(); 203bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman authctxt->postponed = 1; 204bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 205bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 206bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (authenticated != 1) 207bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman auth_clear_options(); 208bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmandone: 209bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg); 210bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (key != NULL) 211bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman key_free(key); 212d059297112922cabb0c674840589be8db821fd9aAdam Langley free(pkalg); 213d059297112922cabb0c674840589be8db821fd9aAdam Langley free(pkblob); 214bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return authenticated; 215bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 216bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 217d059297112922cabb0c674840589be8db821fd9aAdam Langleyvoid 218d059297112922cabb0c674840589be8db821fd9aAdam Langleypubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...) 219d059297112922cabb0c674840589be8db821fd9aAdam Langley{ 220d059297112922cabb0c674840589be8db821fd9aAdam Langley char *fp, *extra; 221d059297112922cabb0c674840589be8db821fd9aAdam Langley va_list ap; 222d059297112922cabb0c674840589be8db821fd9aAdam Langley int i; 223d059297112922cabb0c674840589be8db821fd9aAdam Langley 224d059297112922cabb0c674840589be8db821fd9aAdam Langley extra = NULL; 225d059297112922cabb0c674840589be8db821fd9aAdam Langley if (fmt != NULL) { 226d059297112922cabb0c674840589be8db821fd9aAdam Langley va_start(ap, fmt); 227d059297112922cabb0c674840589be8db821fd9aAdam Langley i = vasprintf(&extra, fmt, ap); 228d059297112922cabb0c674840589be8db821fd9aAdam Langley va_end(ap); 229d059297112922cabb0c674840589be8db821fd9aAdam Langley if (i < 0 || extra == NULL) 230d059297112922cabb0c674840589be8db821fd9aAdam Langley fatal("%s: vasprintf failed", __func__); 231d059297112922cabb0c674840589be8db821fd9aAdam Langley } 232d059297112922cabb0c674840589be8db821fd9aAdam Langley 233d059297112922cabb0c674840589be8db821fd9aAdam Langley if (key_is_cert(key)) { 234d059297112922cabb0c674840589be8db821fd9aAdam Langley fp = sshkey_fingerprint(key->cert->signature_key, 235d059297112922cabb0c674840589be8db821fd9aAdam Langley options.fingerprint_hash, SSH_FP_DEFAULT); 236d059297112922cabb0c674840589be8db821fd9aAdam Langley auth_info(authctxt, "%s ID %s (serial %llu) CA %s %s%s%s", 237d059297112922cabb0c674840589be8db821fd9aAdam Langley key_type(key), key->cert->key_id, 238d059297112922cabb0c674840589be8db821fd9aAdam Langley (unsigned long long)key->cert->serial, 239d059297112922cabb0c674840589be8db821fd9aAdam Langley key_type(key->cert->signature_key), 240d059297112922cabb0c674840589be8db821fd9aAdam Langley fp == NULL ? "(null)" : fp, 241d059297112922cabb0c674840589be8db821fd9aAdam Langley extra == NULL ? "" : ", ", extra == NULL ? "" : extra); 242d059297112922cabb0c674840589be8db821fd9aAdam Langley free(fp); 243d059297112922cabb0c674840589be8db821fd9aAdam Langley } else { 244d059297112922cabb0c674840589be8db821fd9aAdam Langley fp = sshkey_fingerprint(key, options.fingerprint_hash, 245d059297112922cabb0c674840589be8db821fd9aAdam Langley SSH_FP_DEFAULT); 246d059297112922cabb0c674840589be8db821fd9aAdam Langley auth_info(authctxt, "%s %s%s%s", key_type(key), 247d059297112922cabb0c674840589be8db821fd9aAdam Langley fp == NULL ? "(null)" : fp, 248d059297112922cabb0c674840589be8db821fd9aAdam Langley extra == NULL ? "" : ", ", extra == NULL ? "" : extra); 249d059297112922cabb0c674840589be8db821fd9aAdam Langley free(fp); 250d059297112922cabb0c674840589be8db821fd9aAdam Langley } 251d059297112922cabb0c674840589be8db821fd9aAdam Langley free(extra); 252d059297112922cabb0c674840589be8db821fd9aAdam Langley} 253d059297112922cabb0c674840589be8db821fd9aAdam Langley 254ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman/* 255ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman * Splits 's' into an argument vector. Handles quoted string and basic 256ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman * escape characters (\\, \", \'). Caller must free the argument vector 257ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman * and its members. 258ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman */ 259ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartmanstatic int 260ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartmansplit_argv(const char *s, int *argcp, char ***argvp) 261ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman{ 262ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman int r = SSH_ERR_INTERNAL_ERROR; 263ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman int argc = 0, quote, i, j; 264ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman char *arg, **argv = xcalloc(1, sizeof(*argv)); 265ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 266ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman *argvp = NULL; 267ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman *argcp = 0; 268ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 269ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman for (i = 0; s[i] != '\0'; i++) { 270ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman /* Skip leading whitespace */ 271ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (s[i] == ' ' || s[i] == '\t') 272ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman continue; 273ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 274ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman /* Start of a token */ 275ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman quote = 0; 276ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (s[i] == '\\' && 277ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman (s[i + 1] == '\'' || s[i + 1] == '\"' || s[i + 1] == '\\')) 278ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman i++; 279ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman else if (s[i] == '\'' || s[i] == '"') 280ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman quote = s[i++]; 281ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 282ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman argv = xreallocarray(argv, (argc + 2), sizeof(*argv)); 283ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman arg = argv[argc++] = xcalloc(1, strlen(s + i) + 1); 284ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman argv[argc] = NULL; 285ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 286ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman /* Copy the token in, removing escapes */ 287ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman for (j = 0; s[i] != '\0'; i++) { 288ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (s[i] == '\\') { 289ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (s[i + 1] == '\'' || 290ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman s[i + 1] == '\"' || 291ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman s[i + 1] == '\\') { 292ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman i++; /* Skip '\' */ 293ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman arg[j++] = s[i]; 294ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } else { 295ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman /* Unrecognised escape */ 296ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman arg[j++] = s[i]; 297ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 298ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } else if (quote == 0 && (s[i] == ' ' || s[i] == '\t')) 299ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman break; /* done */ 300ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman else if (quote != 0 && s[i] == quote) 301ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman break; /* done */ 302ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman else 303ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman arg[j++] = s[i]; 304ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 305ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (s[i] == '\0') { 306ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (quote != 0) { 307ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman /* Ran out of string looking for close quote */ 308ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman r = SSH_ERR_INVALID_FORMAT; 309ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman goto out; 310ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 311ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman break; 312ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 313ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 314ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman /* Success */ 315ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman *argcp = argc; 316ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman *argvp = argv; 317ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman argc = 0; 318ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman argv = NULL; 319ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman r = 0; 320ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman out: 321ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (argc != 0 && argv != NULL) { 322ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman for (i = 0; i < argc; i++) 323ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman free(argv[i]); 324ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman free(argv); 325ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 326ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman return r; 327ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman} 328ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 329ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman/* 330ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman * Reassemble an argument vector into a string, quoting and escaping as 331ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman * necessary. Caller must free returned string. 332ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman */ 333ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartmanstatic char * 334ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartmanassemble_argv(int argc, char **argv) 335ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman{ 336ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman int i, j, ws, r; 337ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman char c, *ret; 338ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman struct sshbuf *buf, *arg; 339ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 340ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if ((buf = sshbuf_new()) == NULL || (arg = sshbuf_new()) == NULL) 341ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman fatal("%s: sshbuf_new failed", __func__); 342ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 343ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman for (i = 0; i < argc; i++) { 344ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman ws = 0; 345ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman sshbuf_reset(arg); 346ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman for (j = 0; argv[i][j] != '\0'; j++) { 347ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman r = 0; 348ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman c = argv[i][j]; 349ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman switch (c) { 350ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman case ' ': 351ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman case '\t': 352ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman ws = 1; 353ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman r = sshbuf_put_u8(arg, c); 354ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman break; 355ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman case '\\': 356ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman case '\'': 357ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman case '"': 358ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if ((r = sshbuf_put_u8(arg, '\\')) != 0) 359ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman break; 360ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman /* FALLTHROUGH */ 361ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman default: 362ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman r = sshbuf_put_u8(arg, c); 363ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman break; 364ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 365ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (r != 0) 366ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman fatal("%s: sshbuf_put_u8: %s", 367ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman __func__, ssh_err(r)); 368ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 369ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if ((i != 0 && (r = sshbuf_put_u8(buf, ' ')) != 0) || 370ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman (ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0) || 371ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman (r = sshbuf_putb(buf, arg)) != 0 || 372ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman (ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0)) 373ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman fatal("%s: buffer error: %s", __func__, ssh_err(r)); 374ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 375ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if ((ret = malloc(sshbuf_len(buf) + 1)) == NULL) 376ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman fatal("%s: malloc failed", __func__); 377ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman memcpy(ret, sshbuf_ptr(buf), sshbuf_len(buf)); 378ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman ret[sshbuf_len(buf)] = '\0'; 379ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman sshbuf_free(buf); 380ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman sshbuf_free(arg); 381ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman return ret; 382ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman} 383ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 384ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman/* 385ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman * Runs command in a subprocess. Returns pid on success and a FILE* to the 386ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman * subprocess' stdout or 0 on failure. 387ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman * NB. "command" is only used for logging. 388ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman */ 389ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartmanstatic pid_t 390ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartmansubprocess(const char *tag, struct passwd *pw, const char *command, 391ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman int ac, char **av, FILE **child) 392ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman{ 393ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman FILE *f; 394ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman struct stat st; 395ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman int devnull, p[2], i; 396ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman pid_t pid; 397ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman char *cp, errmsg[512]; 398ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman u_int envsize; 399ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman char **child_env; 400ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 401ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman *child = NULL; 402ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 403ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman debug3("%s: %s command \"%s\" running as %s", __func__, 404ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman tag, command, pw->pw_name); 405ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 406ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman /* Verify the path exists and is safe-ish to execute */ 407ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (*av[0] != '/') { 408ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman error("%s path is not absolute", tag); 409ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman return 0; 410ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 411ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman temporarily_use_uid(pw); 412ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (stat(av[0], &st) < 0) { 413ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman error("Could not stat %s \"%s\": %s", tag, 414ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman av[0], strerror(errno)); 415ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman restore_uid(); 416ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman return 0; 417ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 418ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (auth_secure_path(av[0], &st, NULL, 0, 419ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman errmsg, sizeof(errmsg)) != 0) { 420ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman error("Unsafe %s \"%s\": %s", tag, av[0], errmsg); 421ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman restore_uid(); 422ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman return 0; 423ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 424ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 425ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman /* 426ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman * Run the command; stderr is left in place, stdout is the 427ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman * authorized_keys output. 428ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman */ 429ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (pipe(p) != 0) { 430ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman error("%s: pipe: %s", tag, strerror(errno)); 431ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman restore_uid(); 432ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman return 0; 433ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 434ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 435ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman /* 436ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman * Don't want to call this in the child, where it can fatal() and 437ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman * run cleanup_exit() code. 438ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman */ 439ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman restore_uid(); 440ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 441ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman switch ((pid = fork())) { 442ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman case -1: /* error */ 443ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman error("%s: fork: %s", tag, strerror(errno)); 444ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman close(p[0]); 445ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman close(p[1]); 446ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman return 0; 447ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman case 0: /* child */ 448ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman /* Prepare a minimal environment for the child. */ 449ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman envsize = 5; 450ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman child_env = xcalloc(sizeof(*child_env), envsize); 451ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman child_set_env(&child_env, &envsize, "PATH", _PATH_STDPATH); 452ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman child_set_env(&child_env, &envsize, "USER", pw->pw_name); 453ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman child_set_env(&child_env, &envsize, "LOGNAME", pw->pw_name); 454ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman child_set_env(&child_env, &envsize, "HOME", pw->pw_dir); 455ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if ((cp = getenv("LANG")) != NULL) 456ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman child_set_env(&child_env, &envsize, "LANG", cp); 457ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 458ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman for (i = 0; i < NSIG; i++) 459ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman signal(i, SIG_DFL); 460ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 461ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) { 462ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman error("%s: open %s: %s", tag, _PATH_DEVNULL, 463ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman strerror(errno)); 464ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman _exit(1); 465ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 466ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman /* Keep stderr around a while longer to catch errors */ 467ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (dup2(devnull, STDIN_FILENO) == -1 || 468ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman dup2(p[1], STDOUT_FILENO) == -1) { 469ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman error("%s: dup2: %s", tag, strerror(errno)); 470ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman _exit(1); 471ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 472ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman closefrom(STDERR_FILENO + 1); 473ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 474ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman /* Don't use permanently_set_uid() here to avoid fatal() */ 475ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) { 476ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman error("%s: setresgid %u: %s", tag, (u_int)pw->pw_gid, 477ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman strerror(errno)); 478ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman _exit(1); 479ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 480ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0) { 481ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman error("%s: setresuid %u: %s", tag, (u_int)pw->pw_uid, 482ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman strerror(errno)); 483ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman _exit(1); 484ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 485ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman /* stdin is pointed to /dev/null at this point */ 486ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (dup2(STDIN_FILENO, STDERR_FILENO) == -1) { 487ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman error("%s: dup2: %s", tag, strerror(errno)); 488ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman _exit(1); 489ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 490ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 491ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman execve(av[0], av, child_env); 492ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman error("%s exec \"%s\": %s", tag, command, strerror(errno)); 493ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman _exit(127); 494ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman default: /* parent */ 495ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman break; 496ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 497ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 498ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman close(p[1]); 499ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if ((f = fdopen(p[0], "r")) == NULL) { 500ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman error("%s: fdopen: %s", tag, strerror(errno)); 501ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman close(p[0]); 502ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman /* Don't leave zombie child */ 503ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman kill(pid, SIGTERM); 504ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman while (waitpid(pid, NULL, 0) == -1 && errno == EINTR) 505ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman ; 506ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman return 0; 507ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 508ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman /* Success */ 509ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman debug3("%s: %s pid %ld", __func__, tag, (long)pid); 510ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman *child = f; 511ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman return pid; 512ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman} 513ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 514ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman/* Returns 0 if pid exited cleanly, non-zero otherwise */ 515ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartmanstatic int 516ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartmanexited_cleanly(pid_t pid, const char *tag, const char *cmd) 517ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman{ 518ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman int status; 519ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 520ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman while (waitpid(pid, &status, 0) == -1) { 521ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (errno != EINTR) { 522ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman error("%s: waitpid: %s", tag, strerror(errno)); 523ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman return -1; 524ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 525ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 526ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (WIFSIGNALED(status)) { 527ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman error("%s %s exited on signal %d", tag, cmd, WTERMSIG(status)); 528ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman return -1; 529ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } else if (WEXITSTATUS(status) != 0) { 530ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman error("%s %s failed, status %d", tag, cmd, WEXITSTATUS(status)); 531ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman return -1; 532ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 533ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman return 0; 534ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman} 535ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 536bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic int 537d059297112922cabb0c674840589be8db821fd9aAdam Langleymatch_principals_option(const char *principal_list, struct sshkey_cert *cert) 538bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 539bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char *result; 540bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman u_int i; 541bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 542bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* XXX percent_expand() sequences for authorized_principals? */ 543bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 544bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman for (i = 0; i < cert->nprincipals; i++) { 545bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if ((result = match_list(cert->principals[i], 546bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman principal_list, NULL)) != NULL) { 547bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug3("matched principal from key options \"%.100s\"", 548bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman result); 549d059297112922cabb0c674840589be8db821fd9aAdam Langley free(result); 550bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return 1; 551bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 552bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 553bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return 0; 554bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 555bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 556bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic int 557ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartmanprocess_principals(FILE *f, char *file, struct passwd *pw, 558ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman struct sshkey_cert *cert) 559bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 560bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts; 561bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman u_long linenum = 0; 562bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman u_int i; 563bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 564bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { 565bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Skip leading whitespace. */ 566bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman for (cp = line; *cp == ' ' || *cp == '\t'; cp++) 567bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ; 568bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Skip blank and comment lines. */ 569bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if ((ep = strchr(cp, '#')) != NULL) 570bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *ep = '\0'; 571bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (!*cp || *cp == '\n') 572bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman continue; 573bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Trim trailing whitespace. */ 574bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ep = cp + strlen(cp) - 1; 575bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman while (ep > cp && (*ep == '\n' || *ep == ' ' || *ep == '\t')) 576bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *ep-- = '\0'; 577bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* 578bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * If the line has internal whitespace then assume it has 579bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * key options. 580bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 581bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman line_opts = NULL; 582bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if ((ep = strrchr(cp, ' ')) != NULL || 583bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman (ep = strrchr(cp, '\t')) != NULL) { 584bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman for (; *ep == ' ' || *ep == '\t'; ep++) 585bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ; 586bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman line_opts = cp; 587bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman cp = ep; 588bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 589bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman for (i = 0; i < cert->nprincipals; i++) { 590bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (strcmp(cp, cert->principals[i]) == 0) { 591ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman debug3("%s:%lu: matched principal \"%.100s\"", 592ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman file == NULL ? "(command)" : file, 593ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman linenum, cert->principals[i]); 594bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (auth_parse_options(pw, line_opts, 595bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman file, linenum) != 1) 596bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman continue; 597bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return 1; 598bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 599bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 600bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 601ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman return 0; 602ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman} 603ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 604ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartmanstatic int 605ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartmanmatch_principals_file(char *file, struct passwd *pw, struct sshkey_cert *cert) 606ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman{ 607ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman FILE *f; 608ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman int success; 609ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 610ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman temporarily_use_uid(pw); 611ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman debug("trying authorized principals file %s", file); 612ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if ((f = auth_openprincipals(file, pw, options.strict_modes)) == NULL) { 613ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman restore_uid(); 614ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman return 0; 615ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 616ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman success = process_principals(f, file, pw, cert); 617bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fclose(f); 618bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman restore_uid(); 619ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman return success; 620d059297112922cabb0c674840589be8db821fd9aAdam Langley} 621bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 622d059297112922cabb0c674840589be8db821fd9aAdam Langley/* 623ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman * Checks whether principal is allowed in output of command. 624ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman * returns 1 if the principal is allowed or 0 otherwise. 625ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman */ 626ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartmanstatic int 627ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartmanmatch_principals_command(struct passwd *user_pw, struct sshkey_cert *cert) 628ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman{ 629ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman FILE *f = NULL; 630ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman int ok, found_principal = 0; 631ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman struct passwd *pw; 632ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman int i, ac = 0, uid_swapped = 0; 633ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman pid_t pid; 634ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman char *tmp, *username = NULL, *command = NULL, **av = NULL; 635ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman void (*osigchld)(int); 636ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 637ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (options.authorized_principals_command == NULL) 638ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman return 0; 639ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (options.authorized_principals_command_user == NULL) { 640ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman error("No user for AuthorizedPrincipalsCommand specified, " 641ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman "skipping"); 642ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman return 0; 643ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 644ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 645ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman /* 646ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman * NB. all returns later this function should go via "out" to 647ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman * ensure the original SIGCHLD handler is restored properly. 648ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman */ 649ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman osigchld = signal(SIGCHLD, SIG_DFL); 650ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 651ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman /* Prepare and verify the user for the command */ 652ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman username = percent_expand(options.authorized_principals_command_user, 653ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman "u", user_pw->pw_name, (char *)NULL); 654ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman pw = getpwnam(username); 655ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (pw == NULL) { 656ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman error("AuthorizedPrincipalsCommandUser \"%s\" not found: %s", 657ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman username, strerror(errno)); 658ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman goto out; 659ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 660ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 661ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman /* Turn the command into an argument vector */ 662ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (split_argv(options.authorized_principals_command, &ac, &av) != 0) { 663ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman error("AuthorizedPrincipalsCommand \"%s\" contains " 664ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman "invalid quotes", command); 665ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman goto out; 666ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 667ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (ac == 0) { 668ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman error("AuthorizedPrincipalsCommand \"%s\" yielded no arguments", 669ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman command); 670ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman goto out; 671ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 672ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman for (i = 1; i < ac; i++) { 673ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman tmp = percent_expand(av[i], 674ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman "u", user_pw->pw_name, 675ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman "h", user_pw->pw_dir, 676ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman (char *)NULL); 677ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (tmp == NULL) 678ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman fatal("%s: percent_expand failed", __func__); 679ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman free(av[i]); 680ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman av[i] = tmp; 681ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 682ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman /* Prepare a printable command for logs, etc. */ 683ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman command = assemble_argv(ac, av); 684ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 685ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if ((pid = subprocess("AuthorizedPrincipalsCommand", pw, command, 686ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman ac, av, &f)) == 0) 687ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman goto out; 688ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 689ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman uid_swapped = 1; 690ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman temporarily_use_uid(pw); 691ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 692ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman ok = process_principals(f, NULL, pw, cert); 693ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 694ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (exited_cleanly(pid, "AuthorizedPrincipalsCommand", command) != 0) 695ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman goto out; 696ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 697ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman /* Read completed successfully */ 698ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman found_principal = ok; 699ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman out: 700ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (f != NULL) 701ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman fclose(f); 702ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman signal(SIGCHLD, osigchld); 703ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman for (i = 0; i < ac; i++) 704ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman free(av[i]); 705ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman free(av); 706ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (uid_swapped) 707ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman restore_uid(); 708ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman free(command); 709ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman free(username); 710ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman return found_principal; 711ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman} 712ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman/* 713d059297112922cabb0c674840589be8db821fd9aAdam Langley * Checks whether key is allowed in authorized_keys-format file, 714d059297112922cabb0c674840589be8db821fd9aAdam Langley * returns 1 if the key is allowed or 0 otherwise. 715d059297112922cabb0c674840589be8db821fd9aAdam Langley */ 716bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic int 717d059297112922cabb0c674840589be8db821fd9aAdam Langleycheck_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw) 718bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 719bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char line[SSH_MAX_PUBKEY_BYTES]; 720bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman const char *reason; 721bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman int found_key = 0; 722bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman u_long linenum = 0; 723bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman Key *found; 724bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char *fp; 725bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 726bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman found_key = 0; 727bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 728d059297112922cabb0c674840589be8db821fd9aAdam Langley found = NULL; 729bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { 730bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char *cp, *key_options = NULL; 731d059297112922cabb0c674840589be8db821fd9aAdam Langley if (found != NULL) 732d059297112922cabb0c674840589be8db821fd9aAdam Langley key_free(found); 733d059297112922cabb0c674840589be8db821fd9aAdam Langley found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type); 734bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman auth_clear_options(); 735bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 736bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Skip leading whitespace, empty and comment lines. */ 737bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman for (cp = line; *cp == ' ' || *cp == '\t'; cp++) 738bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ; 739bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (!*cp || *cp == '\n' || *cp == '#') 740bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman continue; 741bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 742bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (key_read(found, &cp) != 1) { 743bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* no key? check if there are options for this key */ 744bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman int quoted = 0; 745bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug2("user_key_allowed: check options: '%s'", cp); 746bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman key_options = cp; 747bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { 748bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (*cp == '\\' && cp[1] == '"') 749bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman cp++; /* Skip both */ 750bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman else if (*cp == '"') 751bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman quoted = !quoted; 752bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 753bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Skip remaining whitespace. */ 754bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman for (; *cp == ' ' || *cp == '\t'; cp++) 755bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ; 756bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (key_read(found, &cp) != 1) { 757bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug2("user_key_allowed: advance: '%s'", cp); 758bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* still no key? advance to next line*/ 759bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman continue; 760bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 761bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 762bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (key_is_cert(key)) { 763bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (!key_equal(found, key->cert->signature_key)) 764bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman continue; 765bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (auth_parse_options(pw, key_options, file, 766bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman linenum) != 1) 767bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman continue; 768bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (!key_is_cert_authority) 769bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman continue; 770d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((fp = sshkey_fingerprint(found, 771d059297112922cabb0c674840589be8db821fd9aAdam Langley options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) 772d059297112922cabb0c674840589be8db821fd9aAdam Langley continue; 773bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug("matching CA found: file %s, line %lu, %s %s", 774bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman file, linenum, key_type(found), fp); 775bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* 776bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * If the user has specified a list of principals as 777bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * a key option, then prefer that list to matching 778bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * their username in the certificate principals list. 779bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 780bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (authorized_principals != NULL && 781bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman !match_principals_option(authorized_principals, 782bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman key->cert)) { 783bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman reason = "Certificate does not contain an " 784bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "authorized principal"; 785bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fail_reason: 786d059297112922cabb0c674840589be8db821fd9aAdam Langley free(fp); 787bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("%s", reason); 788bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman auth_debug_add("%s", reason); 789bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman continue; 790bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 791bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (key_cert_check_authority(key, 0, 0, 792bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman authorized_principals == NULL ? pw->pw_name : NULL, 793bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman &reason) != 0) 794bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman goto fail_reason; 795bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (auth_cert_options(key, pw) != 0) { 796d059297112922cabb0c674840589be8db821fd9aAdam Langley free(fp); 797bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman continue; 798bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 799bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman verbose("Accepted certificate ID \"%s\" " 800bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "signed by %s CA %s via %s", key->cert->key_id, 801bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman key_type(found), fp, file); 802d059297112922cabb0c674840589be8db821fd9aAdam Langley free(fp); 803bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman found_key = 1; 804bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman break; 805bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } else if (key_equal(found, key)) { 806bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (auth_parse_options(pw, key_options, file, 807bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman linenum) != 1) 808bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman continue; 809bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (key_is_cert_authority) 810bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman continue; 811d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((fp = sshkey_fingerprint(found, 812d059297112922cabb0c674840589be8db821fd9aAdam Langley options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) 813d059297112922cabb0c674840589be8db821fd9aAdam Langley continue; 814d059297112922cabb0c674840589be8db821fd9aAdam Langley debug("matching key found: file %s, line %lu %s %s", 815d059297112922cabb0c674840589be8db821fd9aAdam Langley file, linenum, key_type(found), fp); 816d059297112922cabb0c674840589be8db821fd9aAdam Langley free(fp); 817bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman found_key = 1; 818bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman break; 819bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 820bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 821d059297112922cabb0c674840589be8db821fd9aAdam Langley if (found != NULL) 822d059297112922cabb0c674840589be8db821fd9aAdam Langley key_free(found); 823bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (!found_key) 824bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug2("key not found"); 825bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return found_key; 826bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 827bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 828bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* Authenticate a certificate key against TrustedUserCAKeys */ 829bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic int 830bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanuser_cert_trusted_ca(struct passwd *pw, Key *key) 831bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 832bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char *ca_fp, *principals_file = NULL; 833bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman const char *reason; 834ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman int ret = 0, found_principal = 0, use_authorized_principals; 835bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 836bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (!key_is_cert(key) || options.trusted_user_ca_keys == NULL) 837bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return 0; 838bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 839d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((ca_fp = sshkey_fingerprint(key->cert->signature_key, 840d059297112922cabb0c674840589be8db821fd9aAdam Langley options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) 841d059297112922cabb0c674840589be8db821fd9aAdam Langley return 0; 842bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 843d059297112922cabb0c674840589be8db821fd9aAdam Langley if (sshkey_in_file(key->cert->signature_key, 844d059297112922cabb0c674840589be8db821fd9aAdam Langley options.trusted_user_ca_keys, 1, 0) != 0) { 845bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug2("%s: CA %s %s is not listed in %s", __func__, 846bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman key_type(key->cert->signature_key), ca_fp, 847bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman options.trusted_user_ca_keys); 848bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman goto out; 849bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 850bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* 851bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * If AuthorizedPrincipals is in use, then compare the certificate 852bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * principals against the names in that file rather than matching 853bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * against the username. 854bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 855bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if ((principals_file = authorized_principals_file(pw)) != NULL) { 856ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (match_principals_file(principals_file, pw, key->cert)) 857ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman found_principal = 1; 858ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 859ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman /* Try querying command if specified */ 860ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (!found_principal && match_principals_command(pw, key->cert)) 861ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman found_principal = 1; 862ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman /* If principals file or command is specified, then require a match */ 863ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman use_authorized_principals = principals_file != NULL || 864ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman options.authorized_principals_command != NULL; 865ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (!found_principal && use_authorized_principals) { 866ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman reason = "Certificate does not contain an authorized principal"; 867bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fail_reason: 868ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman error("%s", reason); 869ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman auth_debug_add("%s", reason); 870ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman goto out; 871bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 872bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (key_cert_check_authority(key, 0, 1, 873ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman use_authorized_principals ? NULL : pw->pw_name, &reason) != 0) 874bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman goto fail_reason; 875bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (auth_cert_options(key, pw) != 0) 876bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman goto out; 877bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 878bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman verbose("Accepted certificate ID \"%s\" signed by %s CA %s via %s", 879bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman key->cert->key_id, key_type(key->cert->signature_key), ca_fp, 880bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman options.trusted_user_ca_keys); 881bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ret = 1; 882bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 883bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman out: 884d059297112922cabb0c674840589be8db821fd9aAdam Langley free(principals_file); 885d059297112922cabb0c674840589be8db821fd9aAdam Langley free(ca_fp); 886bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return ret; 887bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 888bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 889d059297112922cabb0c674840589be8db821fd9aAdam Langley/* 890d059297112922cabb0c674840589be8db821fd9aAdam Langley * Checks whether key is allowed in file. 891d059297112922cabb0c674840589be8db821fd9aAdam Langley * returns 1 if the key is allowed or 0 otherwise. 892d059297112922cabb0c674840589be8db821fd9aAdam Langley */ 893d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic int 894d059297112922cabb0c674840589be8db821fd9aAdam Langleyuser_key_allowed2(struct passwd *pw, Key *key, char *file) 895d059297112922cabb0c674840589be8db821fd9aAdam Langley{ 896d059297112922cabb0c674840589be8db821fd9aAdam Langley FILE *f; 897d059297112922cabb0c674840589be8db821fd9aAdam Langley int found_key = 0; 898d059297112922cabb0c674840589be8db821fd9aAdam Langley 899d059297112922cabb0c674840589be8db821fd9aAdam Langley /* Temporarily use the user's uid. */ 900d059297112922cabb0c674840589be8db821fd9aAdam Langley temporarily_use_uid(pw); 901d059297112922cabb0c674840589be8db821fd9aAdam Langley 902d059297112922cabb0c674840589be8db821fd9aAdam Langley debug("trying public key file %s", file); 903d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((f = auth_openkeyfile(file, pw, options.strict_modes)) != NULL) { 904d059297112922cabb0c674840589be8db821fd9aAdam Langley found_key = check_authkeys_file(f, file, key, pw); 905d059297112922cabb0c674840589be8db821fd9aAdam Langley fclose(f); 906d059297112922cabb0c674840589be8db821fd9aAdam Langley } 907d059297112922cabb0c674840589be8db821fd9aAdam Langley 908d059297112922cabb0c674840589be8db821fd9aAdam Langley restore_uid(); 909d059297112922cabb0c674840589be8db821fd9aAdam Langley return found_key; 910d059297112922cabb0c674840589be8db821fd9aAdam Langley} 911d059297112922cabb0c674840589be8db821fd9aAdam Langley 912d059297112922cabb0c674840589be8db821fd9aAdam Langley/* 913d059297112922cabb0c674840589be8db821fd9aAdam Langley * Checks whether key is allowed in output of command. 914d059297112922cabb0c674840589be8db821fd9aAdam Langley * returns 1 if the key is allowed or 0 otherwise. 915d059297112922cabb0c674840589be8db821fd9aAdam Langley */ 916d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic int 917d059297112922cabb0c674840589be8db821fd9aAdam Langleyuser_key_command_allowed2(struct passwd *user_pw, Key *key) 918d059297112922cabb0c674840589be8db821fd9aAdam Langley{ 919ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman FILE *f = NULL; 920ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman int r, ok, found_key = 0; 921d059297112922cabb0c674840589be8db821fd9aAdam Langley struct passwd *pw; 922ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman int i, uid_swapped = 0, ac = 0; 923d059297112922cabb0c674840589be8db821fd9aAdam Langley pid_t pid; 924ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman char *username = NULL, *key_fp = NULL, *keytext = NULL; 925ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman char *tmp, *command = NULL, **av = NULL; 926ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman void (*osigchld)(int); 927d059297112922cabb0c674840589be8db821fd9aAdam Langley 928ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (options.authorized_keys_command == NULL) 929d059297112922cabb0c674840589be8db821fd9aAdam Langley return 0; 930d059297112922cabb0c674840589be8db821fd9aAdam Langley if (options.authorized_keys_command_user == NULL) { 931d059297112922cabb0c674840589be8db821fd9aAdam Langley error("No user for AuthorizedKeysCommand specified, skipping"); 932d059297112922cabb0c674840589be8db821fd9aAdam Langley return 0; 933d059297112922cabb0c674840589be8db821fd9aAdam Langley } 934d059297112922cabb0c674840589be8db821fd9aAdam Langley 935ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman /* 936ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman * NB. all returns later this function should go via "out" to 937ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman * ensure the original SIGCHLD handler is restored properly. 938ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman */ 939ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman osigchld = signal(SIGCHLD, SIG_DFL); 940ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 941ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman /* Prepare and verify the user for the command */ 942d059297112922cabb0c674840589be8db821fd9aAdam Langley username = percent_expand(options.authorized_keys_command_user, 943d059297112922cabb0c674840589be8db821fd9aAdam Langley "u", user_pw->pw_name, (char *)NULL); 944d059297112922cabb0c674840589be8db821fd9aAdam Langley pw = getpwnam(username); 945d059297112922cabb0c674840589be8db821fd9aAdam Langley if (pw == NULL) { 946d059297112922cabb0c674840589be8db821fd9aAdam Langley error("AuthorizedKeysCommandUser \"%s\" not found: %s", 947d059297112922cabb0c674840589be8db821fd9aAdam Langley username, strerror(errno)); 948ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman goto out; 949d059297112922cabb0c674840589be8db821fd9aAdam Langley } 950d059297112922cabb0c674840589be8db821fd9aAdam Langley 951ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman /* Prepare AuthorizedKeysCommand */ 952ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if ((key_fp = sshkey_fingerprint(key, options.fingerprint_hash, 953ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman SSH_FP_DEFAULT)) == NULL) { 954ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman error("%s: sshkey_fingerprint failed", __func__); 955d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 956d059297112922cabb0c674840589be8db821fd9aAdam Langley } 957ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if ((r = sshkey_to_base64(key, &keytext)) != 0) { 958ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman error("%s: sshkey_to_base64 failed: %s", __func__, ssh_err(r)); 959d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 960d059297112922cabb0c674840589be8db821fd9aAdam Langley } 961d059297112922cabb0c674840589be8db821fd9aAdam Langley 962ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman /* Turn the command into an argument vector */ 963ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (split_argv(options.authorized_keys_command, &ac, &av) != 0) { 964ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman error("AuthorizedKeysCommand \"%s\" contains invalid quotes", 965ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman command); 966d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 967d059297112922cabb0c674840589be8db821fd9aAdam Langley } 968ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (ac == 0) { 969ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman error("AuthorizedKeysCommand \"%s\" yielded no arguments", 970ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman command); 971ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman goto out; 972ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 973ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman for (i = 1; i < ac; i++) { 974ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman tmp = percent_expand(av[i], 975ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman "u", user_pw->pw_name, 976ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman "h", user_pw->pw_dir, 977ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman "t", sshkey_ssh_name(key), 978ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman "f", key_fp, 979ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman "k", keytext, 980ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman (char *)NULL); 981ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (tmp == NULL) 982ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman fatal("%s: percent_expand failed", __func__); 983ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman free(av[i]); 984ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman av[i] = tmp; 985ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman } 986ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman /* Prepare a printable command for logs, etc. */ 987ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman command = assemble_argv(ac, av); 988d059297112922cabb0c674840589be8db821fd9aAdam Langley 989d059297112922cabb0c674840589be8db821fd9aAdam Langley /* 990ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman * If AuthorizedKeysCommand was run without arguments 991ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman * then fall back to the old behaviour of passing the 992ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman * target username as a single argument. 993d059297112922cabb0c674840589be8db821fd9aAdam Langley */ 994ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (ac == 1) { 995ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman av = xreallocarray(av, ac + 2, sizeof(*av)); 996ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman av[1] = xstrdup(user_pw->pw_name); 997ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman av[2] = NULL; 998ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman /* Fix up command too, since it is used in log messages */ 999ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman free(command); 1000ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman xasprintf(&command, "%s %s", av[0], av[1]); 1001d059297112922cabb0c674840589be8db821fd9aAdam Langley } 1002d059297112922cabb0c674840589be8db821fd9aAdam Langley 1003ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if ((pid = subprocess("AuthorizedKeysCommand", pw, command, 1004ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman ac, av, &f)) == 0) 1005ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman goto out; 1006ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 1007ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman uid_swapped = 1; 1008d059297112922cabb0c674840589be8db821fd9aAdam Langley temporarily_use_uid(pw); 1009d059297112922cabb0c674840589be8db821fd9aAdam Langley 1010d059297112922cabb0c674840589be8db821fd9aAdam Langley ok = check_authkeys_file(f, options.authorized_keys_command, key, pw); 1011d059297112922cabb0c674840589be8db821fd9aAdam Langley 1012ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (exited_cleanly(pid, "AuthorizedKeysCommand", command) != 0) 1013d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 1014ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman 1015ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman /* Read completed successfully */ 1016d059297112922cabb0c674840589be8db821fd9aAdam Langley found_key = ok; 1017d059297112922cabb0c674840589be8db821fd9aAdam Langley out: 1018ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (f != NULL) 1019ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman fclose(f); 1020ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman signal(SIGCHLD, osigchld); 1021ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman for (i = 0; i < ac; i++) 1022ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman free(av[i]); 1023ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman free(av); 1024ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman if (uid_swapped) 1025ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman restore_uid(); 1026ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman free(command); 1027ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman free(username); 1028ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman free(key_fp); 1029ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman free(keytext); 1030d059297112922cabb0c674840589be8db821fd9aAdam Langley return found_key; 1031d059297112922cabb0c674840589be8db821fd9aAdam Langley} 1032d059297112922cabb0c674840589be8db821fd9aAdam Langley 1033d059297112922cabb0c674840589be8db821fd9aAdam Langley/* 1034d059297112922cabb0c674840589be8db821fd9aAdam Langley * Check whether key authenticates and authorises the user. 1035d059297112922cabb0c674840589be8db821fd9aAdam Langley */ 1036bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanint 1037ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartmanuser_key_allowed(struct passwd *pw, Key *key, int auth_attempt) 1038bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 1039bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman u_int success, i; 1040bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char *file; 1041bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1042bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (auth_key_is_revoked(key)) 1043bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return 0; 1044bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (key_is_cert(key) && auth_key_is_revoked(key->cert->signature_key)) 1045bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return 0; 1046bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1047bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman success = user_cert_trusted_ca(pw, key); 1048bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (success) 1049bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return success; 1050bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1051d059297112922cabb0c674840589be8db821fd9aAdam Langley success = user_key_command_allowed2(pw, key); 1052d059297112922cabb0c674840589be8db821fd9aAdam Langley if (success > 0) 1053d059297112922cabb0c674840589be8db821fd9aAdam Langley return success; 1054d059297112922cabb0c674840589be8db821fd9aAdam Langley 1055bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman for (i = 0; !success && i < options.num_authkeys_files; i++) { 1056d059297112922cabb0c674840589be8db821fd9aAdam Langley 1057d059297112922cabb0c674840589be8db821fd9aAdam Langley if (strcasecmp(options.authorized_keys_files[i], "none") == 0) 1058d059297112922cabb0c674840589be8db821fd9aAdam Langley continue; 1059bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman file = expand_authorized_keys( 1060bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman options.authorized_keys_files[i], pw); 1061d059297112922cabb0c674840589be8db821fd9aAdam Langley 1062bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman success = user_key_allowed2(pw, key, file); 1063d059297112922cabb0c674840589be8db821fd9aAdam Langley free(file); 1064bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 1065bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1066bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return success; 1067bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 1068bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1069d059297112922cabb0c674840589be8db821fd9aAdam Langley/* Records a public key in the list of previously-successful keys */ 1070d059297112922cabb0c674840589be8db821fd9aAdam Langleyvoid 1071d059297112922cabb0c674840589be8db821fd9aAdam Langleyauth2_record_userkey(Authctxt *authctxt, struct sshkey *key) 1072d059297112922cabb0c674840589be8db821fd9aAdam Langley{ 1073d059297112922cabb0c674840589be8db821fd9aAdam Langley struct sshkey **tmp; 1074d059297112922cabb0c674840589be8db821fd9aAdam Langley 1075d059297112922cabb0c674840589be8db821fd9aAdam Langley if (authctxt->nprev_userkeys >= INT_MAX || 1076d059297112922cabb0c674840589be8db821fd9aAdam Langley (tmp = reallocarray(authctxt->prev_userkeys, 1077d059297112922cabb0c674840589be8db821fd9aAdam Langley authctxt->nprev_userkeys + 1, sizeof(*tmp))) == NULL) 1078d059297112922cabb0c674840589be8db821fd9aAdam Langley fatal("%s: reallocarray failed", __func__); 1079d059297112922cabb0c674840589be8db821fd9aAdam Langley authctxt->prev_userkeys = tmp; 1080d059297112922cabb0c674840589be8db821fd9aAdam Langley authctxt->prev_userkeys[authctxt->nprev_userkeys] = key; 1081d059297112922cabb0c674840589be8db821fd9aAdam Langley authctxt->nprev_userkeys++; 1082d059297112922cabb0c674840589be8db821fd9aAdam Langley} 1083d059297112922cabb0c674840589be8db821fd9aAdam Langley 1084d059297112922cabb0c674840589be8db821fd9aAdam Langley/* Checks whether a key has already been used successfully for authentication */ 1085d059297112922cabb0c674840589be8db821fd9aAdam Langleyint 1086d059297112922cabb0c674840589be8db821fd9aAdam Langleyauth2_userkey_already_used(Authctxt *authctxt, struct sshkey *key) 1087d059297112922cabb0c674840589be8db821fd9aAdam Langley{ 1088d059297112922cabb0c674840589be8db821fd9aAdam Langley u_int i; 1089d059297112922cabb0c674840589be8db821fd9aAdam Langley 1090d059297112922cabb0c674840589be8db821fd9aAdam Langley for (i = 0; i < authctxt->nprev_userkeys; i++) { 1091d059297112922cabb0c674840589be8db821fd9aAdam Langley if (sshkey_equal_public(key, authctxt->prev_userkeys[i])) { 1092d059297112922cabb0c674840589be8db821fd9aAdam Langley return 1; 1093d059297112922cabb0c674840589be8db821fd9aAdam Langley } 1094d059297112922cabb0c674840589be8db821fd9aAdam Langley } 1095d059297112922cabb0c674840589be8db821fd9aAdam Langley return 0; 1096d059297112922cabb0c674840589be8db821fd9aAdam Langley} 1097d059297112922cabb0c674840589be8db821fd9aAdam Langley 1098bd77cf78387b72b7b3ea870459077672bf75c3b5Greg HartmanAuthmethod method_pubkey = { 1099bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "publickey", 1100bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman userauth_pubkey, 1101bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman &options.pubkey_authentication 1102bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}; 1103