GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/ssh/sshd/../auth2-hostbased.c Lines: 0 116 0.0 %
Date: 2017-11-07 Branches: 0 86 0.0 %

Line Branch Exec Source
1
/* $OpenBSD: auth2-hostbased.c,v 1.31 2017/06/24 06:34:38 djm Exp $ */
2
/*
3
 * Copyright (c) 2000 Markus Friedl.  All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 *
14
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
 */
25
26
27
#include <sys/types.h>
28
29
#include <pwd.h>
30
#include <string.h>
31
#include <stdarg.h>
32
33
#include "xmalloc.h"
34
#include "ssh2.h"
35
#include "packet.h"
36
#include "buffer.h"
37
#include "log.h"
38
#include "misc.h"
39
#include "servconf.h"
40
#include "compat.h"
41
#include "sshkey.h"
42
#include "hostfile.h"
43
#include "auth.h"
44
#include "canohost.h"
45
#ifdef GSSAPI
46
#include "ssh-gss.h"
47
#endif
48
#include "monitor_wrap.h"
49
#include "pathnames.h"
50
#include "ssherr.h"
51
#include "match.h"
52
53
/* import */
54
extern ServerOptions options;
55
extern u_char *session_id2;
56
extern u_int session_id2_len;
57
58
static int
59
userauth_hostbased(struct ssh *ssh)
60
{
61
	Authctxt *authctxt = ssh->authctxt;
62
	struct sshbuf *b;
63
	struct sshkey *key = NULL;
64
	char *pkalg, *cuser, *chost, *service;
65
	u_char *pkblob, *sig;
66
	size_t alen, blen, slen;
67
	int r, pktype, authenticated = 0;
68
69
	if (!authctxt->valid) {
70
		debug2("%s: disabled because of invalid user", __func__);
71
		return 0;
72
	}
73
	/* XXX use sshkey_froms() */
74
	if ((r = sshpkt_get_cstring(ssh, &pkalg, &alen)) != 0 ||
75
	    (r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0 ||
76
	    (r = sshpkt_get_cstring(ssh, &chost, NULL)) != 0 ||
77
	    (r = sshpkt_get_cstring(ssh, &cuser, NULL)) != 0 ||
78
	    (r = sshpkt_get_string(ssh, &sig, &slen)) != 0)
79
		fatal("%s: packet parsing: %s", __func__, ssh_err(r));
80
81
	debug("%s: cuser %s chost %s pkalg %s slen %zu", __func__,
82
	    cuser, chost, pkalg, slen);
83
#ifdef DEBUG_PK
84
	debug("signature:");
85
	sshbuf_dump_data(sig, siglen, stderr);
86
#endif
87
	pktype = sshkey_type_from_name(pkalg);
88
	if (pktype == KEY_UNSPEC) {
89
		/* this is perfectly legal */
90
		logit("%s: unsupported public key algorithm: %s",
91
		    __func__, pkalg);
92
		goto done;
93
	}
94
	if ((r = sshkey_from_blob(pkblob, blen, &key)) != 0) {
95
		error("%s: key_from_blob: %s", __func__, ssh_err(r));
96
		goto done;
97
	}
98
	if (key == NULL) {
99
		error("%s: cannot decode key: %s", __func__, pkalg);
100
		goto done;
101
	}
102
	if (key->type != pktype) {
103
		error("%s: type mismatch for decoded key "
104
		    "(received %d, expected %d)", __func__, key->type, pktype);
105
		goto done;
106
	}
107
	if (sshkey_type_plain(key->type) == KEY_RSA &&
108
	    (ssh->compat & SSH_BUG_RSASIGMD5) != 0) {
109
		error("Refusing RSA key because peer uses unsafe "
110
		    "signature format");
111
		goto done;
112
	}
113
	if (match_pattern_list(sshkey_ssh_name(key),
114
	    options.hostbased_key_types, 0) != 1) {
115
		logit("%s: key type %s not in HostbasedAcceptedKeyTypes",
116
		    __func__, sshkey_type(key));
117
		goto done;
118
	}
119
120
	service = ssh->compat & SSH_BUG_HBSERVICE ? "ssh-userauth" :
121
	    authctxt->service;
122
	if ((b = sshbuf_new()) == NULL)
123
		fatal("%s: sshbuf_new failed", __func__);
124
	/* reconstruct packet */
125
	if ((r = sshbuf_put_string(b, session_id2, session_id2_len)) != 0 ||
126
	    (r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
127
	    (r = sshbuf_put_cstring(b, authctxt->user)) != 0 ||
128
	    (r = sshbuf_put_cstring(b, service)) != 0 ||
129
	    (r = sshbuf_put_cstring(b, "hostbased")) != 0 ||
130
	    (r = sshbuf_put_string(b, pkalg, alen)) != 0 ||
131
	    (r = sshbuf_put_string(b, pkblob, blen)) != 0 ||
132
	    (r = sshbuf_put_cstring(b, chost)) != 0 ||
133
	    (r = sshbuf_put_cstring(b, cuser)) != 0)
134
		fatal("%s: buffer error: %s", __func__, ssh_err(r));
135
#ifdef DEBUG_PK
136
	sshbuf_dump(b, stderr);
137
#endif
138
139
	auth2_record_info(authctxt,
140
	    "client user \"%.100s\", client host \"%.100s\"", cuser, chost);
141
142
	/* test for allowed key and correct signature */
143
	authenticated = 0;
144
	if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) &&
145
	    PRIVSEP(sshkey_verify(key, sig, slen,
146
	    sshbuf_ptr(b), sshbuf_len(b), ssh->compat)) == 0)
147
		authenticated = 1;
148
149
	auth2_record_key(authctxt, authenticated, key);
150
	sshbuf_free(b);
151
done:
152
	debug2("%s: authenticated %d", __func__, authenticated);
153
	sshkey_free(key);
154
	free(pkalg);
155
	free(pkblob);
156
	free(cuser);
157
	free(chost);
158
	free(sig);
159
	return authenticated;
160
}
161
162
/* return 1 if given hostkey is allowed */
163
int
164
hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
165
    struct sshkey *key)
166
{
167
	struct ssh *ssh = active_state; /* XXX */
168
	const char *resolvedname, *ipaddr, *lookup, *reason;
169
	HostStatus host_status;
170
	int len;
171
	char *fp;
172
173
	if (auth_key_is_revoked(key))
174
		return 0;
175
176
	resolvedname = auth_get_canonical_hostname(ssh, options.use_dns);
177
	ipaddr = ssh_remote_ipaddr(ssh);
178
179
	debug2("%s: chost %s resolvedname %s ipaddr %s", __func__,
180
	    chost, resolvedname, ipaddr);
181
182
	if (((len = strlen(chost)) > 0) && chost[len - 1] == '.') {
183
		debug2("stripping trailing dot from chost %s", chost);
184
		chost[len - 1] = '\0';
185
	}
186
187
	if (options.hostbased_uses_name_from_packet_only) {
188
		if (auth_rhosts2(pw, cuser, chost, chost) == 0) {
189
			debug2("%s: auth_rhosts2 refused "
190
			    "user \"%.100s\" host \"%.100s\" (from packet)",
191
			    __func__, cuser, chost);
192
			return 0;
193
		}
194
		lookup = chost;
195
	} else {
196
		if (strcasecmp(resolvedname, chost) != 0)
197
			logit("userauth_hostbased mismatch: "
198
			    "client sends %s, but we resolve %s to %s",
199
			    chost, ipaddr, resolvedname);
200
		if (auth_rhosts2(pw, cuser, resolvedname, ipaddr) == 0) {
201
			debug2("%s: auth_rhosts2 refused "
202
			    "user \"%.100s\" host \"%.100s\" addr \"%.100s\"",
203
			    __func__, cuser, resolvedname, ipaddr);
204
			return 0;
205
		}
206
		lookup = resolvedname;
207
	}
208
	debug2("%s: access allowed by auth_rhosts2", __func__);
209
210
	if (sshkey_is_cert(key) &&
211
	    sshkey_cert_check_authority(key, 1, 0, lookup, &reason)) {
212
		error("%s", reason);
213
		auth_debug_add("%s", reason);
214
		return 0;
215
	}
216
217
	host_status = check_key_in_hostfiles(pw, key, lookup,
218
	    _PATH_SSH_SYSTEM_HOSTFILE,
219
	    options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE);
220
221
	/* backward compat if no key has been found. */
222
	if (host_status == HOST_NEW) {
223
		host_status = check_key_in_hostfiles(pw, key, lookup,
224
		    _PATH_SSH_SYSTEM_HOSTFILE2,
225
		    options.ignore_user_known_hosts ? NULL :
226
		    _PATH_SSH_USER_HOSTFILE2);
227
	}
228
229
	if (host_status == HOST_OK) {
230
		if (sshkey_is_cert(key)) {
231
			if ((fp = sshkey_fingerprint(key->cert->signature_key,
232
			    options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
233
				fatal("%s: sshkey_fingerprint fail", __func__);
234
			verbose("Accepted certificate ID \"%s\" signed by "
235
			    "%s CA %s from %s@%s", key->cert->key_id,
236
			    sshkey_type(key->cert->signature_key), fp,
237
			    cuser, lookup);
238
		} else {
239
			if ((fp = sshkey_fingerprint(key,
240
			    options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
241
				fatal("%s: sshkey_fingerprint fail", __func__);
242
			verbose("Accepted %s public key %s from %s@%s",
243
			    sshkey_type(key), fp, cuser, lookup);
244
		}
245
		free(fp);
246
	}
247
248
	return (host_status == HOST_OK);
249
}
250
251
Authmethod method_hostbased = {
252
	"hostbased",
253
	userauth_hostbased,
254
	&options.hostbased_authentication
255
};