version 1.2.2.4, 2001/03/21 18:52:32 |
version 1.3, 2000/09/07 20:27:49 |
|
|
* Author: Tatu Ylonen <ylo@cs.hut.fi> |
* Author: Tatu Ylonen <ylo@cs.hut.fi> |
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
* All rights reserved |
* All rights reserved |
|
* RSA-based authentication. This code determines whether to admit a login |
|
* based on RSA authentication. This file also contains functions to check |
|
* validity of the host key. |
|
* |
* As far as I am concerned, the code I have written for this software |
* As far as I am concerned, the code I have written for this software |
* can be used freely for any purpose. Any derived versions of this |
* can be used freely for any purpose. Any derived versions of this |
* software must be clearly marked as such, and if the derived work is |
* software must be clearly marked as such, and if the derived work is |
* incompatible with the protocol description in the RFC file, it must be |
* incompatible with the protocol description in the RFC file, it must be |
* called by a name other than "ssh" or "Secure Shell". |
* called by a name other than "ssh" or "Secure Shell". |
|
* |
|
* |
|
* Copyright (c) 2000 Markus Friedl. All rights reserved. |
|
* |
|
* Redistribution and use in source and binary forms, with or without |
|
* modification, are permitted provided that the following conditions |
|
* are met: |
|
* 1. Redistributions of source code must retain the above copyright |
|
* notice, this list of conditions and the following disclaimer. |
|
* 2. Redistributions in binary form must reproduce the above copyright |
|
* notice, this list of conditions and the following disclaimer in the |
|
* documentation and/or other materials provided with the distribution. |
|
* |
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
*/ |
|
|
#include "includes.h" |
#include "includes.h" |
RCSID("$OpenBSD$"); |
RCSID("$OpenBSD$"); |
|
|
|
#include "ssh.h" |
#include "packet.h" |
#include "packet.h" |
#include "xmalloc.h" |
#include "xmalloc.h" |
#include "match.h" |
#include "match.h" |
#include "log.h" |
|
#include "canohost.h" |
|
#include "channels.h" |
|
#include "auth-options.h" |
|
#include "servconf.h" |
|
|
|
/* Flags set authorized_keys flags */ |
/* Flags set authorized_keys flags */ |
int no_port_forwarding_flag = 0; |
int no_port_forwarding_flag = 0; |
|
|
/* "environment=" options. */ |
/* "environment=" options. */ |
struct envstring *custom_environment = NULL; |
struct envstring *custom_environment = NULL; |
|
|
extern ServerOptions options; |
/* return 1 if access is granted, 0 if not. side effect: sets key option flags */ |
|
|
void |
|
auth_clear_options(void) |
|
{ |
|
no_agent_forwarding_flag = 0; |
|
no_port_forwarding_flag = 0; |
|
no_pty_flag = 0; |
|
no_x11_forwarding_flag = 0; |
|
while (custom_environment) { |
|
struct envstring *ce = custom_environment; |
|
custom_environment = ce->next; |
|
xfree(ce->s); |
|
xfree(ce); |
|
} |
|
if (forced_command) { |
|
xfree(forced_command); |
|
forced_command = NULL; |
|
} |
|
channel_clear_permitted_opens(); |
|
} |
|
|
|
/* |
|
* return 1 if access is granted, 0 if not. |
|
* side effect: sets key option flags |
|
*/ |
|
int |
int |
auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) |
auth_parse_options(struct passwd *pw, char *options, unsigned long linenum) |
{ |
{ |
const char *cp; |
const char *cp; |
int i; |
if (!options) |
|
|
/* reset options */ |
|
auth_clear_options(); |
|
|
|
if (!opts) |
|
return 1; |
return 1; |
|
while (*options && *options != ' ' && *options != '\t') { |
while (*opts && *opts != ' ' && *opts != '\t') { |
|
cp = "no-port-forwarding"; |
cp = "no-port-forwarding"; |
if (strncasecmp(opts, cp, strlen(cp)) == 0) { |
if (strncmp(options, cp, strlen(cp)) == 0) { |
packet_send_debug("Port forwarding disabled."); |
packet_send_debug("Port forwarding disabled."); |
no_port_forwarding_flag = 1; |
no_port_forwarding_flag = 1; |
opts += strlen(cp); |
options += strlen(cp); |
goto next_option; |
goto next_option; |
} |
} |
cp = "no-agent-forwarding"; |
cp = "no-agent-forwarding"; |
if (strncasecmp(opts, cp, strlen(cp)) == 0) { |
if (strncmp(options, cp, strlen(cp)) == 0) { |
packet_send_debug("Agent forwarding disabled."); |
packet_send_debug("Agent forwarding disabled."); |
no_agent_forwarding_flag = 1; |
no_agent_forwarding_flag = 1; |
opts += strlen(cp); |
options += strlen(cp); |
goto next_option; |
goto next_option; |
} |
} |
cp = "no-X11-forwarding"; |
cp = "no-X11-forwarding"; |
if (strncasecmp(opts, cp, strlen(cp)) == 0) { |
if (strncmp(options, cp, strlen(cp)) == 0) { |
packet_send_debug("X11 forwarding disabled."); |
packet_send_debug("X11 forwarding disabled."); |
no_x11_forwarding_flag = 1; |
no_x11_forwarding_flag = 1; |
opts += strlen(cp); |
options += strlen(cp); |
goto next_option; |
goto next_option; |
} |
} |
cp = "no-pty"; |
cp = "no-pty"; |
if (strncasecmp(opts, cp, strlen(cp)) == 0) { |
if (strncmp(options, cp, strlen(cp)) == 0) { |
packet_send_debug("Pty allocation disabled."); |
packet_send_debug("Pty allocation disabled."); |
no_pty_flag = 1; |
no_pty_flag = 1; |
opts += strlen(cp); |
options += strlen(cp); |
goto next_option; |
goto next_option; |
} |
} |
cp = "command=\""; |
cp = "command=\""; |
if (strncasecmp(opts, cp, strlen(cp)) == 0) { |
if (strncmp(options, cp, strlen(cp)) == 0) { |
opts += strlen(cp); |
int i; |
forced_command = xmalloc(strlen(opts) + 1); |
options += strlen(cp); |
|
forced_command = xmalloc(strlen(options) + 1); |
i = 0; |
i = 0; |
while (*opts) { |
while (*options) { |
if (*opts == '"') |
if (*options == '"') |
break; |
break; |
if (*opts == '\\' && opts[1] == '"') { |
if (*options == '\\' && options[1] == '"') { |
opts += 2; |
options += 2; |
forced_command[i++] = '"'; |
forced_command[i++] = '"'; |
continue; |
continue; |
} |
} |
forced_command[i++] = *opts++; |
forced_command[i++] = *options++; |
} |
} |
if (!*opts) { |
if (!*options) { |
debug("%.100s, line %lu: missing end quote", |
debug("%.100s, line %lu: missing end quote", |
file, linenum); |
SSH_USER_PERMITTED_KEYS, linenum); |
packet_send_debug("%.100s, line %lu: missing end quote", |
packet_send_debug("%.100s, line %lu: missing end quote", |
file, linenum); |
SSH_USER_PERMITTED_KEYS, linenum); |
xfree(forced_command); |
continue; |
forced_command = NULL; |
|
goto bad_option; |
|
} |
} |
forced_command[i] = 0; |
forced_command[i] = 0; |
packet_send_debug("Forced command: %.900s", forced_command); |
packet_send_debug("Forced command: %.900s", forced_command); |
opts++; |
options++; |
goto next_option; |
goto next_option; |
} |
} |
cp = "environment=\""; |
cp = "environment=\""; |
if (strncasecmp(opts, cp, strlen(cp)) == 0) { |
if (strncmp(options, cp, strlen(cp)) == 0) { |
|
int i; |
char *s; |
char *s; |
struct envstring *new_envstring; |
struct envstring *new_envstring; |
|
options += strlen(cp); |
opts += strlen(cp); |
s = xmalloc(strlen(options) + 1); |
s = xmalloc(strlen(opts) + 1); |
|
i = 0; |
i = 0; |
while (*opts) { |
while (*options) { |
if (*opts == '"') |
if (*options == '"') |
break; |
break; |
if (*opts == '\\' && opts[1] == '"') { |
if (*options == '\\' && options[1] == '"') { |
opts += 2; |
options += 2; |
s[i++] = '"'; |
s[i++] = '"'; |
continue; |
continue; |
} |
} |
s[i++] = *opts++; |
s[i++] = *options++; |
} |
} |
if (!*opts) { |
if (!*options) { |
debug("%.100s, line %lu: missing end quote", |
debug("%.100s, line %lu: missing end quote", |
file, linenum); |
SSH_USER_PERMITTED_KEYS, linenum); |
packet_send_debug("%.100s, line %lu: missing end quote", |
packet_send_debug("%.100s, line %lu: missing end quote", |
file, linenum); |
SSH_USER_PERMITTED_KEYS, linenum); |
xfree(s); |
continue; |
goto bad_option; |
|
} |
} |
s[i] = 0; |
s[i] = 0; |
packet_send_debug("Adding to environment: %.900s", s); |
packet_send_debug("Adding to environment: %.900s", s); |
debug("Adding to environment: %.900s", s); |
debug("Adding to environment: %.900s", s); |
opts++; |
options++; |
new_envstring = xmalloc(sizeof(struct envstring)); |
new_envstring = xmalloc(sizeof(struct envstring)); |
new_envstring->s = s; |
new_envstring->s = s; |
new_envstring->next = custom_environment; |
new_envstring->next = custom_environment; |
|
|
goto next_option; |
goto next_option; |
} |
} |
cp = "from=\""; |
cp = "from=\""; |
if (strncasecmp(opts, cp, strlen(cp)) == 0) { |
if (strncmp(options, cp, strlen(cp)) == 0) { |
int mname, mip; |
int mname, mip; |
const char *remote_ip = get_remote_ipaddr(); |
char *patterns = xmalloc(strlen(options) + 1); |
const char *remote_host = get_canonical_hostname( |
int i; |
options.reverse_mapping_check); |
options += strlen(cp); |
char *patterns = xmalloc(strlen(opts) + 1); |
|
|
|
opts += strlen(cp); |
|
i = 0; |
i = 0; |
while (*opts) { |
while (*options) { |
if (*opts == '"') |
if (*options == '"') |
break; |
break; |
if (*opts == '\\' && opts[1] == '"') { |
if (*options == '\\' && options[1] == '"') { |
opts += 2; |
options += 2; |
patterns[i++] = '"'; |
patterns[i++] = '"'; |
continue; |
continue; |
} |
} |
patterns[i++] = *opts++; |
patterns[i++] = *options++; |
} |
} |
if (!*opts) { |
if (!*options) { |
debug("%.100s, line %lu: missing end quote", |
debug("%.100s, line %lu: missing end quote", |
file, linenum); |
SSH_USER_PERMITTED_KEYS, linenum); |
packet_send_debug("%.100s, line %lu: missing end quote", |
packet_send_debug("%.100s, line %lu: missing end quote", |
file, linenum); |
SSH_USER_PERMITTED_KEYS, linenum); |
xfree(patterns); |
continue; |
goto bad_option; |
|
} |
} |
patterns[i] = 0; |
patterns[i] = 0; |
opts++; |
options++; |
/* |
/* |
* Deny access if we get a negative |
* Deny access if we get a negative |
* match for the hostname or the ip |
* match for the hostname or the ip |
* or if we get not match at all |
* or if we get not match at all |
*/ |
*/ |
mname = match_hostname(remote_host, patterns, |
mname = match_hostname(get_canonical_hostname(), |
strlen(patterns)); |
patterns, strlen(patterns)); |
mip = match_hostname(remote_ip, patterns, |
mip = match_hostname(get_remote_ipaddr(), |
strlen(patterns)); |
patterns, strlen(patterns)); |
xfree(patterns); |
xfree(patterns); |
if (mname == -1 || mip == -1 || |
if (mname == -1 || mip == -1 || |
(mname != 1 && mip != 1)) { |
(mname != 1 && mip != 1)) { |
log("Authentication tried for %.100s with " |
log("Authentication tried for %.100s with correct key but not from a permitted host (host=%.200s, ip=%.200s).", |
"correct key but not from a permitted " |
pw->pw_name, get_canonical_hostname(), |
"host (host=%.200s, ip=%.200s).", |
get_remote_ipaddr()); |
pw->pw_name, remote_host, remote_ip); |
packet_send_debug("Your host '%.200s' is not permitted to use this key for login.", |
packet_send_debug("Your host '%.200s' is not " |
get_canonical_hostname()); |
"permitted to use this key for login.", |
/* key invalid for this host, reset flags */ |
remote_host); |
no_agent_forwarding_flag = 0; |
|
no_port_forwarding_flag = 0; |
|
no_pty_flag = 0; |
|
no_x11_forwarding_flag = 0; |
|
while (custom_environment) { |
|
struct envstring *ce = custom_environment; |
|
custom_environment = ce->next; |
|
xfree(ce->s); |
|
xfree(ce); |
|
} |
|
if (forced_command) { |
|
xfree(forced_command); |
|
forced_command = NULL; |
|
} |
/* deny access */ |
/* deny access */ |
return 0; |
return 0; |
} |
} |
/* Host name matches. */ |
/* Host name matches. */ |
goto next_option; |
goto next_option; |
} |
} |
cp = "permitopen=\""; |
|
if (strncasecmp(opts, cp, strlen(cp)) == 0) { |
|
u_short port; |
|
char *c, *ep; |
|
char *patterns = xmalloc(strlen(opts) + 1); |
|
|
|
opts += strlen(cp); |
|
i = 0; |
|
while (*opts) { |
|
if (*opts == '"') |
|
break; |
|
if (*opts == '\\' && opts[1] == '"') { |
|
opts += 2; |
|
patterns[i++] = '"'; |
|
continue; |
|
} |
|
patterns[i++] = *opts++; |
|
} |
|
if (!*opts) { |
|
debug("%.100s, line %lu: missing end quote", |
|
file, linenum); |
|
packet_send_debug("%.100s, line %lu: missing end quote", |
|
file, linenum); |
|
xfree(patterns); |
|
goto bad_option; |
|
} |
|
patterns[i] = 0; |
|
opts++; |
|
c = strchr(patterns, ':'); |
|
if (c == NULL) { |
|
debug("%.100s, line %lu: permitopen: missing colon <%.100s>", |
|
file, linenum, patterns); |
|
packet_send_debug("%.100s, line %lu: missing colon", |
|
file, linenum); |
|
xfree(patterns); |
|
goto bad_option; |
|
} |
|
*c = 0; |
|
c++; |
|
port = strtol(c, &ep, 0); |
|
if (c == ep) { |
|
debug("%.100s, line %lu: permitopen: missing port <%.100s>", |
|
file, linenum, patterns); |
|
packet_send_debug("%.100s, line %lu: missing port", |
|
file, linenum); |
|
xfree(patterns); |
|
goto bad_option; |
|
} |
|
if (options.allow_tcp_forwarding) |
|
channel_add_permitted_opens(patterns, port); |
|
xfree(patterns); |
|
goto next_option; |
|
} |
|
next_option: |
next_option: |
/* |
/* |
* Skip the comma, and move to the next option |
* Skip the comma, and move to the next option |
* (or break out if there are no more). |
* (or break out if there are no more). |
*/ |
*/ |
if (!*opts) |
if (!*options) |
fatal("Bugs in auth-options.c option processing."); |
fatal("Bugs in auth-options.c option processing."); |
if (*opts == ' ' || *opts == '\t') |
if (*options == ' ' || *options == '\t') |
break; /* End of options. */ |
break; /* End of options. */ |
if (*opts != ',') |
if (*options != ',') |
goto bad_option; |
goto bad_option; |
opts++; |
options++; |
/* Process the next option. */ |
/* Process the next option. */ |
} |
} |
/* grant access */ |
/* grant access */ |
|
|
|
|
bad_option: |
bad_option: |
log("Bad options in %.100s file, line %lu: %.50s", |
log("Bad options in %.100s file, line %lu: %.50s", |
file, linenum, opts); |
SSH_USER_PERMITTED_KEYS, linenum, options); |
packet_send_debug("Bad options in %.100s file, line %lu: %.50s", |
packet_send_debug("Bad options in %.100s file, line %lu: %.50s", |
file, linenum, opts); |
SSH_USER_PERMITTED_KEYS, linenum, options); |
/* deny access */ |
/* deny access */ |
return 0; |
return 0; |
} |
} |