version 1.20.2.3, 2001/03/21 19:46:22 |
version 1.20.2.4, 2001/05/07 21:09:26 |
|
|
#include "uidswap.h" |
#include "uidswap.h" |
#include "auth-options.h" |
#include "auth-options.h" |
#include "misc.h" |
#include "misc.h" |
|
#include "hostfile.h" |
|
#include "canohost.h" |
|
#include "tildexpand.h" |
|
|
/* import */ |
/* import */ |
extern ServerOptions options; |
extern ServerOptions options; |
|
|
|
|
/* helper */ |
/* helper */ |
Authmethod *authmethod_lookup(const char *name); |
Authmethod *authmethod_lookup(const char *name); |
int user_key_allowed(struct passwd *pw, Key *key); |
|
char *authmethods_get(void); |
char *authmethods_get(void); |
|
int user_key_allowed(struct passwd *pw, Key *key); |
|
int |
|
hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost, |
|
Key *key); |
|
|
/* auth */ |
/* auth */ |
void userauth_banner(void); |
void userauth_banner(void); |
|
void userauth_reply(Authctxt *authctxt, int authenticated); |
int userauth_none(Authctxt *authctxt); |
int userauth_none(Authctxt *authctxt); |
int userauth_passwd(Authctxt *authctxt); |
int userauth_passwd(Authctxt *authctxt); |
int userauth_pubkey(Authctxt *authctxt); |
int userauth_pubkey(Authctxt *authctxt); |
|
int userauth_hostbased(Authctxt *authctxt); |
int userauth_kbdint(Authctxt *authctxt); |
int userauth_kbdint(Authctxt *authctxt); |
|
|
Authmethod authmethods[] = { |
Authmethod authmethods[] = { |
|
|
{"keyboard-interactive", |
{"keyboard-interactive", |
userauth_kbdint, |
userauth_kbdint, |
&options.kbd_interactive_authentication}, |
&options.kbd_interactive_authentication}, |
|
{"hostbased", |
|
userauth_hostbased, |
|
&options.hostbased_authentication}, |
{NULL, NULL, NULL} |
{NULL, NULL, NULL} |
}; |
}; |
|
|
|
|
dispatch_init(&protocol_error); |
dispatch_init(&protocol_error); |
dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request); |
dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request); |
dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt); |
dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt); |
do_authenticated2(authctxt); |
do_authenticated(authctxt); |
} |
} |
|
|
void |
void |
|
|
} else if (authctxt->valid) { |
} else if (authctxt->valid) { |
if (strcmp(user, authctxt->user) != 0 || |
if (strcmp(user, authctxt->user) != 0 || |
strcmp(service, authctxt->service) != 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); |
user, service, authctxt->user, authctxt->service); |
authctxt->valid = 0; |
authctxt->valid = 0; |
} |
} |
|
|
/* reset state */ |
/* reset state */ |
dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, &protocol_error); |
dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, &protocol_error); |
authctxt->postponed = 0; |
authctxt->postponed = 0; |
|
#ifdef BSD_AUTH |
|
if (authctxt->as) { |
|
auth_close(authctxt->as); |
|
authctxt->as = NULL; |
|
} |
|
#endif |
|
|
/* try to authenticate user */ |
/* try to authenticate user */ |
m = authmethod_lookup(method); |
m = authmethod_lookup(method); |
|
|
debug2("input_userauth_request: try method %s", method); |
debug2("input_userauth_request: try method %s", method); |
authenticated = m->userauth(authctxt); |
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) |
if (!authctxt->valid && authenticated) |
fatal("INTERNAL ERROR: authenticated invalid user %s", |
fatal("INTERNAL ERROR: authenticated invalid user %s", |
authctxt->user); |
authctxt->user); |
|
|
|
|
if (!authctxt->postponed) |
if (!authctxt->postponed) |
userauth_reply(authctxt, authenticated); |
userauth_reply(authctxt, authenticated); |
|
|
xfree(service); |
|
xfree(user); |
|
xfree(method); |
|
} |
} |
|
|
void |
void |
|
|
|
|
if (options.banner == NULL || (datafellows & SSH_BUG_BANNER)) |
if (options.banner == NULL || (datafellows & SSH_BUG_BANNER)) |
return; |
return; |
if ((fd = open(options.banner, O_RDONLY)) < 0) { |
if ((fd = open(options.banner, O_RDONLY)) < 0) |
error("userauth_banner: open %s failed: %s", |
|
options.banner, strerror(errno)); |
|
return; |
return; |
} |
|
if (fstat(fd, &st) < 0) |
if (fstat(fd, &st) < 0) |
goto done; |
goto done; |
len = st.st_size; |
len = st.st_size; |
|
|
m->enabled = NULL; |
m->enabled = NULL; |
packet_done(); |
packet_done(); |
userauth_banner(); |
userauth_banner(); |
return authctxt->valid ? auth_password(authctxt->pw, "") : 0; |
return authctxt->valid ? auth_password(authctxt, "") : 0; |
} |
} |
|
|
int |
int |
|
|
password = packet_get_string(&len); |
password = packet_get_string(&len); |
packet_done(); |
packet_done(); |
if (authctxt->valid && |
if (authctxt->valid && |
auth_password(authctxt->pw, password) == 1) |
auth_password(authctxt, password) == 1) |
authenticated = 1; |
authenticated = 1; |
memset(password, 0, len); |
memset(password, 0, len); |
xfree(password); |
xfree(password); |
|
|
} else { |
} else { |
buffer_put_cstring(&b, "publickey"); |
buffer_put_cstring(&b, "publickey"); |
buffer_put_char(&b, have_sig); |
buffer_put_char(&b, have_sig); |
buffer_put_cstring(&b, key_ssh_name(key)); |
buffer_put_cstring(&b, pkalg); |
} |
} |
buffer_put_string(&b, pkblob, blen); |
buffer_put_string(&b, pkblob, blen); |
#ifdef DEBUG_PK |
#ifdef DEBUG_PK |
|
|
return authenticated; |
return authenticated; |
} |
} |
|
|
|
int |
|
userauth_hostbased(Authctxt *authctxt) |
|
{ |
|
Buffer b; |
|
Key *key; |
|
char *pkalg, *pkblob, *sig, *cuser, *chost, *service; |
|
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; |
|
} |
|
service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" : |
|
authctxt->service; |
|
buffer_init(&b); |
|
buffer_put_string(&b, session_id2, session_id2_len); |
|
/* reconstruct packet */ |
|
buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); |
|
buffer_put_cstring(&b, authctxt->user); |
|
buffer_put_cstring(&b, 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 */ |
/* get current user */ |
|
|
struct passwd* |
struct passwd* |
|
|
return 0; |
return 0; |
|
|
/* Temporarily use the user's uid. */ |
/* Temporarily use the user's uid. */ |
temporarily_use_uid(pw->pw_uid); |
temporarily_use_uid(pw); |
|
|
/* The authorized keys. */ |
/* The authorized keys. */ |
snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir, |
snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir, |
|
|
if (!found_key) |
if (!found_key) |
debug2("key not found"); |
debug2("key not found"); |
return found_key; |
return found_key; |
|
} |
|
|
|
/* return 1 if given hostkey is allowed */ |
|
int |
|
hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost, |
|
Key *key) |
|
{ |
|
Key *found; |
|
const char *resolvedname, *ipaddr, *lookup; |
|
struct stat st; |
|
char *user_hostfile; |
|
int host_status, len; |
|
|
|
resolvedname = get_canonical_hostname(options.reverse_mapping_check); |
|
ipaddr = get_remote_ipaddr(); |
|
|
|
debug2("userauth_hostbased: chost %s resolvedname %s ipaddr %s", |
|
chost, resolvedname, ipaddr); |
|
|
|
if (options.hostbased_uses_name_from_packet_only) { |
|
if (auth_rhosts2(pw, cuser, chost, chost) == 0) |
|
return 0; |
|
lookup = chost; |
|
} else { |
|
if (((len = strlen(chost)) > 0) && chost[len - 1] == '.') { |
|
debug2("stripping trailing dot from chost %s", chost); |
|
chost[len - 1] = '\0'; |
|
} |
|
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); |
} |
} |