auth2-hostbased.c revision 181110
1168404Spjd/* $OpenBSD: auth2-hostbased.c,v 1.11 2006/08/03 03:34:41 deraadt Exp $ */
2168404Spjd/*
3168404Spjd * Copyright (c) 2000 Markus Friedl.  All rights reserved.
4168404Spjd *
5168404Spjd * Redistribution and use in source and binary forms, with or without
6168404Spjd * modification, are permitted provided that the following conditions
7168404Spjd * are met:
8168404Spjd * 1. Redistributions of source code must retain the above copyright
9168404Spjd *    notice, this list of conditions and the following disclaimer.
10168404Spjd * 2. Redistributions in binary form must reproduce the above copyright
11168404Spjd *    notice, this list of conditions and the following disclaimer in the
12168404Spjd *    documentation and/or other materials provided with the distribution.
13168404Spjd *
14168404Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15168404Spjd * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16168404Spjd * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17168404Spjd * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18168404Spjd * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19168404Spjd * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20168404Spjd * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21168404Spjd * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22200724Sdelphij * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23168404Spjd * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24168404Spjd */
25168404Spjd
26168404Spjd#include "includes.h"
27263398Sdelphij
28263398Sdelphij#include <sys/types.h>
29263398Sdelphij
30263398Sdelphij#include <pwd.h>
31168404Spjd#include <string.h>
32168404Spjd#include <stdarg.h>
33168404Spjd
34168404Spjd#include "xmalloc.h"
35168404Spjd#include "ssh2.h"
36168404Spjd#include "packet.h"
37168404Spjd#include "buffer.h"
38168404Spjd#include "log.h"
39168404Spjd#include "servconf.h"
40168404Spjd#include "compat.h"
41168404Spjd#include "key.h"
42168404Spjd#include "hostfile.h"
43168404Spjd#include "auth.h"
44168404Spjd#include "canohost.h"
45168404Spjd#ifdef GSSAPI
46168404Spjd#include "ssh-gss.h"
47219089Spjd#endif
48219089Spjd#include "monitor_wrap.h"
49168404Spjd#include "pathnames.h"
50168404Spjd
51168404Spjd/* import */
52168404Spjdextern ServerOptions options;
53168404Spjdextern u_char *session_id2;
54263398Sdelphijextern u_int session_id2_len;
55168404Spjd
56168404Spjdstatic int
57168404Spjduserauth_hostbased(Authctxt *authctxt)
58168404Spjd{
59168404Spjd	Buffer b;
60168404Spjd	Key *key = NULL;
61168404Spjd	char *pkalg, *cuser, *chost, *service;
62168404Spjd	u_char *pkblob, *sig;
63219089Spjd	u_int alen, blen, slen;
64219089Spjd	int pktype;
65168404Spjd	int authenticated = 0;
66219089Spjd
67168404Spjd	if (!authctxt->valid) {
68219089Spjd		debug2("userauth_hostbased: disabled because of invalid user");
69219089Spjd		return 0;
70219089Spjd	}
71219089Spjd	pkalg = packet_get_string(&alen);
72219089Spjd	pkblob = packet_get_string(&blen);
73219089Spjd	chost = packet_get_string(NULL);
74219089Spjd	cuser = packet_get_string(NULL);
75219089Spjd	sig = packet_get_string(&slen);
76219089Spjd
77219089Spjd	debug("userauth_hostbased: cuser %s chost %s pkalg %s slen %d",
78219089Spjd	    cuser, chost, pkalg, slen);
79219089Spjd#ifdef DEBUG_PK
80219089Spjd	debug("signature:");
81219089Spjd	buffer_init(&b);
82219089Spjd	buffer_append(&b, sig, slen);
83168404Spjd	buffer_dump(&b);
84168404Spjd	buffer_free(&b);
85219089Spjd#endif
86168404Spjd	pktype = key_type_from_name(pkalg);
87168404Spjd	if (pktype == KEY_UNSPEC) {
88168404Spjd		/* this is perfectly legal */
89168404Spjd		logit("userauth_hostbased: unsupported "
90168404Spjd		    "public key algorithm: %s", pkalg);
91168404Spjd		goto done;
92168404Spjd	}
93168404Spjd	key = key_from_blob(pkblob, blen);
94219089Spjd	if (key == NULL) {
95168404Spjd		error("userauth_hostbased: cannot decode key: %s", pkalg);
96168404Spjd		goto done;
97168404Spjd	}
98168404Spjd	if (key->type != pktype) {
99168404Spjd		error("userauth_hostbased: type mismatch for decoded key "
100168404Spjd		    "(received %d, expected %d)", key->type, pktype);
101168404Spjd		goto done;
102219089Spjd	}
103168404Spjd	service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" :
104168404Spjd	    authctxt->service;
105168404Spjd	buffer_init(&b);
106168404Spjd	buffer_put_string(&b, session_id2, session_id2_len);
107168404Spjd	/* reconstruct packet */
108168404Spjd	buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
109168404Spjd	buffer_put_cstring(&b, authctxt->user);
110168404Spjd	buffer_put_cstring(&b, service);
111168404Spjd	buffer_put_cstring(&b, "hostbased");
112168404Spjd	buffer_put_string(&b, pkalg, alen);
113168404Spjd	buffer_put_string(&b, pkblob, blen);
114219089Spjd	buffer_put_cstring(&b, chost);
115168404Spjd	buffer_put_cstring(&b, cuser);
116219089Spjd#ifdef DEBUG_PK
117168404Spjd	buffer_dump(&b);
118168404Spjd#endif
119168404Spjd	/* test for allowed key and correct signature */
120168404Spjd	authenticated = 0;
121168404Spjd	if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) &&
122168404Spjd	    PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
123168404Spjd			buffer_len(&b))) == 1)
124168404Spjd		authenticated = 1;
125219089Spjd
126168404Spjd	buffer_free(&b);
127168404Spjddone:
128168404Spjd	debug2("userauth_hostbased: authenticated %d", authenticated);
129168404Spjd	if (key != NULL)
130219089Spjd		key_free(key);
131219089Spjd	xfree(pkalg);
132219089Spjd	xfree(pkblob);
133168404Spjd	xfree(cuser);
134209962Smm	xfree(chost);
135168404Spjd	xfree(sig);
136168404Spjd	return authenticated;
137168404Spjd}
138219089Spjd
139263398Sdelphij/* return 1 if given hostkey is allowed */
140168404Spjdint
141168404Spjdhostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
142219089Spjd    Key *key)
143219089Spjd{
144209962Smm	const char *resolvedname, *ipaddr, *lookup;
145209962Smm	HostStatus host_status;
146209962Smm	int len;
147168404Spjd
148219089Spjd	resolvedname = get_canonical_hostname(options.use_dns);
149219089Spjd	ipaddr = get_remote_ipaddr();
150219089Spjd
151219089Spjd	debug2("userauth_hostbased: chost %s resolvedname %s ipaddr %s",
152219089Spjd	    chost, resolvedname, ipaddr);
153219089Spjd
154219089Spjd	if (options.hostbased_uses_name_from_packet_only) {
155168404Spjd		if (auth_rhosts2(pw, cuser, chost, chost) == 0)
156219089Spjd			return 0;
157219089Spjd		lookup = chost;
158219089Spjd	} else {
159168404Spjd		if (((len = strlen(chost)) > 0) && chost[len - 1] == '.') {
160219089Spjd			debug2("stripping trailing dot from chost %s", chost);
161219089Spjd			chost[len - 1] = '\0';
162219089Spjd		}
163219089Spjd		if (strcasecmp(resolvedname, chost) != 0)
164219089Spjd			logit("userauth_hostbased mismatch: "
165219089Spjd			    "client sends %s, but we resolve %s to %s",
166168404Spjd			    chost, ipaddr, resolvedname);
167168404Spjd		if (auth_rhosts2(pw, cuser, resolvedname, ipaddr) == 0)
168168404Spjd			return 0;
169168404Spjd		lookup = resolvedname;
170168404Spjd	}
171168404Spjd	debug2("userauth_hostbased: access allowed by auth_rhosts2");
172168404Spjd
173219089Spjd	host_status = check_key_in_hostfiles(pw, key, lookup,
174168404Spjd	    _PATH_SSH_SYSTEM_HOSTFILE,
175168404Spjd	    options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE);
176168404Spjd
177168404Spjd	/* backward compat if no key has been found. */
178168404Spjd	if (host_status == HOST_NEW)
179168404Spjd		host_status = check_key_in_hostfiles(pw, key, lookup,
180168404Spjd		    _PATH_SSH_SYSTEM_HOSTFILE2,
181168404Spjd		    options.ignore_user_known_hosts ? NULL :
182168404Spjd		    _PATH_SSH_USER_HOSTFILE2);
183168404Spjd
184168404Spjd	return (host_status == HOST_OK);
185168404Spjd}
186168404Spjd
187168404SpjdAuthmethod method_hostbased = {
188219089Spjd	"hostbased",
189168404Spjd	userauth_hostbased,
190168404Spjd	&options.hostbased_authentication
191168404Spjd};
192168404Spjd