*/
#include "includes.h"
-RCSID("$OpenBSD: auth2.c,v 1.43 2001/02/22 21:59:44 markus Exp $");
+RCSID("$OpenBSD: auth2.c,v 1.52 2001/04/12 19:15:24 markus Exp $");
#include <openssl/evp.h>
#include "uidswap.h"
#include "auth-options.h"
#include "misc.h"
+#include "hostfile.h"
+#include "canohost.h"
+#include "tildexpand.h"
/* import */
extern ServerOptions options;
/* helper */
Authmethod *authmethod_lookup(const char *name);
-int user_key_allowed(struct passwd *pw, Key *key);
char *authmethods_get(void);
+int user_key_allowed(struct passwd *pw, Key *key);
+int
+hostbased_key_allowed(struct passwd *pw, const char *cuser, const char *chost,
+ Key *key);
/* auth */
void userauth_banner(void);
+void userauth_reply(Authctxt *authctxt, int authenticated);
int userauth_none(Authctxt *authctxt);
int userauth_passwd(Authctxt *authctxt);
int userauth_pubkey(Authctxt *authctxt);
+int userauth_hostbased(Authctxt *authctxt);
int userauth_kbdint(Authctxt *authctxt);
Authmethod authmethods[] = {
{"keyboard-interactive",
userauth_kbdint,
&options.kbd_interactive_authentication},
+ {"hostbased",
+ userauth_hostbased,
+ &options.hostbased_authentication},
{NULL, NULL, NULL}
};
dispatch_init(&protocol_error);
dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
- do_authenticated2(authctxt);
+ do_authenticated(authctxt);
}
void
} else if (authctxt->valid) {
if (strcmp(user, authctxt->user) != 0 ||
strcmp(service, authctxt->service) != 0) {
- log("input_userauth_request: missmatch: (%s,%s)!=(%s,%s)",
+ log("input_userauth_request: mismatch: (%s,%s)!=(%s,%s)",
user, service, authctxt->user, authctxt->service);
authctxt->valid = 0;
}
debug2("input_userauth_request: try method %s", method);
authenticated = m->userauth(authctxt);
}
+ userauth_finish(authctxt, authenticated, method);
+
+ xfree(service);
+ xfree(user);
+ xfree(method);
+}
+
+void
+userauth_finish(Authctxt *authctxt, int authenticated, char *method)
+{
if (!authctxt->valid && authenticated)
fatal("INTERNAL ERROR: authenticated invalid user %s",
authctxt->user);
if (!authctxt->postponed)
userauth_reply(authctxt, authenticated);
-
- xfree(service);
- xfree(user);
- xfree(method);
}
void
if (options.banner == NULL || (datafellows & SSH_BUG_BANNER))
return;
- if ((fd = open(options.banner, O_RDONLY)) < 0) {
- error("userauth_banner: open %s failed: %s",
- options.banner, strerror(errno));
+ if ((fd = open(options.banner, O_RDONLY)) < 0)
return;
- }
if (fstat(fd, &st) < 0)
goto done;
len = st.st_size;
return authenticated;
}
+int
+userauth_hostbased(Authctxt *authctxt)
+{
+ Buffer b;
+ Key *key;
+ char *pkalg, *pkblob, *sig;
+ char *cuser, *chost;
+ u_int alen, blen, slen;
+ int pktype;
+ int authenticated = 0;
+
+ if (!authctxt->valid) {
+ debug2("userauth_hostbased: disabled because of invalid user");
+ return 0;
+ }
+ pkalg = packet_get_string(&alen);
+ pkblob = packet_get_string(&blen);
+ chost = packet_get_string(NULL);
+ cuser = packet_get_string(NULL);
+ sig = packet_get_string(&slen);
+
+ debug("userauth_hostbased: cuser %s chost %s pkalg %s slen %d",
+ cuser, chost, pkalg, slen);
+#ifdef DEBUG_PK
+ debug("signature:");
+ buffer_init(&b);
+ buffer_append(&b, sig, slen);
+ buffer_dump(&b);
+ buffer_free(&b);
+#endif
+ pktype = key_type_from_name(pkalg);
+ if (pktype == KEY_UNSPEC) {
+ /* this is perfectly legal */
+ log("userauth_hostbased: unsupported "
+ "public key algorithm: %s", pkalg);
+ goto done;
+ }
+ key = key_from_blob(pkblob, blen);
+ if (key == NULL) {
+ debug("userauth_hostbased: cannot decode key: %s", pkalg);
+ goto done;
+ }
+ buffer_init(&b);
+ if (datafellows & SSH_OLD_SESSIONID) {
+ buffer_append(&b, session_id2, session_id2_len);
+ } else {
+ buffer_put_string(&b, session_id2, session_id2_len);
+ }
+ if (datafellows & SSH_BUG_HBSERVICE)
+ debug("SSH_BUG_HBSERVICE");
+ /* reconstruct packet */
+ buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
+ buffer_put_cstring(&b, authctxt->user);
+ buffer_put_cstring(&b,
+ datafellows & SSH_BUG_HBSERVICE ?
+ "ssh-userauth" :
+ authctxt->service);
+ buffer_put_cstring(&b, "hostbased");
+ buffer_put_string(&b, pkalg, alen);
+ buffer_put_string(&b, pkblob, blen);
+ buffer_put_cstring(&b, chost);
+ buffer_put_cstring(&b, cuser);
+#ifdef DEBUG_PK
+ buffer_dump(&b);
+#endif
+ /* test for allowed key and correct signature */
+ if (hostbased_key_allowed(authctxt->pw, cuser, chost, key) &&
+ key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
+ authenticated = 1;
+
+ buffer_clear(&b);
+ key_free(key);
+
+done:
+ debug2("userauth_hostbased: authenticated %d", authenticated);
+ xfree(pkalg);
+ xfree(pkblob);
+ xfree(cuser);
+ xfree(chost);
+ xfree(sig);
+ return authenticated;
+}
+
/* get current user */
struct passwd*
return 0;
/* Temporarily use the user's uid. */
- temporarily_use_uid(pw->pw_uid);
+ temporarily_use_uid(pw);
/* The authorized keys. */
snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
}
if (fail) {
fclose(f);
- log("%s",buf);
+ log("%s", buf);
restore_uid();
return 0;
}
restore_uid();
fclose(f);
key_free(found);
+ if (!found_key)
+ debug2("key not found");
return found_key;
}
+
+/* return 1 if given hostkey is allowed */
+int
+hostbased_key_allowed(struct passwd *pw, const char *cuser, const char *chost,
+ Key *key)
+{
+ Key *found;
+ const char *resolvedname, *ipaddr, *lookup;
+ struct stat st;
+ char *user_hostfile;
+ int host_status;
+
+ resolvedname = get_canonical_hostname(options.reverse_mapping_check);
+ ipaddr = get_remote_ipaddr();
+
+ debug2("userauth_hostbased: resolvedname %s ipaddr %s",
+ resolvedname, ipaddr);
+
+ if (options.hostbased_uses_name_from_packet_only) {
+ if (auth_rhosts2(pw, cuser, chost, chost) == 0)
+ return 0;
+ lookup = chost;
+ } else {
+ if (strcasecmp(resolvedname, chost) != 0)
+ log("userauth_hostbased mismatch: "
+ "client sends %s, but we resolve %s to %s",
+ chost, ipaddr, resolvedname);
+ if (auth_rhosts2(pw, cuser, resolvedname, ipaddr) == 0)
+ return 0;
+ lookup = resolvedname;
+ }
+ debug2("userauth_hostbased: access allowed by auth_rhosts2");
+
+ /* XXX this is copied from auth-rh-rsa.c and should be shared */
+ found = key_new(key->type);
+ host_status = check_host_in_hostfile(_PATH_SSH_SYSTEM_HOSTFILE2, lookup,
+ key, found, NULL);
+
+ if (host_status != HOST_OK && !options.ignore_user_known_hosts) {
+ user_hostfile = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE2,
+ pw->pw_uid);
+ if (options.strict_modes &&
+ (stat(user_hostfile, &st) == 0) &&
+ ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
+ (st.st_mode & 022) != 0)) {
+ log("Hostbased authentication refused for %.100s: "
+ "bad owner or modes for %.200s",
+ pw->pw_name, user_hostfile);
+ } else {
+ temporarily_use_uid(pw);
+ host_status = check_host_in_hostfile(user_hostfile,
+ lookup, key, found, NULL);
+ restore_uid();
+ }
+ xfree(user_hostfile);
+ }
+ key_free(found);
+
+ debug2("userauth_hostbased: key %s for %s", host_status == HOST_OK ?
+ "ok" : "not found", lookup);
+ return (host_status == HOST_OK);
+}