Fix conflicts.

This commit is contained in:
Dag-Erling Smørgrav 2002-03-18 10:09:43 +00:00
parent 0412d17c69
commit af12a3e74a
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=92559
51 changed files with 6842 additions and 6350 deletions

View file

@ -23,83 +23,61 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth-chall.c,v 1.7 2001/04/05 10:42:47 markus Exp $");
RCSID("$OpenBSD: auth-chall.c,v 1.8 2001/05/18 14:13:28 markus Exp $");
RCSID("$FreeBSD$");
#include "auth.h"
#include "log.h"
#include "xmalloc.h"
/* limited protocol v1 interface to kbd-interactive authentication */
extern KbdintDevice *devices[];
static KbdintDevice *device;
#ifdef BSD_AUTH
char *
get_challenge(Authctxt *authctxt, char *devs)
get_challenge(Authctxt *authctxt)
{
char *challenge;
char *challenge, *name, *info, **prompts;
u_int i, numprompts;
u_int *echo_on;
if (authctxt->as != NULL) {
debug2("try reuse session");
challenge = auth_getitem(authctxt->as, AUTHV_CHALLENGE);
if (challenge != NULL) {
debug2("reuse bsd auth session");
return challenge;
}
auth_close(authctxt->as);
authctxt->as = NULL;
device = devices[0]; /* we always use the 1st device for protocol 1 */
if (device == NULL)
return NULL;
if ((authctxt->kbdintctxt = device->init_ctx(authctxt)) == NULL)
return NULL;
if (device->query(authctxt->kbdintctxt, &name, &info,
&numprompts, &prompts, &echo_on)) {
device->free_ctx(authctxt->kbdintctxt);
authctxt->kbdintctxt = NULL;
return NULL;
}
debug2("new bsd auth session");
if (devs == NULL || strlen(devs) == 0)
devs = authctxt->style;
debug3("bsd auth: devs %s", devs ? devs : "<default>");
authctxt->as = auth_userchallenge(authctxt->user, devs, "auth-ssh",
&challenge);
if (authctxt->as == NULL)
return NULL;
debug2("get_challenge: <%s>", challenge ? challenge : "EMPTY");
return challenge;
}
int
verify_response(Authctxt *authctxt, char *response)
{
int authok;
if (numprompts < 1)
fatal("get_challenge: numprompts < 1");
challenge = xstrdup(prompts[0]);
for (i = 0; i < numprompts; i++)
xfree(prompts[i]);
xfree(prompts);
xfree(name);
xfree(echo_on);
xfree(info);
if (authctxt->as == 0)
error("verify_response: no bsd auth session");
authok = auth_userresponse(authctxt->as, response, 0);
authctxt->as = NULL;
debug("verify_response: <%s> = <%d>", response, authok);
return authok != 0;
return (challenge);
}
#else
#ifdef SKEY
#include <opie.h>
int
verify_response(Authctxt *authctxt, const char *response)
{
char *resp[1];
int res;
char *
get_challenge(Authctxt *authctxt, char *devs)
{
static char challenge[1024];
struct opie opie;
if (opiechallenge(&opie, authctxt->user, challenge) == -1)
return NULL;
strlcat(challenge, "\nS/Key Password: ", sizeof challenge);
return challenge;
if (device == NULL)
return 0;
if (authctxt->kbdintctxt == NULL)
return 0;
resp[0] = (char *)response;
res = device->respond(authctxt->kbdintctxt, 1, resp);
device->free_ctx(authctxt->kbdintctxt);
authctxt->kbdintctxt = NULL;
return res ? 0 : 1;
}
int
verify_response(Authctxt *authctxt, char *response)
{
return (authctxt->valid &&
opie_haskey(authctxt->pw->pw_name) == 0 &&
opie_passverify(authctxt->pw->pw_name, response) != -1);
}
#else
/* not available */
char *
get_challenge(Authctxt *authctxt, char *devs)
{
return NULL;
}
int
verify_response(Authctxt *authctxt, char *response)
{
return 0;
}
#endif
#endif

View file

@ -23,7 +23,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth-krb4.c,v 1.23 2001/01/22 08:15:00 markus Exp $");
RCSID("$OpenBSD: auth-krb4.c,v 1.25 2001/12/19 07:18:56 deraadt Exp $");
RCSID("$FreeBSD$");
#include "ssh.h"
@ -32,6 +32,7 @@ RCSID("$FreeBSD$");
#include "xmalloc.h"
#include "log.h"
#include "servconf.h"
#include "uidswap.h"
#include "auth.h"
#ifdef AFS
@ -39,48 +40,92 @@ RCSID("$FreeBSD$");
#endif
#ifdef KRB4
char *ticket = NULL;
extern ServerOptions options;
static int
krb4_init(void *context)
{
static int cleanup_registered = 0;
Authctxt *authctxt = (Authctxt *)context;
const char *tkt_root = TKT_ROOT;
struct stat st;
int fd;
if (!authctxt->krb4_ticket_file) {
/* Set unique ticket string manually since we're still root. */
authctxt->krb4_ticket_file = xmalloc(MAXPATHLEN);
#ifdef AFS
if (lstat("/ticket", &st) != -1)
tkt_root = "/ticket/";
#endif /* AFS */
snprintf(authctxt->krb4_ticket_file, MAXPATHLEN, "%s%u_%d",
tkt_root, authctxt->pw->pw_uid, getpid());
krb_set_tkt_string(authctxt->krb4_ticket_file);
}
/* Register ticket cleanup in case of fatal error. */
if (!cleanup_registered) {
fatal_add_cleanup(krb4_cleanup_proc, authctxt);
cleanup_registered = 1;
}
/* Try to create our ticket file. */
if ((fd = mkstemp(authctxt->krb4_ticket_file)) != -1) {
close(fd);
return (1);
}
/* Ticket file exists - make sure user owns it (just passed ticket). */
if (lstat(authctxt->krb4_ticket_file, &st) != -1) {
if (st.st_mode == (S_IFREG | S_IRUSR | S_IWUSR) &&
st.st_uid == authctxt->pw->pw_uid)
return (1);
}
/* Failure - cancel cleanup function, leaving ticket for inspection. */
log("WARNING: bad ticket file %s", authctxt->krb4_ticket_file);
fatal_remove_cleanup(krb4_cleanup_proc, authctxt);
cleanup_registered = 0;
xfree(authctxt->krb4_ticket_file);
authctxt->krb4_ticket_file = NULL;
return (0);
}
/*
* try krb4 authentication,
* return 1 on success, 0 on failure, -1 if krb4 is not available
*/
int
auth_krb4_password(struct passwd * pw, const char *password)
auth_krb4_password(Authctxt *authctxt, const char *password)
{
AUTH_DAT adata;
KTEXT_ST tkt;
struct hostent *hp;
u_long faddr;
char localhost[MAXHOSTNAMELEN];
char phost[INST_SZ];
char realm[REALM_SZ];
struct passwd *pw;
char localhost[MAXHOSTNAMELEN], phost[INST_SZ], realm[REALM_SZ];
u_int32_t faddr;
int r;
if ((pw = authctxt->pw) == NULL)
return (0);
/*
* Try Kerberos password authentication only for non-root
* users and only if Kerberos is installed.
*/
if (pw->pw_uid != 0 && krb_get_lrealm(realm, 1) == KSUCCESS) {
/* Set up our ticket file. */
if (!krb4_init(pw->pw_uid)) {
if (!krb4_init(authctxt)) {
log("Couldn't initialize Kerberos ticket file for %s!",
pw->pw_name);
goto kerberos_auth_failure;
goto failure;
}
/* Try to get TGT using our password. */
r = krb_get_pw_in_tkt((char *) pw->pw_name, "",
realm, "krbtgt", realm,
DEFAULT_TKT_LIFE, (char *) password);
r = krb_get_pw_in_tkt((char *) pw->pw_name, "", realm,
"krbtgt", realm, DEFAULT_TKT_LIFE, (char *)password);
if (r != INTK_OK) {
packet_send_debug("Kerberos V4 password "
"authentication for %s failed: %s",
pw->pw_name, krb_err_txt[r]);
goto kerberos_auth_failure;
debug("Kerberos v4 password authentication for %s "
"failed: %s", pw->pw_name, krb_err_txt[r]);
goto failure;
}
/* Successful authentication. */
chown(tkt_string(), pw->pw_uid, pw->pw_gid);
@ -90,17 +135,17 @@ auth_krb4_password(struct passwd * pw, const char *password)
* "rcmd" ticket to ensure that we are not talking
* to a bogus Kerberos server.
*/
(void) gethostname(localhost, sizeof(localhost));
(void) strlcpy(phost, (char *) krb_get_phost(localhost),
INST_SZ);
gethostname(localhost, sizeof(localhost));
strlcpy(phost, (char *)krb_get_phost(localhost),
sizeof(phost));
r = krb_mk_req(&tkt, KRB4_SERVICE_NAME, phost, realm, 33);
if (r == KSUCCESS) {
if (!(hp = gethostbyname(localhost))) {
if ((hp = gethostbyname(localhost)) == NULL) {
log("Couldn't get local host address!");
goto kerberos_auth_failure;
goto failure;
}
memmove((void *) &faddr, (void *) hp->h_addr,
memmove((void *)&faddr, (void *)hp->h_addr,
sizeof(faddr));
/* Verify our "rcmd" ticket. */
@ -111,116 +156,71 @@ auth_krb4_password(struct passwd * pw, const char *password)
* Probably didn't have a srvtab on
* localhost. Disallow login.
*/
log("Kerberos V4 TGT for %s unverifiable, "
log("Kerberos v4 TGT for %s unverifiable, "
"no srvtab installed? krb_rd_req: %s",
pw->pw_name, krb_err_txt[r]);
goto kerberos_auth_failure;
goto failure;
} else if (r != KSUCCESS) {
log("Kerberos V4 %s ticket unverifiable: %s",
log("Kerberos v4 %s ticket unverifiable: %s",
KRB4_SERVICE_NAME, krb_err_txt[r]);
goto kerberos_auth_failure;
goto failure;
}
} else if (r == KDC_PR_UNKNOWN) {
/*
* Disallow login if no rcmd service exists, and
* log the error.
*/
log("Kerberos V4 TGT for %s unverifiable: %s; %s.%s "
log("Kerberos v4 TGT for %s unverifiable: %s; %s.%s "
"not registered, or srvtab is wrong?", pw->pw_name,
krb_err_txt[r], KRB4_SERVICE_NAME, phost);
goto kerberos_auth_failure;
krb_err_txt[r], KRB4_SERVICE_NAME, phost);
goto failure;
} else {
/*
* TGT is bad, forget it. Possibly spoofed!
*/
packet_send_debug("WARNING: Kerberos V4 TGT "
"possibly spoofed for %s: %s",
pw->pw_name, krb_err_txt[r]);
goto kerberos_auth_failure;
debug("WARNING: Kerberos v4 TGT possibly spoofed "
"for %s: %s", pw->pw_name, krb_err_txt[r]);
goto failure;
}
/* Authentication succeeded. */
return 1;
kerberos_auth_failure:
krb4_cleanup_proc(NULL);
if (!options.krb4_or_local_passwd)
return 0;
} else {
return (1);
} else
/* Logging in as root or no local Kerberos realm. */
packet_send_debug("Unable to authenticate to Kerberos.");
}
debug("Unable to authenticate to Kerberos.");
failure:
krb4_cleanup_proc(authctxt);
if (!options.kerberos_or_local_passwd)
return (0);
/* Fall back to ordinary passwd authentication. */
return -1;
return (-1);
}
void
krb4_cleanup_proc(void *ignore)
krb4_cleanup_proc(void *context)
{
Authctxt *authctxt = (Authctxt *)context;
debug("krb4_cleanup_proc called");
if (ticket) {
if (authctxt->krb4_ticket_file) {
(void) dest_tkt();
xfree(ticket);
ticket = NULL;
xfree(authctxt->krb4_ticket_file);
authctxt->krb4_ticket_file = NULL;
}
}
int
krb4_init(uid_t uid)
{
static int cleanup_registered = 0;
const char *tkt_root = TKT_ROOT;
struct stat st;
int fd;
if (!ticket) {
/* Set unique ticket string manually since we're still root. */
ticket = xmalloc(MAXPATHLEN);
#ifdef AFS
if (lstat("/ticket", &st) != -1)
tkt_root = "/ticket/";
#endif /* AFS */
snprintf(ticket, MAXPATHLEN, "%s%u_%d", tkt_root, uid, getpid());
(void) krb_set_tkt_string(ticket);
}
/* Register ticket cleanup in case of fatal error. */
if (!cleanup_registered) {
fatal_add_cleanup(krb4_cleanup_proc, NULL);
cleanup_registered = 1;
}
/* Try to create our ticket file. */
if ((fd = mkstemp(ticket)) != -1) {
close(fd);
return 1;
}
/* Ticket file exists - make sure user owns it (just passed ticket). */
if (lstat(ticket, &st) != -1) {
if (st.st_mode == (S_IFREG | S_IRUSR | S_IWUSR) &&
st.st_uid == uid)
return 1;
}
/* Failure - cancel cleanup function, leaving bad ticket for inspection. */
log("WARNING: bad ticket file %s", ticket);
fatal_remove_cleanup(krb4_cleanup_proc, NULL);
cleanup_registered = 0;
xfree(ticket);
ticket = NULL;
return 0;
}
int
auth_krb4(const char *server_user, KTEXT auth, char **client)
auth_krb4(Authctxt *authctxt, KTEXT auth, char **client)
{
AUTH_DAT adat = {0};
KTEXT_ST reply;
char instance[INST_SZ];
int r, s;
socklen_t slen;
u_int cksum;
Key_schedule schedule;
struct sockaddr_in local, foreign;
char instance[INST_SZ];
socklen_t slen;
u_int cksum;
int r, s;
s = packet_get_connection_in();
@ -238,9 +238,10 @@ auth_krb4(const char *server_user, KTEXT auth, char **client)
instance[1] = 0;
/* Get the encrypted request, challenge, and session key. */
if ((r = krb_rd_req(auth, KRB4_SERVICE_NAME, instance, 0, &adat, ""))) {
packet_send_debug("Kerberos V4 krb_rd_req: %.100s", krb_err_txt[r]);
return 0;
if ((r = krb_rd_req(auth, KRB4_SERVICE_NAME, instance,
0, &adat, ""))) {
debug("Kerberos v4 krb_rd_req: %.100s", krb_err_txt[r]);
return (0);
}
des_key_sched((des_cblock *) adat.session, schedule);
@ -249,12 +250,11 @@ auth_krb4(const char *server_user, KTEXT auth, char **client)
*adat.pinst ? "." : "", adat.pinst, adat.prealm);
/* Check ~/.klogin authorization now. */
if (kuserok(&adat, (char *) server_user) != KSUCCESS) {
packet_send_debug("Kerberos V4 .klogin authorization failed!");
log("Kerberos V4 .klogin authorization failed for %s to account %s",
*client, server_user);
if (kuserok(&adat, authctxt->user) != KSUCCESS) {
log("Kerberos v4 .klogin authorization failed for %s to "
"account %s", *client, authctxt->user);
xfree(*client);
return 0;
return (0);
}
/* Increment the checksum, and return it encrypted with the
session key. */
@ -265,7 +265,7 @@ auth_krb4(const char *server_user, KTEXT auth, char **client)
empty message, admitting our failure. */
if ((r = krb_mk_priv((u_char *) & cksum, reply.dat, sizeof(cksum) + 1,
schedule, &adat.session, &local, &foreign)) < 0) {
packet_send_debug("Kerberos V4 mk_priv: (%d) %s", r, krb_err_txt[r]);
debug("Kerberos v4 mk_priv: (%d) %s", r, krb_err_txt[r]);
reply.dat[0] = 0;
reply.length = 0;
} else
@ -278,89 +278,79 @@ auth_krb4(const char *server_user, KTEXT auth, char **client)
packet_put_string((char *) reply.dat, reply.length);
packet_send();
packet_write_wait();
return 1;
return (1);
}
#endif /* KRB4 */
#ifdef AFS
int
auth_krb4_tgt(struct passwd *pw, const char *string)
auth_krb4_tgt(Authctxt *authctxt, const char *string)
{
CREDENTIALS creds;
struct passwd *pw;
if ((pw = authctxt->pw) == NULL)
goto failure;
temporarily_use_uid(pw);
if (pw == NULL)
goto auth_kerberos_tgt_failure;
if (!radix_to_creds(string, &creds)) {
log("Protocol error decoding Kerberos V4 tgt");
packet_send_debug("Protocol error decoding Kerberos V4 tgt");
goto auth_kerberos_tgt_failure;
log("Protocol error decoding Kerberos v4 TGT");
goto failure;
}
if (strncmp(creds.service, "", 1) == 0) /* backward compatibility */
strlcpy(creds.service, "krbtgt", sizeof creds.service);
if (strcmp(creds.service, "krbtgt")) {
log("Kerberos V4 tgt (%s%s%s@%s) rejected for %s", creds.pname,
creds.pinst[0] ? "." : "", creds.pinst, creds.realm,
pw->pw_name);
packet_send_debug("Kerberos V4 tgt (%s%s%s@%s) rejected for %s",
log("Kerberos v4 TGT (%s%s%s@%s) rejected for %s",
creds.pname, creds.pinst[0] ? "." : "", creds.pinst,
creds.realm, pw->pw_name);
goto auth_kerberos_tgt_failure;
goto failure;
}
if (!krb4_init(pw->pw_uid))
goto auth_kerberos_tgt_failure;
if (!krb4_init(authctxt))
goto failure;
if (in_tkt(creds.pname, creds.pinst) != KSUCCESS)
goto auth_kerberos_tgt_failure;
goto failure;
if (save_credentials(creds.service, creds.instance, creds.realm,
creds.session, creds.lifetime, creds.kvno,
&creds.ticket_st, creds.issue_date) != KSUCCESS) {
packet_send_debug("Kerberos V4 tgt refused: couldn't save credentials");
goto auth_kerberos_tgt_failure;
creds.session, creds.lifetime, creds.kvno, &creds.ticket_st,
creds.issue_date) != KSUCCESS) {
debug("Kerberos v4 TGT refused: couldn't save credentials");
goto failure;
}
/* Successful authentication, passed all checks. */
chown(tkt_string(), pw->pw_uid, pw->pw_gid);
packet_send_debug("Kerberos V4 tgt accepted (%s.%s@%s, %s%s%s@%s)",
creds.service, creds.instance, creds.realm, creds.pname,
creds.pinst[0] ? "." : "", creds.pinst, creds.realm);
debug("Kerberos v4 TGT accepted (%s%s%s@%s)",
creds.pname, creds.pinst[0] ? "." : "", creds.pinst, creds.realm);
memset(&creds, 0, sizeof(creds));
packet_start(SSH_SMSG_SUCCESS);
packet_send();
packet_write_wait();
return 1;
auth_kerberos_tgt_failure:
krb4_cleanup_proc(NULL);
restore_uid();
return (1);
failure:
krb4_cleanup_proc(authctxt);
memset(&creds, 0, sizeof(creds));
packet_start(SSH_SMSG_FAILURE);
packet_send();
packet_write_wait();
return 0;
restore_uid();
return (0);
}
int
auth_afs_token(struct passwd *pw, const char *token_string)
auth_afs_token(Authctxt *authctxt, const char *token_string)
{
CREDENTIALS creds;
struct passwd *pw;
uid_t uid;
if (pw == NULL) {
/* XXX fake protocol error */
packet_send_debug("Protocol error decoding AFS token");
packet_start(SSH_SMSG_FAILURE);
packet_send();
packet_write_wait();
return 0;
}
if ((pw = authctxt->pw) == NULL)
return (0);
if (!radix_to_creds(token_string, &creds)) {
log("Protocol error decoding AFS token");
packet_send_debug("Protocol error decoding AFS token");
packet_start(SSH_SMSG_FAILURE);
packet_send();
packet_write_wait();
return 0;
return (0);
}
if (strncmp(creds.service, "", 1) == 0) /* backward compatibility */
strlcpy(creds.service, "afs", sizeof creds.service);
@ -371,22 +361,14 @@ auth_afs_token(struct passwd *pw, const char *token_string)
uid = pw->pw_uid;
if (kafs_settoken(creds.realm, uid, &creds)) {
log("AFS token (%s@%s) rejected for %s", creds.pname, creds.realm,
pw->pw_name);
packet_send_debug("AFS token (%s@%s) rejected for %s", creds.pname,
creds.realm, pw->pw_name);
log("AFS token (%s@%s) rejected for %s",
creds.pname, creds.realm, pw->pw_name);
memset(&creds, 0, sizeof(creds));
packet_start(SSH_SMSG_FAILURE);
packet_send();
packet_write_wait();
return 0;
return (0);
}
packet_send_debug("AFS token accepted (%s@%s, %s@%s)", creds.service,
creds.realm, creds.pname, creds.realm);
debug("AFS token accepted (%s@%s)", creds.pname, creds.realm);
memset(&creds, 0, sizeof(creds));
packet_start(SSH_SMSG_SUCCESS);
packet_send();
packet_write_wait();
return 1;
return (1);
}
#endif /* AFS */

View file

@ -1,250 +1,272 @@
/*
* Kerberos v5 authentication and ticket-passing routines.
*
* $FreeBSD$
*/
#include "includes.h"
RCSID("$OpenBSD: auth-krb5.c,v 1.6 2002/03/04 17:27:39 stevesk Exp $");
RCSID("$FreeBSD$");
#include "ssh.h"
#include "ssh1.h"
#include "packet.h"
#include "xmalloc.h"
#include "log.h"
#include "servconf.h"
#include "uidswap.h"
#include "auth.h"
#ifdef KRB5
#include <krb5.h>
krb5_context ssh_context = NULL;
krb5_auth_context auth_context;
krb5_ccache mem_ccache = NULL; /* Credential cache for acquired ticket */
extern ServerOptions options;
/* Try krb5 authentication. server_user is passed for logging purposes only,
in auth is received ticket, in client is returned principal from the
ticket */
int
auth_krb5(const char* server_user, krb5_data *auth, krb5_principal *client)
static int
krb5_init(void *context)
{
Authctxt *authctxt = (Authctxt *)context;
krb5_error_code problem;
static int cleanup_registered = 0;
if (authctxt->krb5_ctx == NULL) {
problem = krb5_init_context(&authctxt->krb5_ctx);
if (problem)
return (problem);
krb5_init_ets(authctxt->krb5_ctx);
}
if (!cleanup_registered) {
fatal_add_cleanup(krb5_cleanup_proc, authctxt);
cleanup_registered = 1;
}
return (0);
}
/*
* Try krb5 authentication. server_user is passed for logging purposes
* only, in auth is received ticket, in client is returned principal
* from the ticket
*/
int
auth_krb5(Authctxt *authctxt, krb5_data *auth, char **client)
{
krb5_error_code problem;
krb5_principal server = NULL;
krb5_principal tkt_client = NULL;
krb5_principal server;
krb5_data reply;
krb5_ticket *ticket = NULL;
int fd;
int ret;
reply.length = 0;
problem = krb5_init();
if (problem)
return 0;
problem = krb5_auth_con_init(ssh_context, &auth_context);
if (problem) {
log("Kerberos v5 authentication failed: %.100s",
krb5_get_err_text(ssh_context, problem));
krb5_ticket *ticket;
int fd, ret;
return 0;
}
fd = packet_get_connection_in();
problem = krb5_auth_con_setaddrs_from_fd(ssh_context, auth_context, &fd);
if (problem) {
ret = 0;
goto err;
}
problem = krb5_sname_to_principal(ssh_context, NULL, NULL ,
ret = 0;
server = NULL;
ticket = NULL;
reply.length = 0;
problem = krb5_init(authctxt);
if (problem)
goto err;
problem = krb5_auth_con_init(authctxt->krb5_ctx,
&authctxt->krb5_auth_ctx);
if (problem)
goto err;
fd = packet_get_connection_in();
problem = krb5_auth_con_setaddrs_from_fd(authctxt->krb5_ctx,
authctxt->krb5_auth_ctx, &fd);
if (problem)
goto err;
problem = krb5_sname_to_principal(authctxt->krb5_ctx, NULL, NULL ,
KRB5_NT_SRV_HST, &server);
if (problem) {
ret = 0;
goto err;
}
problem = krb5_rd_req(ssh_context, &auth_context, auth, server, NULL,
NULL, &ticket);
if (problem) {
ret = 0;
goto err;
}
problem = krb5_copy_principal(ssh_context, ticket->client, &tkt_client);
if (problem) {
ret = 0;
goto err;
}
if (problem)
goto err;
problem = krb5_rd_req(authctxt->krb5_ctx, &authctxt->krb5_auth_ctx,
auth, server, NULL, NULL, &ticket);
if (problem)
goto err;
problem = krb5_copy_principal(authctxt->krb5_ctx, ticket->client,
&authctxt->krb5_user);
if (problem)
goto err;
/* if client wants mutual auth */
problem = krb5_mk_rep(ssh_context, auth_context, &reply);
if (problem) {
ret = 0;
goto err;
}
*client = tkt_client;
problem = krb5_mk_rep(authctxt->krb5_ctx, authctxt->krb5_auth_ctx,
&reply);
if (problem)
goto err;
/* Check .k5login authorization now. */
if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user,
authctxt->pw->pw_name))
goto err;
if (client)
krb5_unparse_name(authctxt->krb5_ctx, authctxt->krb5_user,
client);
packet_start(SSH_SMSG_AUTH_KERBEROS_RESPONSE);
packet_put_string((char *) reply.data, reply.length);
packet_send();
packet_write_wait();
ret = 1;
err:
err:
if (server)
krb5_free_principal(ssh_context, server);
krb5_free_principal(authctxt->krb5_ctx, server);
if (ticket)
krb5_free_ticket(ssh_context, ticket);
krb5_free_ticket(authctxt->krb5_ctx, ticket);
if (reply.length)
xfree(reply.data);
return ret;
xfree(reply.data);
if (problem) {
if (authctxt->krb5_ctx != NULL)
debug("Kerberos v5 authentication failed: %s",
krb5_get_err_text(authctxt->krb5_ctx, problem));
else
debug("Kerberos v5 authentication failed: %d",
problem);
}
return (ret);
}
int
auth_krb5_tgt(char *server_user, krb5_data *tgt, krb5_principal tkt_client)
auth_krb5_tgt(Authctxt *authctxt, krb5_data *tgt)
{
krb5_error_code problem;
krb5_ccache ccache = NULL;
if (ssh_context == NULL) {
goto fail;
}
problem = krb5_cc_gen_new(ssh_context, &krb5_mcc_ops, &ccache);
if (problem) {
goto fail;
}
problem = krb5_cc_initialize(ssh_context, ccache, tkt_client);
if (problem) {
goto fail;
}
problem = krb5_rd_cred2(ssh_context, auth_context, ccache, tgt);
if (problem) {
goto fail;
}
mem_ccache = ccache;
ccache = NULL;
/*
problem = krb5_cc_copy_cache(ssh_context, ccache, mem_ccache);
if (problem) {
mem_ccache = NULL;
goto fail;
}
problem = krb5_cc_destroy(ssh_context, ccache);
if (problem)
goto fail;
*/
#if 0
packet_start(SSH_SMSG_SUCCESS);
packet_send();
packet_write_wait();
#endif
return 1;
fail:
if (ccache)
krb5_cc_destroy(ssh_context, ccache);
#if 0
packet_start(SSH_SMSG_FAILURE);
packet_send();
packet_write_wait();
#endif
return 0;
krb5_error_code problem;
krb5_ccache ccache = NULL;
char *pname;
if (authctxt->pw == NULL || authctxt->krb5_user == NULL)
return (0);
temporarily_use_uid(authctxt->pw);
problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_fcc_ops, &ccache);
if (problem)
goto fail;
problem = krb5_cc_initialize(authctxt->krb5_ctx, ccache,
authctxt->krb5_user);
if (problem)
goto fail;
problem = krb5_rd_cred2(authctxt->krb5_ctx, authctxt->krb5_auth_ctx,
ccache, tgt);
if (problem)
goto fail;
authctxt->krb5_fwd_ccache = ccache;
ccache = NULL;
authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
problem = krb5_unparse_name(authctxt->krb5_ctx, authctxt->krb5_user,
&pname);
if (problem)
goto fail;
debug("Kerberos v5 TGT accepted (%s)", pname);
restore_uid();
return (1);
fail:
if (problem)
debug("Kerberos v5 TGT passing failed: %s",
krb5_get_err_text(authctxt->krb5_ctx, problem));
if (ccache)
krb5_cc_destroy(authctxt->krb5_ctx, ccache);
restore_uid();
return (0);
}
int
auth_krb5_password(struct passwd *pw, const char *password)
auth_krb5_password(Authctxt *authctxt, const char *password)
{
krb5_error_code problem;
krb5_ccache ccache = NULL;
krb5_principal client = NULL;
int ret;
problem = krb5_init();
if (problem)
return 0;
problem = krb5_parse_name(ssh_context, pw->pw_name, &client);
if (problem) {
ret = 0;
goto out;
}
krb5_error_code problem;
problem = krb5_cc_gen_new(ssh_context, &krb5_mcc_ops, &ccache);
if (problem) {
ret = 0;
goto out;
}
problem = krb5_cc_initialize(ssh_context, ccache, client);
if (problem) {
ret = 0;
goto out;
}
problem = krb5_verify_user(ssh_context, client, ccache, password, 1, NULL);
if (problem) {
ret = 0;
goto out;
}
/*
problem = krb5_cc_copy_cache(ssh_context, ccache, mem_ccache);
if (problem) {
ret = 0;
mem_ccache = NULL;
goto out;
}
*/
mem_ccache = ccache;
ccache = NULL;
ret = 1;
out:
if (client != NULL)
krb5_free_principal(ssh_context, client);
if (ccache != NULL)
krb5_cc_destroy(ssh_context, ccache);
return ret;
if (authctxt->pw == NULL)
return (0);
temporarily_use_uid(authctxt->pw);
problem = krb5_init(authctxt);
if (problem)
goto out;
problem = krb5_parse_name(authctxt->krb5_ctx, authctxt->pw->pw_name,
&authctxt->krb5_user);
if (problem)
goto out;
problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_mcc_ops,
&authctxt->krb5_fwd_ccache);
if (problem)
goto out;
problem = krb5_cc_initialize(authctxt->krb5_ctx,
authctxt->krb5_fwd_ccache, authctxt->krb5_user);
if (problem)
goto out;
restore_uid();
problem = krb5_verify_user(authctxt->krb5_ctx, authctxt->krb5_user,
authctxt->krb5_fwd_ccache, password, 1, NULL);
temporarily_use_uid(authctxt->pw);
if (problem)
goto out;
authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
out:
restore_uid();
if (problem) {
if (authctxt->krb5_ctx != NULL)
debug("Kerberos password authentication failed: %s",
krb5_get_err_text(authctxt->krb5_ctx, problem));
else
debug("Kerberos password authentication failed: %d",
problem);
krb5_cleanup_proc(authctxt);
if (options.kerberos_or_local_passwd)
return (-1);
else
return (0);
}
return (1);
}
void
krb5_cleanup_proc(void *ignore)
krb5_cleanup_proc(void *context)
{
extern krb5_principal tkt_client;
debug("krb5_cleanup_proc() called");
if (mem_ccache)
krb5_cc_destroy(ssh_context, mem_ccache);
if (tkt_client)
krb5_free_principal(ssh_context, tkt_client);
if (auth_context)
krb5_auth_con_free(ssh_context, auth_context);
if (ssh_context)
krb5_free_context(ssh_context);
Authctxt *authctxt = (Authctxt *)context;
debug("krb5_cleanup_proc called");
if (authctxt->krb5_fwd_ccache) {
krb5_cc_destroy(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
authctxt->krb5_fwd_ccache = NULL;
}
if (authctxt->krb5_user) {
krb5_free_principal(authctxt->krb5_ctx, authctxt->krb5_user);
authctxt->krb5_user = NULL;
}
if (authctxt->krb5_auth_ctx) {
krb5_auth_con_free(authctxt->krb5_ctx,
authctxt->krb5_auth_ctx);
authctxt->krb5_auth_ctx = NULL;
}
if (authctxt->krb5_ctx) {
krb5_free_context(authctxt->krb5_ctx);
authctxt->krb5_ctx = NULL;
}
}
int
krb5_init(void)
{
krb5_error_code problem;
static cleanup_registered = 0;
if (ssh_context == NULL) {
problem = krb5_init_context(&ssh_context);
if (problem)
return problem;
krb5_init_ets(ssh_context);
}
if (!cleanup_registered) {
fatal_add_cleanup(krb5_cleanup_proc, NULL);
cleanup_registered = 1;
}
return 0;
}
#endif /* KRB5 */

View file

@ -223,9 +223,9 @@ int do_pam_account(char *username, char *remote_user)
do_pam_set_conv(&conv);
debug("PAM setting rhost to \"%.200s\"",
get_canonical_hostname(options.reverse_mapping_check));
get_canonical_hostname(options.verify_reverse_mapping));
pam_retval = pam_set_item(pamh, PAM_RHOST,
get_canonical_hostname(options.reverse_mapping_check));
get_canonical_hostname(options.verify_reverse_mapping));
if (pam_retval != PAM_SUCCESS) {
fatal("PAM set rhost failed[%d]: %.200s",
pam_retval, PAM_STRERROR(pamh, pam_retval));

View file

@ -36,11 +36,10 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth-passwd.c,v 1.22 2001/03/20 18:57:04 markus Exp $");
RCSID("$OpenBSD: auth-passwd.c,v 1.24 2002/03/04 12:43:06 markus Exp $");
RCSID("$FreeBSD$");
#include "packet.h"
#include "xmalloc.h"
#include "log.h"
#include "servconf.h"
#include "auth.h"
@ -65,6 +64,22 @@ auth_password(Authctxt *authctxt, const char *password)
return 0;
if (*password == '\0' && options.permit_empty_passwd == 0)
return 0;
#ifdef KRB5
if (options.kerberos_authentication == 1) {
int ret = auth_krb5_password(authctxt, password);
if (ret == 1 || ret == 0)
return ret;
/* Fall back to ordinary passwd authentication. */
}
#endif
#ifdef KRB4
if (options.kerberos_authentication == 1) {
int ret = auth_krb4_password(authctxt, password);
if (ret == 1 || ret == 0)
return ret;
/* Fall back to ordinary passwd authentication. */
}
#endif
#ifdef BSD_AUTH
if (auth_userokay(pw->pw_name, authctxt->style, "auth-ssh",
(char *)password) == 0)
@ -72,23 +87,6 @@ auth_password(Authctxt *authctxt, const char *password)
else
return 1;
#endif
#ifdef KRB5
if (options.kerberos_authentication == 1) {
if (auth_krb5_password(pw, password))
return 1;
/* Fall back to ordinary passwd authentication. */
}
#endif /* KRB5 */
#ifdef KRB4
if (options.kerberos_authentication == 1) {
int ret = auth_krb4_password(pw, password);
if (ret == 1 || ret == 0)
return ret;
/* Fall back to ordinary passwd authentication. */
}
#endif
/* Check for users with no password. */
if (strcmp(password, "") == 0 && strcmp(pw->pw_passwd, "") == 0)
return 1;

View file

@ -13,11 +13,10 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth-rh-rsa.c,v 1.23 2001/04/06 21:00:04 markus Exp $");
RCSID("$OpenBSD: auth-rh-rsa.c,v 1.29 2002/03/04 12:43:06 markus Exp $");
RCSID("$FreeBSD$");
#include "packet.h"
#include "xmalloc.h"
#include "uidswap.h"
#include "log.h"
#include "servconf.h"
@ -25,7 +24,6 @@ RCSID("$FreeBSD$");
#include "hostfile.h"
#include "pathnames.h"
#include "auth.h"
#include "tildexpand.h"
#include "canohost.h"
/*
@ -34,16 +32,15 @@ RCSID("$FreeBSD$");
*/
int
auth_rhosts_rsa(struct passwd *pw, const char *client_user, RSA *client_host_key)
auth_rhosts_rsa(struct passwd *pw, const char *client_user, Key *client_host_key)
{
extern ServerOptions options;
const char *canonical_hostname;
HostStatus host_status;
Key *client_key, *found;
debug("Trying rhosts with RSA host authentication for client user %.100s", client_user);
if (pw == NULL || client_host_key == NULL)
if (pw == NULL || client_host_key == NULL || client_host_key->rsa == NULL)
return 0;
/* Check if we would accept it using rhosts authentication. */
@ -51,45 +48,13 @@ auth_rhosts_rsa(struct passwd *pw, const char *client_user, RSA *client_host_key
return 0;
canonical_hostname = get_canonical_hostname(
options.reverse_mapping_check);
options.verify_reverse_mapping);
debug("Rhosts RSA authentication: canonical host %.900s", canonical_hostname);
/* wrap the RSA key into a 'generic' key */
client_key = key_new(KEY_RSA1);
BN_copy(client_key->rsa->e, client_host_key->e);
BN_copy(client_key->rsa->n, client_host_key->n);
found = key_new(KEY_RSA1);
/* Check if we know the host and its host key. */
host_status = check_host_in_hostfile(_PATH_SSH_SYSTEM_HOSTFILE, canonical_hostname,
client_key, found, NULL);
/* Check user host file unless ignored. */
if (host_status != HOST_OK && !options.ignore_user_known_hosts) {
struct stat st;
char *user_hostfile = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid);
/*
* Check file permissions of _PATH_SSH_USER_HOSTFILE, auth_rsa()
* did already check pw->pw_dir, but there is a race XXX
*/
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("Rhosts RSA authentication refused for %.100s: bad owner or modes for %.200s",
pw->pw_name, user_hostfile);
} else {
/* XXX race between stat and the following open() */
temporarily_use_uid(pw);
host_status = check_host_in_hostfile(user_hostfile, canonical_hostname,
client_key, found, NULL);
restore_uid();
}
xfree(user_hostfile);
}
key_free(client_key);
key_free(found);
host_status = check_key_in_hostfiles(pw, client_host_key,
canonical_hostname, _PATH_SSH_SYSTEM_HOSTFILE,
options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE);
if (host_status != HOST_OK) {
debug("Rhosts with RSA host authentication denied: unknown or invalid host key");
@ -99,7 +64,7 @@ auth_rhosts_rsa(struct passwd *pw, const char *client_user, RSA *client_host_key
/* A matching host key was found and is known. */
/* Perform the challenge-response dialog with the client for the host key. */
if (!auth_rsa_challenge_dialog(client_host_key)) {
if (!auth_rsa_challenge_dialog(client_host_key->rsa)) {
log("Client on %.800s failed to respond correctly to host authentication.",
canonical_hostname);
return 0;

View file

@ -14,7 +14,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth-rsa.c,v 1.40 2001/04/06 21:00:07 markus Exp $");
RCSID("$OpenBSD: auth-rsa.c,v 1.50 2001/12/28 14:50:54 markus Exp $");
RCSID("$FreeBSD$");
#include <openssl/rsa.h>
@ -32,6 +32,7 @@ RCSID("$FreeBSD$");
#include "log.h"
#include "servconf.h"
#include "auth.h"
#include "hostfile.h"
/* import */
extern ServerOptions options;
@ -66,14 +67,17 @@ auth_rsa_challenge_dialog(RSA *pk)
u_char buf[32], mdbuf[16], response[16];
MD5_CTX md;
u_int i;
int plen, len;
int len;
encrypted_challenge = BN_new();
challenge = BN_new();
if ((encrypted_challenge = BN_new()) == NULL)
fatal("auth_rsa_challenge_dialog: BN_new() failed");
if ((challenge = BN_new()) == NULL)
fatal("auth_rsa_challenge_dialog: BN_new() failed");
/* Generate a random challenge. */
BN_rand(challenge, 256, 0, 0);
ctx = BN_CTX_new();
if ((ctx = BN_CTX_new()) == NULL)
fatal("auth_rsa_challenge_dialog: BN_CTX_new() failed");
BN_mod(challenge, challenge, pk->n, ctx);
BN_CTX_free(ctx);
@ -88,10 +92,10 @@ auth_rsa_challenge_dialog(RSA *pk)
packet_write_wait();
/* Wait for a response. */
packet_read_expect(&plen, SSH_CMSG_AUTH_RSA_RESPONSE);
packet_integrity_check(plen, 16, SSH_CMSG_AUTH_RSA_RESPONSE);
packet_read_expect(SSH_CMSG_AUTH_RSA_RESPONSE);
for (i = 0; i < 16; i++)
response[i] = packet_get_char();
packet_check_eom();
/* The response is MD5 of decrypted challenge plus session id. */
len = BN_num_bytes(challenge);
@ -123,13 +127,14 @@ auth_rsa_challenge_dialog(RSA *pk)
int
auth_rsa(struct passwd *pw, BIGNUM *client_n)
{
char line[8192], file[MAXPATHLEN];
char line[8192], *file;
int authenticated;
u_int bits;
FILE *f;
u_long linenum = 0;
struct stat st;
RSA *pk;
Key *key;
char *fp;
/* no user given */
if (pw == NULL)
@ -139,13 +144,14 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
temporarily_use_uid(pw);
/* The authorized keys. */
snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
_PATH_SSH_USER_PERMITTED_KEYS);
file = authorized_keys_file(pw);
debug("trying public RSA key file %s", file);
/* Fail quietly if file does not exist */
if (stat(file, &st) < 0) {
/* Restore the privileged uid. */
restore_uid();
xfree(file);
return 0;
}
/* Open the file containing the authorized keys. */
@ -155,50 +161,22 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
restore_uid();
packet_send_debug("Could not open %.900s for reading.", file);
packet_send_debug("If your home is on an NFS volume, it may need to be world-readable.");
xfree(file);
return 0;
}
if (options.strict_modes) {
int fail = 0;
char buf[1024];
/* Check open file in order to avoid open/stat races */
if (fstat(fileno(f), &st) < 0 ||
(st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
(st.st_mode & 022) != 0) {
snprintf(buf, sizeof buf, "RSA authentication refused for %.100s: "
"bad ownership or modes for '%s'.", pw->pw_name, file);
fail = 1;
} else {
/* Check path to _PATH_SSH_USER_PERMITTED_KEYS */
int i;
static const char *check[] = {
"", _PATH_SSH_USER_DIR, NULL
};
for (i = 0; check[i]; i++) {
snprintf(line, sizeof line, "%.500s/%.100s", pw->pw_dir, check[i]);
if (stat(line, &st) < 0 ||
(st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
(st.st_mode & 022) != 0) {
snprintf(buf, sizeof buf, "RSA authentication refused for %.100s: "
"bad ownership or modes for '%s'.", pw->pw_name, line);
fail = 1;
break;
}
}
}
if (fail) {
fclose(f);
log("%s", buf);
packet_send_debug("%s", buf);
restore_uid();
return 0;
}
if (options.strict_modes &&
secure_filename(f, file, pw, line, sizeof(line)) != 0) {
xfree(file);
fclose(f);
log("Authentication refused: %s", line);
packet_send_debug("Authentication refused: %s", line);
restore_uid();
return 0;
}
/* Flag indicating whether authentication has succeeded. */
authenticated = 0;
pk = RSA_new();
pk->e = BN_new();
pk->n = BN_new();
key = key_new(KEY_RSA1);
/*
* Go though the accepted keys, looking for the current key. If
@ -236,24 +214,22 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
options = NULL;
/* Parse the key from the line. */
if (!auth_rsa_read_key(&cp, &bits, pk->e, pk->n)) {
debug("%.100s, line %lu: bad key syntax",
file, linenum);
packet_send_debug("%.100s, line %lu: bad key syntax",
if (hostfile_read_key(&cp, &bits, key) == 0) {
debug("%.100s, line %lu: non ssh1 key syntax",
file, linenum);
continue;
}
/* cp now points to the comment part. */
/* Check if the we have found the desired key (identified by its modulus). */
if (BN_cmp(pk->n, client_n) != 0)
if (BN_cmp(key->rsa->n, client_n) != 0)
continue;
/* check the real bits */
if (bits != BN_num_bits(pk->n))
log("Warning: %s, line %ld: keysize mismatch: "
if (bits != BN_num_bits(key->rsa->n))
log("Warning: %s, line %lu: keysize mismatch: "
"actual %d vs. announced %d.",
file, linenum, BN_num_bits(pk->n), bits);
file, linenum, BN_num_bits(key->rsa->n), bits);
/* We have found the desired key. */
/*
@ -264,11 +240,15 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
continue;
/* Perform the challenge-response dialog for this key. */
if (!auth_rsa_challenge_dialog(pk)) {
if (!auth_rsa_challenge_dialog(key->rsa)) {
/* Wrong response. */
verbose("Wrong response to RSA authentication challenge.");
packet_send_debug("Wrong response to RSA authentication challenge.");
continue;
/*
* Break out of the loop. Otherwise we might send
* another challenge and break the protocol.
*/
break;
}
/*
* Correct response. The client has been successfully
@ -279,6 +259,12 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
* otherwise continue searching.
*/
authenticated = 1;
fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
verbose("Found matching %s key: %s",
key_type(key), fp);
xfree(fp);
break;
}
@ -286,9 +272,10 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
restore_uid();
/* Close the file. */
xfree(file);
fclose(f);
RSA_free(pk);
key_free(key);
if (authenticated)
packet_send_debug("RSA authentication accepted.");

View file

@ -23,9 +23,11 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth.c,v 1.21 2001/03/19 17:07:23 markus Exp $");
RCSID("$OpenBSD: auth.c,v 1.35 2002/03/01 13:12:10 markus Exp $");
RCSID("$FreeBSD$");
#include <libgen.h>
#include "xmalloc.h"
#include "match.h"
#include "groupaccess.h"
@ -34,6 +36,10 @@ RCSID("$FreeBSD$");
#include "auth.h"
#include "auth-options.h"
#include "canohost.h"
#include "buffer.h"
#include "bufaux.h"
#include "uidswap.h"
#include "tildexpand.h"
/* import */
extern ServerOptions options;
@ -51,6 +57,7 @@ int
allowed_user(struct passwd * pw)
{
struct stat st;
const char *hostname = NULL, *ipaddr = NULL;
char *shell;
int i;
@ -65,36 +72,60 @@ allowed_user(struct passwd * pw)
shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
/* deny if shell does not exists or is not executable */
if (stat(shell, &st) != 0)
if (stat(shell, &st) != 0) {
log("User %.100s not allowed because shell %.100s does not exist",
pw->pw_name, shell);
return 0;
if (!((st.st_mode & S_IFREG) && (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP))))
}
if (!((st.st_mode & S_IFREG) && (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)))) {
log("User %.100s not allowed because shell %.100s is not executable",
pw->pw_name, shell);
return 0;
}
if (options.num_deny_users > 0 || options.num_allow_users > 0) {
hostname = get_canonical_hostname(options.verify_reverse_mapping);
ipaddr = get_remote_ipaddr();
}
/* Return false if user is listed in DenyUsers */
if (options.num_deny_users > 0) {
for (i = 0; i < options.num_deny_users; i++)
if (match_pattern(pw->pw_name, options.deny_users[i]))
if (match_user(pw->pw_name, hostname, ipaddr,
options.deny_users[i])) {
log("User %.100s not allowed because listed in DenyUsers",
pw->pw_name);
return 0;
}
}
/* Return false if AllowUsers isn't empty and user isn't listed there */
if (options.num_allow_users > 0) {
for (i = 0; i < options.num_allow_users; i++)
if (match_pattern(pw->pw_name, options.allow_users[i]))
if (match_user(pw->pw_name, hostname, ipaddr,
options.allow_users[i]))
break;
/* i < options.num_allow_users iff we break for loop */
if (i >= options.num_allow_users)
if (i >= options.num_allow_users) {
log("User %.100s not allowed because not listed in AllowUsers",
pw->pw_name);
return 0;
}
}
if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
/* Get the user's group access list (primary and supplementary) */
if (ga_init(pw->pw_name, pw->pw_gid) == 0)
if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
log("User %.100s not allowed because not in any group",
pw->pw_name);
return 0;
}
/* Return false if one of user's groups is listed in DenyGroups */
if (options.num_deny_groups > 0)
if (ga_match(options.deny_groups,
options.num_deny_groups)) {
ga_free();
log("User %.100s not allowed because a group is listed in DenyGroups",
pw->pw_name);
return 0;
}
/*
@ -105,6 +136,8 @@ allowed_user(struct passwd * pw)
if (!ga_match(options.allow_groups,
options.num_allow_groups)) {
ga_free();
log("User %.100s not allowed because none of user's groups are listed in AllowGroups",
pw->pw_name);
return 0;
}
ga_free();
@ -143,7 +176,7 @@ auth_log(Authctxt *authctxt, int authenticated, char *method, char *info)
authmsg,
method,
authctxt->valid ? "" : "illegal user ",
authctxt->valid && authctxt->pw->pw_uid == 0 ? "ROOT" : authctxt->user,
authctxt->user,
get_remote_ipaddr(),
get_remote_port(),
info);
@ -173,3 +206,184 @@ auth_root_allowed(char *method)
log("ROOT LOGIN REFUSED FROM %.200s", get_remote_ipaddr());
return 0;
}
/*
* Given a template and a passwd structure, build a filename
* by substituting % tokenised options. Currently, %% becomes '%',
* %h becomes the home directory and %u the username.
*
* This returns a buffer allocated by xmalloc.
*/
char *
expand_filename(const char *filename, struct passwd *pw)
{
Buffer buffer;
char *file;
const char *cp;
/*
* Build the filename string in the buffer by making the appropriate
* substitutions to the given file name.
*/
buffer_init(&buffer);
for (cp = filename; *cp; cp++) {
if (cp[0] == '%' && cp[1] == '%') {
buffer_append(&buffer, "%", 1);
cp++;
continue;
}
if (cp[0] == '%' && cp[1] == 'h') {
buffer_append(&buffer, pw->pw_dir, strlen(pw->pw_dir));
cp++;
continue;
}
if (cp[0] == '%' && cp[1] == 'u') {
buffer_append(&buffer, pw->pw_name,
strlen(pw->pw_name));
cp++;
continue;
}
buffer_append(&buffer, cp, 1);
}
buffer_append(&buffer, "\0", 1);
/*
* Ensure that filename starts anchored. If not, be backward
* compatible and prepend the '%h/'
*/
file = xmalloc(MAXPATHLEN);
cp = buffer_ptr(&buffer);
if (*cp != '/')
snprintf(file, MAXPATHLEN, "%s/%s", pw->pw_dir, cp);
else
strlcpy(file, cp, MAXPATHLEN);
buffer_free(&buffer);
return file;
}
char *
authorized_keys_file(struct passwd *pw)
{
return expand_filename(options.authorized_keys_file, pw);
}
char *
authorized_keys_file2(struct passwd *pw)
{
return expand_filename(options.authorized_keys_file2, pw);
}
/* return ok if key exists in sysfile or userfile */
HostStatus
check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host,
const char *sysfile, const char *userfile)
{
Key *found;
char *user_hostfile;
struct stat st;
HostStatus host_status;
/* Check if we know the host and its host key. */
found = key_new(key->type);
host_status = check_host_in_hostfile(sysfile, host, key, found, NULL);
if (host_status != HOST_OK && userfile != NULL) {
user_hostfile = tilde_expand_filename(userfile, 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("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,
host, key, found, NULL);
restore_uid();
}
xfree(user_hostfile);
}
key_free(found);
debug2("check_key_in_hostfiles: key %s for %s", host_status == HOST_OK ?
"ok" : "not found", host);
return host_status;
}
/*
* Check a given file for security. This is defined as all components
* of the path to the file must either be owned by either the owner of
* of the file or root and no directories must be group or world writable.
*
* XXX Should any specific check be done for sym links ?
*
* Takes an open file descriptor, the file name, a uid and and
* error buffer plus max size as arguments.
*
* Returns 0 on success and -1 on failure
*/
int
secure_filename(FILE *f, const char *file, struct passwd *pw,
char *err, size_t errlen)
{
uid_t uid = pw->pw_uid;
char buf[MAXPATHLEN], homedir[MAXPATHLEN];
char *cp;
struct stat st;
if (realpath(file, buf) == NULL) {
snprintf(err, errlen, "realpath %s failed: %s", file,
strerror(errno));
return -1;
}
if (realpath(pw->pw_dir, homedir) == NULL) {
snprintf(err, errlen, "realpath %s failed: %s", pw->pw_dir,
strerror(errno));
return -1;
}
/* check the open file to avoid races */
if (fstat(fileno(f), &st) < 0 ||
(st.st_uid != 0 && st.st_uid != uid) ||
(st.st_mode & 022) != 0) {
snprintf(err, errlen, "bad ownership or modes for file %s",
buf);
return -1;
}
/* for each component of the canonical path, walking upwards */
for (;;) {
if ((cp = dirname(buf)) == NULL) {
snprintf(err, errlen, "dirname() failed");
return -1;
}
strlcpy(buf, cp, sizeof(buf));
debug3("secure_filename: checking '%s'", buf);
if (stat(buf, &st) < 0 ||
(st.st_uid != 0 && st.st_uid != uid) ||
(st.st_mode & 022) != 0) {
snprintf(err, errlen,
"bad ownership or modes for directory %s", buf);
return -1;
}
/* If are passed the homedir then we can stop */
if (strcmp(homedir, buf) == 0) {
debug3("secure_filename: terminating check at '%s'",
buf);
break;
}
/*
* dirname should always complete with a "/" path,
* but we can be paranoid and check for "." too
*/
if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0))
break;
}
return 0;
}

View file

@ -1,3 +1,6 @@
/* $OpenBSD: auth.h,v 1.29 2002/03/04 17:27:39 stevesk Exp $ */
/* $FreeBSD$ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@ -21,12 +24,13 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $OpenBSD: auth.h,v 1.15 2001/04/12 19:15:24 markus Exp $
* $FreeBSD$
*/
#ifndef AUTH_H
#define AUTH_H
#include "key.h"
#include "hostfile.h"
#include <openssl/rsa.h>
#ifdef HAVE_LOGIN_CAP
@ -35,119 +39,115 @@
#ifdef BSD_AUTH
#include <bsd_auth.h>
#endif
#ifdef KRB5
#include <krb5.h>
#endif
typedef struct Authctxt Authctxt;
typedef struct KbdintDevice KbdintDevice;
struct Authctxt {
int success;
int postponed;
int valid;
int attempt;
int failures;
char *user;
char *service;
struct passwd *pw;
char *style;
int success;
int postponed;
int valid;
int attempt;
int failures;
char *user;
char *service;
struct passwd *pw;
char *style;
void *kbdintctxt;
#ifdef BSD_AUTH
auth_session_t *as;
auth_session_t *as;
#endif
#ifdef KRB4
char *krb4_ticket_file;
#endif
#ifdef KRB5
krb5_context krb5_ctx;
krb5_auth_context krb5_auth_ctx;
krb5_ccache krb5_fwd_ccache;
krb5_principal krb5_user;
char *krb5_ticket_file;
#endif
};
/*
* Tries to authenticate the user using the .rhosts file. Returns true if
* authentication succeeds. If ignore_rhosts is non-zero, this will not
* consider .rhosts and .shosts (/etc/hosts.equiv will still be used).
* Keyboard interactive device:
* init_ctx returns: non NULL upon success
* query returns: 0 - success, otherwise failure
* respond returns: 0 - success, 1 - need further interaction,
* otherwise - failure
*/
int auth_rhosts(struct passwd * pw, const char *client_user);
struct KbdintDevice
{
const char *name;
void* (*init_ctx)(Authctxt*);
int (*query)(void *ctx, char **name, char **infotxt,
u_int *numprompts, char ***prompts, u_int **echo_on);
int (*respond)(void *ctx, u_int numresp, char **responses);
void (*free_ctx)(void *ctx);
};
/* extended interface similar to auth_rhosts() */
int auth_rhosts(struct passwd *, const char *);
int
auth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname,
const char *ipaddr);
auth_rhosts2(struct passwd *, const char *, const char *, const char *);
/*
* Tries to authenticate the user using the .rhosts file and the host using
* its host key. Returns true if authentication succeeds.
*/
int
auth_rhosts_rsa(struct passwd * pw, const char *client_user, RSA* client_host_key);
/*
* Tries to authenticate the user using password. Returns true if
* authentication succeeds.
*/
int auth_password(Authctxt *authctxt, const char *password);
/*
* Performs the RSA authentication dialog with the client. This returns 0 if
* the client could not be authenticated, and 1 if authentication was
* successful. This may exit if there is a serious protocol violation.
*/
int auth_rsa(struct passwd * pw, BIGNUM * client_n);
/*
* Parses an RSA key (number of bits, e, n) from a string. Moves the pointer
* over the key. Skips any whitespace at the beginning and at end.
*/
int auth_rsa_read_key(char **cpp, u_int *bitsp, BIGNUM * e, BIGNUM * n);
/*
* Performs the RSA authentication challenge-response dialog with the client,
* and returns true (non-zero) if the client gave the correct answer to our
* challenge; returns zero if the client gives a wrong answer.
*/
int auth_rsa_challenge_dialog(RSA *pk);
int auth_rhosts_rsa(struct passwd *, const char *, Key *);
int auth_password(Authctxt *, const char *);
int auth_rsa(struct passwd *, BIGNUM *);
int auth_rsa_challenge_dialog(RSA *);
#ifdef KRB4
#include <krb.h>
#endif /* KRB4 */
#ifdef KRB5
#include <krb5.h>
int auth_krb5(); /* XXX Doplnit prototypy */
int auth_krb5_tgt();
int krb5_init();
void krb5_cleanup_proc(void *ignore);
int auth_krb5_password(struct passwd *pw, const char *password);
#endif /* KRB5 */
#ifdef KRB4
#include <krb.h>
/*
* Performs Kerberos v4 mutual authentication with the client. This returns 0
* if the client could not be authenticated, and 1 if authentication was
* successful. This may exit if there is a serious protocol violation.
*/
int auth_krb4(const char *server_user, KTEXT auth, char **client);
int krb4_init(uid_t uid);
void krb4_cleanup_proc(void *ignore);
int auth_krb4_password(struct passwd * pw, const char *password);
int auth_krb4(Authctxt *, KTEXT, char **);
int auth_krb4_password(Authctxt *, const char *);
void krb4_cleanup_proc(void *);
#ifdef AFS
#include <kafs.h>
int auth_krb4_tgt(Authctxt *, const char *);
int auth_afs_token(Authctxt *, const char *);
#endif /* AFS */
/* Accept passed Kerberos v4 ticket-granting ticket and AFS tokens. */
int auth_kerberos_tgt(struct passwd * pw, const char *string);
int auth_afs_token(struct passwd * pw, const char *token_string);
#endif /* AFS */
#endif /* KRB4 */
#endif /* KRB4 */
#ifdef KRB5
int auth_krb5(Authctxt *authctxt, krb5_data *auth, char **client);
int auth_krb5_tgt(Authctxt *authctxt, krb5_data *tgt);
int auth_krb5_password(Authctxt *authctxt, const char *password);
void krb5_cleanup_proc(void *authctxt);
#endif /* KRB5 */
void do_authentication(void);
void do_authentication2(void);
Authctxt *authctxt_new(void);
void auth_log(Authctxt *authctxt, int authenticated, char *method, char *info);
void userauth_finish(Authctxt *authctxt, int authenticated, char *method);
int auth_root_allowed(char *method);
void auth_log(Authctxt *, int, char *, char *);
void userauth_finish(Authctxt *, int, char *);
int auth_root_allowed(char *);
int auth2_challenge(Authctxt *authctxt, char *devs);
int auth2_challenge(Authctxt *, char *);
void auth2_challenge_stop(Authctxt *);
int allowed_user(struct passwd * pw);
int allowed_user(struct passwd *);
char *get_challenge(Authctxt *authctxt, char *devs);
int verify_response(Authctxt *authctxt, char *response);
char *get_challenge(Authctxt *);
int verify_response(Authctxt *, const char *);
struct passwd * auth_get_user(void);
char *expand_filename(const char *, struct passwd *);
char *authorized_keys_file(struct passwd *);
char *authorized_keys_file2(struct passwd *);
int
secure_filename(FILE *, const char *, struct passwd *, char *, size_t);
HostStatus
check_key_in_hostfiles(struct passwd *, Key *, const char *,
const char *, const char *);
#define AUTH_FAIL_MAX 6
#define AUTH_FAIL_LOG (AUTH_FAIL_MAX/2)
#define AUTH_FAIL_MSG "Too many authentication failures for %.100s"

View file

@ -10,7 +10,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth1.c,v 1.22 2001/03/23 12:02:49 markus Exp $");
RCSID("$OpenBSD: auth1.c,v 1.35 2002/02/03 17:53:25 markus Exp $");
RCSID("$FreeBSD$");
#include "xmalloc.h"
@ -23,18 +23,15 @@ RCSID("$FreeBSD$");
#include "servconf.h"
#include "compat.h"
#include "auth.h"
#include "auth-pam.h"
#include "channels.h"
#include "session.h"
#include "canohost.h"
#include "misc.h"
#include <login_cap.h>
#include <security/pam_appl.h>
#include "uidswap.h"
#ifdef KRB5
extern krb5_context ssh_context;
krb5_principal tkt_client = NULL; /* Principal from the received ticket.
Also is used as an indication of succesful krb5 authentization. */
#endif
#include <login_cap.h>
#include "auth-pam.h"
#include <security/pam_appl.h>
/* import */
extern ServerOptions options;
@ -42,7 +39,7 @@ extern ServerOptions options;
/*
* convert ssh auth msg type into description
*/
char *
static char *
get_authname(int type)
{
static char buf[1024];
@ -71,17 +68,16 @@ get_authname(int type)
* read packets, try to authenticate the user and
* return only if authentication is successful
*/
void
static void
do_authloop(Authctxt *authctxt)
{
int authenticated = 0;
u_int bits;
RSA *client_host_key;
Key *client_host_key;
BIGNUM *n;
char *client_user, *password;
char info[1024];
u_int dlen;
int plen, nlen, elen;
u_int ulen;
int type = 0;
struct passwd *pw = authctxt->pw;
@ -95,41 +91,23 @@ do_authloop(Authctxt *authctxt)
#if defined(HAVE_LOGIN_CAP) || defined(LOGIN_ACCESS)
const char *from_host, *from_ip;
from_host = get_canonical_hostname(options.reverse_mapping_check);
from_host = get_canonical_hostname(options.verify_reverse_mapping);
from_ip = get_remote_ipaddr();
#endif /* HAVE_LOGIN_CAP || LOGIN_ACCESS */
#if 0
#ifdef KRB5
{
krb5_error_code ret;
ret = krb5_init_context(&ssh_context);
if (ret)
verbose("Error while initializing Kerberos V5.");
krb5_init_ets(ssh_context);
}
#endif /* KRB5 */
#endif
debug("Attempting authentication for %s%.100s.",
authctxt->valid ? "" : "illegal user ", authctxt->user);
authctxt->valid ? "" : "illegal user ", authctxt->user);
/* If the user has no password, accept authentication immediately. */
if (options.password_authentication &&
#if defined(KRB4) || defined(KRB5)
(!options.kerberos_authentication
#if defined(KRB4)
|| options.krb4_or_local_passwd
#endif
) &&
(!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
#endif
#ifdef USE_PAM
auth_pam_password(authctxt, "")
auth_pam_password(authctxt, "")) {
#else
auth_password(authctxt, "")
auth_password(authctxt, "")) {
#endif
) {
auth_log(authctxt, 1, "without authentication", "");
return;
}
@ -148,101 +126,67 @@ do_authloop(Authctxt *authctxt)
info[0] = '\0';
/* Get a packet from the client. */
type = packet_read(&plen);
type = packet_read();
/* Process the packet. */
switch (type) {
#ifdef AFS
#ifndef KRB5
case SSH_CMSG_HAVE_KERBEROS_TGT:
if (!options.krb4_tgt_passing) {
/* packet_get_all(); */
verbose("Kerberos v4 tgt passing disabled.");
break;
} else {
/* Accept Kerberos v4 tgt. */
char *tgt = packet_get_string(&dlen);
packet_integrity_check(plen, 4 + dlen, type);
if (!auth_krb4_tgt(pw, tgt))
verbose("Kerberos v4 tgt REFUSED for %.100ss", authctxt->user);
xfree(tgt);
}
continue;
#endif /* !KRB5 */
case SSH_CMSG_HAVE_AFS_TOKEN:
if (!options.afs_token_passing || !k_hasafs()) {
verbose("AFS token passing disabled.");
break;
} else {
/* Accept AFS token. */
char *token_string = packet_get_string(&dlen);
packet_integrity_check(plen, 4 + dlen, type);
if (!auth_afs_token(pw, token_string))
verbose("AFS token REFUSED for %.100s", authctxt->user);
xfree(token_string);
}
continue;
#endif /* AFS */
#if defined(KRB4) || defined(KRB5)
case SSH_CMSG_AUTH_KERBEROS:
if (!options.kerberos_authentication) {
verbose("Kerberos authentication disabled.");
break;
} else {
/* Try Kerberos authentication. */
u_int len;
char *tkt_user = NULL;
char *kdata = packet_get_string(&len);
packet_integrity_check(plen, 4 + len, type);
char *kdata = packet_get_string(&dlen);
packet_check_eom();
if (!authctxt->valid) {
/* Do nothing. */
} else if (kdata[0] == 4) { /* 4 == KRB_PROT_VERSION */
if (kdata[0] == 4) { /* KRB_PROT_VERSION */
#ifdef KRB4
KTEXT_ST auth;
KTEXT_ST tkt;
auth.length = len;
if (auth.length < MAX_KTXT_LEN)
memcpy(auth.dat, kdata, auth.length);
authenticated = auth_krb4(pw->pw_name, &auth, &tkt_user);
tkt.length = dlen;
if (tkt.length < MAX_KTXT_LEN)
memcpy(tkt.dat, kdata, tkt.length);
if (authenticated) {
snprintf(info, sizeof info,
" tktuser %.100s", tkt_user);
xfree(tkt_user);
if (auth_krb4(authctxt, &tkt, &client_user)) {
authenticated = 1;
snprintf(info, sizeof(info),
" tktuser %.100s",
client_user);
xfree(client_user);
}
#else
verbose("Kerberos v4 authentication disabled.");
#endif /* KRB4 */
} else {
#ifndef KRB5
verbose("Kerberos v5 authentication disabled.");
#else
krb5_data k5data;
k5data.length = len;
k5data.data = kdata;
#if 0
if (krb5_init_context(&ssh_context)) {
verbose("Error while initializing Kerberos V5.");
break;
}
krb5_init_ets(ssh_context);
#endif
/* pw->name is passed just for logging purposes */
if (auth_krb5(pw->pw_name, &k5data, &tkt_client)) {
/* authorize client against .k5login */
if (krb5_kuserok(ssh_context,
tkt_client,
pw->pw_name))
authenticated = 1;
#ifdef KRB5
krb5_data tkt;
tkt.length = dlen;
tkt.data = kdata;
if (auth_krb5(authctxt, &tkt, &client_user)) {
authenticated = 1;
snprintf(info, sizeof(info),
" tktuser %.100s",
client_user);
xfree(client_user);
}
#endif /* KRB5 */
}
}
xfree(kdata);
}
break;
}
break;
#endif /* KRB4 || KRB5 */
#if defined(AFS) || defined(KRB5)
/* XXX - punt on backward compatibility here. */
case SSH_CMSG_HAVE_KERBEROS_TGT:
packet_send_debug("Kerberos TGT passing disabled before authentication.");
break;
#ifdef AFS
case SSH_CMSG_HAVE_AFS_TOKEN:
packet_send_debug("AFS token passing disabled before authentication.");
break;
#endif /* AFS */
#endif /* AFS || KRB5 */
case SSH_CMSG_AUTH_RHOSTS:
if (!options.rhosts_authentication) {
verbose("Rhosts authentication disabled.");
@ -255,7 +199,7 @@ do_authloop(Authctxt *authctxt)
* IP-spoofing on a local network.)
*/
client_user = packet_get_string(&ulen);
packet_integrity_check(plen, 4 + ulen, type);
packet_check_eom();
/* Try to authenticate using /etc/hosts.equiv and .rhosts. */
authenticated = auth_rhosts(pw, client_user);
@ -276,24 +220,20 @@ do_authloop(Authctxt *authctxt)
client_user = packet_get_string(&ulen);
/* Get the client host key. */
client_host_key = RSA_new();
if (client_host_key == NULL)
fatal("RSA_new failed");
client_host_key->e = BN_new();
client_host_key->n = BN_new();
if (client_host_key->e == NULL || client_host_key->n == NULL)
fatal("BN_new failed");
client_host_key = key_new(KEY_RSA1);
bits = packet_get_int();
packet_get_bignum(client_host_key->e, &elen);
packet_get_bignum(client_host_key->n, &nlen);
packet_get_bignum(client_host_key->rsa->e);
packet_get_bignum(client_host_key->rsa->n);
if (bits != BN_num_bits(client_host_key->n))
if (bits != BN_num_bits(client_host_key->rsa->n))
verbose("Warning: keysize mismatch for client_host_key: "
"actual %d, announced %d", BN_num_bits(client_host_key->n), bits);
packet_integrity_check(plen, (4 + ulen) + 4 + elen + nlen, type);
"actual %d, announced %d",
BN_num_bits(client_host_key->rsa->n), bits);
packet_check_eom();
authenticated = auth_rhosts_rsa(pw, client_user, client_host_key);
RSA_free(client_host_key);
authenticated = auth_rhosts_rsa(pw, client_user,
client_host_key);
key_free(client_host_key);
snprintf(info, sizeof info, " ruser %.100s", client_user);
break;
@ -304,9 +244,10 @@ do_authloop(Authctxt *authctxt)
break;
}
/* RSA authentication requested. */
n = BN_new();
packet_get_bignum(n, &nlen);
packet_integrity_check(plen, nlen, type);
if ((n = BN_new()) == NULL)
fatal("do_authloop: BN_new failed");
packet_get_bignum(n);
packet_check_eom();
authenticated = auth_rsa(pw, n);
BN_clear_free(n);
break;
@ -322,7 +263,7 @@ do_authloop(Authctxt *authctxt)
* not visible to an outside observer.
*/
password = packet_get_string(&dlen);
packet_integrity_check(plen, 4 + dlen, type);
packet_check_eom();
#ifdef USE_PAM
/* Do PAM auth with password */
@ -356,12 +297,9 @@ do_authloop(Authctxt *authctxt)
continue;
case SSH_CMSG_AUTH_TIS_RESPONSE:
debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE");
if (pam_cookie == NULL)
break;
{
if (pam_cookie != NULL) {
char *response = packet_get_string(&dlen);
packet_integrity_check(plen, 4 + dlen, type);
pam_cookie->resp[0]->resp = strdup(response);
xfree(response);
authenticated = ipam_complete_auth(pam_cookie);
@ -372,12 +310,13 @@ do_authloop(Authctxt *authctxt)
#elif defined(SKEY)
case SSH_CMSG_AUTH_TIS:
debug("rcvd SSH_CMSG_AUTH_TIS");
if (options.challenge_reponse_authentication == 1) {
char *challenge = get_challenge(authctxt, authctxt->style);
if (options.challenge_response_authentication == 1) {
char *challenge = get_challenge(authctxt);
if (challenge != NULL) {
debug("sending challenge '%s'", challenge);
packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
packet_put_cstring(challenge);
xfree(challenge);
packet_send();
packet_write_wait();
continue;
@ -386,10 +325,10 @@ do_authloop(Authctxt *authctxt)
break;
case SSH_CMSG_AUTH_TIS_RESPONSE:
debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE");
if (options.challenge_reponse_authentication == 1) {
if (options.challenge_response_authentication == 1) {
char *response = packet_get_string(&dlen);
debug("got response '%s'", response);
packet_integrity_check(plen, 4 + dlen, type);
packet_check_eom();
authenticated = verify_response(authctxt, response);
memset(response, 'r', dlen);
xfree(response);
@ -401,32 +340,6 @@ do_authloop(Authctxt *authctxt)
log("TIS authentication unsupported.");
break;
#endif
#ifdef KRB5
case SSH_CMSG_HAVE_KERBEROS_TGT:
/* Passing krb5 ticket */
if (!options.krb5_tgt_passing
/*|| !options.krb5_authentication */) {
verbose("Kerberos v5 tgt passing disabled.");
break;
}
if (tkt_client == NULL) {
/* passing tgt without krb5 authentication */
}
{
krb5_data tgt;
u_int tgtlen;
tgt.data = packet_get_string(&tgtlen);
tgt.length = tgtlen;
if (!auth_krb5_tgt(pw->pw_name, &tgt, tkt_client))
verbose ("Kerberos V5 TGT refused for %.100s", pw->pw_name);
xfree(tgt.data);
break;
}
#endif /* KRB5 */
default:
/*
@ -481,7 +394,7 @@ do_authloop(Authctxt *authctxt)
if (pw != NULL && pw->pw_uid == 0)
log("ROOT LOGIN as '%.100s' from %.100s",
pw->pw_name,
get_canonical_hostname(options.reverse_mapping_check));
get_canonical_hostname(options.verify_reverse_mapping));
/* Log before sending the reply */
auth_log(authctxt, authenticated, get_authname(type), info);
@ -513,23 +426,26 @@ do_authloop(Authctxt *authctxt)
* been exchanged and encryption is enabled.
*/
void
do_authentication()
do_authentication(void)
{
Authctxt *authctxt;
struct passwd *pw;
int plen;
u_int ulen;
char *user, *style = NULL;
char *p, *user, *style = NULL;
/* Get the name of the user that we wish to log in as. */
packet_read_expect(&plen, SSH_CMSG_USER);
packet_read_expect(SSH_CMSG_USER);
/* Get the user name. */
user = packet_get_string(&ulen);
packet_integrity_check(plen, (4 + ulen), SSH_CMSG_USER);
packet_check_eom();
if ((style = strchr(user, ':')) != NULL)
*style++ = 0;
*style++ = '\0';
/* XXX - SSH.com Kerberos v5 braindeath. */
if ((p = strchr(user, '@')) != NULL)
*p = '\0';
authctxt = authctxt_new();
authctxt->user = user;

View file

@ -23,7 +23,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: auth2.c,v 1.56 2001/04/19 00:05:11 markus Exp $");
RCSID("$OpenBSD: auth2.c,v 1.85 2002/02/24 19:14:59 markus Exp $");
RCSID("$FreeBSD$");
#include <openssl/evp.h>
@ -51,7 +51,7 @@ RCSID("$FreeBSD$");
#include "misc.h"
#include "hostfile.h"
#include "canohost.h"
#include "tildexpand.h"
#include "match.h"
#ifdef HAVE_LOGIN_CAP
#include <login_cap.h>
@ -74,26 +74,22 @@ struct Authmethod {
/* protocol */
void input_service_request(int type, int plen, void *ctxt);
void input_userauth_request(int type, int plen, void *ctxt);
void protocol_error(int type, int plen, void *ctxt);
static void input_service_request(int, u_int32_t, void *);
static void input_userauth_request(int, u_int32_t, void *);
/* helper */
Authmethod *authmethod_lookup(const char *name);
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);
static Authmethod *authmethod_lookup(const char *);
static char *authmethods_get(void);
static int user_key_allowed(struct passwd *, Key *);
static int hostbased_key_allowed(struct passwd *, const char *, char *, 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);
static void userauth_banner(void);
static int userauth_none(Authctxt *);
static int userauth_passwd(Authctxt *);
static int userauth_pubkey(Authctxt *);
static int userauth_hostbased(Authctxt *);
static int userauth_kbdint(Authctxt *);
Authmethod authmethods[] = {
{"none",
@ -119,44 +115,30 @@ Authmethod authmethods[] = {
*/
void
do_authentication2()
do_authentication2(void)
{
Authctxt *authctxt = authctxt_new();
x_authctxt = authctxt; /*XXX*/
#if defined(KRB4) || defined(KRB5)
/* turn off kerberos, not supported by SSH2 */
options.kerberos_authentication = 0;
#endif
/* challenge-reponse is implemented via keyboard interactive */
if (options.challenge_reponse_authentication)
/* challenge-response is implemented via keyboard interactive */
if (options.challenge_response_authentication)
options.kbd_interactive_authentication = 1;
dispatch_init(&protocol_error);
dispatch_init(&dispatch_protocol_error);
dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
do_authenticated(authctxt);
}
void
protocol_error(int type, int plen, void *ctxt)
{
log("auth: protocol error: type %d plen %d", type, plen);
packet_start(SSH2_MSG_UNIMPLEMENTED);
packet_put_int(0);
packet_send();
packet_write_wait();
}
void
input_service_request(int type, int plen, void *ctxt)
static void
input_service_request(int type, u_int32_t seq, void *ctxt)
{
Authctxt *authctxt = ctxt;
u_int len;
int accept = 0;
char *service = packet_get_string(&len);
packet_done();
packet_check_eom();
if (authctxt == NULL)
fatal("input_service_request: no authctxt");
@ -182,8 +164,8 @@ input_service_request(int type, int plen, void *ctxt)
xfree(service);
}
void
input_userauth_request(int type, int plen, void *ctxt)
static void
input_userauth_request(int type, u_int32_t seq, void *ctxt)
{
Authctxt *authctxt = ctxt;
Authmethod *m = NULL;
@ -195,7 +177,7 @@ input_userauth_request(int type, int plen, void *ctxt)
#if defined(HAVE_LOGIN_CAP) || defined(LOGIN_ACCESS)
const char *from_host, *from_ip;
from_host = get_canonical_hostname(options.reverse_mapping_check);
from_host = get_canonical_hostname(options.verify_reverse_mapping);
from_ip = get_remote_ipaddr();
#endif /* HAVE_LOGIN_CAP || LOGIN_ACCESS */
@ -229,14 +211,12 @@ input_userauth_request(int type, int plen, void *ctxt)
setproctitle("%s", pw ? user : "unknown");
authctxt->user = xstrdup(user);
authctxt->service = xstrdup(service);
authctxt->style = style ? xstrdup(style) : NULL; /* currently unused */
} else if (authctxt->valid) {
if (strcmp(user, authctxt->user) != 0 ||
strcmp(service, authctxt->service) != 0) {
log("input_userauth_request: mismatch: (%s,%s)!=(%s,%s)",
user, service, authctxt->user, authctxt->service);
authctxt->valid = 0;
}
authctxt->style = style ? xstrdup(style) : NULL;
} else if (strcmp(user, authctxt->user) != 0 ||
strcmp(service, authctxt->service) != 0) {
packet_disconnect("Change of username or service not allowed: "
"(%s,%s) -> (%s,%s)",
authctxt->user, authctxt->service, user, service);
}
#ifdef HAVE_LOGIN_CAP
@ -267,14 +247,8 @@ input_userauth_request(int type, int plen, void *ctxt)
}
#endif /* LOGIN_ACCESS */
/* reset state */
dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, &protocol_error);
auth2_challenge_stop(authctxt);
authctxt->postponed = 0;
#ifdef BSD_AUTH
if (authctxt->as) {
auth_close(authctxt->as);
authctxt->as = NULL;
}
#endif
/* try to authenticate user */
m = authmethod_lookup(method);
@ -296,6 +270,8 @@ input_userauth_request(int type, int plen, void *ctxt)
void
userauth_finish(Authctxt *authctxt, int authenticated, char *method)
{
char *methods;
if (!authctxt->valid && authenticated)
fatal("INTERNAL ERROR: authenticated invalid user %s",
authctxt->user);
@ -308,11 +284,32 @@ userauth_finish(Authctxt *authctxt, int authenticated, char *method)
/* Log before sending the reply */
auth_log(authctxt, authenticated, method, " ssh2");
if (!authctxt->postponed)
userauth_reply(authctxt, authenticated);
if (authctxt->postponed)
return;
/* XXX todo: check if multiple auth methods are needed */
if (authenticated == 1) {
/* turn off userauth */
dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore);
packet_start(SSH2_MSG_USERAUTH_SUCCESS);
packet_send();
packet_write_wait();
/* now we can break out */
authctxt->success = 1;
} else {
if (authctxt->failures++ > AUTH_FAIL_MAX)
packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
methods = authmethods_get();
packet_start(SSH2_MSG_USERAUTH_FAILURE);
packet_put_cstring(methods);
packet_put_char(0); /* XXX partial success, unused */
packet_send();
packet_write_wait();
xfree(methods);
}
}
void
static void
userauth_banner(void)
{
struct stat st;
@ -343,41 +340,14 @@ userauth_banner(void)
return;
}
void
userauth_reply(Authctxt *authctxt, int authenticated)
{
char *methods;
/* XXX todo: check if multiple auth methods are needed */
if (authenticated == 1) {
/* turn off userauth */
dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
packet_start(SSH2_MSG_USERAUTH_SUCCESS);
packet_send();
packet_write_wait();
/* now we can break out */
authctxt->success = 1;
} else {
if (authctxt->failures++ > AUTH_FAIL_MAX)
packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
methods = authmethods_get();
packet_start(SSH2_MSG_USERAUTH_FAILURE);
packet_put_cstring(methods);
packet_put_char(0); /* XXX partial success, unused */
packet_send();
packet_write_wait();
xfree(methods);
}
}
int
static int
userauth_none(Authctxt *authctxt)
{
/* disable method "none", only allowed one time */
Authmethod *m = authmethod_lookup("none");
if (m != NULL)
m->enabled = NULL;
packet_done();
packet_check_eom();
userauth_banner();
#ifdef USE_PAM
return authctxt->valid ? auth_pam_password(authctxt, "") : 0;
@ -386,7 +356,7 @@ userauth_none(Authctxt *authctxt)
#endif /* USE_PAM */
}
int
static int
userauth_passwd(Authctxt *authctxt)
{
char *password;
@ -397,7 +367,7 @@ userauth_passwd(Authctxt *authctxt)
if (change)
log("password change not supported");
password = packet_get_string(&len);
packet_done();
packet_check_eom();
if (authctxt->valid &&
#ifdef USE_PAM
auth_password(authctxt, password) == 1)
@ -410,33 +380,33 @@ userauth_passwd(Authctxt *authctxt)
return authenticated;
}
int
static int
userauth_kbdint(Authctxt *authctxt)
{
int authenticated = 0;
char *lang = NULL;
char *devs = NULL;
char *lang, *devs;
lang = packet_get_string(NULL);
devs = packet_get_string(NULL);
packet_done();
packet_check_eom();
debug("keyboard-interactive language %s devs %s", lang, devs);
debug("keyboard-interactive devs %s", devs);
if (options.challenge_reponse_authentication)
if (options.challenge_response_authentication)
authenticated = auth2_challenge(authctxt, devs);
xfree(lang);
xfree(devs);
xfree(lang);
return authenticated;
}
int
static int
userauth_pubkey(Authctxt *authctxt)
{
Buffer b;
Key *key;
char *pkalg, *pkblob, *sig;
Key *key = NULL;
char *pkalg;
u_char *pkblob, *sig;
u_int alen, blen, slen;
int have_sig, pktype;
int authenticated = 0;
@ -462,83 +432,92 @@ userauth_pubkey(Authctxt *authctxt)
pktype = key_type_from_name(pkalg);
if (pktype == KEY_UNSPEC) {
/* this is perfectly legal */
log("userauth_pubkey: unsupported public key algorithm: %s", pkalg);
xfree(pkalg);
xfree(pkblob);
return 0;
log("userauth_pubkey: unsupported public key algorithm: %s",
pkalg);
goto done;
}
key = key_from_blob(pkblob, blen);
if (key != NULL) {
if (have_sig) {
sig = packet_get_string(&slen);
packet_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);
}
/* reconstruct packet */
buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
buffer_put_cstring(&b, authctxt->user);
buffer_put_cstring(&b,
datafellows & SSH_BUG_PKSERVICE ?
"ssh-userauth" :
authctxt->service);
if (datafellows & SSH_BUG_PKAUTH) {
buffer_put_char(&b, have_sig);
} else {
buffer_put_cstring(&b, "publickey");
buffer_put_char(&b, have_sig);
buffer_put_cstring(&b, pkalg);
}
buffer_put_string(&b, pkblob, blen);
#ifdef DEBUG_PK
buffer_dump(&b);
#endif
/* test for correct signature */
if (user_key_allowed(authctxt->pw, key) &&
key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
authenticated = 1;
buffer_clear(&b);
xfree(sig);
} else {
debug("test whether pkalg/pkblob are acceptable");
packet_done();
/* XXX fake reply and always send PK_OK ? */
/*
* XXX this allows testing whether a user is allowed
* to login: if you happen to have a valid pubkey this
* message is sent. the message is NEVER sent at all
* if a user is not allowed to login. is this an
* issue? -markus
*/
if (user_key_allowed(authctxt->pw, key)) {
packet_start(SSH2_MSG_USERAUTH_PK_OK);
packet_put_string(pkalg, alen);
packet_put_string(pkblob, blen);
packet_send();
packet_write_wait();
authctxt->postponed = 1;
}
}
if (authenticated != 1)
auth_clear_options();
key_free(key);
if (key == NULL) {
error("userauth_pubkey: cannot decode key: %s", pkalg);
goto done;
}
if (key->type != pktype) {
error("userauth_pubkey: type mismatch for decoded key "
"(received %d, expected %d)", key->type, pktype);
goto done;
}
if (have_sig) {
sig = packet_get_string(&slen);
packet_check_eom();
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);
}
/* reconstruct packet */
buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
buffer_put_cstring(&b, authctxt->user);
buffer_put_cstring(&b,
datafellows & SSH_BUG_PKSERVICE ?
"ssh-userauth" :
authctxt->service);
if (datafellows & SSH_BUG_PKAUTH) {
buffer_put_char(&b, have_sig);
} else {
buffer_put_cstring(&b, "publickey");
buffer_put_char(&b, have_sig);
buffer_put_cstring(&b, pkalg);
}
buffer_put_string(&b, pkblob, blen);
#ifdef DEBUG_PK
buffer_dump(&b);
#endif
/* test for correct signature */
if (user_key_allowed(authctxt->pw, key) &&
key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
authenticated = 1;
buffer_clear(&b);
xfree(sig);
} else {
debug("test whether pkalg/pkblob are acceptable");
packet_check_eom();
/* XXX fake reply and always send PK_OK ? */
/*
* XXX this allows testing whether a user is allowed
* to login: if you happen to have a valid pubkey this
* message is sent. the message is NEVER sent at all
* if a user is not allowed to login. is this an
* issue? -markus
*/
if (user_key_allowed(authctxt->pw, key)) {
packet_start(SSH2_MSG_USERAUTH_PK_OK);
packet_put_string(pkalg, alen);
packet_put_string(pkblob, blen);
packet_send();
packet_write_wait();
authctxt->postponed = 1;
}
}
if (authenticated != 1)
auth_clear_options();
done:
debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg);
if (key != NULL)
key_free(key);
xfree(pkalg);
xfree(pkblob);
return authenticated;
}
int
static int
userauth_hostbased(Authctxt *authctxt)
{
Buffer b;
Key *key;
char *pkalg, *pkblob, *sig, *cuser, *chost, *service;
Key *key = NULL;
char *pkalg, *cuser, *chost, *service;
u_char *pkblob, *sig;
u_int alen, blen, slen;
int pktype;
int authenticated = 0;
@ -571,7 +550,12 @@ userauth_hostbased(Authctxt *authctxt)
}
key = key_from_blob(pkblob, blen);
if (key == NULL) {
debug("userauth_hostbased: cannot decode key: %s", pkalg);
error("userauth_hostbased: cannot decode key: %s", pkalg);
goto done;
}
if (key->type != pktype) {
error("userauth_hostbased: type mismatch for decoded key "
"(received %d, expected %d)", key->type, pktype);
goto done;
}
service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" :
@ -596,10 +580,10 @@ userauth_hostbased(Authctxt *authctxt)
authenticated = 1;
buffer_clear(&b);
key_free(key);
done:
debug2("userauth_hostbased: authenticated %d", authenticated);
if (key != NULL)
key_free(key);
xfree(pkalg);
xfree(pkblob);
xfree(cuser);
@ -618,39 +602,30 @@ auth_get_user(void)
#define DELIM ","
char *
static char *
authmethods_get(void)
{
Authmethod *method = NULL;
u_int size = 0;
Buffer b;
char *list;
buffer_init(&b);
for (method = authmethods; method->name != NULL; method++) {
if (strcmp(method->name, "none") == 0)
continue;
if (method->enabled != NULL && *(method->enabled) != 0) {
if (size != 0)
size += strlen(DELIM);
size += strlen(method->name);
}
}
size++; /* trailing '\0' */
list = xmalloc(size);
list[0] = '\0';
for (method = authmethods; method->name != NULL; method++) {
if (strcmp(method->name, "none") == 0)
continue;
if (method->enabled != NULL && *(method->enabled) != 0) {
if (list[0] != '\0')
strlcat(list, DELIM, size);
strlcat(list, method->name, size);
if (buffer_len(&b) > 0)
buffer_append(&b, ",", 1);
buffer_append(&b, method->name, strlen(method->name));
}
}
buffer_append(&b, "\0", 1);
list = xstrdup(buffer_ptr(&b));
buffer_free(&b);
return list;
}
Authmethod *
static Authmethod *
authmethod_lookup(const char *name)
{
Authmethod *method = NULL;
@ -665,15 +640,16 @@ authmethod_lookup(const char *name)
}
/* return 1 if user allows given key */
int
user_key_allowed(struct passwd *pw, Key *key)
static int
user_key_allowed2(struct passwd *pw, Key *key, char *file)
{
char line[8192], file[MAXPATHLEN];
char line[8192];
int found_key = 0;
FILE *f;
u_long linenum = 0;
struct stat st;
Key *found;
char *fp;
if (pw == NULL)
return 0;
@ -681,9 +657,7 @@ user_key_allowed(struct passwd *pw, Key *key)
/* Temporarily use the user's uid. */
temporarily_use_uid(pw);
/* The authorized keys. */
snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
_PATH_SSH_USER_PERMITTED_KEYS2);
debug("trying public key file %s", file);
/* Fail quietly if file does not exist */
if (stat(file, &st) < 0) {
@ -698,46 +672,14 @@ user_key_allowed(struct passwd *pw, Key *key)
restore_uid();
return 0;
}
if (options.strict_modes) {
int fail = 0;
char buf[1024];
/* Check open file in order to avoid open/stat races */
if (fstat(fileno(f), &st) < 0 ||
(st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
(st.st_mode & 022) != 0) {
snprintf(buf, sizeof buf,
"%s authentication refused for %.100s: "
"bad ownership or modes for '%s'.",
key_type(key), pw->pw_name, file);
fail = 1;
} else {
/* Check path to _PATH_SSH_USER_PERMITTED_KEYS */
int i;
static const char *check[] = {
"", _PATH_SSH_USER_DIR, NULL
};
for (i = 0; check[i]; i++) {
snprintf(line, sizeof line, "%.500s/%.100s",
pw->pw_dir, check[i]);
if (stat(line, &st) < 0 ||
(st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
(st.st_mode & 022) != 0) {
snprintf(buf, sizeof buf,
"%s authentication refused for %.100s: "
"bad ownership or modes for '%s'.",
key_type(key), pw->pw_name, line);
fail = 1;
break;
}
}
}
if (fail) {
fclose(f);
log("%s", buf);
restore_uid();
return 0;
}
if (options.strict_modes &&
secure_filename(f, file, pw, line, sizeof(line)) != 0) {
fclose(f);
log("Authentication refused: %s", line);
restore_uid();
return 0;
}
found_key = 0;
found = key_new(key->type);
@ -750,7 +692,7 @@ user_key_allowed(struct passwd *pw, Key *key)
if (!*cp || *cp == '\n' || *cp == '#')
continue;
if (key_read(found, &cp) == -1) {
if (key_read(found, &cp) != 1) {
/* no key? check if there are options for this key */
int quoted = 0;
debug2("user_key_allowed: check options: '%s'", cp);
@ -764,7 +706,7 @@ user_key_allowed(struct passwd *pw, Key *key)
/* Skip remaining whitespace. */
for (; *cp == ' ' || *cp == '\t'; cp++)
;
if (key_read(found, &cp) == -1) {
if (key_read(found, &cp) != 1) {
debug2("user_key_allowed: advance: '%s'", cp);
/* still no key? advance to next line*/
continue;
@ -773,8 +715,12 @@ user_key_allowed(struct passwd *pw, Key *key)
if (key_equal(found, key) &&
auth_parse_options(pw, options, file, linenum) == 1) {
found_key = 1;
debug("matching key found: file %s, line %ld",
debug("matching key found: file %s, line %lu",
file, linenum);
fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
verbose("Found matching %s key: %s",
key_type(found), fp);
xfree(fp);
break;
}
}
@ -786,18 +732,36 @@ user_key_allowed(struct passwd *pw, Key *key)
return found_key;
}
/* check whether given key is in .ssh/authorized_keys* */
static int
user_key_allowed(struct passwd *pw, Key *key)
{
int success;
char *file;
file = authorized_keys_file(pw);
success = user_key_allowed2(pw, key, file);
xfree(file);
if (success)
return success;
/* try suffix "2" for backward compat, too */
file = authorized_keys_file2(pw);
success = user_key_allowed2(pw, key, file);
xfree(file);
return success;
}
/* return 1 if given hostkey is allowed */
int
static 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;
HostStatus host_status;
int len;
resolvedname = get_canonical_hostname(options.reverse_mapping_check);
resolvedname = get_canonical_hostname(options.verify_reverse_mapping);
ipaddr = get_remote_ipaddr();
debug2("userauth_hostbased: chost %s resolvedname %s ipaddr %s",
@ -822,32 +786,16 @@ hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
}
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);
host_status = check_key_in_hostfiles(pw, key, lookup,
_PATH_SSH_SYSTEM_HOSTFILE,
options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE);
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);
/* backward compat if no key has been found. */
if (host_status == HOST_NEW)
host_status = check_key_in_hostfiles(pw, key, lookup,
_PATH_SSH_SYSTEM_HOSTFILE2,
options.ignore_user_known_hosts ? NULL :
_PATH_SSH_USER_HOSTFILE2);
debug2("userauth_hostbased: key %s for %s", host_status == HOST_OK ?
"ok" : "not found", lookup);
return (host_status == HOST_OK);
}

View file

@ -35,7 +35,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: authfd.c,v 1.39 2001/04/05 10:42:48 markus Exp $");
RCSID("$OpenBSD: authfd.c,v 1.48 2002/02/24 19:14:59 markus Exp $");
RCSID("$FreeBSD$");
#include <openssl/evp.h>
@ -59,7 +59,8 @@ int decode_reply(int type);
/* macro to check for "agent failure" message */
#define agent_failed(x) \
((x == SSH_AGENT_FAILURE) || (x == SSH_COM_AGENT2_FAILURE))
((x == SSH_AGENT_FAILURE) || (x == SSH_COM_AGENT2_FAILURE) || \
(x == SSH2_AGENT_FAILURE))
/* Returns the number of the authentication fd, or -1 if there is none. */
@ -67,7 +68,7 @@ int
ssh_get_authentication_socket(void)
{
const char *authsocket;
int sock, len;
int sock;
struct sockaddr_un sunaddr;
authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME);
@ -76,8 +77,6 @@ ssh_get_authentication_socket(void)
sunaddr.sun_family = AF_UNIX;
strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
len = SUN_LEN(&sunaddr)+1;
sunaddr.sun_len = len;
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0)
@ -88,14 +87,14 @@ ssh_get_authentication_socket(void)
close(sock);
return -1;
}
if (connect(sock, (struct sockaddr *) & sunaddr, len) < 0) {
if (connect(sock, (struct sockaddr *) &sunaddr, sizeof sunaddr) < 0) {
close(sock);
return -1;
}
return sock;
}
int
static int
ssh_request_reply(AuthenticationConnection *auth, Buffer *request, Buffer *reply)
{
int l, len;
@ -219,7 +218,7 @@ ssh_get_num_identities(AuthenticationConnection *auth, int version)
int type, code1 = 0, code2 = 0;
Buffer request;
switch(version){
switch (version) {
case 1:
code1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
code2 = SSH_AGENT_RSA_IDENTITIES_ANSWER;
@ -288,7 +287,7 @@ ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int versio
* Get the next entry from the packet. These will abort with a fatal
* error if the packet is too short or contains corrupt data.
*/
switch(version){
switch (version) {
case 1:
key = key_new(KEY_RSA1);
bits = buffer_get_int(&auth->identities);
@ -346,7 +345,7 @@ ssh_decrypt_challenge(AuthenticationConnection *auth,
buffer_put_bignum(&buffer, key->rsa->e);
buffer_put_bignum(&buffer, key->rsa->n);
buffer_put_bignum(&buffer, challenge);
buffer_append(&buffer, (char *) session_id, 16);
buffer_append(&buffer, session_id, 16);
buffer_put_int(&buffer, response_type);
if (ssh_request_reply(auth, &buffer, &buffer) == 0) {
@ -376,8 +375,8 @@ ssh_decrypt_challenge(AuthenticationConnection *auth,
int
ssh_agent_sign(AuthenticationConnection *auth,
Key *key,
u_char **sigp, int *lenp,
u_char *data, int datalen)
u_char **sigp, u_int *lenp,
u_char *data, u_int datalen)
{
extern int datafellows;
Buffer msg;
@ -418,7 +417,7 @@ ssh_agent_sign(AuthenticationConnection *auth,
/* Encode key for a message to the agent. */
void
static void
ssh_encode_identity_rsa1(Buffer *b, RSA *key, const char *comment)
{
buffer_clear(b);
@ -431,16 +430,16 @@ ssh_encode_identity_rsa1(Buffer *b, RSA *key, const char *comment)
buffer_put_bignum(b, key->iqmp); /* ssh key->u */
buffer_put_bignum(b, key->q); /* ssh key->p, SSL key->q */
buffer_put_bignum(b, key->p); /* ssh key->q, SSL key->p */
buffer_put_string(b, comment, strlen(comment));
buffer_put_cstring(b, comment);
}
void
static void
ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment)
{
buffer_clear(b);
buffer_put_char(b, SSH2_AGENTC_ADD_IDENTITY);
buffer_put_cstring(b, key_ssh_name(key));
switch(key->type){
switch (key->type) {
case KEY_RSA:
buffer_put_bignum2(b, key->rsa->n);
buffer_put_bignum2(b, key->rsa->e);
@ -533,6 +532,25 @@ ssh_remove_identity(AuthenticationConnection *auth, Key *key)
return decode_reply(type);
}
int
ssh_update_card(AuthenticationConnection *auth, int add, const char *reader_id)
{
Buffer msg;
int type;
buffer_init(&msg);
buffer_put_char(&msg, add ? SSH_AGENTC_ADD_SMARTCARD_KEY :
SSH_AGENTC_REMOVE_SMARTCARD_KEY);
buffer_put_cstring(&msg, reader_id);
if (ssh_request_reply(auth, &msg, &msg) == 0) {
buffer_free(&msg);
return 0;
}
type = buffer_get_char(&msg);
buffer_free(&msg);
return decode_reply(type);
}
/*
* Removes all identities from the agent. This call is not meant to be used
* by normal applications.
@ -565,6 +583,7 @@ decode_reply(int type)
switch (type) {
case SSH_AGENT_FAILURE:
case SSH_COM_AGENT2_FAILURE:
case SSH2_AGENT_FAILURE:
log("SSH_AGENT_FAILURE");
return 0;
case SSH_AGENT_SUCCESS:

View file

@ -36,7 +36,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: authfile.c,v 1.32 2001/04/18 23:44:51 markus Exp $");
RCSID("$OpenBSD: authfile.c,v 1.48 2002/02/28 15:46:33 markus Exp $");
RCSID("$FreeBSD$");
#include <openssl/err.h>
@ -51,6 +51,7 @@ RCSID("$FreeBSD$");
#include "ssh.h"
#include "log.h"
#include "authfile.h"
#include "rsa.h"
/* Version identification string for SSH v1 identity files. */
static const char authfile_id_string[] =
@ -63,13 +64,13 @@ static const char authfile_id_string[] =
* passphrase.
*/
int
static int
key_save_private_rsa1(Key *key, const char *filename, const char *passphrase,
const char *comment)
{
Buffer buffer, encrypted;
char buf[100], *cp;
int fd, i;
u_char buf[100], *cp;
int fd, i, cipher_num;
CipherContext ciphercontext;
Cipher *cipher;
u_int32_t rand;
@ -78,11 +79,9 @@ key_save_private_rsa1(Key *key, const char *filename, const char *passphrase,
* If the passphrase is empty, use SSH_CIPHER_NONE to ease converting
* to another cipher; otherwise use SSH_AUTHFILE_CIPHER.
*/
if (strcmp(passphrase, "") == 0)
cipher = cipher_by_number(SSH_CIPHER_NONE);
else
cipher = cipher_by_number(SSH_AUTHFILE_CIPHER);
if (cipher == NULL)
cipher_num = (strcmp(passphrase, "") == 0) ?
SSH_CIPHER_NONE : SSH_AUTHFILE_CIPHER;
if ((cipher = cipher_by_number(cipher_num)) == NULL)
fatal("save_private_key_rsa: bad cipher");
/* This buffer is used to built the secret part of the private key. */
@ -119,21 +118,23 @@ key_save_private_rsa1(Key *key, const char *filename, const char *passphrase,
buffer_put_char(&encrypted, 0);
/* Store cipher type. */
buffer_put_char(&encrypted, cipher->number);
buffer_put_char(&encrypted, cipher_num);
buffer_put_int(&encrypted, 0); /* For future extension */
/* Store public key. This will be in plain text. */
buffer_put_int(&encrypted, BN_num_bits(key->rsa->n));
buffer_put_bignum(&encrypted, key->rsa->n);
buffer_put_bignum(&encrypted, key->rsa->e);
buffer_put_string(&encrypted, comment, strlen(comment));
buffer_put_cstring(&encrypted, comment);
/* Allocate space for the private part of the key in the buffer. */
buffer_append_space(&encrypted, &cp, buffer_len(&buffer));
cp = buffer_append_space(&encrypted, buffer_len(&buffer));
cipher_set_key_string(&ciphercontext, cipher, passphrase);
cipher_encrypt(&ciphercontext, (u_char *) cp,
(u_char *) buffer_ptr(&buffer), buffer_len(&buffer));
cipher_set_key_string(&ciphercontext, cipher, passphrase,
CIPHER_ENCRYPT);
cipher_crypt(&ciphercontext, cp,
buffer_ptr(&buffer), buffer_len(&buffer));
cipher_cleanup(&ciphercontext);
memset(&ciphercontext, 0, sizeof(ciphercontext));
/* Destroy temporary data. */
@ -148,7 +149,7 @@ key_save_private_rsa1(Key *key, const char *filename, const char *passphrase,
if (write(fd, buffer_ptr(&encrypted), buffer_len(&encrypted)) !=
buffer_len(&encrypted)) {
error("write to key file %s failed: %s", filename,
strerror(errno));
strerror(errno));
buffer_free(&encrypted);
close(fd);
unlink(filename);
@ -160,7 +161,7 @@ key_save_private_rsa1(Key *key, const char *filename, const char *passphrase,
}
/* save SSH v2 key in OpenSSL PEM format */
int
static int
key_save_private_pem(Key *key, const char *filename, const char *_passphrase,
const char *comment)
{
@ -168,8 +169,8 @@ key_save_private_pem(Key *key, const char *filename, const char *_passphrase,
int fd;
int success = 0;
int len = strlen(_passphrase);
char *passphrase = (len > 0) ? (char *)_passphrase : NULL;
EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL;
u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL;
const EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL;
if (len > 0 && len <= 4) {
error("passphrase too short: have %d bytes, need > 4", len);
@ -227,7 +228,7 @@ key_save_private(Key *key, const char *filename, const char *passphrase,
* otherwise.
*/
Key *
static Key *
key_load_public_rsa1(int fd, const char *filename, char **commentp)
{
Buffer buffer;
@ -240,7 +241,7 @@ key_load_public_rsa1(int fd, const char *filename, char **commentp)
lseek(fd, (off_t) 0, SEEK_SET);
buffer_init(&buffer);
buffer_append_space(&buffer, &cp, len);
cp = buffer_append_space(&buffer, len);
if (read(fd, cp, (size_t) len) != (size_t) len) {
debug("Read from key file %.200s failed: %.100s", filename,
@ -251,7 +252,7 @@ key_load_public_rsa1(int fd, const char *filename, char **commentp)
/* Check that it is at least big enough to contain the ID string. */
if (len < sizeof(authfile_id_string)) {
debug3("No RSA1 key file %.200s.", filename);
debug3("Not a RSA1 key file %.200s.", filename);
buffer_free(&buffer);
return NULL;
}
@ -261,7 +262,7 @@ key_load_public_rsa1(int fd, const char *filename, char **commentp)
*/
for (i = 0; i < sizeof(authfile_id_string); i++)
if (buffer_get_char(&buffer) != authfile_id_string[i]) {
debug3("No RSA1 key file %.200s.", filename);
debug3("Not a RSA1 key file %.200s.", filename);
buffer_free(&buffer);
return NULL;
}
@ -307,25 +308,23 @@ key_load_public_type(int type, const char *filename, char **commentp)
* Assumes we are called under uid of the owner of the file.
*/
Key *
static Key *
key_load_private_rsa1(int fd, const char *filename, const char *passphrase,
char **commentp)
{
int i, check1, check2, cipher_type;
off_t len;
Buffer buffer, decrypted;
char *cp;
u_char *cp;
CipherContext ciphercontext;
Cipher *cipher;
BN_CTX *ctx;
BIGNUM *aux;
Key *prv = NULL;
len = lseek(fd, (off_t) 0, SEEK_END);
lseek(fd, (off_t) 0, SEEK_SET);
buffer_init(&buffer);
buffer_append_space(&buffer, &cp, len);
cp = buffer_append_space(&buffer, len);
if (read(fd, cp, (size_t) len) != (size_t) len) {
debug("Read from key file %.200s failed: %.100s", filename,
@ -337,7 +336,7 @@ key_load_private_rsa1(int fd, const char *filename, const char *passphrase,
/* Check that it is at least big enough to contain the ID string. */
if (len < sizeof(authfile_id_string)) {
debug3("No RSA1 key file %.200s.", filename);
debug3("Not a RSA1 key file %.200s.", filename);
buffer_free(&buffer);
close(fd);
return NULL;
@ -348,7 +347,7 @@ key_load_private_rsa1(int fd, const char *filename, const char *passphrase,
*/
for (i = 0; i < sizeof(authfile_id_string); i++)
if (buffer_get_char(&buffer) != authfile_id_string[i]) {
debug3("No RSA1 key file %.200s.", filename);
debug3("Not a RSA1 key file %.200s.", filename);
buffer_free(&buffer);
close(fd);
return NULL;
@ -379,12 +378,14 @@ key_load_private_rsa1(int fd, const char *filename, const char *passphrase,
}
/* Initialize space for decrypted data. */
buffer_init(&decrypted);
buffer_append_space(&decrypted, &cp, buffer_len(&buffer));
cp = buffer_append_space(&decrypted, buffer_len(&buffer));
/* Rest of the buffer is encrypted. Decrypt it using the passphrase. */
cipher_set_key_string(&ciphercontext, cipher, passphrase);
cipher_decrypt(&ciphercontext, (u_char *) cp,
(u_char *) buffer_ptr(&buffer), buffer_len(&buffer));
cipher_set_key_string(&ciphercontext, cipher, passphrase,
CIPHER_DECRYPT);
cipher_crypt(&ciphercontext, cp,
buffer_ptr(&buffer), buffer_len(&buffer));
cipher_cleanup(&ciphercontext);
memset(&ciphercontext, 0, sizeof(ciphercontext));
buffer_free(&buffer);
@ -407,17 +408,7 @@ key_load_private_rsa1(int fd, const char *filename, const char *passphrase,
buffer_get_bignum(&decrypted, prv->rsa->p); /* q */
/* calculate p-1 and q-1 */
ctx = BN_CTX_new();
aux = BN_new();
BN_sub(aux, prv->rsa->q, BN_value_one());
BN_mod(prv->rsa->dmq1, prv->rsa->d, aux, ctx);
BN_sub(aux, prv->rsa->p, BN_value_one());
BN_mod(prv->rsa->dmp1, prv->rsa->d, aux, ctx);
BN_clear_free(aux);
BN_CTX_free(ctx);
rsa_generate_additional_parameters(prv->rsa);
buffer_free(&decrypted);
close(fd);
@ -431,7 +422,7 @@ key_load_private_rsa1(int fd, const char *filename, const char *passphrase,
return NULL;
}
Key *
static Key *
key_load_private_pem(int fd, int type, const char *passphrase,
char **commentp)
{
@ -451,7 +442,7 @@ key_load_private_pem(int fd, int type, const char *passphrase,
debug("PEM_read_PrivateKey failed");
(void)ERR_get_error();
} else if (pk->type == EVP_PKEY_RSA &&
(type == KEY_UNSPEC||type==KEY_RSA)) {
(type == KEY_UNSPEC||type==KEY_RSA)) {
prv = key_new(KEY_UNSPEC);
prv->rsa = EVP_PKEY_get1_RSA(pk);
prv->type = KEY_RSA;
@ -460,7 +451,7 @@ key_load_private_pem(int fd, int type, const char *passphrase,
RSA_print_fp(stderr, prv->rsa, 8);
#endif
} else if (pk->type == EVP_PKEY_DSA &&
(type == KEY_UNSPEC||type==KEY_DSA)) {
(type == KEY_UNSPEC||type==KEY_DSA)) {
prv = key_new(KEY_UNSPEC);
prv->dsa = EVP_PKEY_get1_DSA(pk);
prv->type = KEY_DSA;
@ -482,20 +473,23 @@ key_load_private_pem(int fd, int type, const char *passphrase,
return prv;
}
int
static int
key_perm_ok(int fd, const char *filename)
{
struct stat st;
/* check owner and modes */
if (fstat(fd, &st) < 0 ||
(st.st_uid != 0 && getuid() != 0 && st.st_uid != getuid()) ||
(st.st_mode & 077) != 0) {
close(fd);
if (fstat(fd, &st) < 0)
return 0;
/*
* if a key owned by the user is accessed, then we check the
* permissions of the file. if the key owned by a different user,
* then we don't care.
*/
if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) {
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @");
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
error("Bad ownership or mode(0%3.3o) for '%s'.",
error("Permissions 0%3.3o for '%s' are too open.",
st.st_mode & 0777, filename);
error("It is recommended that your private key files are NOT accessible by others.");
error("This private key will be ignored.");
@ -541,7 +535,7 @@ Key *
key_load_private(const char *filename, const char *passphrase,
char **commentp)
{
Key *pub;
Key *pub, *prv;
int fd;
fd = open(filename, O_RDONLY);
@ -556,16 +550,20 @@ key_load_private(const char *filename, const char *passphrase,
lseek(fd, (off_t) 0, SEEK_SET); /* rewind */
if (pub == NULL) {
/* closes fd */
return key_load_private_pem(fd, KEY_UNSPEC, passphrase, commentp);
prv = key_load_private_pem(fd, KEY_UNSPEC, passphrase, NULL);
/* use the filename as a comment for PEM */
if (commentp && prv)
*commentp = xstrdup(filename);
} else {
/* it's a SSH v1 key if the public key part is readable */
key_free(pub);
/* closes fd */
return key_load_private_rsa1(fd, filename, passphrase, NULL);
prv = key_load_private_rsa1(fd, filename, passphrase, NULL);
}
return prv;
}
int
static int
key_try_load_public(Key *k, const char *filename, char **commentp)
{
FILE *f;
@ -577,7 +575,7 @@ key_try_load_public(Key *k, const char *filename, char **commentp)
while (fgets(line, sizeof(line), f)) {
line[sizeof(line)-1] = '\0';
cp = line;
switch(*cp){
switch (*cp) {
case '#':
case '\n':
case '\0':

View file

@ -37,7 +37,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: bufaux.c,v 1.17 2001/01/21 19:05:45 markus Exp $");
RCSID("$OpenBSD: bufaux.c,v 1.22 2002/01/18 18:14:17 stevesk Exp $");
RCSID("$FreeBSD$");
#include <openssl/bn.h>
@ -63,7 +63,7 @@ buffer_put_bignum(Buffer *buffer, BIGNUM *value)
oi = BN_bn2bin(value, buf);
if (oi != bin_size)
fatal("buffer_put_bignum: BN_bn2bin() failed: oi %d != bin_size %d",
oi, bin_size);
oi, bin_size);
/* Store the number of bits in the buffer in two bytes, msb first. */
PUT_16BIT(msg, bits);
@ -78,7 +78,7 @@ buffer_put_bignum(Buffer *buffer, BIGNUM *value)
/*
* Retrieves an BIGNUM from the buffer.
*/
int
void
buffer_get_bignum(Buffer *buffer, BIGNUM *value)
{
int bits, bytes;
@ -91,11 +91,9 @@ buffer_get_bignum(Buffer *buffer, BIGNUM *value)
bytes = (bits + 7) / 8;
if (buffer_len(buffer) < bytes)
fatal("buffer_get_bignum: input buffer too small");
bin = (u_char *) buffer_ptr(buffer);
bin = buffer_ptr(buffer);
BN_bin2bn(bin, bytes, value);
buffer_consume(buffer, bytes);
return 2 + bytes;
}
/*
@ -113,16 +111,16 @@ buffer_put_bignum2(Buffer *buffer, BIGNUM *value)
oi = BN_bn2bin(value, buf+1);
if (oi != bytes-1)
fatal("buffer_put_bignum: BN_bn2bin() failed: oi %d != bin_size %d",
oi, bytes);
oi, bytes);
hasnohigh = (buf[1] & 0x80) ? 0 : 1;
if (value->neg) {
/**XXX should be two's-complement */
int i, carry;
u_char *uc = buf;
log("negativ!");
for(i = bytes-1, carry = 1; i>=0; i--) {
for (i = bytes-1, carry = 1; i>=0; i--) {
uc[i] ^= 0xff;
if(carry)
if (carry)
carry = !++uc[i];
}
}
@ -131,15 +129,14 @@ buffer_put_bignum2(Buffer *buffer, BIGNUM *value)
xfree(buf);
}
int
void
buffer_get_bignum2(Buffer *buffer, BIGNUM *value)
{
/**XXX should be two's-complement */
int len;
u_char *bin = (u_char *)buffer_get_string(buffer, (u_int *)&len);
u_char *bin = buffer_get_string(buffer, (u_int *)&len);
BN_bin2bn(bin, len, value);
xfree(bin);
return len;
}
/*
@ -188,11 +185,11 @@ buffer_put_int64(Buffer *buffer, u_int64_t value)
* will be stored there. A null character will be automatically appended
* to the returned string, and is not counted in length.
*/
char *
void *
buffer_get_string(Buffer *buffer, u_int *length_ptr)
{
u_int len;
char *value;
u_char *value;
/* Get the length. */
len = buffer_get_int(buffer);
if (len > 256 * 1024)

View file

@ -12,7 +12,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: canohost.c,v 1.26 2001/04/18 14:15:00 markus Exp $");
RCSID("$OpenBSD: canohost.c,v 1.31 2002/02/27 21:23:13 stevesk Exp $");
RCSID("$FreeBSD$");
#include "packet.h"
@ -20,15 +20,15 @@ RCSID("$FreeBSD$");
#include "log.h"
#include "canohost.h"
void check_ip_options(int socket, char *ipaddr);
static void check_ip_options(int, char *);
/*
* Return the canonical name of the host at the other end of the socket. The
* caller should free the returned string with xfree.
*/
char *
get_remote_hostname(int socket, int reverse_mapping_check)
static char *
get_remote_hostname(int socket, int verify_reverse_mapping)
{
struct sockaddr_storage from;
int i;
@ -47,13 +47,13 @@ get_remote_hostname(int socket, int reverse_mapping_check)
check_ip_options(socket, ntop);
if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
NULL, 0, NI_NUMERICHOST) != 0)
NULL, 0, NI_NUMERICHOST) != 0)
fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed");
debug3("Trying to reverse map address %.100s.", ntop);
/* Map the IP address to a host name. */
if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
NULL, 0, NI_NAMEREQD) != 0) {
NULL, 0, NI_NAMEREQD) != 0) {
/* Host name not found. Use ip address. */
log("Could not reverse map address %.100s.", ntop);
return xstrdup(ntop);
@ -69,7 +69,7 @@ get_remote_hostname(int socket, int reverse_mapping_check)
if (isupper(name[i]))
name[i] = tolower(name[i]);
if (!reverse_mapping_check)
if (!verify_reverse_mapping)
return xstrdup(name);
/*
* Map it back to an IP address and check that the given
@ -119,7 +119,7 @@ get_remote_hostname(int socket, int reverse_mapping_check)
* exit here if we detect any IP options.
*/
/* IPv4 only */
void
static void
check_ip_options(int socket, char *ipaddr)
{
u_char options[200];
@ -133,7 +133,7 @@ check_ip_options(int socket, char *ipaddr)
else
ipproto = IPPROTO_IP;
option_size = sizeof(options);
if (getsockopt(socket, ipproto, IP_OPTIONS, (void *)options,
if (getsockopt(socket, ipproto, IP_OPTIONS, options,
&option_size) >= 0 && option_size != 0) {
text[0] = '\0';
for (i = 0; i < option_size; i++)
@ -153,14 +153,14 @@ check_ip_options(int socket, char *ipaddr)
*/
const char *
get_canonical_hostname(int reverse_mapping_check)
get_canonical_hostname(int verify_reverse_mapping)
{
static char *canonical_host_name = NULL;
static int reverse_mapping_checked = 0;
static int verify_reverse_mapping_done = 0;
/* Check if we have previously retrieved name with same option. */
if (canonical_host_name != NULL) {
if (reverse_mapping_checked != reverse_mapping_check)
if (verify_reverse_mapping_done != verify_reverse_mapping)
xfree(canonical_host_name);
else
return canonical_host_name;
@ -169,11 +169,11 @@ get_canonical_hostname(int reverse_mapping_check)
/* Get the real hostname if socket; otherwise return UNKNOWN. */
if (packet_connection_is_on_socket())
canonical_host_name = get_remote_hostname(
packet_get_connection_in(), reverse_mapping_check);
packet_get_connection_in(), verify_reverse_mapping);
else
canonical_host_name = xstrdup("UNKNOWN");
reverse_mapping_checked = reverse_mapping_check;
verify_reverse_mapping_done = verify_reverse_mapping;
return canonical_host_name;
}
@ -181,7 +181,7 @@ get_canonical_hostname(int reverse_mapping_check)
* Returns the remote IP-address of socket as a string. The returned
* string must be freed.
*/
char *
static char *
get_socket_address(int socket, int remote, int flags)
{
struct sockaddr_storage addr;
@ -209,7 +209,7 @@ get_socket_address(int socket, int remote, int flags)
}
/* Get the address in ascii. */
if (getnameinfo((struct sockaddr *)&addr, addrlen, ntop, sizeof(ntop),
NULL, 0, flags) != 0) {
NULL, 0, flags) != 0) {
error("get_socket_ipaddr: getnameinfo %d failed", flags);
return NULL;
}
@ -240,7 +240,7 @@ get_local_name(int socket)
*/
const char *
get_remote_ipaddr()
get_remote_ipaddr(void)
{
static char *canonical_host_ip = NULL;
@ -260,11 +260,11 @@ get_remote_ipaddr()
}
const char *
get_remote_name_or_ip(u_int utmp_len, int reverse_mapping_check)
get_remote_name_or_ip(u_int utmp_len, int verify_reverse_mapping)
{
static const char *remote = "";
if (utmp_len > 0)
remote = get_canonical_hostname(reverse_mapping_check);
remote = get_canonical_hostname(verify_reverse_mapping);
if (utmp_len == 0 || strlen(remote) > utmp_len)
remote = get_remote_ipaddr();
return remote;
@ -272,7 +272,7 @@ get_remote_name_or_ip(u_int utmp_len, int reverse_mapping_check)
/* Returns the local/remote port for the socket. */
int
static int
get_sock_port(int sock, int local)
{
struct sockaddr_storage from;
@ -295,14 +295,14 @@ get_sock_port(int sock, int local)
}
/* Return port number. */
if (getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0,
strport, sizeof(strport), NI_NUMERICSERV) != 0)
strport, sizeof(strport), NI_NUMERICSERV) != 0)
fatal("get_sock_port: getnameinfo NI_NUMERICSERV failed");
return atoi(strport);
}
/* Returns remote/local port number for the current connection. */
int
static int
get_port(int local)
{
/*
@ -323,13 +323,13 @@ get_peer_port(int sock)
}
int
get_remote_port()
get_remote_port(void)
{
return get_port(0);
}
int
get_local_port()
get_local_port(void)
{
return get_port(1);
}

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,6 @@
/* $OpenBSD: channels.h,v 1.65 2002/03/04 17:27:39 stevesk Exp $ */
/* $FreeBSD$ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -10,7 +13,7 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -32,16 +35,13 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* RCSID("$OpenBSD: channels.h,v 1.31 2001/04/13 22:46:53 beck Exp $"); */
/* RCSID("$FreeBSD$"); */
#ifndef CHANNELS_H
#define CHANNELS_H
#ifndef CHANNEL_H
#define CHANNEL_H
#include "buffer.h"
/* Definitions for channel types. */
#define SSH_CHANNEL_FREE 0 /* This channel is free (unused). */
#define SSH_CHANNEL_X11_LISTENER 1 /* Listening for inet X11 conn. */
#define SSH_CHANNEL_PORT_LISTENER 2 /* Listening on a port. */
#define SSH_CHANNEL_OPENING 3 /* waiting for confirmation */
@ -55,38 +55,38 @@
#define SSH_CHANNEL_RPORT_LISTENER 11 /* Listening to a R-style port */
#define SSH_CHANNEL_CONNECTING 12
#define SSH_CHANNEL_DYNAMIC 13
#define SSH_CHANNEL_MAX_TYPE 14
#define SSH_CHANNEL_ZOMBIE 14 /* Almost dead. */
#define SSH_CHANNEL_MAX_TYPE 15
#define SSH_CHANNEL_PATH_LEN 256
/*
* Data structure for channel data. This is iniailized in channel_allocate
* and cleared in channel_free.
*/
struct Channel;
typedef struct Channel Channel;
typedef void channel_callback_fn(int id, void *arg);
typedef int channel_filter_fn(struct Channel *c, char *buf, int len);
typedef void channel_callback_fn(int, void *);
typedef int channel_filter_fn(struct Channel *, char *, int);
struct Channel {
int type; /* channel type/state */
int self; /* my own channel identifier */
int remote_id; /* channel identifier for remote peer */
/* peer can be reached over encrypted connection, via packet-sent */
int istate; /* input from channel (state of receive half) */
int ostate; /* output to channel (state of transmit half) */
u_int istate; /* input from channel (state of receive half) */
u_int ostate; /* output to channel (state of transmit half) */
int flags; /* close sent/rcvd */
int rfd; /* read fd */
int wfd; /* write fd */
int efd; /* extended fd */
int sock; /* sock fd */
int isatty; /* rfd is a tty */
int force_drain; /* force close on iEOF */
int delayed; /* fdset hack */
Buffer input; /* data read from socket, to be sent over
* encrypted connection */
Buffer output; /* data received over encrypted connection for
* send on socket */
Buffer extended;
char path[200]; /* path for unix domain sockets, or host name
* for forwards */
char path[SSH_CHANNEL_PATH_LEN];
/* path for unix domain sockets, or host name for forwards */
int listening_port; /* port being listened for forwards */
int host_port; /* remote port to connect for forwards */
char *remote_name; /* remote hostname */
@ -98,14 +98,13 @@ struct Channel {
int local_consumed;
int local_maxpacket;
int extended_usage;
int single_connection;
char *ctype; /* type */
/* callback */
channel_callback_fn *cb_fn;
void *cb_arg;
int cb_event;
channel_callback_fn *dettach_user;
channel_callback_fn *confirm;
channel_callback_fn *detach_user;
/* filter */
channel_filter_fn *input_filter;
@ -116,199 +115,110 @@ struct Channel {
#define CHAN_EXTENDED_WRITE 2
/* default window/packet sizes for tcp/x11-fwd-channel */
#define CHAN_SES_WINDOW_DEFAULT (32*1024)
#define CHAN_SES_PACKET_DEFAULT (CHAN_SES_WINDOW_DEFAULT/2)
#define CHAN_TCP_WINDOW_DEFAULT (32*1024)
#define CHAN_TCP_PACKET_DEFAULT (CHAN_TCP_WINDOW_DEFAULT/2)
#define CHAN_X11_WINDOW_DEFAULT (4*1024)
#define CHAN_X11_PACKET_DEFAULT (CHAN_X11_WINDOW_DEFAULT/2)
#define CHAN_SES_PACKET_DEFAULT (32*1024)
#define CHAN_SES_WINDOW_DEFAULT (4*CHAN_SES_PACKET_DEFAULT)
#define CHAN_TCP_PACKET_DEFAULT (32*1024)
#define CHAN_TCP_WINDOW_DEFAULT (4*CHAN_TCP_PACKET_DEFAULT)
#define CHAN_X11_PACKET_DEFAULT (16*1024)
#define CHAN_X11_WINDOW_DEFAULT (4*CHAN_X11_PACKET_DEFAULT)
/* possible input states */
#define CHAN_INPUT_OPEN 0
#define CHAN_INPUT_WAIT_DRAIN 1
#define CHAN_INPUT_WAIT_OCLOSE 2
#define CHAN_INPUT_CLOSED 3
void channel_open(int id);
void channel_request(int id, char *service, int wantconfirm);
void channel_request_start(int id, char *service, int wantconfirm);
void channel_register_callback(int id, int mtype, channel_callback_fn *fn, void *arg);
void channel_register_cleanup(int id, channel_callback_fn *fn);
void channel_register_filter(int id, channel_filter_fn *fn);
void channel_cancel_cleanup(int id);
Channel *channel_lookup(int id);
/* possible output states */
#define CHAN_OUTPUT_OPEN 0
#define CHAN_OUTPUT_WAIT_DRAIN 1
#define CHAN_OUTPUT_WAIT_IEOF 2
#define CHAN_OUTPUT_CLOSED 3
int
channel_new(char *ctype, int type, int rfd, int wfd, int efd,
int window, int maxpack, int extended_usage, char *remote_name,
int nonblock);
void
channel_set_fds(int id, int rfd, int wfd, int efd,
int extusage, int nonblock);
#define CHAN_CLOSE_SENT 0x01
#define CHAN_CLOSE_RCVD 0x02
void deny_input_open(int type, int plen, void *ctxt);
/* channel management */
void channel_input_channel_request(int type, int plen, void *ctxt);
void channel_input_close(int type, int plen, void *ctxt);
void channel_input_close_confirmation(int type, int plen, void *ctxt);
void channel_input_data(int type, int plen, void *ctxt);
void channel_input_extended_data(int type, int plen, void *ctxt);
void channel_input_ieof(int type, int plen, void *ctxt);
void channel_input_oclose(int type, int plen, void *ctxt);
void channel_input_open_confirmation(int type, int plen, void *ctxt);
void channel_input_open_failure(int type, int plen, void *ctxt);
void channel_input_port_open(int type, int plen, void *ctxt);
void channel_input_window_adjust(int type, int plen, void *ctxt);
Channel *channel_lookup(int);
Channel *channel_new(char *, int, int, int, int, int, int, int, char *, int);
void channel_set_fds(int, int, int, int, int, int, u_int);
void channel_free(Channel *);
void channel_free_all(void);
void channel_stop_listening(void);
/* Sets specific protocol options. */
void channel_set_options(int hostname_in_open);
void channel_send_open(int);
void channel_request_start(int, char *, int);
void channel_register_cleanup(int, channel_callback_fn *);
void channel_register_confirm(int, channel_callback_fn *);
void channel_register_filter(int, channel_filter_fn *);
void channel_cancel_cleanup(int);
int channel_close_fd(int *);
/*
* Allocate a new channel object and set its type and socket. Remote_name
* must have been allocated with xmalloc; this will free it when the channel
* is freed.
*/
int channel_allocate(int type, int sock, char *remote_name);
/* protocol handler */
/* Free the channel and close its socket. */
void channel_free(int channel);
void channel_input_close(int, u_int32_t, void *);
void channel_input_close_confirmation(int, u_int32_t, void *);
void channel_input_data(int, u_int32_t, void *);
void channel_input_extended_data(int, u_int32_t, void *);
void channel_input_ieof(int, u_int32_t, void *);
void channel_input_oclose(int, u_int32_t, void *);
void channel_input_open_confirmation(int, u_int32_t, void *);
void channel_input_open_failure(int, u_int32_t, void *);
void channel_input_port_open(int, u_int32_t, void *);
void channel_input_window_adjust(int, u_int32_t, void *);
/*
* Allocate/update select bitmasks and add any bits relevant to channels in
* select bitmasks.
*/
void
channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
int rekeying);
/* file descriptor handling (read/write) */
/*
* After select, perform any appropriate operations for channels which have
* events pending.
*/
void channel_after_select(fd_set * readset, fd_set * writeset);
void channel_prepare_select(fd_set **, fd_set **, int *, int*, int);
void channel_after_select(fd_set *, fd_set *);
void channel_output_poll(void);
/* If there is data to send to the connection, send some of it now. */
void channel_output_poll(void);
int channel_not_very_much_buffered_data(void);
void channel_close_all(void);
int channel_still_open(void);
char *channel_open_message(void);
int channel_find_open(void);
/* Returns true if no channel has too much buffered data. */
int channel_not_very_much_buffered_data(void);
/* tcp forwarding */
void channel_set_af(int af);
void channel_permit_all_opens(void);
void channel_add_permitted_opens(char *, int);
void channel_clear_permitted_opens(void);
void channel_input_port_forward_request(int, int);
int channel_connect_to(const char *, u_short);
int channel_connect_by_listen_address(u_short);
void channel_request_remote_forwarding(u_short, const char *, u_short);
int channel_setup_local_fwd_listener(u_short, const char *, u_short, int);
int channel_setup_remote_fwd_listener(const char *, u_short, int);
/* This closes any sockets that are listening for connections; this removes
any unix domain sockets. */
void channel_stop_listening(void);
/* x11 forwarding */
/*
* Closes the sockets of all channels. This is used to close extra file
* descriptors after a fork.
*/
void channel_close_all(void);
int x11_connect_display(void);
int x11_create_display_inet(int, int, int);
void x11_input_open(int, u_int32_t, void *);
void x11_request_forwarding_with_spoofing(int, const char *, const char *);
void deny_input_open(int, u_int32_t, void *);
/* Returns true if there is still an open channel over the connection. */
int channel_still_open(void);
/* agent forwarding */
/*
* Returns a string containing a list of all open channels. The list is
* suitable for displaying to the user. It uses crlf instead of newlines.
* The caller should free the string with xfree.
*/
char *channel_open_message(void);
void auth_request_forwarding(void);
char *auth_get_socket_name(void);
int auth_input_request_forwarding(struct passwd *);
void auth_input_open_request(int, u_int32_t, void *);
/*
* Initiate forwarding of connections to local port "port" through the secure
* channel to host:port from remote side.
*/
int
channel_request_local_forwarding(u_short listen_port,
const char *host_to_connect, u_short port_to_connect, int gateway_ports);
int
channel_request_forwarding(const char *listen_address, u_short listen_port,
const char *host_to_connect, u_short port_to_connect, int gateway_ports,
int remote_fwd);
/* channel close */
/*
* Initiate forwarding of connections to port "port" on remote host through
* the secure channel to host:port from local side. This never returns if
* there was an error. This registers that open requests for that port are
* permitted.
*/
void
channel_request_remote_forwarding(u_short port, const char *host,
u_short remote_port);
int chan_is_dead(Channel *, int);
void chan_mark_dead(Channel *);
/*
* Permits opening to any host/port if permitted_opens[] is empty. This is
* usually called by the server, because the user could connect to any port
* anyway, and the server has no way to know but to trust the client anyway.
*/
void channel_permit_all_opens(void);
/* channel events */
/* Add host/port to list of allowed targets for port forwarding */
void channel_add_permitted_opens(char *host, int port);
void chan_rcvd_oclose(Channel *);
void chan_read_failed(Channel *);
void chan_ibuf_empty(Channel *);
/* Flush list */
void channel_clear_permitted_opens(void);
/*
* This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates
* listening for the port, and sends back a success reply (or disconnect
* message if there was an error). This never returns if there was an error.
*/
void channel_input_port_forward_request(int is_root, int gateway_ports);
/*
* Creates a port for X11 connections, and starts listening for it. Returns
* the display name, or NULL if an error was encountered.
*/
char *x11_create_display(int screen);
/*
* Creates an internet domain socket for listening for X11 connections.
* Returns a suitable value for the DISPLAY variable, or NULL if an error
* occurs.
*/
char *x11_create_display_inet(int screen, int x11_display_offset);
/*
* This is called when SSH_SMSG_X11_OPEN is received. The packet contains
* the remote channel number. We should do whatever we want, and respond
* with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE.
*/
void x11_input_open(int type, int plen, void *ctxt);
/*
* Requests forwarding of X11 connections. This should be called on the
* client only.
*/
void x11_request_forwarding(void);
/*
* Requests forwarding for X11 connections, with authentication spoofing.
* This should be called in the client only.
*/
void
x11_request_forwarding_with_spoofing(int client_session_id,
const char *proto, const char *data);
/* Sends a message to the server to request authentication fd forwarding. */
void auth_request_forwarding(void);
/*
* Returns the name of the forwarded authentication socket. Returns NULL if
* there is no forwarded authentication socket. The returned value points to
* a static buffer.
*/
char *auth_get_socket_name(void);
/*
* This is called to process SSH_CMSG_AGENT_REQUEST_FORWARDING on the server.
* This starts forwarding authentication requests.
*/
int auth_input_request_forwarding(struct passwd * pw);
/* This is called to process an SSH_SMSG_AGENT_OPEN message. */
void auth_input_open_request(int type, int plen, void *ctxt);
/* XXX */
void auth_sock_cleanup_proc(void *pw);
int channel_connect_to(const char *host, u_short host_port);
int channel_connect_by_listen_adress(u_short listen_port);
int x11_connect_display(void);
int channel_find_open(void);
void chan_rcvd_ieof(Channel *);
void chan_write_failed(Channel *);
void chan_obuf_empty(Channel *);
#endif

View file

@ -11,7 +11,7 @@
*
*
* Copyright (c) 1999 Niels Provos. All rights reserved.
* Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
* Copyright (c) 1999, 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
@ -35,7 +35,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: cipher.c,v 1.43 2001/02/04 15:32:23 stevesk Exp $");
RCSID("$OpenBSD: cipher.c,v 1.52 2002/02/18 13:05:32 markus Exp $");
RCSID("$FreeBSD$");
#include "xmalloc.h"
@ -43,389 +43,53 @@ RCSID("$FreeBSD$");
#include "cipher.h"
#include <openssl/md5.h>
#include "rijndael.h"
static EVP_CIPHER *evp_ssh1_3des(void);
static EVP_CIPHER *evp_ssh1_bf(void);
static EVP_CIPHER *evp_rijndael(void);
/* no encryption */
void
none_setkey(CipherContext *cc, const u_char *key, u_int keylen)
{
}
void
none_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
{
}
void
none_crypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
{
memcpy(dest, src, len);
}
struct Cipher {
char *name;
int number; /* for ssh1 only */
u_int block_size;
u_int key_len;
EVP_CIPHER *(*evptype)(void);
} ciphers[] = {
{ "none", SSH_CIPHER_NONE, 8, 0, EVP_enc_null },
{ "des", SSH_CIPHER_DES, 8, 8, EVP_des_cbc },
{ "3des", SSH_CIPHER_3DES, 8, 16, evp_ssh1_3des },
{ "blowfish", SSH_CIPHER_BLOWFISH, 8, 32, evp_ssh1_bf },
/* DES */
void
des_ssh1_setkey(CipherContext *cc, const u_char *key, u_int keylen)
{
static int dowarn = 1;
if (dowarn) {
error("Warning: use of DES is strongly discouraged "
"due to cryptographic weaknesses");
dowarn = 0;
}
des_set_key((void *)key, cc->u.des.key);
}
void
des_ssh1_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
{
memset(cc->u.des.iv, 0, sizeof(cc->u.des.iv));
}
void
des_ssh1_encrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
{
des_ncbc_encrypt(src, dest, len, cc->u.des.key, &cc->u.des.iv,
DES_ENCRYPT);
}
void
des_ssh1_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
{
des_ncbc_encrypt(src, dest, len, cc->u.des.key, &cc->u.des.iv,
DES_DECRYPT);
}
{ "3des-cbc", SSH_CIPHER_SSH2, 8, 24, EVP_des_ede3_cbc },
{ "blowfish-cbc", SSH_CIPHER_SSH2, 8, 16, EVP_bf_cbc },
{ "cast128-cbc", SSH_CIPHER_SSH2, 8, 16, EVP_cast5_cbc },
{ "arcfour", SSH_CIPHER_SSH2, 8, 16, EVP_rc4 },
{ "aes128-cbc", SSH_CIPHER_SSH2, 16, 16, evp_rijndael },
{ "aes192-cbc", SSH_CIPHER_SSH2, 16, 24, evp_rijndael },
{ "aes256-cbc", SSH_CIPHER_SSH2, 16, 32, evp_rijndael },
/* 3DES */
void
des3_setkey(CipherContext *cc, const u_char *key, u_int keylen)
{
des_set_key((void *) key, cc->u.des3.key1);
des_set_key((void *) (key+8), cc->u.des3.key2);
des_set_key((void *) (key+16), cc->u.des3.key3);
}
void
des3_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
{
memset(cc->u.des3.iv2, 0, sizeof(cc->u.des3.iv2));
memset(cc->u.des3.iv3, 0, sizeof(cc->u.des3.iv3));
if (iv == NULL)
return;
memcpy(cc->u.des3.iv3, (char *)iv, 8);
}
void
des3_cbc_encrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
{
des_ede3_cbc_encrypt(src, dest, len,
cc->u.des3.key1, cc->u.des3.key2, cc->u.des3.key3,
&cc->u.des3.iv3, DES_ENCRYPT);
}
void
des3_cbc_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
{
des_ede3_cbc_encrypt(src, dest, len,
cc->u.des3.key1, cc->u.des3.key2, cc->u.des3.key3,
&cc->u.des3.iv3, DES_DECRYPT);
}
/*
* This is used by SSH1:
*
* What kind of triple DES are these 2 routines?
*
* Why is there a redundant initialization vector?
*
* If only iv3 was used, then, this would till effect have been
* outer-cbc. However, there is also a private iv1 == iv2 which
* perhaps makes differential analysis easier. On the other hand, the
* private iv1 probably makes the CRC-32 attack ineffective. This is a
* result of that there is no longer any known iv1 to use when
* choosing the X block.
*/
void
des3_ssh1_setkey(CipherContext *cc, const u_char *key, u_int keylen)
{
des_set_key((void *) key, cc->u.des3.key1);
des_set_key((void *) (key+8), cc->u.des3.key2);
if (keylen <= 16)
des_set_key((void *) key, cc->u.des3.key3);
else
des_set_key((void *) (key+16), cc->u.des3.key3);
}
void
des3_ssh1_encrypt(CipherContext *cc, u_char *dest, const u_char *src,
u_int len)
{
des_cblock iv1;
des_cblock *iv2 = &cc->u.des3.iv2;
des_cblock *iv3 = &cc->u.des3.iv3;
memcpy(&iv1, iv2, 8);
des_ncbc_encrypt(src, dest, len, cc->u.des3.key1, &iv1, DES_ENCRYPT);
des_ncbc_encrypt(dest, dest, len, cc->u.des3.key2, iv2, DES_DECRYPT);
des_ncbc_encrypt(dest, dest, len, cc->u.des3.key3, iv3, DES_ENCRYPT);
}
void
des3_ssh1_decrypt(CipherContext *cc, u_char *dest, const u_char *src,
u_int len)
{
des_cblock iv1;
des_cblock *iv2 = &cc->u.des3.iv2;
des_cblock *iv3 = &cc->u.des3.iv3;
memcpy(&iv1, iv2, 8);
des_ncbc_encrypt(src, dest, len, cc->u.des3.key3, iv3, DES_DECRYPT);
des_ncbc_encrypt(dest, dest, len, cc->u.des3.key2, iv2, DES_ENCRYPT);
des_ncbc_encrypt(dest, dest, len, cc->u.des3.key1, &iv1, DES_DECRYPT);
}
/* Blowfish */
void
blowfish_setkey(CipherContext *cc, const u_char *key, u_int keylen)
{
BF_set_key(&cc->u.bf.key, keylen, (u_char *)key);
}
void
blowfish_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
{
if (iv == NULL)
memset(cc->u.bf.iv, 0, 8);
else
memcpy(cc->u.bf.iv, (char *)iv, 8);
}
void
blowfish_cbc_encrypt(CipherContext *cc, u_char *dest, const u_char *src,
u_int len)
{
BF_cbc_encrypt((void *)src, dest, len, &cc->u.bf.key, cc->u.bf.iv,
BF_ENCRYPT);
}
void
blowfish_cbc_decrypt(CipherContext *cc, u_char *dest, const u_char *src,
u_int len)
{
BF_cbc_encrypt((void *)src, dest, len, &cc->u.bf.key, cc->u.bf.iv,
BF_DECRYPT);
}
/*
* SSH1 uses a variation on Blowfish, all bytes must be swapped before
* and after encryption/decryption. Thus the swap_bytes stuff (yuk).
*/
static void
swap_bytes(const u_char *src, u_char *dst, int n)
{
char c[4];
/* Process 4 bytes every lap. */
for (n = n / 4; n > 0; n--) {
c[3] = *src++;
c[2] = *src++;
c[1] = *src++;
c[0] = *src++;
*dst++ = c[0];
*dst++ = c[1];
*dst++ = c[2];
*dst++ = c[3];
}
}
void
blowfish_ssh1_encrypt(CipherContext *cc, u_char *dest, const u_char *src,
u_int len)
{
swap_bytes(src, dest, len);
BF_cbc_encrypt((void *)dest, dest, len, &cc->u.bf.key, cc->u.bf.iv,
BF_ENCRYPT);
swap_bytes(dest, dest, len);
}
void
blowfish_ssh1_decrypt(CipherContext *cc, u_char *dest, const u_char *src,
u_int len)
{
swap_bytes(src, dest, len);
BF_cbc_encrypt((void *)dest, dest, len, &cc->u.bf.key, cc->u.bf.iv,
BF_DECRYPT);
swap_bytes(dest, dest, len);
}
/* alleged rc4 */
void
arcfour_setkey(CipherContext *cc, const u_char *key, u_int keylen)
{
RC4_set_key(&cc->u.rc4, keylen, (u_char *)key);
}
void
arcfour_crypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
{
RC4(&cc->u.rc4, len, (u_char *)src, dest);
}
/* CAST */
void
cast_setkey(CipherContext *cc, const u_char *key, u_int keylen)
{
CAST_set_key(&cc->u.cast.key, keylen, (u_char *) key);
}
void
cast_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
{
if (iv == NULL)
fatal("no IV for %s.", cc->cipher->name);
memcpy(cc->u.cast.iv, (char *)iv, 8);
}
void
cast_cbc_encrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
{
CAST_cbc_encrypt(src, dest, len, &cc->u.cast.key, cc->u.cast.iv,
CAST_ENCRYPT);
}
void
cast_cbc_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
{
CAST_cbc_encrypt(src, dest, len, &cc->u.cast.key, cc->u.cast.iv,
CAST_DECRYPT);
}
/* RIJNDAEL */
#define RIJNDAEL_BLOCKSIZE 16
void
rijndael_setkey(CipherContext *cc, const u_char *key, u_int keylen)
{
rijndael_set_key(&cc->u.rijndael.enc, (u4byte *)key, 8*keylen, 1);
rijndael_set_key(&cc->u.rijndael.dec, (u4byte *)key, 8*keylen, 0);
}
void
rijndael_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
{
if (iv == NULL)
fatal("no IV for %s.", cc->cipher->name);
memcpy((u_char *)cc->u.rijndael.iv, iv, RIJNDAEL_BLOCKSIZE);
}
void
rijndael_cbc_encrypt(CipherContext *cc, u_char *dest, const u_char *src,
u_int len)
{
rijndael_ctx *ctx = &cc->u.rijndael.enc;
u4byte *iv = cc->u.rijndael.iv;
u4byte in[4];
u4byte *cprev, *cnow, *plain;
int i, blocks = len / RIJNDAEL_BLOCKSIZE;
if (len == 0)
return;
if (len % RIJNDAEL_BLOCKSIZE)
fatal("rijndael_cbc_encrypt: bad len %d", len);
cnow = (u4byte*) dest;
plain = (u4byte*) src;
cprev = iv;
for(i = 0; i < blocks; i++, plain+=4, cnow+=4) {
in[0] = plain[0] ^ cprev[0];
in[1] = plain[1] ^ cprev[1];
in[2] = plain[2] ^ cprev[2];
in[3] = plain[3] ^ cprev[3];
rijndael_encrypt(ctx, in, cnow);
cprev = cnow;
}
memcpy(iv, cprev, RIJNDAEL_BLOCKSIZE);
}
void
rijndael_cbc_decrypt(CipherContext *cc, u_char *dest, const u_char *src,
u_int len)
{
rijndael_ctx *ctx = &cc->u.rijndael.dec;
u4byte *iv = cc->u.rijndael.iv;
u4byte ivsaved[4];
u4byte *cnow = (u4byte*) (src+len-RIJNDAEL_BLOCKSIZE);
u4byte *plain = (u4byte*) (dest+len-RIJNDAEL_BLOCKSIZE);
u4byte *ivp;
int i, blocks = len / RIJNDAEL_BLOCKSIZE;
if (len == 0)
return;
if (len % RIJNDAEL_BLOCKSIZE)
fatal("rijndael_cbc_decrypt: bad len %d", len);
memcpy(ivsaved, cnow, RIJNDAEL_BLOCKSIZE);
for(i = blocks; i > 0; i--, cnow-=4, plain-=4) {
rijndael_decrypt(ctx, cnow, plain);
ivp = (i == 1) ? iv : cnow-4;
plain[0] ^= ivp[0];
plain[1] ^= ivp[1];
plain[2] ^= ivp[2];
plain[3] ^= ivp[3];
}
memcpy(iv, ivsaved, RIJNDAEL_BLOCKSIZE);
}
Cipher ciphers[] = {
{ "none",
SSH_CIPHER_NONE, 8, 0,
none_setkey, none_setiv,
none_crypt, none_crypt },
{ "des",
SSH_CIPHER_DES, 8, 8,
des_ssh1_setkey, des_ssh1_setiv,
des_ssh1_encrypt, des_ssh1_decrypt },
{ "3des",
SSH_CIPHER_3DES, 8, 16,
des3_ssh1_setkey, des3_setiv,
des3_ssh1_encrypt, des3_ssh1_decrypt },
{ "blowfish",
SSH_CIPHER_BLOWFISH, 8, 16,
blowfish_setkey, blowfish_setiv,
blowfish_ssh1_encrypt, blowfish_ssh1_decrypt },
{ "3des-cbc",
SSH_CIPHER_SSH2, 8, 24,
des3_setkey, des3_setiv,
des3_cbc_encrypt, des3_cbc_decrypt },
{ "blowfish-cbc",
SSH_CIPHER_SSH2, 8, 16,
blowfish_setkey, blowfish_setiv,
blowfish_cbc_encrypt, blowfish_cbc_decrypt },
{ "cast128-cbc",
SSH_CIPHER_SSH2, 8, 16,
cast_setkey, cast_setiv,
cast_cbc_encrypt, cast_cbc_decrypt },
{ "arcfour",
SSH_CIPHER_SSH2, 8, 16,
arcfour_setkey, none_setiv,
arcfour_crypt, arcfour_crypt },
{ "aes128-cbc",
SSH_CIPHER_SSH2, 16, 16,
rijndael_setkey, rijndael_setiv,
rijndael_cbc_encrypt, rijndael_cbc_decrypt },
{ "aes192-cbc",
SSH_CIPHER_SSH2, 16, 24,
rijndael_setkey, rijndael_setiv,
rijndael_cbc_encrypt, rijndael_cbc_decrypt },
{ "aes256-cbc",
SSH_CIPHER_SSH2, 16, 32,
rijndael_setkey, rijndael_setiv,
rijndael_cbc_encrypt, rijndael_cbc_decrypt },
{ "rijndael128-cbc",
SSH_CIPHER_SSH2, 16, 16,
rijndael_setkey, rijndael_setiv,
rijndael_cbc_encrypt, rijndael_cbc_decrypt },
{ "rijndael192-cbc",
SSH_CIPHER_SSH2, 16, 24,
rijndael_setkey, rijndael_setiv,
rijndael_cbc_encrypt, rijndael_cbc_decrypt },
{ "rijndael256-cbc",
SSH_CIPHER_SSH2, 16, 32,
rijndael_setkey, rijndael_setiv,
rijndael_cbc_encrypt, rijndael_cbc_decrypt },
{ "rijndael-cbc@lysator.liu.se",
SSH_CIPHER_SSH2, 16, 32,
rijndael_setkey, rijndael_setiv,
rijndael_cbc_encrypt, rijndael_cbc_decrypt },
{ NULL, SSH_CIPHER_ILLEGAL, 0, 0, NULL, NULL, NULL, NULL }
{ NULL, SSH_CIPHER_ILLEGAL, 0, 0, NULL }
};
/*--*/
u_int
cipher_blocksize(Cipher *c)
{
return (c->block_size);
}
u_int
cipher_keylen(Cipher *c)
{
return (c->key_len);
}
u_int
cipher_mask_ssh1(int client)
{
u_int mask = 0;
mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */
mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */
mask |= 1 << SSH_CIPHER_BLOWFISH;
if (client) {
mask |= 1 << SSH_CIPHER_DES;
@ -465,7 +129,7 @@ ciphers_valid(const char *names)
return 0;
ciphers = cp = xstrdup(names);
for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0';
(p = strsep(&cp, CIPHER_SEP))) {
(p = strsep(&cp, CIPHER_SEP))) {
c = cipher_by_name(p);
if (c == NULL || c->number != SSH_CIPHER_SSH2) {
debug("bad cipher %s [%s]", p, names);
@ -504,8 +168,24 @@ cipher_name(int id)
void
cipher_init(CipherContext *cc, Cipher *cipher,
const u_char *key, u_int keylen, const u_char *iv, u_int ivlen)
const u_char *key, u_int keylen, const u_char *iv, u_int ivlen,
int encrypt)
{
static int dowarn = 1;
const EVP_CIPHER *type;
int klen;
if (cipher->number == SSH_CIPHER_DES) {
if (dowarn) {
error("Warning: use of DES is strongly discouraged "
"due to cryptographic weaknesses");
dowarn = 0;
}
if (keylen > 8)
keylen = 8;
}
cc->plaintext = (cipher->number == SSH_CIPHER_NONE);
if (keylen < cipher->key_len)
fatal("cipher_init: key length %d is insufficient for %s.",
keylen, cipher->name);
@ -513,24 +193,40 @@ cipher_init(CipherContext *cc, Cipher *cipher,
fatal("cipher_init: iv length %d is insufficient for %s.",
ivlen, cipher->name);
cc->cipher = cipher;
cipher->setkey(cc, key, keylen);
cipher->setiv(cc, iv, ivlen);
type = (*cipher->evptype)();
EVP_CIPHER_CTX_init(&cc->evp);
if (EVP_CipherInit(&cc->evp, type, NULL, (u_char *)iv,
(encrypt == CIPHER_ENCRYPT)) == 0)
fatal("cipher_init: EVP_CipherInit failed for %s",
cipher->name);
klen = EVP_CIPHER_CTX_key_length(&cc->evp);
if (klen > 0 && keylen != klen) {
debug("cipher_init: set keylen (%d -> %d)", klen, keylen);
if (EVP_CIPHER_CTX_set_key_length(&cc->evp, keylen) == 0)
fatal("cipher_init: set keylen failed (%d -> %d)",
klen, keylen);
}
if (EVP_CipherInit(&cc->evp, NULL, (u_char *)key, NULL, -1) == 0)
fatal("cipher_init: EVP_CipherInit: set key failed for %s",
cipher->name);
}
void
cipher_encrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
cipher_crypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
{
if (len % cc->cipher->block_size)
fatal("cipher_encrypt: bad plaintext length %d", len);
cc->cipher->encrypt(cc, dest, src, len);
if (EVP_Cipher(&cc->evp, dest, (u_char *)src, len) == 0)
fatal("evp_crypt: EVP_Cipher failed");
}
void
cipher_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
cipher_cleanup(CipherContext *cc)
{
if (len % cc->cipher->block_size)
fatal("cipher_decrypt: bad ciphertext length %d", len);
cc->cipher->decrypt(cc, dest, src, len);
if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0)
error("cipher_cleanup: EVP_CIPHER_CTX_cleanup failed");
}
/*
@ -540,7 +236,7 @@ cipher_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
void
cipher_set_key_string(CipherContext *cc, Cipher *cipher,
const char *passphrase)
const char *passphrase, int encrypt)
{
MD5_CTX md;
u_char digest[16];
@ -549,8 +245,257 @@ cipher_set_key_string(CipherContext *cc, Cipher *cipher,
MD5_Update(&md, (const u_char *)passphrase, strlen(passphrase));
MD5_Final(digest, &md);
cipher_init(cc, cipher, digest, 16, NULL, 0);
cipher_init(cc, cipher, digest, 16, NULL, 0, encrypt);
memset(digest, 0, sizeof(digest));
memset(&md, 0, sizeof(md));
}
/* Implementations for other non-EVP ciphers */
/*
* This is used by SSH1:
*
* What kind of triple DES are these 2 routines?
*
* Why is there a redundant initialization vector?
*
* If only iv3 was used, then, this would till effect have been
* outer-cbc. However, there is also a private iv1 == iv2 which
* perhaps makes differential analysis easier. On the other hand, the
* private iv1 probably makes the CRC-32 attack ineffective. This is a
* result of that there is no longer any known iv1 to use when
* choosing the X block.
*/
struct ssh1_3des_ctx
{
EVP_CIPHER_CTX k1, k2, k3;
};
static int
ssh1_3des_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv,
int enc)
{
struct ssh1_3des_ctx *c;
u_char *k1, *k2, *k3;
if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
c = xmalloc(sizeof(*c));
EVP_CIPHER_CTX_set_app_data(ctx, c);
}
if (key == NULL)
return (1);
if (enc == -1)
enc = ctx->encrypt;
k1 = k2 = k3 = (u_char *) key;
k2 += 8;
if (EVP_CIPHER_CTX_key_length(ctx) >= 16+8) {
if (enc)
k3 += 16;
else
k1 += 16;
}
EVP_CIPHER_CTX_init(&c->k1);
EVP_CIPHER_CTX_init(&c->k2);
EVP_CIPHER_CTX_init(&c->k3);
if (EVP_CipherInit(&c->k1, EVP_des_cbc(), k1, NULL, enc) == 0 ||
EVP_CipherInit(&c->k2, EVP_des_cbc(), k2, NULL, !enc) == 0 ||
EVP_CipherInit(&c->k3, EVP_des_cbc(), k3, NULL, enc) == 0) {
memset(c, 0, sizeof(*c));
xfree(c);
EVP_CIPHER_CTX_set_app_data(ctx, NULL);
return (0);
}
return (1);
}
static int
ssh1_3des_cbc(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src, u_int len)
{
struct ssh1_3des_ctx *c;
if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
error("ssh1_3des_cbc: no context");
return (0);
}
if (EVP_Cipher(&c->k1, dest, (u_char *)src, len) == 0 ||
EVP_Cipher(&c->k2, dest, dest, len) == 0 ||
EVP_Cipher(&c->k3, dest, dest, len) == 0)
return (0);
return (1);
}
static int
ssh1_3des_cleanup(EVP_CIPHER_CTX *ctx)
{
struct ssh1_3des_ctx *c;
if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) {
memset(c, 0, sizeof(*c));
xfree(c);
EVP_CIPHER_CTX_set_app_data(ctx, NULL);
}
return (1);
}
static EVP_CIPHER *
evp_ssh1_3des(void)
{
static EVP_CIPHER ssh1_3des;
memset(&ssh1_3des, 0, sizeof(EVP_CIPHER));
ssh1_3des.nid = NID_undef;
ssh1_3des.block_size = 8;
ssh1_3des.iv_len = 0;
ssh1_3des.key_len = 16;
ssh1_3des.init = ssh1_3des_init;
ssh1_3des.cleanup = ssh1_3des_cleanup;
ssh1_3des.do_cipher = ssh1_3des_cbc;
ssh1_3des.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH;
return (&ssh1_3des);
}
/*
* SSH1 uses a variation on Blowfish, all bytes must be swapped before
* and after encryption/decryption. Thus the swap_bytes stuff (yuk).
*/
static void
swap_bytes(const u_char *src, u_char *dst, int n)
{
u_char c[4];
/* Process 4 bytes every lap. */
for (n = n / 4; n > 0; n--) {
c[3] = *src++;
c[2] = *src++;
c[1] = *src++;
c[0] = *src++;
*dst++ = c[0];
*dst++ = c[1];
*dst++ = c[2];
*dst++ = c[3];
}
}
static int (*orig_bf)(EVP_CIPHER_CTX *, u_char *, const u_char *, u_int) = NULL;
static int
bf_ssh1_cipher(EVP_CIPHER_CTX *ctx, u_char *out, const u_char *in, u_int len)
{
int ret;
swap_bytes(in, out, len);
ret = (*orig_bf)(ctx, out, out, len);
swap_bytes(out, out, len);
return (ret);
}
static EVP_CIPHER *
evp_ssh1_bf(void)
{
static EVP_CIPHER ssh1_bf;
memcpy(&ssh1_bf, EVP_bf_cbc(), sizeof(EVP_CIPHER));
orig_bf = ssh1_bf.do_cipher;
ssh1_bf.nid = NID_undef;
ssh1_bf.do_cipher = bf_ssh1_cipher;
ssh1_bf.key_len = 32;
return (&ssh1_bf);
}
/* RIJNDAEL */
#define RIJNDAEL_BLOCKSIZE 16
struct ssh_rijndael_ctx
{
rijndael_ctx r_ctx;
u_char r_iv[RIJNDAEL_BLOCKSIZE];
};
static int
ssh_rijndael_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv,
int enc)
{
struct ssh_rijndael_ctx *c;
if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
c = xmalloc(sizeof(*c));
EVP_CIPHER_CTX_set_app_data(ctx, c);
}
if (key != NULL) {
if (enc == -1)
enc = ctx->encrypt;
rijndael_set_key(&c->r_ctx, (u_char *)key,
8*EVP_CIPHER_CTX_key_length(ctx), enc);
}
if (iv != NULL)
memcpy(c->r_iv, iv, RIJNDAEL_BLOCKSIZE);
return (1);
}
static int
ssh_rijndael_cbc(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src,
u_int len)
{
struct ssh_rijndael_ctx *c;
u_char buf[RIJNDAEL_BLOCKSIZE];
u_char *cprev, *cnow, *plain, *ivp;
int i, j, blocks = len / RIJNDAEL_BLOCKSIZE;
if (len == 0)
return (1);
if (len % RIJNDAEL_BLOCKSIZE)
fatal("ssh_rijndael_cbc: bad len %d", len);
if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
error("ssh_rijndael_cbc: no context");
return (0);
}
if (ctx->encrypt) {
cnow = dest;
plain = (u_char *)src;
cprev = c->r_iv;
for (i = 0; i < blocks; i++, plain+=RIJNDAEL_BLOCKSIZE,
cnow+=RIJNDAEL_BLOCKSIZE) {
for (j = 0; j < RIJNDAEL_BLOCKSIZE; j++)
buf[j] = plain[j] ^ cprev[j];
rijndael_encrypt(&c->r_ctx, buf, cnow);
cprev = cnow;
}
memcpy(c->r_iv, cprev, RIJNDAEL_BLOCKSIZE);
} else {
cnow = (u_char *) (src+len-RIJNDAEL_BLOCKSIZE);
plain = dest+len-RIJNDAEL_BLOCKSIZE;
memcpy(buf, cnow, RIJNDAEL_BLOCKSIZE);
for (i = blocks; i > 0; i--, cnow-=RIJNDAEL_BLOCKSIZE,
plain-=RIJNDAEL_BLOCKSIZE) {
rijndael_decrypt(&c->r_ctx, cnow, plain);
ivp = (i == 1) ? c->r_iv : cnow-RIJNDAEL_BLOCKSIZE;
for (j = 0; j < RIJNDAEL_BLOCKSIZE; j++)
plain[j] ^= ivp[j];
}
memcpy(c->r_iv, buf, RIJNDAEL_BLOCKSIZE);
}
return (1);
}
static int
ssh_rijndael_cleanup(EVP_CIPHER_CTX *ctx)
{
struct ssh_rijndael_ctx *c;
if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) {
memset(c, 0, sizeof(*c));
xfree(c);
EVP_CIPHER_CTX_set_app_data(ctx, NULL);
}
return (1);
}
static EVP_CIPHER *
evp_rijndael(void)
{
static EVP_CIPHER rijndal_cbc;
memset(&rijndal_cbc, 0, sizeof(EVP_CIPHER));
rijndal_cbc.nid = NID_undef;
rijndal_cbc.block_size = RIJNDAEL_BLOCKSIZE;
rijndal_cbc.iv_len = RIJNDAEL_BLOCKSIZE;
rijndal_cbc.key_len = 16;
rijndal_cbc.init = ssh_rijndael_init;
rijndal_cbc.cleanup = ssh_rijndael_cleanup;
rijndal_cbc.do_cipher = ssh_rijndael_cbc;
rijndal_cbc.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH |
EVP_CIPH_ALWAYS_CALL_INIT;
return (&rijndal_cbc);
}

View file

@ -1,3 +1,6 @@
/* $OpenBSD: cipher.h,v 1.32 2002/03/04 17:27:39 stevesk Exp $ */
/* $FreeBSD$ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -32,17 +35,10 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* RCSID("$OpenBSD: cipher.h,v 1.25 2000/12/19 23:17:56 markus Exp $"); */
/* RCSID("$FreeBSD$"); */
#ifndef CIPHER_H
#define CIPHER_H
#include <openssl/des.h>
#include <openssl/blowfish.h>
#include <openssl/rc4.h>
#include <openssl/cast.h>
#include "rijndael.h"
#include <openssl/evp.h>
/*
* Cipher types for SSH-1. New types can be added, but old types should not
* be removed for compatibility. The maximum allowed value is 31.
@ -60,59 +56,30 @@
#define SSH_CIPHER_RESERVED 7
#define SSH_CIPHER_MAX 31
#define CIPHER_ENCRYPT 1
#define CIPHER_DECRYPT 0
typedef struct Cipher Cipher;
typedef struct CipherContext CipherContext;
struct Cipher;
struct CipherContext {
union {
struct {
des_key_schedule key;
des_cblock iv;
} des;
struct {
des_key_schedule key1;
des_key_schedule key2;
des_cblock iv2;
des_key_schedule key3;
des_cblock iv3;
} des3;
struct {
struct bf_key_st key;
u_char iv[8];
} bf;
struct {
CAST_KEY key;
u_char iv[8];
} cast;
struct {
u4byte iv[4];
rijndael_ctx enc;
rijndael_ctx dec;
} rijndael;
RC4_KEY rc4;
} u;
int plaintext;
EVP_CIPHER_CTX evp;
Cipher *cipher;
};
struct Cipher {
char *name;
int number; /* for ssh1 only */
u_int block_size;
u_int key_len;
void (*setkey)(CipherContext *, const u_char *, u_int);
void (*setiv)(CipherContext *, const u_char *, u_int);
void (*encrypt)(CipherContext *, u_char *, const u_char *, u_int);
void (*decrypt)(CipherContext *, u_char *, const u_char *, u_int);
};
u_int cipher_mask_ssh1(int client);
Cipher *cipher_by_name(const char *name);
Cipher *cipher_by_number(int id);
int cipher_number(const char *name);
char *cipher_name(int id);
int ciphers_valid(const char *names);
void cipher_init(CipherContext *, Cipher *, const u_char *, u_int, const u_char *, u_int);
void cipher_encrypt(CipherContext *context, u_char *dest, const u_char *src, u_int len);
void cipher_decrypt(CipherContext *context, u_char *dest, const u_char *src, u_int len);
void cipher_set_key_string(CipherContext *context, Cipher *cipher, const char *passphrase);
u_int cipher_mask_ssh1(int);
Cipher *cipher_by_name(const char *);
Cipher *cipher_by_number(int);
int cipher_number(const char *);
char *cipher_name(int);
int ciphers_valid(const char *);
void cipher_init(CipherContext *, Cipher *, const u_char *, u_int,
const u_char *, u_int, int);
void cipher_crypt(CipherContext *, u_char *, const u_char *, u_int);
void cipher_cleanup(CipherContext *);
void cipher_set_key_string(CipherContext *, Cipher *, const char *, int);
u_int cipher_blocksize(Cipher *);
u_int cipher_keylen(Cipher *);
#endif /* CIPHER_H */

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
* Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -23,15 +23,15 @@
*/
#include "includes.h"
RCSID("$OpenBSD: compat.c,v 1.61 2002/03/06 00:24:39 markus Exp $");
RCSID("$FreeBSD$");
RCSID("$OpenBSD: compat.c,v 1.47 2001/04/18 23:43:25 markus Exp $");
#include <regex.h>
#include "buffer.h"
#include "packet.h"
#include "xmalloc.h"
#include "compat.h"
#include "log.h"
#include "match.h"
int compat13 = 0;
int compat20 = 0;
@ -53,76 +53,97 @@ enable_compat13(void)
void
compat_datafellows(const char *version)
{
int i, ret;
char ebuf[1024];
regex_t reg;
int i;
static struct {
char *pat;
int bugs;
} check[] = {
{ "^OpenSSH[-_]2\\.[012]",
SSH_OLD_SESSIONID|SSH_BUG_BANNER|
{ "OpenSSH-2.0*,"
"OpenSSH-2.1*,"
"OpenSSH_2.1*,"
"OpenSSH_2.2*", SSH_OLD_SESSIONID|SSH_BUG_BANNER|
SSH_OLD_DHGEX|SSH_BUG_NOREKEY },
{ "^OpenSSH_2\\.3\\.0", SSH_BUG_BANNER|SSH_BUG_BIGENDIANAES|
{ "OpenSSH_2.3.0*", SSH_BUG_BANNER|SSH_BUG_BIGENDIANAES|
SSH_OLD_DHGEX|SSH_BUG_NOREKEY},
{ "^OpenSSH_2\\.3\\.", SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX|
{ "OpenSSH_2.3.*", SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX|
SSH_BUG_NOREKEY},
{ "^OpenSSH_2\\.5\\.[01]p1",
{ "OpenSSH_2.5.0p1*,"
"OpenSSH_2.5.1p1*",
SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX|
SSH_BUG_NOREKEY },
{ "^OpenSSH_2\\.5\\.[012]",
SSH_OLD_DHGEX|SSH_BUG_NOREKEY },
{ "^OpenSSH_2\\.5\\.3",
SSH_BUG_NOREKEY },
{ "^OpenSSH", 0 },
{ "MindTerm", 0 },
{ "^2\\.1\\.0", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
{ "OpenSSH_2.5.0*,"
"OpenSSH_2.5.1*,"
"OpenSSH_2.5.2*", SSH_OLD_DHGEX|SSH_BUG_NOREKEY },
{ "OpenSSH_2.5.3*", SSH_BUG_NOREKEY },
{ "Sun_SSH_1.0*", SSH_BUG_NOREKEY },
{ "OpenSSH*", 0 },
{ "*MindTerm*", 0 },
{ "2.1.0*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
SSH_BUG_RSASIGMD5|SSH_BUG_HBSERVICE },
{ "^2\\.1 ", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
{ "2.1 *", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
SSH_BUG_RSASIGMD5|SSH_BUG_HBSERVICE },
{ "^2\\.0\\.1[3-9]", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
{ "2.0.13*,"
"2.0.14*,"
"2.0.15*,"
"2.0.16*,"
"2.0.17*,"
"2.0.18*,"
"2.0.19*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
SSH_BUG_PKSERVICE|SSH_BUG_X11FWD|
SSH_BUG_PKOK|SSH_BUG_RSASIGMD5|
SSH_BUG_HBSERVICE },
{ "^2\\.0\\.", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
SSH_BUG_HBSERVICE|SSH_BUG_OPENFAILURE|
SSH_BUG_DUMMYCHAN },
{ "2.0.11*,"
"2.0.12*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
SSH_BUG_PKSERVICE|SSH_BUG_X11FWD|
SSH_BUG_PKAUTH|SSH_BUG_PKOK|
SSH_BUG_RSASIGMD5|SSH_BUG_OPENFAILURE|
SSH_BUG_DUMMYCHAN },
{ "2.0.*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
SSH_BUG_PKSERVICE|SSH_BUG_X11FWD|
SSH_BUG_PKAUTH|SSH_BUG_PKOK|
SSH_BUG_RSASIGMD5|SSH_BUG_OPENFAILURE|
SSH_BUG_DERIVEKEY|SSH_BUG_DUMMYCHAN },
{ "2.2.0*,"
"2.3.0*", SSH_BUG_HMAC|SSH_BUG_DEBUG|
SSH_BUG_RSASIGMD5 },
{ "^2\\.[23]\\.0", SSH_BUG_HMAC|SSH_BUG_RSASIGMD5 },
{ "^2\\.3\\.", SSH_BUG_RSASIGMD5 },
{ "^2\\.[2-9]\\.", 0 },
{ "^2\\.4$", SSH_OLD_SESSIONID }, /* Van Dyke */
{ "^3\\.0 SecureCRT", SSH_OLD_SESSIONID },
{ "^1\\.7 SecureFX", SSH_OLD_SESSIONID },
{ "^1\\.2\\.1[89]", SSH_BUG_IGNOREMSG },
{ "^1\\.2\\.2[012]", SSH_BUG_IGNOREMSG },
{ "^1\\.3\\.2", SSH_BUG_IGNOREMSG }, /* f-secure */
{ "^SSH Compatible Server", /* Netscreen */
{ "2.3.*", SSH_BUG_DEBUG|SSH_BUG_RSASIGMD5 },
{ "2.4", SSH_OLD_SESSIONID }, /* Van Dyke */
{ "2.*", SSH_BUG_DEBUG },
{ "3.0.*", SSH_BUG_DEBUG },
{ "3.0 SecureCRT*", SSH_OLD_SESSIONID },
{ "1.7 SecureFX*", SSH_OLD_SESSIONID },
{ "1.2.18*,"
"1.2.19*,"
"1.2.20*,"
"1.2.21*,"
"1.2.22*", SSH_BUG_IGNOREMSG },
{ "1.3.2*", SSH_BUG_IGNOREMSG }, /* f-secure */
{ "*SSH Compatible Server*", /* Netscreen */
SSH_BUG_PASSWORDPAD },
{ "^OSU_0", SSH_BUG_PASSWORDPAD },
{ "^OSU_1\\.[0-4]", SSH_BUG_PASSWORDPAD },
{ "^OSU_1\\.5alpha[1-3]",
SSH_BUG_PASSWORDPAD },
{ "^SSH_Version_Mapper",
{ "*OSU_0*,"
"OSU_1.0*,"
"OSU_1.1*,"
"OSU_1.2*,"
"OSU_1.3*,"
"OSU_1.4*,"
"OSU_1.5alpha1*,"
"OSU_1.5alpha2*,"
"OSU_1.5alpha3*", SSH_BUG_PASSWORDPAD },
{ "*SSH_Version_Mapper*",
SSH_BUG_SCANNER },
{ NULL, 0 }
};
/* process table, return first match */
for (i = 0; check[i].pat; i++) {
ret = regcomp(&reg, check[i].pat, REG_EXTENDED|REG_NOSUB);
if (ret != 0) {
regerror(ret, &reg, ebuf, sizeof(ebuf));
ebuf[sizeof(ebuf)-1] = '\0';
error("regerror: %s", ebuf);
continue;
}
ret = regexec(&reg, version, 0, NULL, 0);
regfree(&reg);
if (ret == 0) {
if (match_pattern_list(version, check[i].pat,
strlen(check[i].pat), 0) == 1) {
debug("match: %s pat %s", version, check[i].pat);
datafellows = check[i].bugs;
return;
@ -142,7 +163,7 @@ proto_spec(const char *spec)
return ret;
q = s = xstrdup(spec);
for ((p = strsep(&q, SEP)); p && *p != '\0'; (p = strsep(&q, SEP))) {
switch(atoi(p)) {
switch (atoi(p)) {
case 1:
if (ret == SSH_PROTO_UNKNOWN)
ret |= SSH_PROTO_1_PREFERRED;
@ -163,24 +184,25 @@ proto_spec(const char *spec)
char *
compat_cipher_proposal(char *cipher_prop)
{
Buffer b;
char *orig_prop, *fix_ciphers;
char *cp, *tmp;
size_t len;
if (!(datafellows & SSH_BUG_BIGENDIANAES))
return(cipher_prop);
len = strlen(cipher_prop) + 1;
fix_ciphers = xmalloc(len);
*fix_ciphers = '\0';
buffer_init(&b);
tmp = orig_prop = xstrdup(cipher_prop);
while((cp = strsep(&tmp, ",")) != NULL) {
if (strncmp(cp, "aes", 3) && strncmp(cp, "rijndael", 8)) {
if (*fix_ciphers)
strlcat(fix_ciphers, ",", len);
strlcat(fix_ciphers, cp, len);
while ((cp = strsep(&tmp, ",")) != NULL) {
if (strncmp(cp, "aes", 3) != 0) {
if (buffer_len(&b) > 0)
buffer_append(&b, ",", 1);
buffer_append(&b, cp, strlen(cp));
}
}
buffer_append(&b, "\0", 1);
fix_ciphers = xstrdup(buffer_ptr(&b));
buffer_free(&b);
xfree(orig_prop);
debug2("Original cipher proposal: %s", cipher_prop);
debug2("Compat cipher proposal: %s", fix_ciphers);

View file

@ -1,5 +1,8 @@
/* $OpenBSD: compat.h,v 1.30 2002/03/04 17:27:39 stevesk Exp $ */
/* $FreeBSD$ */
/*
* Copyright (c) 1999 Markus Friedl. All rights reserved.
* Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -21,8 +24,6 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* RCSID("$FreeBSD$"); */
/* RCSID("$OpenBSD: compat.h,v 1.23 2001/04/12 19:15:24 markus Exp $"); */
#ifndef COMPAT_H
#define COMPAT_H
@ -32,29 +33,33 @@
#define SSH_PROTO_1_PREFERRED 0x02
#define SSH_PROTO_2 0x04
#define SSH_BUG_SIGBLOB 0x0001
#define SSH_BUG_PKSERVICE 0x0002
#define SSH_BUG_HMAC 0x0004
#define SSH_BUG_X11FWD 0x0008
#define SSH_OLD_SESSIONID 0x0010
#define SSH_BUG_PKAUTH 0x0020
#define SSH_BUG_DEBUG 0x0040
#define SSH_BUG_BANNER 0x0080
#define SSH_BUG_IGNOREMSG 0x0100
#define SSH_BUG_PKOK 0x0200
#define SSH_BUG_PASSWORDPAD 0x0400
#define SSH_BUG_SCANNER 0x0800
#define SSH_BUG_BIGENDIANAES 0x1000
#define SSH_BUG_RSASIGMD5 0x2000
#define SSH_OLD_DHGEX 0x4000
#define SSH_BUG_NOREKEY 0x8000
#define SSH_BUG_HBSERVICE 0x10000
#define SSH_BUG_SIGBLOB 0x00000001
#define SSH_BUG_PKSERVICE 0x00000002
#define SSH_BUG_HMAC 0x00000004
#define SSH_BUG_X11FWD 0x00000008
#define SSH_OLD_SESSIONID 0x00000010
#define SSH_BUG_PKAUTH 0x00000020
#define SSH_BUG_DEBUG 0x00000040
#define SSH_BUG_BANNER 0x00000080
#define SSH_BUG_IGNOREMSG 0x00000100
#define SSH_BUG_PKOK 0x00000200
#define SSH_BUG_PASSWORDPAD 0x00000400
#define SSH_BUG_SCANNER 0x00000800
#define SSH_BUG_BIGENDIANAES 0x00001000
#define SSH_BUG_RSASIGMD5 0x00002000
#define SSH_OLD_DHGEX 0x00004000
#define SSH_BUG_NOREKEY 0x00008000
#define SSH_BUG_HBSERVICE 0x00010000
#define SSH_BUG_OPENFAILURE 0x00020000
#define SSH_BUG_DERIVEKEY 0x00040000
#define SSH_BUG_DUMMYCHAN 0x00100000
void enable_compat13(void);
void enable_compat20(void);
void compat_datafellows(const char *);
int proto_spec(const char *);
char *compat_cipher_proposal(char *);
void enable_compat13(void);
void enable_compat20(void);
void compat_datafellows(const char *s);
int proto_spec(const char *spec);
char *compat_cipher_proposal(char *cipher_prop);
extern int compat13;
extern int compat20;
extern int datafellows;

View file

@ -11,7 +11,7 @@
* called by a name other than "ssh" or "Secure Shell".
*
*
* Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
* Copyright (c) 1999, 2000 Markus Friedl. All rights reserved.
* Copyright (c) 1999 Niels Provos. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -36,7 +36,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: hostfile.c,v 1.26 2001/04/12 19:15:24 markus Exp $");
RCSID("$OpenBSD: hostfile.c,v 1.29 2001/12/18 10:04:21 jakob Exp $");
RCSID("$FreeBSD$");
#include "packet.h"
@ -72,18 +72,7 @@ hostfile_read_key(char **cpp, u_int *bitsp, Key *ret)
return 1;
}
int
auth_rsa_read_key(char **cpp, u_int *bitsp, BIGNUM * e, BIGNUM * n)
{
Key *k = key_new(KEY_RSA1);
int ret = hostfile_read_key(cpp, bitsp, k);
BN_copy(e, k->rsa->e);
BN_copy(n, k->rsa->n);
key_free(k);
return ret;
}
int
static int
hostfile_check_key(int bits, Key *key, const char *host, const char *filename, int linenum)
{
if (key == NULL || key->type != KEY_RSA1 || key->rsa == NULL)

View file

@ -1,4 +1,5 @@
/* $OpenBSD: includes.h,v 1.14 2001/01/29 01:58:16 niklas Exp $ */
/* $OpenBSD: includes.h,v 1.17 2002/01/26 16:44:22 stevesk Exp $ */
/* $FreeBSD$ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -11,8 +12,6 @@
* 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
* called by a name other than "ssh" or "Secure Shell".
*
* $FreeBSD$
*/
#ifndef INCLUDES_H
@ -57,11 +56,6 @@
#include "version.h"
/* Define this to be the path of the xauth program. */
#ifndef XAUTH_PATH
#define XAUTH_PATH "/usr/X11R6/bin/xauth"
#endif
/*
* Define this to use pipes instead of socketpairs for communicating with the
* client program. Socketpairs do not seem to work on all systems.

View file

@ -9,7 +9,7 @@
* called by a name other than "ssh" or "Secure Shell".
*
*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -32,7 +32,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
RCSID("$OpenBSD: key.c,v 1.25 2001/04/17 10:53:24 markus Exp $");
RCSID("$OpenBSD: key.c,v 1.41 2002/02/28 15:46:33 markus Exp $");
RCSID("$FreeBSD$");
#include <openssl/evp.h>
@ -55,22 +55,31 @@ key_new(int type)
DSA *dsa;
k = xmalloc(sizeof(*k));
k->type = type;
k->flags = 0;
k->dsa = NULL;
k->rsa = NULL;
switch (k->type) {
case KEY_RSA1:
case KEY_RSA:
rsa = RSA_new();
rsa->n = BN_new();
rsa->e = BN_new();
if ((rsa = RSA_new()) == NULL)
fatal("key_new: RSA_new failed");
if ((rsa->n = BN_new()) == NULL)
fatal("key_new: BN_new failed");
if ((rsa->e = BN_new()) == NULL)
fatal("key_new: BN_new failed");
k->rsa = rsa;
break;
case KEY_DSA:
dsa = DSA_new();
dsa->p = BN_new();
dsa->q = BN_new();
dsa->g = BN_new();
dsa->pub_key = BN_new();
if ((dsa = DSA_new()) == NULL)
fatal("key_new: DSA_new failed");
if ((dsa->p = BN_new()) == NULL)
fatal("key_new: BN_new failed");
if ((dsa->q = BN_new()) == NULL)
fatal("key_new: BN_new failed");
if ((dsa->g = BN_new()) == NULL)
fatal("key_new: BN_new failed");
if ((dsa->pub_key = BN_new()) == NULL)
fatal("key_new: BN_new failed");
k->dsa = dsa;
break;
case KEY_UNSPEC:
@ -88,15 +97,22 @@ key_new_private(int type)
switch (k->type) {
case KEY_RSA1:
case KEY_RSA:
k->rsa->d = BN_new();
k->rsa->iqmp = BN_new();
k->rsa->q = BN_new();
k->rsa->p = BN_new();
k->rsa->dmq1 = BN_new();
k->rsa->dmp1 = BN_new();
if ((k->rsa->d = BN_new()) == NULL)
fatal("key_new_private: BN_new failed");
if ((k->rsa->iqmp = BN_new()) == NULL)
fatal("key_new_private: BN_new failed");
if ((k->rsa->q = BN_new()) == NULL)
fatal("key_new_private: BN_new failed");
if ((k->rsa->p = BN_new()) == NULL)
fatal("key_new_private: BN_new failed");
if ((k->rsa->dmq1 = BN_new()) == NULL)
fatal("key_new_private: BN_new failed");
if ((k->rsa->dmp1 = BN_new()) == NULL)
fatal("key_new_private: BN_new failed");
break;
case KEY_DSA:
k->dsa->priv_key = BN_new();
if ((k->dsa->priv_key = BN_new()) == NULL)
fatal("key_new_private: BN_new failed");
break;
case KEY_UNSPEC:
break;
@ -154,14 +170,14 @@ key_equal(Key *a, Key *b)
return 0;
}
u_char*
key_fingerprint_raw(Key *k, enum fp_type dgst_type, size_t *dgst_raw_length)
static u_char*
key_fingerprint_raw(Key *k, enum fp_type dgst_type, u_int *dgst_raw_length)
{
EVP_MD *md = NULL;
const EVP_MD *md = NULL;
EVP_MD_CTX ctx;
u_char *blob = NULL;
u_char *retval = NULL;
int len = 0;
u_int len = 0;
int nlen, elen;
*dgst_raw_length = 0;
@ -201,8 +217,7 @@ key_fingerprint_raw(Key *k, enum fp_type dgst_type, size_t *dgst_raw_length)
retval = xmalloc(EVP_MAX_MD_SIZE);
EVP_DigestInit(&ctx, md);
EVP_DigestUpdate(&ctx, blob, len);
EVP_DigestFinal(&ctx, retval, NULL);
*dgst_raw_length = md->md_size;
EVP_DigestFinal(&ctx, retval, dgst_raw_length);
memset(blob, 0, len);
xfree(blob);
} else {
@ -211,15 +226,15 @@ key_fingerprint_raw(Key *k, enum fp_type dgst_type, size_t *dgst_raw_length)
return retval;
}
char*
key_fingerprint_hex(u_char* dgst_raw, size_t dgst_raw_len)
static char*
key_fingerprint_hex(u_char* dgst_raw, u_int dgst_raw_len)
{
char *retval;
int i;
retval = xmalloc(dgst_raw_len * 3 + 1);
retval[0] = '\0';
for(i = 0; i < dgst_raw_len; i++) {
for (i = 0; i < dgst_raw_len; i++) {
char hex[4];
snprintf(hex, sizeof(hex), "%02x:", dgst_raw[i]);
strlcat(retval, hex, dgst_raw_len * 3);
@ -228,8 +243,8 @@ key_fingerprint_hex(u_char* dgst_raw, size_t dgst_raw_len)
return retval;
}
char*
key_fingerprint_bubblebabble(u_char* dgst_raw, size_t dgst_raw_len)
static char*
key_fingerprint_bubblebabble(u_char* dgst_raw, u_int dgst_raw_len)
{
char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' };
char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm',
@ -280,12 +295,12 @@ key_fingerprint(Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep)
{
char *retval = NULL;
u_char *dgst_raw;
size_t dgst_raw_len;
u_int dgst_raw_len;
dgst_raw = key_fingerprint_raw(k, dgst_type, &dgst_raw_len);
if (!dgst_raw)
fatal("key_fingerprint: null from key_fingerprint_raw()");
switch(dgst_rep) {
switch (dgst_rep) {
case SSH_FP_HEX:
retval = key_fingerprint_hex(dgst_raw, dgst_raw_len);
break;
@ -309,7 +324,7 @@ key_fingerprint(Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep)
* last processed (and maybe modified) character. Note that this may modify
* the buffer containing the number.
*/
int
static int
read_bignum(char **cpp, BIGNUM * value)
{
char *cp = *cpp;
@ -345,7 +360,7 @@ read_bignum(char **cpp, BIGNUM * value)
*cpp = cp;
return 1;
}
int
static int
write_bignum(FILE *f, BIGNUM *num)
{
char *buf = BN_bn2dec(num);
@ -354,11 +369,11 @@ write_bignum(FILE *f, BIGNUM *num)
return 0;
}
fprintf(f, " %s", buf);
xfree(buf);
OPENSSL_free(buf);
return 1;
}
/* returns 1 ok, -1 error, 0 type mismatch */
/* returns 1 ok, -1 error */
int
key_read(Key *ret, char **cpp)
{
@ -371,7 +386,7 @@ key_read(Key *ret, char **cpp)
cp = *cpp;
switch(ret->type) {
switch (ret->type) {
case KEY_RSA1:
/* Get number of bits. */
if (*cp < '0' || *cp > '9')
@ -413,21 +428,22 @@ key_read(Key *ret, char **cpp)
} else if (ret->type != type) {
/* is a key, but different type */
debug3("key_read: type mismatch");
return 0;
return -1;
}
len = 2*strlen(cp);
blob = xmalloc(len);
n = uudecode(cp, blob, len);
if (n < 0) {
error("key_read: uudecode %s failed", cp);
xfree(blob);
return -1;
}
k = key_from_blob(blob, n);
xfree(blob);
if (k == NULL) {
error("key_read: key_from_blob %s failed", cp);
return -1;
}
xfree(blob);
if (k->type != type) {
error("key_read: type mismatch: encoding error");
key_free(k);
@ -454,9 +470,9 @@ key_read(Key *ret, char **cpp)
#endif
}
/*XXXX*/
key_free(k);
if (success != 1)
break;
key_free(k);
/* advance cp: skip whitespace and data */
while (*cp == ' ' || *cp == '\t')
cp++;
@ -473,8 +489,9 @@ key_read(Key *ret, char **cpp)
int
key_write(Key *key, FILE *f)
{
int success = 0;
u_int bits = 0;
int n, success = 0;
u_int len, bits = 0;
u_char *blob, *uu;
if (key->type == KEY_RSA1 && key->rsa != NULL) {
/* size of modulus 'n' */
@ -488,8 +505,6 @@ key_write(Key *key, FILE *f)
}
} else if ((key->type == KEY_DSA && key->dsa != NULL) ||
(key->type == KEY_RSA && key->rsa != NULL)) {
int len, n;
u_char *blob, *uu;
key_to_blob(key, &blob, &len);
uu = xmalloc(2*len);
n = uuencode(blob, len, uu, 2*len);
@ -532,7 +547,8 @@ key_ssh_name(Key *k)
return "ssh-unknown";
}
u_int
key_size(Key *k){
key_size(Key *k)
{
switch (k->type) {
case KEY_RSA1:
case KEY_RSA:
@ -545,7 +561,7 @@ key_size(Key *k){
return 0;
}
RSA *
static RSA *
rsa_generate_private_key(u_int bits)
{
RSA *private;
@ -555,7 +571,7 @@ rsa_generate_private_key(u_int bits)
return private;
}
DSA*
static DSA*
dsa_generate_private_key(u_int bits)
{
DSA *private = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, NULL, NULL);
@ -615,15 +631,15 @@ key_from_private(Key *k)
int
key_type_from_name(char *name)
{
if (strcmp(name, "rsa1") == 0){
if (strcmp(name, "rsa1") == 0) {
return KEY_RSA1;
} else if (strcmp(name, "rsa") == 0){
} else if (strcmp(name, "rsa") == 0) {
return KEY_RSA;
} else if (strcmp(name, "dsa") == 0){
} else if (strcmp(name, "dsa") == 0) {
return KEY_DSA;
} else if (strcmp(name, "ssh-rsa") == 0){
} else if (strcmp(name, "ssh-rsa") == 0) {
return KEY_RSA;
} else if (strcmp(name, "ssh-dss") == 0){
} else if (strcmp(name, "ssh-dss") == 0) {
return KEY_DSA;
}
debug2("key_type_from_name: unknown key type '%s'", name);
@ -639,7 +655,7 @@ key_names_valid2(const char *names)
return 0;
s = cp = xstrdup(names);
for ((p = strsep(&cp, ",")); p && *p != '\0';
(p = strsep(&cp, ","))) {
(p = strsep(&cp, ","))) {
switch (key_type_from_name(p)) {
case KEY_RSA1:
case KEY_UNSPEC:
@ -653,7 +669,7 @@ key_names_valid2(const char *names)
}
Key *
key_from_blob(char *blob, int blen)
key_from_blob(u_char *blob, int blen)
{
Buffer b;
char *ktype;
@ -668,7 +684,7 @@ key_from_blob(char *blob, int blen)
ktype = buffer_get_string(&b, NULL);
type = key_type_from_name(ktype);
switch(type){
switch (type) {
case KEY_RSA:
key = key_new(type);
buffer_get_bignum2(&b, key->rsa->e);
@ -714,7 +730,7 @@ key_to_blob(Key *key, u_char **blobp, u_int *lenp)
return 0;
}
buffer_init(&b);
switch(key->type){
switch (key->type) {
case KEY_DSA:
buffer_put_cstring(&b, key_ssh_name(key));
buffer_put_bignum2(&b, key->dsa->p);
@ -728,8 +744,9 @@ key_to_blob(Key *key, u_char **blobp, u_int *lenp)
buffer_put_bignum2(&b, key->rsa->n);
break;
default:
error("key_to_blob: illegal key type %d", key->type);
break;
error("key_to_blob: unsupported key type %d", key->type);
buffer_free(&b);
return 0;
}
len = buffer_len(&b);
buf = xmalloc(len);
@ -746,10 +763,10 @@ key_to_blob(Key *key, u_char **blobp, u_int *lenp)
int
key_sign(
Key *key,
u_char **sigp, int *lenp,
u_char *data, int datalen)
u_char **sigp, u_int *lenp,
u_char *data, u_int datalen)
{
switch(key->type){
switch (key->type) {
case KEY_DSA:
return ssh_dss_sign(key, sigp, lenp, data, datalen);
break;
@ -766,10 +783,13 @@ key_sign(
int
key_verify(
Key *key,
u_char *signature, int signaturelen,
u_char *data, int datalen)
u_char *signature, u_int signaturelen,
u_char *data, u_int datalen)
{
switch(key->type){
if (signaturelen == 0)
return -1;
switch (key->type) {
case KEY_DSA:
return ssh_dss_verify(key, signature, signaturelen, data, datalen);
break;

View file

@ -1,3 +1,6 @@
/* $OpenBSD: packet.h,v 1.33 2002/03/04 17:27:39 stevesk Exp $ */
/* $FreeBSD$ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -11,191 +14,69 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: packet.h,v 1.22 2001/04/14 16:33:20 stevesk Exp $"); */
/* RCSID("$FreeBSD$"); */
#ifndef PACKET_H
#define PACKET_H
#include <openssl/bn.h>
/*
* Sets the socket used for communication. Disables encryption until
* packet_set_encryption_key is called. It is permissible that fd_in and
* fd_out are the same descriptor; in that case it is assumed to be a socket.
*/
void packet_set_connection(int fd_in, int fd_out);
void packet_set_connection(int, int);
void packet_set_nonblocking(void);
int packet_get_connection_in(void);
int packet_get_connection_out(void);
void packet_close(void);
void packet_set_encryption_key(const u_char *, u_int, int);
void packet_set_protocol_flags(u_int);
u_int packet_get_protocol_flags(void);
void packet_start_compression(int);
void packet_set_interactive(int);
int packet_is_interactive(void);
/* Puts the connection file descriptors into non-blocking mode. */
void packet_set_nonblocking(void);
void packet_start(u_char);
void packet_put_char(int ch);
void packet_put_int(u_int value);
void packet_put_bignum(BIGNUM * value);
void packet_put_bignum2(BIGNUM * value);
void packet_put_string(const void *buf, u_int len);
void packet_put_cstring(const char *str);
void packet_put_raw(const void *buf, u_int len);
void packet_send(void);
/* Returns the file descriptor used for input. */
int packet_get_connection_in(void);
int packet_read(void);
void packet_read_expect(int type);
int packet_read_poll(void);
void packet_process_incoming(const char *buf, u_int len);
int packet_read_seqnr(u_int32_t *seqnr_p);
int packet_read_poll_seqnr(u_int32_t *seqnr_p);
/* Returns the file descriptor used for output. */
int packet_get_connection_out(void);
u_int packet_get_char(void);
u_int packet_get_int(void);
void packet_get_bignum(BIGNUM * value);
void packet_get_bignum2(BIGNUM * value);
void *packet_get_raw(int *length_ptr);
void *packet_get_string(u_int *length_ptr);
void packet_disconnect(const char *fmt,...) __attribute__((format(printf, 1, 2)));
void packet_send_debug(const char *fmt,...) __attribute__((format(printf, 1, 2)));
/*
* Closes the connection (both descriptors) and clears and frees internal
* data structures.
*/
void packet_close(void);
void packet_write_poll(void);
void packet_write_wait(void);
int packet_have_data_to_write(void);
int packet_not_very_much_data_to_write(void);
/*
* Causes any further packets to be encrypted using the given key. The same
* key is used for both sending and reception. However, both directions are
* encrypted independently of each other. Cipher types are defined in ssh.h.
*/
void
packet_set_encryption_key(const u_char *key, u_int keylen,
int cipher_type);
int packet_connection_is_on_socket(void);
int packet_connection_is_ipv4(void);
int packet_remaining(void);
void packet_send_ignore(int);
void packet_add_padding(u_char);
/*
* Sets remote side protocol flags for the current connection. This can be
* called at any time.
*/
void packet_set_protocol_flags(u_int flags);
void tty_make_modes(int, struct termios *);
void tty_parse_modes(int, int *);
/* Returns the remote protocol flags set earlier by the above function. */
u_int packet_get_protocol_flags(void);
/* Enables compression in both directions starting from the next packet. */
void packet_start_compression(int level);
/*
* Informs that the current session is interactive. Sets IP flags for
* optimal performance in interactive use.
*/
void packet_set_interactive(int interactive);
/* Returns true if the current connection is interactive. */
int packet_is_interactive(void);
/* Starts constructing a packet to send. */
void packet_start(int type);
/* Appends a character to the packet data. */
void packet_put_char(int ch);
/* Appends an integer to the packet data. */
void packet_put_int(u_int value);
/* Appends an arbitrary precision integer to packet data. */
void packet_put_bignum(BIGNUM * value);
void packet_put_bignum2(BIGNUM * value);
/* Appends a string to packet data. */
void packet_put_string(const char *buf, u_int len);
void packet_put_cstring(const char *str);
void packet_put_raw(const char *buf, u_int len);
/*
* Finalizes and sends the packet. If the encryption key has been set,
* encrypts the packet before sending.
*/
void packet_send(void);
/* Waits until a packet has been received, and returns its type. */
int packet_read(int *payload_len_ptr);
/*
* Waits until a packet has been received, verifies that its type matches
* that given, and gives a fatal error and exits if there is a mismatch.
*/
void packet_read_expect(int *payload_len_ptr, int type);
/*
* Checks if a full packet is available in the data received so far via
* packet_process_incoming. If so, reads the packet; otherwise returns
* SSH_MSG_NONE. This does not wait for data from the connection.
* SSH_MSG_DISCONNECT is handled specially here. Also, SSH_MSG_IGNORE
* messages are skipped by this function and are never returned to higher
* levels.
*/
int packet_read_poll(int *packet_len_ptr);
/*
* Buffers the given amount of input characters. This is intended to be used
* together with packet_read_poll.
*/
void packet_process_incoming(const char *buf, u_int len);
/* Returns a character (0-255) from the packet data. */
u_int packet_get_char(void);
/* Returns an integer from the packet data. */
u_int packet_get_int(void);
/*
* Returns an arbitrary precision integer from the packet data. The integer
* must have been initialized before this call.
*/
void packet_get_bignum(BIGNUM * value, int *length_ptr);
void packet_get_bignum2(BIGNUM * value, int *length_ptr);
char *packet_get_raw(int *length_ptr);
/*
* Returns a string from the packet data. The string is allocated using
* xmalloc; it is the responsibility of the calling program to free it when
* no longer needed. The length_ptr argument may be NULL, or point to an
* integer into which the length of the string is stored.
*/
char *packet_get_string(u_int *length_ptr);
/*
* Logs the error in syslog using LOG_INFO, constructs and sends a disconnect
* packet, closes the connection, and exits. This function never returns.
* The error message should not contain a newline. The total length of the
* message must not exceed 1024 bytes.
*/
void packet_disconnect(const char *fmt,...) __attribute__((format(printf, 1, 2)));
/*
* Sends a diagnostic message to the other side. This message can be sent at
* any time (but not while constructing another message). The message is
* printed immediately, but only if the client is being executed in verbose
* mode. These messages are primarily intended to ease debugging
* authentication problems. The total length of the message must not exceed
* 1024 bytes. This will automatically call packet_write_wait. If the
* remote side protocol flags do not indicate that it supports SSH_MSG_DEBUG,
* this will do nothing.
*/
void packet_send_debug(const char *fmt,...) __attribute__((format(printf, 1, 2)));
/* Checks if there is any buffered output, and tries to write some of the output. */
void packet_write_poll(void);
/* Waits until all pending output data has been written. */
void packet_write_wait(void);
/* Returns true if there is buffered data to write to the connection. */
int packet_have_data_to_write(void);
/* Returns true if there is not too much data to write to the connection. */
int packet_not_very_much_data_to_write(void);
/* maximum packet size, requested by client with SSH_CMSG_MAX_PACKET_SIZE */
extern int max_packet_size;
int packet_set_maxsize(int s);
#define packet_get_maxsize() max_packet_size
int packet_set_maxsize(int);
#define packet_get_maxsize() max_packet_size
/* Stores tty modes from the fd or tiop into current packet. */
void tty_make_modes(int fd, struct termios *tiop);
/* Parses tty modes for the fd from the current packet. */
void tty_parse_modes(int fd, int *n_bytes_ptr);
#define packet_integrity_check(payload_len, expected_len, type) \
do { \
int _p = (payload_len), _e = (expected_len); \
if (_p != _e) { \
log("Packet integrity error (%d != %d) at %s:%d", \
_p, _e, __FILE__, __LINE__); \
packet_disconnect("Packet integrity error. (%d)", (type)); \
} \
} while (0)
#define packet_done() \
/* don't allow remaining bytes after the end of the message */
#define packet_check_eom() \
do { \
int _len = packet_remaining(); \
if (_len > 0) { \
@ -205,20 +86,4 @@ do { \
} \
} while (0)
/* remote host is connected via a socket/ipv4 */
int packet_connection_is_on_socket(void);
int packet_connection_is_ipv4(void);
/* enable SSH2 packet format */
void packet_set_ssh2_format(void);
/* returns remaining payload bytes */
int packet_remaining(void);
/* append an ignore message */
void packet_send_ignore(int nbytes);
/* add an ignore message and make sure size (current+ignore) = n*sumlen */
void packet_inject_ignore(int sumlen);
#endif /* PACKET_H */

View file

@ -1,4 +1,4 @@
/* $OpenBSD: pathnames.h,v 1.5 2001/04/12 19:15:24 markus Exp $ */
/* $OpenBSD: pathnames.h,v 1.11 2002/02/09 17:37:34 deraadt Exp $ */
/* $FreeBSD$ */
/*
@ -13,26 +13,30 @@
* called by a name other than "ssh" or "Secure Shell".
*/
#define ETCDIR "/etc/ssh"
#define ETCDIR "/etc"
#define SSHDIR ETCDIR "/ssh"
#define _PATH_SSH_PIDDIR "/var/run"
/*
* System-wide file containing host keys of known hosts. This file should be
* world-readable.
*/
#define _PATH_SSH_SYSTEM_HOSTFILE ETCDIR "/ssh_known_hosts"
#define _PATH_SSH_SYSTEM_HOSTFILE2 ETCDIR "/ssh_known_hosts2"
#define _PATH_SSH_SYSTEM_HOSTFILE SSHDIR "/ssh_known_hosts"
/* backward compat for protocol 2 */
#define _PATH_SSH_SYSTEM_HOSTFILE2 SSHDIR "/ssh_known_hosts2"
/*
* Of these, ssh_host_key must be readable only by root, whereas ssh_config
* should be world-readable.
*/
#define _PATH_SERVER_CONFIG_FILE ETCDIR "/sshd_config"
#define _PATH_HOST_CONFIG_FILE ETCDIR "/ssh_config"
#define _PATH_HOST_KEY_FILE ETCDIR "/ssh_host_key"
#define _PATH_HOST_DSA_KEY_FILE ETCDIR "/ssh_host_dsa_key"
#define _PATH_HOST_RSA_KEY_FILE ETCDIR "/ssh_host_rsa_key"
#define _PATH_DH_PRIMES ETCDIR "/primes"
#define _PATH_SERVER_CONFIG_FILE SSHDIR "/sshd_config"
#define _PATH_HOST_CONFIG_FILE SSHDIR "/ssh_config"
#define _PATH_HOST_KEY_FILE SSHDIR "/ssh_host_key"
#define _PATH_HOST_DSA_KEY_FILE SSHDIR "/ssh_host_dsa_key"
#define _PATH_HOST_RSA_KEY_FILE SSHDIR "/ssh_host_rsa_key"
#define _PATH_DH_MODULI SSHDIR "/moduli"
/* Backwards compatibility */
#define _PATH_DH_PRIMES SSHDIR "/primes"
#define _PATH_SSH_PROGRAM "/usr/bin/ssh"
@ -54,6 +58,7 @@
* contain anything particularly secret.
*/
#define _PATH_SSH_USER_HOSTFILE "~/.ssh/known_hosts"
/* backward compat for protocol 2 */
#define _PATH_SSH_USER_HOSTFILE2 "~/.ssh/known_hosts2"
/*
@ -81,6 +86,8 @@
* running as root.)
*/
#define _PATH_SSH_USER_PERMITTED_KEYS ".ssh/authorized_keys"
/* backward compat for protocol v2 */
#define _PATH_SSH_USER_PERMITTED_KEYS2 ".ssh/authorized_keys2"
/*
@ -90,13 +97,13 @@
* use. xauth will be run if neither of these exists.
*/
#define _PATH_SSH_USER_RC ".ssh/rc"
#define _PATH_SSH_SYSTEM_RC ETCDIR "/sshrc"
#define _PATH_SSH_SYSTEM_RC SSHDIR "/sshrc"
/*
* Ssh-only version of /etc/hosts.equiv. Additionally, the daemon may use
* ~/.rhosts and /etc/hosts.equiv if rhosts authentication is enabled.
*/
#define _PATH_SSH_HOSTS_EQUIV ETCDIR "/shosts.equiv"
#define _PATH_SSH_HOSTS_EQUIV SSHDIR "/shosts.equiv"
#define _PATH_RHOSTS_EQUIV "/etc/hosts.equiv"
/*
@ -104,6 +111,12 @@
*/
#define _PATH_SSH_ASKPASS_DEFAULT "/usr/X11R6/bin/ssh-askpass"
/* xauth for X11 forwarding */
#define _PATH_XAUTH "/usr/X11R6/bin/xauth"
/* UNIX domain socket for X11 server; displaynum will replace %u */
#define _PATH_UNIX_X "/tmp/.X11-unix/X%u"
/* for scp */
#define _PATH_CP "cp"

View file

@ -12,7 +12,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: readconf.c,v 1.76 2001/04/17 10:53:25 markus Exp $");
RCSID("$OpenBSD: readconf.c,v 1.95 2002/02/04 12:15:25 markus Exp $");
RCSID("$FreeBSD$");
#include "ssh.h"
@ -99,12 +99,12 @@ typedef enum {
oChallengeResponseAuthentication, oXAuthLocation,
#if defined(KRB4) || defined(KRB5)
oKerberosAuthentication,
#endif /* KRB4 */
#ifdef KRB5
oKrb5TgtPassing,
#endif /* KRB5 */
#endif
#if defined(AFS) || defined(KRB5)
oKerberosTgtPassing,
#endif
#ifdef AFS
oKrb4TgtPassing, oAFSTokenPassing,
oAFSTokenPassing,
#endif
oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
@ -115,7 +115,8 @@ typedef enum {
oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
oHostKeyAlgorithms
oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
oClearAllForwardings, oNoHostAuthenticationForLocalhost
} OpCodes;
/* Textual representations of the tokens. */
@ -143,12 +144,11 @@ static struct {
{ "tisauthentication", oChallengeResponseAuthentication }, /* alias */
#if defined(KRB4) || defined(KRB5)
{ "kerberosauthentication", oKerberosAuthentication },
#endif /* KRB4 || KRB5 */
#ifdef KRB5
{ "kerberos5tgtpassing", oKrb5TgtPassing },
#endif /* KRB5 */
#endif
#if defined(AFS) || defined(KRB5)
{ "kerberostgtpassing", oKerberosTgtPassing },
#endif
#ifdef AFS
{ "kerberos4tgtpassing", oKrb4TgtPassing },
{ "afstokenpassing", oAFSTokenPassing },
#endif
{ "fallbacktorsh", oFallBackToRsh },
@ -169,9 +169,9 @@ static struct {
{ "host", oHost },
{ "escapechar", oEscapeChar },
{ "globalknownhostsfile", oGlobalKnownHostsFile },
{ "userknownhostsfile", oUserKnownHostsFile },
{ "userknownhostsfile", oUserKnownHostsFile }, /* obsolete */
{ "globalknownhostsfile2", oGlobalKnownHostsFile2 },
{ "userknownhostsfile2", oUserKnownHostsFile2 },
{ "userknownhostsfile2", oUserKnownHostsFile2 }, /* obsolete */
{ "connectionattempts", oConnectionAttempts },
{ "batchmode", oBatchMode },
{ "checkhostip", oCheckHostIP },
@ -184,7 +184,11 @@ static struct {
{ "dynamicforward", oDynamicForward },
{ "preferredauthentications", oPreferredAuthentications },
{ "hostkeyalgorithms", oHostKeyAlgorithms },
{ NULL, 0 }
{ "bindaddress", oBindAddress },
{ "smartcarddevice", oSmartcardDevice },
{ "clearallforwardings", oClearAllForwardings },
{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
{ NULL, oBadOption }
};
/*
@ -220,13 +224,26 @@ add_remote_forward(Options *options, u_short port, const char *host,
Forward *fwd;
if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
fatal("Too many remote forwards (max %d).",
SSH_MAX_FORWARDS_PER_DIRECTION);
SSH_MAX_FORWARDS_PER_DIRECTION);
fwd = &options->remote_forwards[options->num_remote_forwards++];
fwd->port = port;
fwd->host = xstrdup(host);
fwd->host_port = host_port;
}
static void
clear_forwardings(Options *options)
{
int i;
for (i = 0; i < options->num_local_forwards; i++)
xfree(options->local_forwards[i].host);
options->num_local_forwards = 0;
for (i = 0; i < options->num_remote_forwards; i++)
xfree(options->remote_forwards[i].host);
options->num_remote_forwards = 0;
}
/*
* Returns the number of the token pointed to by cp or oBadOption.
*/
@ -258,6 +275,7 @@ process_config_line(Options *options, const char *host,
char buf[256], *s, *string, **charptr, *endofnumber, *keyword, *arg;
int opcode, *intptr, value;
u_short fwd_port, fwd_host_port;
char sfwd_host_port[6];
s = line;
/* Get the keyword. (Each line is supposed to begin with a keyword). */
@ -336,32 +354,24 @@ process_config_line(Options *options, const char *host,
intptr = &options->hostbased_authentication;
goto parse_flag;
case oChallengeResponseAuthentication:
intptr = &options->challenge_response_authentication;
goto parse_flag;
#if defined(KRB4) || defined(KRB5)
case oKerberosAuthentication:
intptr = &options->kerberos_authentication;
goto parse_flag;
#endif /* KRB4 || KRB5 */
case oChallengeResponseAuthentication:
intptr = &options->challenge_reponse_authentication;
#endif
#if defined(AFS) || defined(KRB5)
case oKerberosTgtPassing:
intptr = &options->kerberos_tgt_passing;
goto parse_flag;
#ifdef KRB5
case oKrb5TgtPassing:
intptr = &options->krb5_tgt_passing;
goto parse_flag;
#endif /* KRB5 */
#endif
#ifdef AFS
case oKrb4TgtPassing:
intptr = &options->krb4_tgt_passing;
goto parse_flag;
case oAFSTokenPassing:
intptr = &options->afs_token_passing;
goto parse_flag;
#endif
case oFallBackToRsh:
intptr = &options->fallback_to_rsh;
goto parse_flag;
@ -383,7 +393,7 @@ process_config_line(Options *options, const char *host,
arg = strdelim(&s);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing yes/no/ask argument.",
filename, linenum);
filename, linenum);
value = 0; /* To avoid compiler warning... */
if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
value = 1;
@ -405,6 +415,10 @@ process_config_line(Options *options, const char *host,
intptr = &options->keepalives;
goto parse_flag;
case oNoHostAuthenticationForLocalhost:
intptr = &options->no_host_authentication_for_localhost;
goto parse_flag;
case oNumberOfPasswordPrompts:
intptr = &options->number_of_password_prompts;
goto parse_int;
@ -421,7 +435,7 @@ process_config_line(Options *options, const char *host,
intptr = &options->num_identity_files;
if (*intptr >= SSH_MAX_IDENTITY_FILES)
fatal("%.200s line %d: Too many identity files specified (max %d).",
filename, linenum, SSH_MAX_IDENTITY_FILES);
filename, linenum, SSH_MAX_IDENTITY_FILES);
charptr = &options->identity_files[*intptr];
*charptr = xstrdup(arg);
*intptr = *intptr + 1;
@ -470,6 +484,14 @@ process_config_line(Options *options, const char *host,
charptr = &options->preferred_authentications;
goto parse_string;
case oBindAddress:
charptr = &options->bind_address;
goto parse_string;
case oSmartcardDevice:
charptr = &options->smartcard_device;
goto parse_string;
case oProxyCommand:
charptr = &options->proxy_command;
string = xstrdup("");
@ -513,7 +535,7 @@ process_config_line(Options *options, const char *host,
value = cipher_number(arg);
if (value == -1)
fatal("%.200s line %d: Bad cipher '%s'.",
filename, linenum, arg ? arg : "<NONE>");
filename, linenum, arg ? arg : "<NONE>");
if (*activep && *intptr == -1)
*intptr = value;
break;
@ -524,7 +546,7 @@ process_config_line(Options *options, const char *host,
fatal("%.200s line %d: Missing argument.", filename, linenum);
if (!ciphers_valid(arg))
fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
filename, linenum, arg ? arg : "<NONE>");
filename, linenum, arg ? arg : "<NONE>");
if (*activep && options->ciphers == NULL)
options->ciphers = xstrdup(arg);
break;
@ -535,7 +557,7 @@ process_config_line(Options *options, const char *host,
fatal("%.200s line %d: Missing argument.", filename, linenum);
if (!mac_valid(arg))
fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
filename, linenum, arg ? arg : "<NONE>");
filename, linenum, arg ? arg : "<NONE>");
if (*activep && options->macs == NULL)
options->macs = xstrdup(arg);
break;
@ -546,7 +568,7 @@ process_config_line(Options *options, const char *host,
fatal("%.200s line %d: Missing argument.", filename, linenum);
if (!key_names_valid2(arg))
fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.",
filename, linenum, arg ? arg : "<NONE>");
filename, linenum, arg ? arg : "<NONE>");
if (*activep && options->hostkeyalgorithms == NULL)
options->hostkeyalgorithms = xstrdup(arg);
break;
@ -559,7 +581,7 @@ process_config_line(Options *options, const char *host,
value = proto_spec(arg);
if (value == SSH_PROTO_UNKNOWN)
fatal("%.200s line %d: Bad protocol spec '%s'.",
filename, linenum, arg ? arg : "<NONE>");
filename, linenum, arg ? arg : "<NONE>");
if (*activep && *intptr == SSH_PROTO_UNKNOWN)
*intptr = value;
break;
@ -568,49 +590,41 @@ process_config_line(Options *options, const char *host,
intptr = (int *) &options->log_level;
arg = strdelim(&s);
value = log_level_number(arg);
if (value == (LogLevel) - 1)
if (value == SYSLOG_LEVEL_NOT_SET)
fatal("%.200s line %d: unsupported log level '%s'",
filename, linenum, arg ? arg : "<NONE>");
if (*activep && (LogLevel) * intptr == -1)
filename, linenum, arg ? arg : "<NONE>");
if (*activep && (LogLevel) *intptr == SYSLOG_LEVEL_NOT_SET)
*intptr = (LogLevel) value;
break;
case oLocalForward:
case oRemoteForward:
arg = strdelim(&s);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.", filename, linenum);
fwd_port = a2port(arg);
if (fwd_port == 0)
fatal("%.200s line %d: Badly formatted port number.",
filename, linenum);
fatal("%.200s line %d: Missing port argument.",
filename, linenum);
if ((fwd_port = a2port(arg)) == 0)
fatal("%.200s line %d: Bad listen port.",
filename, linenum);
arg = strdelim(&s);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing second argument.",
filename, linenum);
if (sscanf(arg, "%255[^:]:%hu", buf, &fwd_host_port) != 2)
fatal("%.200s line %d: Badly formatted host:port.",
filename, linenum);
if (*activep)
add_remote_forward(options, fwd_port, buf, fwd_host_port);
break;
case oLocalForward:
arg = strdelim(&s);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.", filename, linenum);
fwd_port = a2port(arg);
if (fwd_port == 0)
fatal("%.200s line %d: Badly formatted port number.",
filename, linenum);
arg = strdelim(&s);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing second argument.",
filename, linenum);
if (sscanf(arg, "%255[^:]:%hu", buf, &fwd_host_port) != 2)
fatal("%.200s line %d: Badly formatted host:port.",
filename, linenum);
if (*activep)
add_local_forward(options, fwd_port, buf, fwd_host_port);
filename, linenum);
if (sscanf(arg, "%255[^:]:%5[0-9]", buf, sfwd_host_port) != 2 &&
sscanf(arg, "%255[^/]/%5[0-9]", buf, sfwd_host_port) != 2)
fatal("%.200s line %d: Bad forwarding specification.",
filename, linenum);
if ((fwd_host_port = a2port(sfwd_host_port)) == 0)
fatal("%.200s line %d: Bad forwarding port.",
filename, linenum);
if (*activep) {
if (opcode == oLocalForward)
add_local_forward(options, fwd_port, buf,
fwd_host_port);
else if (opcode == oRemoteForward)
add_remote_forward(options, fwd_port, buf,
fwd_host_port);
}
break;
case oDynamicForward:
@ -622,9 +636,14 @@ process_config_line(Options *options, const char *host,
if (fwd_port == 0)
fatal("%.200s line %d: Badly formatted port number.",
filename, linenum);
add_local_forward(options, fwd_port, "socks4", 0);
if (*activep)
add_local_forward(options, fwd_port, "socks4", 0);
break;
case oClearAllForwardings:
intptr = &options->clear_forwardings;
goto parse_flag;
case oHost:
*activep = 0;
while ((arg = strdelim(&s)) != NULL && *arg != '\0')
@ -647,10 +666,10 @@ process_config_line(Options *options, const char *host,
else if (strlen(arg) == 1)
value = (u_char) arg[0];
else if (strcmp(arg, "none") == 0)
value = -2;
value = SSH_ESCAPECHAR_NONE;
else {
fatal("%.200s line %d: Bad escape character.",
filename, linenum);
filename, linenum);
/* NOTREACHED */
value = 0; /* Avoid compiler warning. */
}
@ -665,7 +684,7 @@ process_config_line(Options *options, const char *host,
/* Check that there is no garbage at end of line. */
if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
filename, linenum, arg);
filename, linenum, arg);
}
return 0;
}
@ -674,10 +693,10 @@ process_config_line(Options *options, const char *host,
/*
* Reads the config file and modifies the options accordingly. Options
* should already be initialized before this call. This never returns if
* there is an error. If the file does not exist, this returns immediately.
* there is an error. If the file does not exist, this returns 0.
*/
void
int
read_config_file(const char *filename, const char *host, Options *options)
{
FILE *f;
@ -688,7 +707,7 @@ read_config_file(const char *filename, const char *host, Options *options)
/* Open the file. */
f = fopen(filename, "r");
if (!f)
return;
return 0;
debug("Reading configuration data %.200s", filename);
@ -707,7 +726,8 @@ read_config_file(const char *filename, const char *host, Options *options)
fclose(f);
if (bad_options > 0)
fatal("%s: terminating, %d bad configuration options",
filename, bad_options);
filename, bad_options);
return 1;
}
/*
@ -729,15 +749,14 @@ initialize_options(Options * options)
options->rhosts_authentication = -1;
options->rsa_authentication = -1;
options->pubkey_authentication = -1;
options->challenge_reponse_authentication = -1;
options->challenge_response_authentication = -1;
#if defined(KRB4) || defined(KRB5)
options->kerberos_authentication = -1;
#endif
#ifdef KRB5
options->krb5_tgt_passing = -1;
#endif /* KRB5 */
#if defined(AFS) || defined(KRB5)
options->kerberos_tgt_passing = -1;
#endif
#ifdef AFS
options->krb4_tgt_passing = -1;
options->afs_token_passing = -1;
#endif
options->password_authentication = -1;
@ -773,8 +792,12 @@ initialize_options(Options * options)
options->user_hostfile2 = NULL;
options->num_local_forwards = 0;
options->num_remote_forwards = 0;
options->log_level = (LogLevel) - 1;
options->clear_forwardings = -1;
options->log_level = SYSLOG_LEVEL_NOT_SET;
options->preferred_authentications = NULL;
options->bind_address = NULL;
options->smartcard_device = NULL;
options->no_host_authentication_for_localhost = - 1;
}
/*
@ -791,10 +814,8 @@ fill_default_options(Options * options)
options->forward_agent = 0;
if (options->forward_x11 == -1)
options->forward_x11 = 0;
#ifdef XAUTH_PATH
if (options->xauth_location == NULL)
options->xauth_location = XAUTH_PATH;
#endif /* XAUTH_PATH */
options->xauth_location = _PATH_XAUTH;
if (options->gateway_ports == -1)
options->gateway_ports = 0;
if (options->use_privileged_port == -1)
@ -805,22 +826,20 @@ fill_default_options(Options * options)
options->rsa_authentication = 1;
if (options->pubkey_authentication == -1)
options->pubkey_authentication = 1;
if (options->challenge_reponse_authentication == -1)
options->challenge_reponse_authentication = 0;
if (options->challenge_response_authentication == -1)
options->challenge_response_authentication = 1;
#if defined(KRB4) || defined(KRB5)
if (options->kerberos_authentication == -1)
options->kerberos_authentication = 1;
#endif /* KRB4 || KRB5 */
#ifdef KRB5
if (options->krb5_tgt_passing == -1)
options->krb5_tgt_passing = 1;
#endif /* KRB5 */
#endif
#if defined(AFS) || defined(KRB5)
if (options->kerberos_tgt_passing == -1)
options->kerberos_tgt_passing = 1;
#endif
#ifdef AFS
if (options->krb4_tgt_passing == -1)
options->krb4_tgt_passing = 1;
if (options->afs_token_passing == -1)
options->afs_token_passing = 1;
#endif /* AFS */
#endif
if (options->password_authentication == -1)
options->password_authentication = 1;
if (options->kbd_interactive_authentication == -1)
@ -848,7 +867,7 @@ fill_default_options(Options * options)
if (options->port == -1)
options->port = 0; /* Filled in ssh_connect. */
if (options->connection_attempts == -1)
options->connection_attempts = 4;
options->connection_attempts = 1;
if (options->number_of_password_prompts == -1)
options->number_of_password_prompts = 3;
/* Selected in ssh_login(). */
@ -891,8 +910,12 @@ fill_default_options(Options * options)
options->system_hostfile2 = _PATH_SSH_SYSTEM_HOSTFILE2;
if (options->user_hostfile2 == NULL)
options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2;
if (options->log_level == (LogLevel) - 1)
if (options->log_level == SYSLOG_LEVEL_NOT_SET)
options->log_level = SYSLOG_LEVEL_INFO;
if (options->clear_forwardings == 1)
clear_forwardings(options);
if (options->no_host_authentication_for_localhost == - 1)
options->no_host_authentication_for_localhost = 0;
/* options->proxy_command should not be set by default */
/* options->user will be set in the main program if appropriate */
/* options->hostname will be set in the main program if appropriate */

View file

@ -1,3 +1,6 @@
/* $OpenBSD: readconf.h,v 1.42 2002/03/04 17:27:39 stevesk Exp $ */
/* $FreeBSD$ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -11,9 +14,6 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: readconf.h,v 1.30 2001/04/17 10:53:25 markus Exp $"); */
/* RCSID("$FreeBSD$"); */
#ifndef READCONF_H
#define READCONF_H
@ -40,19 +40,15 @@ typedef struct {
int rsa_authentication; /* Try RSA authentication. */
int pubkey_authentication; /* Try ssh2 pubkey authentication. */
int hostbased_authentication; /* ssh2's rhosts_rsa */
int challenge_reponse_authentication;
int challenge_response_authentication;
/* Try S/Key or TIS, authentication. */
#if defined(KRB4) || defined(KRB5)
int kerberos_authentication; /* Try Kerberos
* authentication. */
int kerberos_authentication; /* Try Kerberos authentication. */
#endif
#if defined(AFS) || defined(KRB5)
int kerberos_tgt_passing; /* Try Kerberos TGT passing. */
#endif
#ifdef KRB5
int krb5_tgt_passing;
#endif /* KRB5 */
#ifdef AFS
int krb4_tgt_passing; /* Try Kerberos v4 tgt passing. */
int afs_token_passing; /* Try AFS token passing. */
#endif
int password_authentication; /* Try password
@ -86,11 +82,13 @@ typedef struct {
char *user; /* User to log in as. */
int escape_char; /* Escape character; -2 = none */
char *system_hostfile;/* Path for /etc/ssh_known_hosts. */
char *system_hostfile;/* Path for /etc/ssh/ssh_known_hosts. */
char *user_hostfile; /* Path for $HOME/.ssh/known_hosts. */
char *system_hostfile2;
char *user_hostfile2;
char *preferred_authentications;
char *bind_address; /* local socket address for connection to sshd */
char *smartcard_device; /* Smartcard reader device */
int num_identity_files; /* Number of files for RSA/DSA identities. */
char *identity_files[SSH_MAX_IDENTITY_FILES];
@ -103,56 +101,19 @@ typedef struct {
/* Remote TCP/IP forward requests. */
int num_remote_forwards;
Forward remote_forwards[SSH_MAX_FORWARDS_PER_DIRECTION];
int clear_forwardings;
int no_host_authentication_for_localhost;
} Options;
/*
* Initializes options to special values that indicate that they have not yet
* been set. Read_config_file will only set options with this value. Options
* are processed in the following order: command line, user config file,
* system config file. Last, fill_default_options is called.
*/
void initialize_options(Options * options);
void initialize_options(Options *);
void fill_default_options(Options *);
int read_config_file(const char *, const char *, Options *);
/*
* Called after processing other sources of option data, this fills those
* options for which no value has been specified with their default values.
*/
void fill_default_options(Options * options);
/*
* Processes a single option line as used in the configuration files. This
* only sets those values that have not already been set. Returns 0 for legal
* options
*/
int
process_config_line(Options * options, const char *host,
char *line, const char *filename, int linenum,
int *activep);
process_config_line(Options *, const char *, char *, const char *, int, int *);
/*
* Reads the config file and modifies the options accordingly. Options
* should already be initialized before this call. This never returns if
* there is an error. If the file does not exist, this returns immediately.
*/
void
read_config_file(const char *filename, const char *host,
Options * options);
/*
* Adds a local TCP/IP port forward to options. Never returns if there is an
* error.
*/
void
add_local_forward(Options * options, u_short port, const char *host,
u_short host_port);
/*
* Adds a remote TCP/IP port forward to options. Never returns if there is
* an error.
*/
void
add_remote_forward(Options * options, u_short port, const char *host,
u_short host_port);
void add_local_forward(Options *, u_short, const char *, u_short);
void add_remote_forward(Options *, u_short, const char *, u_short);
#endif /* READCONF_H */

View file

@ -1,4 +1,5 @@
/* $OpenBSD: rijndael.c,v 1.13 2001/12/19 07:18:56 deraadt Exp $ */
/* $FreeBSD$ */
/**
* rijndael-alg-fst.c
@ -25,6 +26,7 @@
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>

View file

@ -60,7 +60,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: rsa.c,v 1.22 2001/03/26 23:23:23 markus Exp $");
RCSID("$OpenBSD: rsa.c,v 1.24 2001/12/27 18:22:16 markus Exp $");
RCSID("$FreeBSD$");
#include "rsa.h"
@ -121,14 +121,17 @@ rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *key)
return len;
}
/* calculate p-1 and q-1 */
void
generate_additional_parameters(RSA *rsa)
rsa_generate_additional_parameters(RSA *rsa)
{
BIGNUM *aux;
BN_CTX *ctx;
/* Generate additional parameters */
aux = BN_new();
ctx = BN_CTX_new();
if ((aux = BN_new()) == NULL)
fatal("rsa_generate_additional_parameters: BN_new failed");
if ((ctx = BN_CTX_new()) == NULL)
fatal("rsa_generate_additional_parameters: BN_CTX_new failed");
BN_sub(aux, rsa->q, BN_value_one());
BN_mod(rsa->dmq1, rsa->d, aux, ctx);

View file

@ -1,3 +1,6 @@
/* $OpenBSD: rsa.h,v 1.15 2002/03/04 17:27:39 stevesk Exp $ */
/* $FreeBSD$ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -11,18 +14,14 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: rsa.h,v 1.11 2001/03/26 23:23:24 markus Exp $"); */
/* RCSID("$FreeBSD$"); */
#ifndef RSA_H
#define RSA_H
#include <openssl/bn.h>
#include <openssl/rsa.h>
void rsa_public_encrypt __P((BIGNUM * out, BIGNUM * in, RSA * prv));
int rsa_private_decrypt __P((BIGNUM * out, BIGNUM * in, RSA * prv));
void generate_additional_parameters __P((RSA *rsa));
void rsa_public_encrypt(BIGNUM *, BIGNUM *, RSA *);
int rsa_private_decrypt(BIGNUM *, BIGNUM *, RSA *);
void rsa_generate_additional_parameters(RSA *);
#endif /* RSA_H */

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,6 @@
/* $OpenBSD: servconf.h,v 1.54 2002/03/04 17:27:39 stevesk Exp $ */
/* $FreeBSD$ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -11,9 +14,6 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: servconf.h,v 1.41 2001/04/13 22:46:53 beck Exp $"); */
/* RCSID("$FreeBSD$"); */
#ifndef SERVCONF_H
#define SERVCONF_H
@ -53,10 +53,11 @@ typedef struct {
* for RhostsRsaAuth */
int print_motd; /* If true, print /etc/motd. */
int print_lastlog; /* If true, print lastlog */
int check_mail; /* If true, check for new mail. */
int check_mail; /* If true, check for new mail */
int x11_forwarding; /* If true, permit inet (spoofing) X11 fwd. */
int x11_display_offset; /* What DISPLAY number to start
* searching at */
int x11_use_localhost; /* If true, use localhost for fake X11 server. */
char *xauth_location; /* Location of xauth program */
int strict_modes; /* If true, require string home dir modes. */
int keepalives; /* If true, set SO_KEEPALIVE. */
@ -73,32 +74,29 @@ typedef struct {
int hostbased_authentication; /* If true, permit ssh2 hostbased auth */
int hostbased_uses_name_from_packet_only; /* experimental */
int rsa_authentication; /* If true, permit RSA authentication. */
#if defined(KRB4) || defined(KRB5)
int kerberos_authentication; /* If true, permit Kerberos auth. */
#endif /* KRB4 || KRB5 */
int pubkey_authentication; /* If true, permit ssh2 pubkey authentication. */
#ifdef KRB4
int krb4_or_local_passwd; /* If true, permit kerberos v4
#if defined(KRB4) || defined(KRB5)
int kerberos_authentication; /* If true, permit Kerberos
* authentication. */
int kerberos_or_local_passwd; /* If true, permit kerberos
* and any other password
* authentication mechanism,
* such as SecurID or
* /etc/passwd */
int krb4_ticket_cleanup; /* If true, destroy ticket
int kerberos_ticket_cleanup; /* If true, destroy ticket
* file on logout. */
#endif
#ifdef KRB5
int krb5_tgt_passing;
#endif /* KRB5 */
#ifdef AFS
int krb4_tgt_passing; /* If true, permit Kerberos v4 tgt
#if defined(AFS) || defined(KRB5)
int kerberos_tgt_passing; /* If true, permit Kerberos TGT
* passing. */
#endif
#ifdef AFS
int afs_token_passing; /* If true, permit AFS token passing. */
#endif
int password_authentication; /* If true, permit password
* authentication. */
int kbd_interactive_authentication; /* If true, permit */
int challenge_reponse_authentication;
int challenge_response_authentication;
int permit_empty_passwd; /* If false, do not permit empty
* passwords. */
int use_login; /* If true, login(1) is used */
@ -111,11 +109,6 @@ typedef struct {
char *allow_groups[MAX_ALLOW_GROUPS];
u_int num_deny_groups;
char *deny_groups[MAX_DENY_GROUPS];
unsigned int connections_per_period; /*
* If not 0, number of sshd
* connections accepted per
* connections_period.
*/
unsigned int connections_period;
u_int num_subsystems;
@ -126,31 +119,26 @@ typedef struct {
int max_startups_rate;
int max_startups;
char *banner; /* SSH-2 banner message */
int reverse_mapping_check; /* cross-check ip and dns */
int verify_reverse_mapping; /* cross-check ip and dns */
int client_alive_interval; /*
* poke the client this often to
* see if it's still there
* poke the client this often to
* see if it's still there
*/
int client_alive_count_max; /*
*If the client is unresponsive
* for this many intervals, above
* diconnect the session
* If the client is unresponsive
* for this many intervals above,
* disconnect the session
*/
char *authorized_keys_file; /* File containing public keys */
char *authorized_keys_file2;
} ServerOptions;
/*
* Initializes the server options to special values that indicate that they
* have not yet been set.
*/
void initialize_server_options(ServerOptions * options);
/*
* Reads the server configuration file. This only sets the values for those
* options that have the special value indicating they have not been set.
*/
void read_server_config(ServerOptions * options, const char *filename);
void initialize_server_options(ServerOptions *);
void read_server_config(ServerOptions *, const char *);
void fill_default_server_options(ServerOptions *);
int process_server_config_line(ServerOptions *, char *, const char *, int);
/* Sets values for those values that have not yet been set. */
void fill_default_server_options(ServerOptions * options);
#endif /* SERVCONF_H */

View file

@ -11,7 +11,7 @@
* called by a name other than "ssh" or "Secure Shell".
*
* SSH2 support by Markus Friedl.
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -35,8 +35,8 @@
*/
#include "includes.h"
RCSID("$OpenBSD: serverloop.c,v 1.98 2002/02/06 14:55:16 markus Exp $");
RCSID("$FreeBSD$");
RCSID("$OpenBSD: serverloop.c,v 1.61 2001/04/13 22:46:54 beck Exp $");
#include "xmalloc.h"
#include "packet.h"
@ -60,6 +60,7 @@ extern ServerOptions options;
/* XXX */
extern Kex *xxx_kex;
static Authctxt *xxx_authctxt;
static Buffer stdin_buffer; /* Buffer for stdin data. */
static Buffer stdout_buffer; /* Buffer for stdout data. */
@ -80,46 +81,71 @@ static int connection_in; /* Connection to client (input). */
static int connection_out; /* Connection to client (output). */
static int connection_closed = 0; /* Connection to client closed. */
static u_int buffer_high; /* "Soft" max buffer size. */
static int client_alive_timeouts = 0;
/*
* This SIGCHLD kludge is used to detect when the child exits. The server
* will exit after that, as soon as forwarded connections have terminated.
*/
static pid_t child_pid; /* Pid of the child. */
static volatile int child_terminated; /* The child has terminated. */
static volatile int child_wait_status; /* Status from wait(). */
static volatile sig_atomic_t child_terminated = 0; /* The child has terminated. */
void server_init_dispatch(void);
/* prototypes */
static void server_init_dispatch(void);
int client_alive_timeouts = 0;
void
sigchld_handler(int sig)
/*
* we write to this pipe if a SIGCHLD is caught in order to avoid
* the race between select() and child_terminated
*/
static int notify_pipe[2];
static void
notify_setup(void)
{
int save_errno = errno;
pid_t wait_pid;
debug("Received SIGCHLD.");
wait_pid = wait((int *) &child_wait_status);
if (wait_pid != -1) {
if (wait_pid != child_pid)
error("Strange, got SIGCHLD and wait returned pid %d but child is %d",
wait_pid, child_pid);
if (WIFEXITED(child_wait_status) ||
WIFSIGNALED(child_wait_status))
child_terminated = 1;
if (pipe(notify_pipe) < 0) {
error("pipe(notify_pipe) failed %s", strerror(errno));
} else if ((fcntl(notify_pipe[0], F_SETFD, 1) == -1) ||
(fcntl(notify_pipe[1], F_SETFD, 1) == -1)) {
error("fcntl(notify_pipe, F_SETFD) failed %s", strerror(errno));
close(notify_pipe[0]);
close(notify_pipe[1]);
} else {
set_nonblock(notify_pipe[0]);
set_nonblock(notify_pipe[1]);
return;
}
signal(SIGCHLD, sigchld_handler);
errno = save_errno;
notify_pipe[0] = -1; /* read end */
notify_pipe[1] = -1; /* write end */
}
void
sigchld_handler2(int sig)
static void
notify_parent(void)
{
if (notify_pipe[1] != -1)
write(notify_pipe[1], "", 1);
}
static void
notify_prepare(fd_set *readset)
{
if (notify_pipe[0] != -1)
FD_SET(notify_pipe[0], readset);
}
static void
notify_done(fd_set *readset)
{
char c;
if (notify_pipe[0] != -1 && FD_ISSET(notify_pipe[0], readset))
while (read(notify_pipe[0], &c, 1) != -1)
debug2("notify_done: reading");
}
static void
sigchld_handler(int sig)
{
int save_errno = errno;
debug("Received SIGCHLD.");
child_terminated = 1;
signal(SIGCHLD, sigchld_handler2);
signal(SIGCHLD, sigchld_handler);
notify_parent();
errno = save_errno;
}
@ -127,7 +153,7 @@ sigchld_handler2(int sig)
* Make packets from buffered stderr data, and buffer it for sending
* to the client.
*/
void
static void
make_packets_from_stderr_data(void)
{
int len;
@ -156,7 +182,7 @@ make_packets_from_stderr_data(void)
* Make packets from buffered stdout data, and buffer it for sending to the
* client.
*/
void
static void
make_packets_from_stdout_data(void)
{
int len;
@ -181,44 +207,69 @@ make_packets_from_stdout_data(void)
}
}
static void
client_alive_check(void)
{
static int had_channel = 0;
int id;
id = channel_find_open();
if (id == -1) {
if (!had_channel)
return;
packet_disconnect("No open channels after timeout!");
}
had_channel = 1;
/* timeout, check to see how many we have had */
if (++client_alive_timeouts > options.client_alive_count_max)
packet_disconnect("Timeout, your session not responding.");
/*
* send a bogus channel request with "wantreply",
* we should get back a failure
*/
channel_request_start(id, "keepalive@openssh.com", 1);
packet_send();
}
/*
* Sleep in select() until we can do something. This will initialize the
* select masks. Upon return, the masks will indicate which descriptors
* have data or can accept data. Optionally, a maximum time can be specified
* for the duration of the wait (0 = infinite).
*/
void
static void
wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
u_int max_time_milliseconds)
int *nallocp, u_int max_time_milliseconds)
{
struct timeval tv, *tvp;
int ret;
int client_alive_scheduled = 0;
/*
* if using client_alive, set the max timeout accordingly,
* if using client_alive, set the max timeout accordingly,
* and indicate that this particular timeout was for client
* alive by setting the client_alive_scheduled flag.
*
* this could be randomized somewhat to make traffic
* analysis more difficult, but we're not doing it yet.
* analysis more difficult, but we're not doing it yet.
*/
if (max_time_milliseconds == 0 && options.client_alive_interval) {
client_alive_scheduled = 1;
if (compat20 &&
max_time_milliseconds == 0 && options.client_alive_interval) {
client_alive_scheduled = 1;
max_time_milliseconds = options.client_alive_interval * 1000;
} else
client_alive_scheduled = 0;
/* When select fails we restart from here. */
retry_select:
}
/* Allocate and update select() masks for channel descriptors. */
channel_prepare_select(readsetp, writesetp, maxfdp, 0);
channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, 0);
if (compat20) {
#if 0
/* wrong: bad condition XXX */
if (channel_not_very_much_buffered_data())
FD_SET(connection_in, *readsetp);
#endif
FD_SET(connection_in, *readsetp);
} else {
/*
* Read packets from the client unless we have too much
@ -244,6 +295,7 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
if (fdin != -1 && buffer_len(&stdin_buffer) > 0)
FD_SET(fdin, *writesetp);
}
notify_prepare(*readsetp);
/*
* If we have buffered packet data going to the client, mark that
@ -268,48 +320,28 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
tvp = &tv;
}
if (tvp!=NULL)
debug3("tvp!=NULL kid %d mili %d", child_terminated, max_time_milliseconds);
debug3("tvp!=NULL kid %d mili %d", (int) child_terminated,
max_time_milliseconds);
/* Wait for something to happen, or the timeout to expire. */
ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp);
if (ret == -1) {
memset(*readsetp, 0, *nallocp);
memset(*writesetp, 0, *nallocp);
if (errno != EINTR)
error("select: %.100s", strerror(errno));
else
goto retry_select;
}
if (ret == 0 && client_alive_scheduled) {
/* timeout, check to see how many we have had */
client_alive_timeouts++;
} else if (ret == 0 && client_alive_scheduled)
client_alive_check();
if (client_alive_timeouts > options.client_alive_count_max ) {
packet_disconnect(
"Timeout, your session not responding.");
} else {
/*
* send a bogus channel request with "wantreply"
* we should get back a failure
*/
int id;
id = channel_find_open();
if (id != -1) {
channel_request_start(id,
"keepalive@openssh.com", 1);
packet_send();
} else
packet_disconnect(
"No open channels after timeout!");
}
}
notify_done(*readsetp);
}
/*
* Processes input from the client and the program. Input data is stored
* in buffers and processed later.
*/
void
static void
process_input(fd_set * readset)
{
int len;
@ -365,31 +397,31 @@ process_input(fd_set * readset)
/*
* Sends data from internal buffers to client program stdin.
*/
void
static void
process_output(fd_set * writeset)
{
struct termios tio;
u_char *data;
u_int dlen;
int len;
/* Write buffered data to program stdin. */
if (!compat20 && fdin != -1 && FD_ISSET(fdin, writeset)) {
len = write(fdin, buffer_ptr(&stdin_buffer),
buffer_len(&stdin_buffer));
data = buffer_ptr(&stdin_buffer);
dlen = buffer_len(&stdin_buffer);
len = write(fdin, data, dlen);
if (len < 0 && (errno == EINTR || errno == EAGAIN)) {
/* do nothing */
} else if (len <= 0) {
#ifdef USE_PIPES
close(fdin);
#else
if (fdin != fdout)
close(fdin);
else
shutdown(fdin, SHUT_WR); /* We will no longer send. */
#endif
fdin = -1;
} else {
/* Successful write. */
if (fdin_is_tty && tcgetattr(fdin, &tio) == 0 &&
if (fdin_is_tty && dlen >= 1 && data[0] != '\r' &&
tcgetattr(fdin, &tio) == 0 &&
!(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) {
/*
* Simulate echo to reduce the impact of
@ -413,7 +445,7 @@ process_output(fd_set * writeset)
* Wait until all buffered output has been sent to the client.
* This is used when the program terminates.
*/
void
static void
drain_output(void)
{
/* Send any buffered stdout data to the client. */
@ -438,7 +470,7 @@ drain_output(void)
packet_write_wait();
}
void
static void
process_buffered_input_packets(void)
{
dispatch_run(DISPATCH_NONBLOCK, NULL, compat20 ? xxx_kex : NULL);
@ -455,7 +487,7 @@ void
server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
{
fd_set *readset = NULL, *writeset = NULL;
int max_fd;
int max_fd = 0, nalloc = 0;
int wait_status; /* Status returned by wait(). */
pid_t wait_pid; /* pid returned by wait(). */
int waiting_termination = 0; /* Have displayed waiting close message. */
@ -467,7 +499,6 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
debug("Entering interactive session.");
/* Initialize the SIGCHLD kludge. */
child_pid = pid;
child_terminated = 0;
signal(SIGCHLD, sigchld_handler);
@ -489,6 +520,8 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
connection_in = packet_get_connection_in();
connection_out = packet_get_connection_out();
notify_setup();
previous_stdout_buffer_bytes = 0;
/* Set approximate I/O buffer size. */
@ -497,12 +530,14 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
else
buffer_high = 64 * 1024;
#if 0
/* Initialize max_fd to the maximum of the known file descriptors. */
max_fd = MAX(fdin, fdout);
max_fd = MAX(connection_in, connection_out);
max_fd = MAX(max_fd, fdin);
max_fd = MAX(max_fd, fdout);
if (fderr != -1)
max_fd = MAX(max_fd, fderr);
max_fd = MAX(max_fd, connection_in);
max_fd = MAX(max_fd, connection_out);
#endif
/* Initialize Initialize buffers. */
buffer_init(&stdin_buffer);
@ -531,14 +566,10 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
* input data, cause a real eof by closing fdin.
*/
if (stdin_eof && fdin != -1 && buffer_len(&stdin_buffer) == 0) {
#ifdef USE_PIPES
close(fdin);
#else
if (fdin != fdout)
close(fdin);
else
shutdown(fdin, SHUT_WR); /* We will no longer send. */
#endif
fdin = -1;
}
/* Make packets from buffered stderr data to send to the client. */
@ -588,9 +619,15 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
xfree(cp);
}
}
max_fd = MAX(connection_in, connection_out);
max_fd = MAX(max_fd, fdin);
max_fd = MAX(max_fd, fdout);
max_fd = MAX(max_fd, fderr);
max_fd = MAX(max_fd, notify_pipe[0]);
/* Sleep in select() until we can do something. */
wait_until_can_do_something(&readset, &writeset, &max_fd,
max_time_milliseconds);
&nalloc, max_time_milliseconds);
/* Process any channel events. */
channel_after_select(readset, writeset);
@ -612,7 +649,7 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
drain_output();
debug("End of interactive session; stdin %ld, stdout (read %ld, sent %ld), stderr %ld bytes.",
stdin_bytes, fdout_bytes, stdout_bytes, stderr_bytes);
stdin_bytes, fdout_bytes, stdout_bytes, stderr_bytes);
/* Free and clear the buffers. */
buffer_free(&stdin_buffer);
@ -632,31 +669,18 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
close(fdin);
fdin = -1;
/* Stop listening for channels; this removes unix domain sockets. */
channel_stop_listening();
/* Wait for the child to exit. Get its exit status. */
wait_pid = wait(&wait_status);
if (wait_pid == -1) {
/*
* It is possible that the wait was handled by SIGCHLD
* handler. This may result in either: this call
* returning with EINTR, or: this call returning ECHILD.
*/
if (child_terminated)
wait_status = child_wait_status;
else
packet_disconnect("wait: %.100s", strerror(errno));
} else {
/* Check if it matches the process we forked. */
if (wait_pid != pid)
error("Strange, wait returned pid %d, expected %d",
wait_pid, pid);
}
channel_free_all();
/* We no longer want our SIGCHLD handler to be called. */
signal(SIGCHLD, SIG_DFL);
wait_pid = waitpid(-1, &wait_status, 0);
if (wait_pid == -1)
packet_disconnect("wait: %.100s", strerror(errno));
else if (wait_pid != pid)
error("Strange, wait returned pid %d, expected %d",
wait_pid, pid);
/* Check if it exited normally. */
if (WIFEXITED(wait_status)) {
/* Yes, normal exit. Get exit status and send it to the client. */
@ -674,8 +698,7 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
* the exit status.
*/
do {
int plen;
type = packet_read(&plen);
type = packet_read();
}
while (type != SSH_CMSG_EXIT_CONFIRMATION);
@ -692,21 +715,44 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
/* NOTREACHED */
}
static void
collect_children(void)
{
pid_t pid;
sigset_t oset, nset;
int status;
/* block SIGCHLD while we check for dead children */
sigemptyset(&nset);
sigaddset(&nset, SIGCHLD);
sigprocmask(SIG_BLOCK, &nset, &oset);
if (child_terminated) {
while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
session_close_by_pid(pid, status);
child_terminated = 0;
}
sigprocmask(SIG_SETMASK, &oset, NULL);
}
void
server_loop2(void)
server_loop2(Authctxt *authctxt)
{
fd_set *readset = NULL, *writeset = NULL;
int rekeying = 0, max_fd, status;
pid_t pid;
int rekeying = 0, max_fd, nalloc = 0;
debug("Entering interactive session for SSH2.");
signal(SIGCHLD, sigchld_handler2);
signal(SIGCHLD, sigchld_handler);
child_terminated = 0;
connection_in = packet_get_connection_in();
connection_out = packet_get_connection_out();
notify_setup();
max_fd = MAX(connection_in, connection_out);
max_fd = MAX(max_fd, notify_pipe[0]);
xxx_authctxt = authctxt;
server_init_dispatch();
@ -718,12 +764,9 @@ server_loop2(void)
if (!rekeying && packet_not_very_much_data_to_write())
channel_output_poll();
wait_until_can_do_something(&readset, &writeset, &max_fd,
rekeying);
if (child_terminated) {
while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
session_close_by_pid(pid, status);
child_terminated = 0;
}
&nalloc, 0);
collect_children();
if (!rekeying)
channel_after_select(readset, writeset);
process_input(readset);
@ -731,32 +774,35 @@ server_loop2(void)
break;
process_output(writeset);
}
collect_children();
if (readset)
xfree(readset);
if (writeset)
xfree(writeset);
signal(SIGCHLD, SIG_DFL);
while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
session_close_by_pid(pid, status);
channel_stop_listening();
/* free all channels, no more reads and writes */
channel_free_all();
/* free remaining sessions, e.g. remove wtmp entries */
session_destroy_all();
}
void
server_input_channel_failure(int type, int plen, void *ctxt)
static void
server_input_channel_failure(int type, u_int32_t seq, void *ctxt)
{
debug("Got CHANNEL_FAILURE for keepalive");
/*
* reset timeout, since we got a sane answer from the client.
/*
* reset timeout, since we got a sane answer from the client.
* even if this was generated by something other than
* the bogus CHANNEL_REQUEST we send for keepalives.
*/
client_alive_timeouts = 0;
client_alive_timeouts = 0;
}
void
server_input_stdin_data(int type, int plen, void *ctxt)
static void
server_input_stdin_data(int type, u_int32_t seq, void *ctxt)
{
char *data;
u_int data_len;
@ -766,14 +812,14 @@ server_input_stdin_data(int type, int plen, void *ctxt)
if (fdin == -1)
return;
data = packet_get_string(&data_len);
packet_integrity_check(plen, (4 + data_len), type);
packet_check_eom();
buffer_append(&stdin_buffer, data, data_len);
memset(data, 0, data_len);
xfree(data);
}
void
server_input_eof(int type, int plen, void *ctxt)
static void
server_input_eof(int type, u_int32_t seq, void *ctxt)
{
/*
* Eof from the client. The stdin descriptor to the
@ -781,12 +827,12 @@ server_input_eof(int type, int plen, void *ctxt)
* drained.
*/
debug("EOF received for stdin.");
packet_integrity_check(plen, 0, type);
packet_check_eom();
stdin_eof = 1;
}
void
server_input_window_size(int type, int plen, void *ctxt)
static void
server_input_window_size(int type, u_int32_t seq, void *ctxt)
{
int row = packet_get_int();
int col = packet_get_int();
@ -794,15 +840,16 @@ server_input_window_size(int type, int plen, void *ctxt)
int ypixel = packet_get_int();
debug("Window change received.");
packet_integrity_check(plen, 4 * 4, type);
packet_check_eom();
if (fdin != -1)
pty_change_window_size(fdin, row, col, xpixel, ypixel);
}
Channel *
static Channel *
server_request_direct_tcpip(char *ctype)
{
int sock, newch;
Channel *c;
int sock;
char *target, *originator;
int target_port, originator_port;
@ -810,7 +857,7 @@ server_request_direct_tcpip(char *ctype)
target_port = packet_get_int();
originator = packet_get_string(NULL);
originator_port = packet_get_int();
packet_done();
packet_check_eom();
debug("server_request_direct_tcpip: originator %s port %d, target %s port %d",
originator, originator_port, target, target_port);
@ -821,42 +868,39 @@ server_request_direct_tcpip(char *ctype)
xfree(originator);
if (sock < 0)
return NULL;
newch = channel_new(ctype, SSH_CHANNEL_CONNECTING,
c = channel_new(ctype, SSH_CHANNEL_CONNECTING,
sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT,
CHAN_TCP_PACKET_DEFAULT, 0, xstrdup("direct-tcpip"), 1);
return (newch >= 0) ? channel_lookup(newch) : NULL;
return c;
}
Channel *
static Channel *
server_request_session(char *ctype)
{
int newch;
Channel *c;
debug("input_session_request");
packet_done();
packet_check_eom();
/*
* A server session has no fd to read or write until a
* CHANNEL_REQUEST for a shell is made, so we set the type to
* SSH_CHANNEL_LARVAL. Additionally, a callback for handling all
* CHANNEL_REQUEST messages is registered.
*/
newch = channel_new(ctype, SSH_CHANNEL_LARVAL,
-1, -1, -1, 0, CHAN_SES_PACKET_DEFAULT,
c = channel_new(ctype, SSH_CHANNEL_LARVAL,
-1, -1, -1, /*window size*/0, CHAN_SES_PACKET_DEFAULT,
0, xstrdup("server-session"), 1);
if (session_open(newch) == 1) {
channel_register_callback(newch, SSH2_MSG_CHANNEL_REQUEST,
session_input_channel_req, (void *)0);
channel_register_cleanup(newch, session_close_by_channel);
return channel_lookup(newch);
} else {
debug("session open failed, free channel %d", newch);
channel_free(newch);
if (session_open(xxx_authctxt, c->self) != 1) {
debug("session open failed, free channel %d", c->self);
channel_free(c);
return NULL;
}
return NULL;
channel_register_cleanup(c->self, session_close_by_channel);
return c;
}
void
server_input_channel_open(int type, int plen, void *ctxt)
static void
server_input_channel_open(int type, u_int32_t seq, void *ctxt)
{
Channel *c = NULL;
char *ctype;
@ -883,27 +927,30 @@ server_input_channel_open(int type, int plen, void *ctxt)
c->remote_id = rchan;
c->remote_window = rwindow;
c->remote_maxpacket = rmaxpack;
packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
packet_put_int(c->remote_id);
packet_put_int(c->self);
packet_put_int(c->local_window);
packet_put_int(c->local_maxpacket);
packet_send();
if (c->type != SSH_CHANNEL_CONNECTING) {
packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
packet_put_int(c->remote_id);
packet_put_int(c->self);
packet_put_int(c->local_window);
packet_put_int(c->local_maxpacket);
packet_send();
}
} else {
debug("server_input_channel_open: failure %s", ctype);
packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
packet_put_int(rchan);
packet_put_int(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED);
packet_put_cstring("bla bla");
packet_put_cstring("");
if (!(datafellows & SSH_BUG_OPENFAILURE)) {
packet_put_cstring("open failed");
packet_put_cstring("");
}
packet_send();
}
xfree(ctype);
}
void
server_input_global_request(int type, int plen, void *ctxt)
static void
server_input_global_request(int type, u_int32_t seq, void *ctxt)
{
char *rtype;
int want_reply;
@ -935,11 +982,8 @@ server_input_global_request(int type, int plen, void *ctxt)
packet_send_debug("Server has disabled port forwarding.");
} else {
/* Start listening on the port */
success = channel_request_forwarding(
listen_address, listen_port,
/*unspec host_to_connect*/ "<unspec host>",
/*unspec port_to_connect*/ 0,
options.gateway_ports, /*remote*/ 1);
success = channel_setup_remote_fwd_listener(
listen_address, listen_port, options.gateway_ports);
}
xfree(listen_address);
}
@ -951,8 +995,35 @@ server_input_global_request(int type, int plen, void *ctxt)
}
xfree(rtype);
}
static void
server_input_channel_req(int type, u_int32_t seq, void *ctxt)
{
Channel *c;
int id, reply, success = 0;
char *rtype;
void
id = packet_get_int();
rtype = packet_get_string(NULL);
reply = packet_get_char();
debug("server_input_channel_req: channel %d request %s reply %d",
id, rtype, reply);
if ((c = channel_lookup(id)) == NULL)
packet_disconnect("server_input_channel_req: "
"unknown channel %d", id);
if (c->type == SSH_CHANNEL_LARVAL || c->type == SSH_CHANNEL_OPEN)
success = session_input_channel_req(c, rtype);
if (reply) {
packet_start(success ?
SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
packet_put_int(c->remote_id);
packet_send();
}
xfree(rtype);
}
static void
server_init_dispatch_20(void)
{
debug("server_init_dispatch_20");
@ -964,7 +1035,7 @@ server_init_dispatch_20(void)
dispatch_set(SSH2_MSG_CHANNEL_OPEN, &server_input_channel_open);
dispatch_set(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &channel_input_channel_request);
dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &server_input_channel_req);
dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust);
dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &server_input_global_request);
/* client_alive */
@ -972,7 +1043,7 @@ server_init_dispatch_20(void)
/* rekeying */
dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit);
}
void
static void
server_init_dispatch_13(void)
{
debug("server_init_dispatch_13");
@ -987,7 +1058,7 @@ server_init_dispatch_13(void)
dispatch_set(SSH_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open);
}
void
static void
server_init_dispatch_15(void)
{
server_init_dispatch_13();
@ -995,7 +1066,7 @@ server_init_dispatch_15(void)
dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof);
dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_oclose);
}
void
static void
server_init_dispatch(void)
{
if (compat20)
@ -1005,4 +1076,3 @@ server_init_dispatch(void)
else
server_init_dispatch_15();
}

File diff suppressed because it is too large Load diff

View file

@ -11,7 +11,7 @@
* called by a name other than "ssh" or "Secure Shell".
*
* SSH2 implementation,
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -35,8 +35,8 @@
*/
#include "includes.h"
RCSID("$OpenBSD: ssh-add.c,v 1.50 2002/01/29 14:27:57 markus Exp $");
RCSID("$FreeBSD$");
RCSID("$OpenBSD: ssh-add.c,v 1.36 2001/04/18 21:57:42 markus Exp $");
#include <openssl/evp.h>
@ -50,9 +50,21 @@ RCSID("$OpenBSD: ssh-add.c,v 1.36 2001/04/18 21:57:42 markus Exp $");
#include "pathnames.h"
#include "readpass.h"
/* argv0 */
extern char *__progname;
/* Default files to add */
static char *default_files[] = {
_PATH_SSH_CLIENT_ID_RSA,
_PATH_SSH_CLIENT_ID_DSA,
_PATH_SSH_CLIENT_IDENTITY,
NULL
};
/* we keep a cache of one passphrases */
static char *pass = NULL;
void
static void
clear_pass(void)
{
if (pass) {
@ -62,53 +74,61 @@ clear_pass(void)
}
}
void
static int
delete_file(AuthenticationConnection *ac, const char *filename)
{
Key *public;
char *comment = NULL;
int ret = -1;
public = key_load_public(filename, &comment);
if (public == NULL) {
printf("Bad key file %s\n", filename);
return;
return -1;
}
if (ssh_remove_identity(ac, public))
if (ssh_remove_identity(ac, public)) {
fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment);
else
ret = 0;
} else
fprintf(stderr, "Could not remove identity: %s\n", filename);
key_free(public);
xfree(comment);
return ret;
}
/* Send a request to remove all identities. */
void
static int
delete_all(AuthenticationConnection *ac)
{
int success = 1;
int ret = -1;
if (!ssh_remove_all_identities(ac, 1))
success = 0;
if (ssh_remove_all_identities(ac, 1))
ret = 0;
/* ignore error-code for ssh2 */
ssh_remove_all_identities(ac, 2);
if (success)
if (ret == 0)
fprintf(stderr, "All identities removed.\n");
else
fprintf(stderr, "Failed to remove all identities.\n");
return ret;
}
void
static int
add_file(AuthenticationConnection *ac, const char *filename)
{
struct stat st;
Key *private;
char *comment = NULL;
char msg[1024];
int ret = -1;
if (stat(filename, &st) < 0) {
perror(filename);
exit(1);
return -1;
}
/* At first, try empty passphrase */
private = key_load_private(filename, "", &comment);
@ -120,15 +140,14 @@ add_file(AuthenticationConnection *ac, const char *filename)
if (private == NULL) {
/* clear passphrase since it did not work */
clear_pass();
printf("Need passphrase for %.200s\n", filename);
snprintf(msg, sizeof msg, "Enter passphrase for %.200s: ",
comment);
for (;;) {
pass = read_passphrase(msg, 1);
pass = read_passphrase(msg, RP_ALLOW_STDIN);
if (strcmp(pass, "") == 0) {
clear_pass();
xfree(comment);
return;
return -1;
}
private = key_load_private(filename, pass, &comment);
if (private != NULL)
@ -137,15 +156,33 @@ add_file(AuthenticationConnection *ac, const char *filename)
strlcpy(msg, "Bad passphrase, try again: ", sizeof msg);
}
}
if (ssh_add_identity(ac, private, comment))
if (ssh_add_identity(ac, private, comment)) {
fprintf(stderr, "Identity added: %s (%s)\n", filename, comment);
else
ret = 0;
} else
fprintf(stderr, "Could not add identity: %s\n", filename);
xfree(comment);
key_free(private);
return ret;
}
void
static int
update_card(AuthenticationConnection *ac, int add, const char *id)
{
if (ssh_update_card(ac, add, id)) {
fprintf(stderr, "Card %s: %s\n",
add ? "added" : "removed", id);
return 0;
} else {
fprintf(stderr, "Could not %s card: %s\n",
add ? "add" : "remove", id);
return -1;
}
}
static int
list_identities(AuthenticationConnection *ac, int do_fp)
{
Key *key;
@ -155,8 +192,8 @@ list_identities(AuthenticationConnection *ac, int do_fp)
for (version = 1; version <= 2; version++) {
for (key = ssh_get_first_identity(ac, &comment, version);
key != NULL;
key = ssh_get_next_identity(ac, &comment, version)) {
key != NULL;
key = ssh_get_next_identity(ac, &comment, version)) {
had_identities = 1;
if (do_fp) {
fp = key_fingerprint(key, SSH_FP_MD5,
@ -173,19 +210,49 @@ list_identities(AuthenticationConnection *ac, int do_fp)
xfree(comment);
}
}
if (!had_identities)
if (!had_identities) {
printf("The agent has no identities.\n");
return -1;
}
return 0;
}
static int
do_file(AuthenticationConnection *ac, int deleting, char *file)
{
if (deleting) {
if (delete_file(ac, file) == -1)
return -1;
} else {
if (add_file(ac, file) == -1)
return -1;
}
return 0;
}
static void
usage(void)
{
fprintf(stderr, "Usage: %s [options]\n", __progname);
fprintf(stderr, "Options:\n");
fprintf(stderr, " -l List fingerprints of all identities.\n");
fprintf(stderr, " -L List public key parameters of all identities.\n");
fprintf(stderr, " -d Delete identity.\n");
fprintf(stderr, " -D Delete all identities.\n");
#ifdef SMARTCARD
fprintf(stderr, " -s reader Add key in smartcard reader.\n");
fprintf(stderr, " -e reader Remove key in smartcard reader.\n");
#endif
}
int
main(int argc, char **argv)
{
extern char *optarg;
extern int optind;
AuthenticationConnection *ac = NULL;
struct passwd *pw;
char buf[1024];
int no_files = 1;
int i;
int deleting = 0;
char *sc_reader_id = NULL;
int i, ch, deleting = 0, ret = 0;
SSLeay_add_all_algorithms();
@ -193,46 +260,70 @@ main(int argc, char **argv)
ac = ssh_get_authentication_connection();
if (ac == NULL) {
fprintf(stderr, "Could not open a connection to your authentication agent.\n");
exit(1);
exit(2);
}
for (i = 1; i < argc; i++) {
if ((strcmp(argv[i], "-l") == 0) ||
(strcmp(argv[i], "-L") == 0)) {
list_identities(ac, argv[i][1] == 'l' ? 1 : 0);
/* Don't default-add/delete if -l. */
no_files = 0;
continue;
}
if (strcmp(argv[i], "-d") == 0) {
while ((ch = getopt(argc, argv, "lLdDe:s:")) != -1) {
switch (ch) {
case 'l':
case 'L':
if (list_identities(ac, ch == 'l' ? 1 : 0) == -1)
ret = 1;
goto done;
break;
case 'd':
deleting = 1;
continue;
break;
case 'D':
if (delete_all(ac) == -1)
ret = 1;
goto done;
break;
case 's':
sc_reader_id = optarg;
break;
case 'e':
deleting = 1;
sc_reader_id = optarg;
break;
default:
usage();
ret = 1;
goto done;
}
if (strcmp(argv[i], "-D") == 0) {
delete_all(ac);
no_files = 0;
continue;
}
no_files = 0;
if (deleting)
delete_file(ac, argv[i]);
else
add_file(ac, argv[i]);
}
if (no_files) {
pw = getpwuid(getuid());
if (!pw) {
argc -= optind;
argv += optind;
if (sc_reader_id != NULL) {
if (update_card(ac, !deleting, sc_reader_id) == -1)
ret = 1;
goto done;
}
if (argc == 0) {
char buf[MAXPATHLEN];
struct passwd *pw;
if ((pw = getpwuid(getuid())) == NULL) {
fprintf(stderr, "No user found with uid %u\n",
(u_int)getuid());
ssh_close_authentication_connection(ac);
exit(1);
ret = 1;
goto done;
}
for(i = 0; default_files[i]; i++) {
snprintf(buf, sizeof(buf), "%s/%s", pw->pw_dir,
default_files[i]);
if (do_file(ac, deleting, buf) == -1)
ret = 1;
}
} else {
for(i = 0; i < argc; i++) {
if (do_file(ac, deleting, argv[i]) == -1)
ret = 1;
}
snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, _PATH_SSH_CLIENT_IDENTITY);
if (deleting)
delete_file(ac, buf);
else
add_file(ac, buf);
}
clear_pass();
done:
ssh_close_authentication_connection(ac);
exit(0);
return ret;
}

View file

@ -1,5 +1,3 @@
/* $OpenBSD: ssh-agent.c,v 1.54 2001/04/03 13:56:11 stevesk Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -12,8 +10,7 @@
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*
* SSH2 implementation,
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -37,7 +34,8 @@
*/
#include "includes.h"
RCSID("$OpenBSD: ssh-agent.c,v 1.54 2001/04/03 13:56:11 stevesk Exp $");
#include <sys/queue.h>
RCSID("$OpenBSD: ssh-agent.c,v 1.82 2002/03/04 17:27:39 stevesk Exp $");
RCSID("$FreeBSD$");
#include <openssl/evp.h>
@ -48,21 +46,26 @@ RCSID("$FreeBSD$");
#include "buffer.h"
#include "bufaux.h"
#include "xmalloc.h"
#include "packet.h"
#include "getput.h"
#include "mpaux.h"
#include "key.h"
#include "authfd.h"
#include "cipher.h"
#include "kex.h"
#include "compat.h"
#include "log.h"
#ifdef SMARTCARD
#include <openssl/engine.h>
#include "scard.h"
#endif
typedef enum {
AUTH_UNUSED,
AUTH_SOCKET,
AUTH_CONNECTION
} sock_type;
typedef struct {
int fd;
enum {
AUTH_UNUSED, AUTH_SOCKET, AUTH_CONNECTION
} type;
sock_type type;
Buffer input;
Buffer output;
} SocketEntry;
@ -70,14 +73,15 @@ typedef struct {
u_int sockets_alloc = 0;
SocketEntry *sockets = NULL;
typedef struct {
typedef struct identity {
TAILQ_ENTRY(identity) next;
Key *key;
char *comment;
} Identity;
typedef struct {
int nentries;
Identity *identities;
TAILQ_HEAD(idqueue, identity) idlist;
} Idtab;
/* private key table, one per protocol version */
@ -94,20 +98,18 @@ char socket_dir[1024];
extern char *__progname;
int prepare_select(fd_set **, fd_set **, int *);
void
static void
idtab_init(void)
{
int i;
for (i = 0; i <=2; i++){
idtable[i].identities = NULL;
for (i = 0; i <=2; i++) {
TAILQ_INIT(&idtable[i].idlist);
idtable[i].nentries = 0;
}
}
/* return private key table for requested protocol version */
Idtab *
static Idtab *
idtab_lookup(int version)
{
if (version < 1 || version > 2)
@ -116,35 +118,40 @@ idtab_lookup(int version)
}
/* return matching private key for given public key */
Key *
lookup_private_key(Key *key, int *idx, int version)
static Identity *
lookup_identity(Key *key, int version)
{
int i;
Identity *id;
Idtab *tab = idtab_lookup(version);
for (i = 0; i < tab->nentries; i++) {
if (key_equal(key, tab->identities[i].key)) {
if (idx != NULL)
*idx = i;
return tab->identities[i].key;
}
TAILQ_FOREACH(id, &tab->idlist, next) {
if (key_equal(key, id->key))
return (id);
}
return NULL;
return (NULL);
}
static void
free_identity(Identity *id)
{
key_free(id->key);
xfree(id->comment);
xfree(id);
}
/* send list of supported public keys to 'client' */
void
static void
process_request_identities(SocketEntry *e, int version)
{
Idtab *tab = idtab_lookup(version);
Buffer msg;
int i;
Identity *id;
buffer_init(&msg);
buffer_put_char(&msg, (version == 1) ?
SSH_AGENT_RSA_IDENTITIES_ANSWER : SSH2_AGENT_IDENTITIES_ANSWER);
buffer_put_int(&msg, tab->nentries);
for (i = 0; i < tab->nentries; i++) {
Identity *id = &tab->identities[i];
TAILQ_FOREACH(id, &tab->idlist, next) {
if (id->key->type == KEY_RSA1) {
buffer_put_int(&msg, BN_num_bits(id->key->rsa->n));
buffer_put_bignum(&msg, id->key->rsa->e);
@ -164,10 +171,11 @@ process_request_identities(SocketEntry *e, int version)
}
/* ssh1 only */
void
static void
process_authentication_challenge1(SocketEntry *e)
{
Key *key, *private;
Identity *id;
Key *key;
BIGNUM *challenge;
int i, len;
Buffer msg;
@ -177,7 +185,8 @@ process_authentication_challenge1(SocketEntry *e)
buffer_init(&msg);
key = key_new(KEY_RSA1);
challenge = BN_new();
if ((challenge = BN_new()) == NULL)
fatal("process_authentication_challenge1: BN_new failed");
buffer_get_int(&e->input); /* ignored */
buffer_get_bignum(&e->input, key->rsa->e);
@ -187,13 +196,14 @@ process_authentication_challenge1(SocketEntry *e)
/* Only protocol 1.1 is supported */
if (buffer_len(&e->input) == 0)
goto failure;
buffer_get(&e->input, (char *) session_id, 16);
buffer_get(&e->input, session_id, 16);
response_type = buffer_get_int(&e->input);
if (response_type != 1)
goto failure;
private = lookup_private_key(key, NULL, 1);
if (private != NULL) {
id = lookup_identity(key, 1);
if (id != NULL) {
Key *private = id->key;
/* Decrypt the challenge using the private key. */
if (rsa_private_decrypt(challenge, challenge, private->rsa) <= 0)
goto failure;
@ -230,11 +240,11 @@ process_authentication_challenge1(SocketEntry *e)
}
/* ssh2 only */
void
static void
process_sign_request2(SocketEntry *e)
{
extern int datafellows;
Key *key, *private;
Key *key;
u_char *blob, *data, *signature = NULL;
u_int blen, dlen, slen = 0;
int flags;
@ -252,9 +262,9 @@ process_sign_request2(SocketEntry *e)
key = key_from_blob(blob, blen);
if (key != NULL) {
private = lookup_private_key(key, NULL, 2);
if (private != NULL)
ok = key_sign(private, &signature, &slen, data, dlen);
Identity *id = lookup_identity(key, 2);
if (id != NULL)
ok = key_sign(id->key, &signature, &slen, data, dlen);
}
key_free(key);
buffer_init(&msg);
@ -275,16 +285,16 @@ process_sign_request2(SocketEntry *e)
}
/* shared */
void
static void
process_remove_identity(SocketEntry *e, int version)
{
Key *key = NULL, *private;
Key *key = NULL;
u_char *blob;
u_int blen;
u_int bits;
int success = 0;
switch(version){
switch (version) {
case 1:
key = key_new(KEY_RSA1);
bits = buffer_get_int(&e->input);
@ -302,9 +312,8 @@ process_remove_identity(SocketEntry *e, int version)
break;
}
if (key != NULL) {
int idx;
private = lookup_private_key(key, &idx, version);
if (private != NULL) {
Identity *id = lookup_identity(key, version);
if (id != NULL) {
/*
* We have this key. Free the old key. Since we
* don\'t want to leave empty slots in the middle of
@ -313,19 +322,12 @@ process_remove_identity(SocketEntry *e, int version)
* of the array.
*/
Idtab *tab = idtab_lookup(version);
key_free(tab->identities[idx].key);
xfree(tab->identities[idx].comment);
if (tab->nentries < 1)
fatal("process_remove_identity: "
"internal error: tab->nentries %d",
tab->nentries);
if (idx != tab->nentries - 1) {
int i;
for (i = idx; i < tab->nentries - 1; i++)
tab->identities[i] = tab->identities[i+1];
}
tab->identities[tab->nentries - 1].key = NULL;
tab->identities[tab->nentries - 1].comment = NULL;
TAILQ_REMOVE(&tab->idlist, id, next);
free_identity(id);
tab->nentries--;
success = 1;
}
@ -336,16 +338,17 @@ process_remove_identity(SocketEntry *e, int version)
success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
}
void
static void
process_remove_all_identities(SocketEntry *e, int version)
{
u_int i;
Idtab *tab = idtab_lookup(version);
Identity *id;
/* Loop over all identities and clear the keys. */
for (i = 0; i < tab->nentries; i++) {
key_free(tab->identities[i].key);
xfree(tab->identities[i].comment);
for (id = TAILQ_FIRST(&tab->idlist); id;
id = TAILQ_FIRST(&tab->idlist)) {
TAILQ_REMOVE(&tab->idlist, id, next);
free_identity(id);
}
/* Mark that there are no identities. */
@ -357,7 +360,7 @@ process_remove_all_identities(SocketEntry *e, int version)
return;
}
void
static void
process_add_identity(SocketEntry *e, int version)
{
Key *k = NULL;
@ -380,13 +383,13 @@ process_add_identity(SocketEntry *e, int version)
buffer_get_bignum(&e->input, k->rsa->p); /* q */
/* Generate additional parameters */
generate_additional_parameters(k->rsa);
rsa_generate_additional_parameters(k->rsa);
break;
case 2:
type_name = buffer_get_string(&e->input, NULL);
type = key_type_from_name(type_name);
xfree(type_name);
switch(type) {
switch (type) {
case KEY_DSA:
k = key_new_private(type);
buffer_get_bignum2(&e->input, k->dsa->p);
@ -405,7 +408,7 @@ process_add_identity(SocketEntry *e, int version)
buffer_get_bignum2(&e->input, k->rsa->q);
/* Generate additional parameters */
generate_additional_parameters(k->rsa);
rsa_generate_additional_parameters(k->rsa);
break;
default:
buffer_clear(&e->input);
@ -419,14 +422,11 @@ process_add_identity(SocketEntry *e, int version)
goto send;
}
success = 1;
if (lookup_private_key(k, NULL, version) == NULL) {
if (tab->nentries == 0)
tab->identities = xmalloc(sizeof(Identity));
else
tab->identities = xrealloc(tab->identities,
(tab->nentries + 1) * sizeof(Identity));
tab->identities[tab->nentries].key = k;
tab->identities[tab->nentries].comment = comment;
if (lookup_identity(k, version) == NULL) {
Identity *id = xmalloc(sizeof(Identity));
id->key = k;
id->comment = comment;
TAILQ_INSERT_TAIL(&tab->idlist, id, next);
/* Increment the number of identities. */
tab->nentries++;
} else {
@ -439,9 +439,104 @@ process_add_identity(SocketEntry *e, int version)
success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
}
#ifdef SMARTCARD
static void
process_add_smartcard_key (SocketEntry *e)
{
Idtab *tab;
Key *n = NULL, *k = NULL;
char *sc_reader_id = NULL;
int success = 0;
sc_reader_id = buffer_get_string(&e->input, NULL);
k = sc_get_key(sc_reader_id);
xfree(sc_reader_id);
if (k == NULL) {
error("sc_get_pubkey failed");
goto send;
}
success = 1;
tab = idtab_lookup(1);
k->type = KEY_RSA1;
if (lookup_identity(k, 1) == NULL) {
Identity *id = xmalloc(sizeof(Identity));
n = key_new(KEY_RSA1);
BN_copy(n->rsa->n, k->rsa->n);
BN_copy(n->rsa->e, k->rsa->e);
RSA_set_method(n->rsa, sc_get_engine());
id->key = n;
id->comment = xstrdup("rsa1 smartcard");
TAILQ_INSERT_TAIL(&tab->idlist, id, next);
tab->nentries++;
}
k->type = KEY_RSA;
tab = idtab_lookup(2);
if (lookup_identity(k, 2) == NULL) {
Identity *id = xmalloc(sizeof(Identity));
n = key_new(KEY_RSA);
BN_copy(n->rsa->n, k->rsa->n);
BN_copy(n->rsa->e, k->rsa->e);
RSA_set_method(n->rsa, sc_get_engine());
id->key = n;
id->comment = xstrdup("rsa smartcard");
TAILQ_INSERT_TAIL(&tab->idlist, id, next);
tab->nentries++;
}
key_free(k);
send:
buffer_put_int(&e->output, 1);
buffer_put_char(&e->output,
success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
}
static void
process_remove_smartcard_key(SocketEntry *e)
{
Key *k = NULL;
int success = 0;
char *sc_reader_id = NULL;
sc_reader_id = buffer_get_string(&e->input, NULL);
k = sc_get_key(sc_reader_id);
xfree(sc_reader_id);
if (k == NULL) {
error("sc_get_pubkey failed");
} else {
Identity *id;
k->type = KEY_RSA1;
id = lookup_identity(k, 1);
if (id != NULL) {
Idtab *tab = idtab_lookup(1);
TAILQ_REMOVE(&tab->idlist, id, next);
free_identity(id);
tab->nentries--;
success = 1;
}
k->type = KEY_RSA;
id = lookup_identity(k, 2);
if (id != NULL) {
Idtab *tab = idtab_lookup(2);
TAILQ_REMOVE(&tab->idlist, id, next);
free_identity(id);
tab->nentries--;
success = 1;
}
key_free(k);
}
buffer_put_int(&e->output, 1);
buffer_put_char(&e->output,
success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
}
#endif /* SMARTCARD */
/* dispatch incoming messages */
void
static void
process_message(SocketEntry *e)
{
u_int msg_len;
@ -449,7 +544,7 @@ process_message(SocketEntry *e)
u_char *cp;
if (buffer_len(&e->input) < 5)
return; /* Incomplete message. */
cp = (u_char *) buffer_ptr(&e->input);
cp = buffer_ptr(&e->input);
msg_len = GET_32BIT(cp);
if (msg_len > 256 * 1024) {
shutdown(e->fd, SHUT_RDWR);
@ -462,6 +557,7 @@ process_message(SocketEntry *e)
buffer_consume(&e->input, 4);
type = buffer_get_char(&e->input);
debug("type %d", type);
switch (type) {
/* ssh1 */
case SSH_AGENTC_RSA_CHALLENGE:
@ -495,6 +591,14 @@ process_message(SocketEntry *e)
case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
process_remove_all_identities(e, 2);
break;
#ifdef SMARTCARD
case SSH_AGENTC_ADD_SMARTCARD_KEY:
process_add_smartcard_key(e);
break;
case SSH_AGENTC_REMOVE_SMARTCARD_KEY:
process_remove_smartcard_key(e);
break;
#endif /* SMARTCARD */
default:
/* Unknown message. Respond with failure. */
error("Unknown message %d", type);
@ -505,8 +609,8 @@ process_message(SocketEntry *e)
}
}
void
new_socket(int type, int fd)
static void
new_socket(sock_type type, int fd)
{
u_int i, old_alloc;
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
@ -537,8 +641,8 @@ new_socket(int type, int fd)
buffer_init(&sockets[old_alloc].output);
}
int
prepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl)
static int
prepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl, int *nallocp)
{
u_int i, sz;
int n = 0;
@ -558,15 +662,18 @@ prepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl)
}
sz = howmany(n+1, NFDBITS) * sizeof(fd_mask);
if (*fdrp == NULL || n > *fdl) {
if (*fdrp == NULL || sz > *nallocp) {
if (*fdrp)
xfree(*fdrp);
if (*fdwp)
xfree(*fdwp);
*fdrp = xmalloc(sz);
*fdwp = xmalloc(sz);
*fdl = n;
*nallocp = sz;
}
if (n < *fdl)
debug("XXX shrink: %d < %d", n, *fdl);
*fdl = n;
memset(*fdrp, 0, sz);
memset(*fdwp, 0, sz);
@ -585,7 +692,7 @@ prepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl)
return (1);
}
void
static void
after_select(fd_set *readset, fd_set *writeset)
{
u_int i;
@ -604,7 +711,8 @@ after_select(fd_set *readset, fd_set *writeset)
sock = accept(sockets[i].fd,
(struct sockaddr *) &sunaddr, &slen);
if (sock < 0) {
perror("accept from AUTH_SOCKET");
error("accept from AUTH_SOCKET: %s",
strerror(errno));
break;
}
new_socket(AUTH_CONNECTION, sock);
@ -657,22 +765,8 @@ after_select(fd_set *readset, fd_set *writeset)
}
}
void
check_parent_exists(int sig)
{
int save_errno = errno;
if (parent_pid != -1 && kill(parent_pid, 0) < 0) {
/* printf("Parent has died - Authentication agent exiting.\n"); */
exit(1);
}
signal(SIGALRM, check_parent_exists);
alarm(10);
errno = save_errno;
}
void
cleanup_socket(void)
static void
cleanup_socket(void *p)
{
if (socket_name[0])
unlink(socket_name);
@ -680,33 +774,51 @@ cleanup_socket(void)
rmdir(socket_dir);
}
void
static void
cleanup_exit(int i)
{
cleanup_socket();
cleanup_socket(NULL);
exit(i);
}
void
static void
cleanup_handler(int sig)
{
cleanup_socket();
cleanup_socket(NULL);
_exit(2);
}
void
static void
check_parent_exists(int sig)
{
int save_errno = errno;
if (parent_pid != -1 && kill(parent_pid, 0) < 0) {
/* printf("Parent has died - Authentication agent exiting.\n"); */
cleanup_handler(sig); /* safe */
}
signal(SIGALRM, check_parent_exists);
alarm(10);
errno = save_errno;
}
static void
usage(void)
{
fprintf(stderr, "ssh-agent version %s\n", SSH_VERSION);
fprintf(stderr, "Usage: %s [-c | -s] [-k] [command {args...]]\n",
fprintf(stderr, "Usage: %s [options] [command [args ...]]\n",
__progname);
fprintf(stderr, "Options:\n");
fprintf(stderr, " -c Generate C-shell commands on stdout.\n");
fprintf(stderr, " -s Generate Bourne shell commands on stdout.\n");
fprintf(stderr, " -k Kill the current agent.\n");
fprintf(stderr, " -d Debug mode.\n");
exit(1);
}
int
main(int ac, char **av)
{
int sock, c_flag = 0, k_flag = 0, s_flag = 0, ch;
int sock, c_flag = 0, d_flag = 0, k_flag = 0, s_flag = 0, ch, nalloc;
struct sockaddr_un sunaddr;
struct rlimit rlim;
pid_t pid;
@ -716,7 +828,7 @@ main(int ac, char **av)
SSLeay_add_all_algorithms();
while ((ch = getopt(ac, av, "cks")) != -1) {
while ((ch = getopt(ac, av, "cdks")) != -1) {
switch (ch) {
case 'c':
if (s_flag)
@ -731,6 +843,11 @@ main(int ac, char **av)
usage();
s_flag++;
break;
case 'd':
if (d_flag)
usage();
d_flag++;
break;
default:
usage();
}
@ -738,10 +855,10 @@ main(int ac, char **av)
ac -= optind;
av += optind;
if (ac > 0 && (c_flag || k_flag || s_flag))
if (ac > 0 && (c_flag || k_flag || s_flag || d_flag))
usage();
if (ac == 0 && !c_flag && !k_flag && !s_flag) {
if (ac == 0 && !c_flag && !k_flag && !s_flag && !d_flag) {
shell = getenv("SHELL");
if (shell != NULL && strncmp(shell + strlen(shell) - 3, "csh", 3) == 0)
c_flag = 1;
@ -806,10 +923,18 @@ main(int ac, char **av)
* Fork, and have the parent execute the command, if any, or present
* the socket data. The child continues as the authentication agent.
*/
if (d_flag) {
log_init(__progname, SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 1);
format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
SSH_AUTHSOCKET_ENV_NAME);
printf("echo Agent pid %d;\n", parent_pid);
goto skip;
}
pid = fork();
if (pid == -1) {
perror("fork");
exit(1);
cleanup_exit(1);
}
if (pid != 0) { /* Parent - execute the given command. */
close(sock);
@ -832,6 +957,15 @@ main(int ac, char **av)
perror(av[0]);
exit(1);
}
/* child */
log_init(__progname, SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_AUTH, 0);
if (setsid() == -1) {
error("setsid: %s", strerror(errno));
cleanup_exit(1);
}
(void)chdir("/");
close(0);
close(1);
close(2);
@ -839,33 +973,31 @@ main(int ac, char **av)
/* deny core dumps, since memory contains unencrypted private keys */
rlim.rlim_cur = rlim.rlim_max = 0;
if (setrlimit(RLIMIT_CORE, &rlim) < 0) {
perror("setrlimit rlimit_core failed");
cleanup_exit(1);
}
if (setsid() == -1) {
perror("setsid");
cleanup_exit(1);
}
if (atexit(cleanup_socket) < 0) {
perror("atexit");
error("setrlimit RLIMIT_CORE: %s", strerror(errno));
cleanup_exit(1);
}
skip:
fatal_add_cleanup(cleanup_socket, NULL);
new_socket(AUTH_SOCKET, sock);
if (ac > 0) {
signal(SIGALRM, check_parent_exists);
alarm(10);
}
idtab_init();
signal(SIGINT, SIG_IGN);
if (!d_flag)
signal(SIGINT, SIG_IGN);
signal(SIGPIPE, SIG_IGN);
signal(SIGHUP, cleanup_handler);
signal(SIGTERM, cleanup_handler);
nalloc = 0;
while (1) {
prepare_select(&readsetp, &writesetp, &max_fd);
prepare_select(&readsetp, &writesetp, &max_fd, &nalloc);
if (select(max_fd + 1, readsetp, writesetp, NULL, NULL) < 0) {
if (errno == EINTR)
continue;
exit(1);
fatal("select: %s", strerror(errno));
}
after_select(readsetp, writesetp);
}

View file

@ -34,10 +34,9 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" $OpenBSD: ssh.1,v 1.107 2001/04/22 23:58:36 markus Exp $
.\" $OpenBSD: ssh.1,v 1.148 2002/02/18 17:55:20 markus Exp $
.\" $FreeBSD$
.\"
.Dd September 25, 1999
.Dd March 18, 2002
.Dt SSH 1
.Os
.Sh NAME
@ -46,11 +45,12 @@
.Sh SYNOPSIS
.Nm ssh
.Op Fl l Ar login_name
.Op Ar hostname | user@hostname
.Ar hostname | user@hostname
.Op Ar command
.Pp
.Nm ssh
.Op Fl afgknqstvxACNPTX1246
.Op Fl b Ar bind_address
.Op Fl c Ar cipher_spec
.Op Fl e Ar escape_char
.Op Fl i Ar identity_file
@ -58,6 +58,7 @@
.Op Fl m Ar mac_spec
.Op Fl o Ar option
.Op Fl p Ar port
.Op Fl F Ar configfile
.Oo Fl L Xo
.Sm off
.Ar port :
@ -74,7 +75,8 @@
.Sm on
.Xc
.Oc
.Op Ar hostname | user@hostname
.Op Fl D Ar port
.Ar hostname | user@hostname
.Op Ar command
.Sh DESCRIPTION
.Nm
@ -206,16 +208,14 @@ the password cannot be seen by someone listening on the network.
.Pp
.Ss SSH protocol version 2
.Pp
When a user connects using the protocol version 2
different authentication methods are available.
When a user connects using protocol version 2
similar authentication methods are available.
Using the default values for
.Cm PreferredAuthentications ,
the client will try to authenticate first using the public key method;
if this method fails password authentication is attempted,
and finally if this method fails keyboard-interactive authentication
is attempted.
If this method fails password authentication is
tried.
the client will try to authenticate first using the hostbased method;
if this method fails public key authentication is attempted,
and finally if this method fails keyboard-interactive and
password authentication are tried.
.Pp
The public key method is similar to RSA authentication described
in the previous section and allows the RSA or DSA algorithm to be used:
@ -225,7 +225,7 @@ or
.Pa $HOME/.ssh/id_rsa ,
to sign the session identifier and sends the result to the server.
The server checks whether the matching public key is listed in
.Pa $HOME/.ssh/authorized_keys2
.Pa $HOME/.ssh/authorized_keys
and grants access if both the key is found and the signature is correct.
The session identifier is derived from a shared Diffie-Hellman value
and is only known to the client and the server.
@ -270,16 +270,16 @@ of
.Ss Escape Characters
.Pp
When a pseudo terminal has been requested, ssh supports a number of functions
through the use of an escape character.
through the use of an escape character.
.Pp
A single tilde character can be sent as
.Ic ~~
(or by following the tilde by a character other than those described above).
or by following the tilde by a character other than those described below.
The escape character must always follow a newline to be interpreted as
special.
The escape character can be changed in configuration files using the
.Cm EscapeChar
configuration directive or on the command line by the
configuration directive or on the command line by the
.Fl e
option.
.Pp
@ -295,7 +295,7 @@ Background ssh
List forwarded connections
.It Cm ~&
Background ssh at logout when waiting for forwarded connection / X11 sessions
to terminate (protocol version 1 only)
to terminate
.It Cm ~?
Display a list of escape characters
.It Cm ~R
@ -305,18 +305,27 @@ and if the peer supports it)
.Pp
.Ss X11 and TCP forwarding
.Pp
If the user is using X11 (the
If the
.Cm ForwardX11
variable is set to
.Dq yes
(or, see the description of the
.Fl X
and
.Fl x
options described later)
and the user is using X11 (the
.Ev DISPLAY
environment variable is set), the connection to the X11 display can
be forwarded to the remote side in such a way that any X11
environment variable is set), the connection to the X11 display is
automatically forwarded to the remote side in such a way that any X11
programs started from the shell (or command) will go through the
encrypted channel, and the connection to the real X server will be made
from the local machine.
The user should not manually set
.Ev DISPLAY .
Forwarding of X11 connections weakens the security of ssh and is
disabled by default. X11 forwarding can be enabled on the command line
or in configuration files.
Forwarding of X11 connections can be
configured on the command line or in configuration files.
Take note that X11 forwarding can represent a security hazard.
.Pp
The
.Ev DISPLAY
@ -342,10 +351,10 @@ sent to the server machine (and no cookies are sent in the plain).
.Pp
If the user is using an authentication agent, the connection to the agent
is automatically forwarded to the remote side unless disabled on
command line or in a configuration file.
the command line or in a configuration file.
.Pp
Forwarding of arbitrary TCP/IP connections over the secure channel can
be specified either on command line or in a configuration file.
be specified either on the command line or in a configuration file.
One possible application of TCP/IP forwarding is a secure connection to an
electronic purse; another is going through firewalls.
.Pp
@ -354,17 +363,12 @@ electronic purse; another is going through firewalls.
.Nm
automatically maintains and checks a database containing
identifications for all hosts it has ever been used with.
RSA host keys are stored in
Host keys are stored in
.Pa $HOME/.ssh/known_hosts
and
host keys used in the protocol version 2 are stored in
.Pa $HOME/.ssh/known_hosts2
in the user's home directory.
Additionally, the files
Additionally, the file
.Pa /etc/ssh/ssh_known_hosts
and
.Pa /etc/ssh/ssh_known_hosts2
are automatically checked for known hosts.
is automatically checked for known hosts.
Any new hosts are automatically added to the user's file.
If a host's identification
ever changes,
@ -386,20 +390,27 @@ Disables forwarding of the authentication agent connection.
.It Fl A
Enables forwarding of the authentication agent connection.
This can also be specified on a per-host basis in a configuration file.
.It Fl c Ar blowfish|3des
.It Fl b Ar bind_address
Specify the interface to transmit from on machines with multiple
interfaces or aliased addresses.
.It Fl c Ar blowfish|3des|des
Selects the cipher to use for encrypting the session.
.Ar 3des
is used by default.
It is believed to be secure.
.Ar 3des
(triple-des) is an encrypt-decrypt-encrypt triple with three different keys.
It is presumably more secure than the
.Ar des
cipher which is no longer fully supported in
.Nm ssh .
.Ar blowfish
is a fast block cipher, it appears very secure and is much faster than
.Ar 3des .
.Ar des
is only supported in the
.Nm
client for interoperability with legacy protocol 1 implementations
that do not support the
.Ar 3des
cipher. Its use is strongly discouraged due to cryptographic
weaknesses.
.It Fl c Ar cipher_spec
Additionally, for protocol version 2 a comma-separated list of ciphers can
be specified in order of preference.
@ -434,17 +445,27 @@ something like
.It Fl g
Allows remote hosts to connect to local forwarded ports.
.It Fl i Ar identity_file
Selects the file from which the identity (private key) for
Selects a file from which the identity (private key) for
RSA or DSA authentication is read.
Default is
The default is
.Pa $HOME/.ssh/identity
in the user's home directory.
for protocol version 1, and
.Pa $HOME/.ssh/id_rsa
and
.Pa $HOME/.ssh/id_dsa
for protocol version 2.
Identity files may also be specified on
a per-host basis in the configuration file.
It is possible to have multiple
.Fl i
options (and multiple identities specified in
configuration files).
.It Fl I Ar smartcard_device
Specifies which smartcard device to use. The argument is
the device
.Nm
should use to communicate with a smartcard used for storing the user's
private RSA key.
.It Fl k
Disables forwarding of Kerberos tickets and AFS tokens.
This may also be specified on a per-host basis in the configuration file.
@ -480,20 +501,19 @@ needs to ask for a password or passphrase; see also the
option.)
.It Fl N
Do not execute a remote command.
This is useful if you just want to forward ports
This is useful for just forwarding ports
(protocol version 2 only).
.It Fl o Ar option
Can be used to give options in the format used in the config file.
Can be used to give options in the format used in the configuration file.
This is useful for specifying options for which there is no separate
command-line flag.
The option has the same format as a line in the configuration file.
.It Fl p Ar port
Port to connect to on the remote host.
This can be specified on a
per-host basis in the configuration file.
.It Fl P
Use a non-privileged port for outgoing connections.
This can be used if your firewall does
This can be used if a firewall does
not permit connections from privileged ports.
Note that this option turns off
.Cm RhostsAuthentication
@ -503,10 +523,9 @@ for older servers.
.It Fl q
Quiet mode.
Causes all warning and diagnostic messages to be suppressed.
Only fatal errors are displayed.
.It Fl s
May be used to request invocation of a subsystem on the remote system. Subsystems are a feature of the SSH2 protocol which facilitate the use
of SSH as a secure transport for other application (eg. sftp). The
May be used to request invocation of a subsystem on the remote system. Subsystems are a feature of the SSH2 protocol which facilitate the use
of SSH as a secure transport for other applications (eg. sftp). The
subsystem is specified as the remote command.
.It Fl t
Force pseudo-tty allocation.
@ -550,8 +569,16 @@ Compression is desirable on modem lines and other
slow connections, but will only slow down things on fast networks.
The default value can be set on a host-by-host basis in the
configuration files; see the
.Cm Compress
.Cm Compression
option below.
.It Fl F Ar configfile
Specifies an alternative per-user configuration file.
If a configuration file is given on the command line,
the system-wide configuration file
.Pq Pa /etc/ssh/ssh_config
will be ignored.
The default for the per-user configuration file is
.Pa $HOME/.ssh/config .
.It Fl L Ar port:host:hostport
Specifies that the given port on the local (client) host is to be
forwarded to the given host and port on the remote side.
@ -585,6 +612,20 @@ Privileged ports can be forwarded only when
logging in as root on the remote machine.
IPv6 addresses can be specified with an alternative syntax:
.Ar port/host/hostport
.It Fl D Ar port
Specifies a local
.Dq dynamic
application-level port forwarding.
This works by allocating a socket to listen to
.Ar port
on the local side, and whenever a connection is made to this port, the
connection is forwarded over the secure channel, and the application
protocol is then used to determine where to connect to from the
remote machine. Currently the SOCKS4 protocol is supported, and
.Nm
will act as a SOCKS4 server.
Only root can forward privileged ports.
Dynamic port forwardings can also be specified in the configuration file.
.It Fl 1
Forces
.Nm
@ -604,7 +645,8 @@ to use IPv6 addresses only.
.El
.Sh CONFIGURATION FILES
.Nm
obtains configuration data from the following sources (in this order):
obtains configuration data from the following sources in
the following order:
command line options, user's configuration file
.Pq Pa $HOME/.ssh/config ,
and system-wide configuration file
@ -629,9 +671,21 @@ are comments.
.Pp
Otherwise a line is of the format
.Dq keyword arguments .
Configuration options may be separated by whitespace or
optional whitespace and exactly one
.Ql = ;
the latter format is useful to avoid the need to quote whitespace
when specifying configuration options using the
.Nm ssh ,
.Nm scp
and
.Nm sftp
.Fl o
option.
.Pp
The possible
keywords and their meanings are as follows (note that the
configuration files are case-sensitive):
keywords and their meanings are as follows (note that
keywords are case-insensitive and arguments are case-sensitive):
.Bl -tag -width Ds
.It Cm Host
Restricts the following declarations (up to the next
@ -662,14 +716,21 @@ This option applies to protocol version 1 only.
If set to
.Dq yes ,
passphrase/password querying will be disabled.
This option is useful in scripts and other batch jobs where you have no
user to supply the password.
This option is useful in scripts and other batch jobs where no user
is present to supply the password.
The argument must be
.Dq yes
or
.Dq no .
The default is
.Dq no .
.It Cm BindAddress
Specify the interface to transmit from on machines with multiple
interfaces or aliased addresses.
Note that this option does not work if
.Cm UsePrivilegedPort
is set to
.Dq yes .
.It Cm CheckHostIP
If this flag is set to
.Dq yes ,
@ -686,10 +747,19 @@ The default is
Specifies the cipher to use for encrypting the session
in protocol version 1.
Currently,
.Dq blowfish
.Dq blowfish ,
.Dq 3des ,
and
.Dq 3des
.Dq des
are supported.
.Ar des
is only supported in the
.Nm
client for interoperability with legacy protocol 1 implementations
that do not support the
.Ar 3des
cipher. Its use is strongly discouraged due to cryptographic
weaknesses.
The default is
.Dq 3des .
.It Cm Ciphers
@ -702,6 +772,22 @@ The default is
``aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour,
aes192-cbc,aes256-cbc''
.Ed
.It Cm ClearAllForwardings
Specifies that all local, remote and dynamic port forwardings
specified in the configuration files or on the command line be
cleared. This option is primarily useful when used from the
.Nm
command line to clear port forwardings set in
configuration files, and is automatically set by
.Xr scp 1
and
.Xr sftp 1 .
The argument must be
.Dq yes
or
.Dq no .
The default is
.Dq no .
.It Cm Compression
Specifies whether to use compression.
The argument must be
@ -722,7 +808,18 @@ Specifies the number of tries (one per second) to make before falling
back to rsh or exiting.
The argument must be an integer.
This may be useful in scripts if the connection sometimes fails.
The default is 4.
The default is 1.
.It Cm DynamicForward
Specifies that a TCP/IP port on the local machine be forwarded
over the secure channel, and the application
protocol is then used to determine where to connect to from the
remote machine. The argument must be a port number.
Currently the SOCKS4 protocol is supported, and
.Nm
will act as a SOCKS4 server.
Multiple forwardings may be specified, and
additional forwardings can be given on the command line. Only
the superuser can forward privileged ports.
.It Cm EscapeChar
Sets the escape character (default:
.Ql ~ ) .
@ -773,6 +870,15 @@ The default is
.It Cm GatewayPorts
Specifies whether remote hosts are allowed to connect to local
forwarded ports.
By default,
.Nm
binds local port forwardings to the loopback addresss. This
prevents other remote hosts from connecting to forwarded ports.
.Cm GatewayPorts
can be used to specify that
.Nm
should bind local port forwardings to the wildcard address,
thus allowing remote hosts to connect to forwarded ports.
The argument must be
.Dq yes
or
@ -780,13 +886,9 @@ or
The default is
.Dq no .
.It Cm GlobalKnownHostsFile
Specifies a file to use for the protocol version 1 global
Specifies a file to use for the global
host key database instead of
.Pa /etc/ssh/ssh_known_hosts .
.It Cm GlobalKnownHostsFile2
Specifies a file to use for the protocol version 2 global
host key database instead of
.Pa /etc/ssh/ssh_known_hosts2 .
.It Cm HostbasedAuthentication
Specifies whether to try rhosts based authentication with public key
authentication.
@ -795,21 +897,21 @@ The argument must be
or
.Dq no .
The default is
.Dq yes .
.Dq no .
This option applies to protocol version 2 only and
is similar to
.Cm RhostsRSAAuthentication .
.It Cm HostKeyAlgorithms
Specfies the protocol version 2 host key algorithms
Specifies the protocol version 2 host key algorithms
that the client wants to use in order of preference.
The default for this option is:
.Dq ssh-rsa,ssh-dss
.Dq ssh-rsa,ssh-dss .
.It Cm HostKeyAlias
Specifies an alias that should be used instead of the
real host name when looking up or saving the host key
in the host key database files.
This option is useful for tunneling ssh connections
or if you have multiple servers running on a single host.
or for multiple servers running on a single host.
.It Cm HostName
Specifies the real host name to log into.
This can be used to specify nicknames or abbreviations for hosts.
@ -818,10 +920,14 @@ Numeric IP addresses are also permitted (both on the command line and in
.Cm HostName
specifications).
.It Cm IdentityFile
Specifies the file from which the user's RSA or DSA authentication identity
is read (default
Specifies a file from which the user's RSA or DSA authentication identity
is read. The default is
.Pa $HOME/.ssh/identity
in the user's home directory).
for protocol version 1, and
.Pa $HOME/.ssh/id_rsa
and
.Pa $HOME/.ssh/id_dsa
for protocol version 2.
Additionally, any identities represented by the authentication agent
will be used for authentication.
The file name may use the tilde
@ -830,7 +936,7 @@ It is possible to have
multiple identity files specified in configuration files; all these
identities will be tried in sequence.
.It Cm KeepAlive
Specifies whether the system should send keepalive messages to the
Specifies whether the system should send TCP keepalive messages to the
other side.
If they are sent, death of the connection or crash of one
of the machines will be properly noticed.
@ -845,8 +951,7 @@ if the network goes down or the remote host dies.
This is important in scripts, and many users want it too.
.Pp
To disable keepalives, the value should be set to
.Dq no
in both the server and the client configuration files.
.Dq no .
.It Cm KerberosAuthentication
Specifies whether Kerberos authentication will be used.
The argument to this keyword must be
@ -862,9 +967,11 @@ or
.Dq no .
.It Cm LocalForward
Specifies that a TCP/IP port on the local machine be forwarded over
the secure channel to given host:port from the remote machine.
the secure channel to the specified host and port from the remote machine.
The first argument must be a port number, and the second must be
host:port.
.Ar host:port .
IPv6 addresses can be specified with an alternative syntax:
.Ar host/port .
Multiple forwardings may be specified, and additional
forwardings can be given on the command line.
Only the superuser can forward privileged ports.
@ -872,20 +979,27 @@ Only the superuser can forward privileged ports.
Gives the verbosity level that is used when logging messages from
.Nm ssh .
The possible values are:
QUIET, FATAL, ERROR, INFO, VERBOSE and DEBUG.
The default is INFO.
QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG, DEBUG1, DEBUG2 and DEBUG3.
The default is INFO. DEBUG and DEBUG1 are equivalent. DEBUG2
and DEBUG3 each specify higher levels of verbose output.
.It Cm MACs
Specifies the MAC (message authentication code) algorithms
Specifies the MAC (message authentication code) algorithms
in order of preference.
The MAC algorithm is used in protocol version 2
for data integrity protection.
Multiple algorithms must be comma-separated.
The default is
.Pp
.Bd -literal
``hmac-md5,hmac-sha1,hmac-ripemd160,hmac-ripemd160@openssh.com,
hmac-sha1-96,hmac-md5-96''
.Ed
.Dq hmac-md5,hmac-sha1,hmac-ripemd160,hmac-sha1-96,hmac-md5-96 .
.It Cm NoHostAuthenticationForLocalhost
This option can be used if the home directory is shared across machines.
In this case localhost will refer to a different machine on each of
the machines and the user will get many warnings about changed host keys.
However, this option disables host authentication for localhost.
The argument to this keyword must be
.Dq yes
or
.Dq no .
The default is to check the host key for localhost.
.It Cm NumberOfPasswordPrompts
Specifies the number of password prompts before giving up.
The argument to this keyword must be an integer.
@ -902,13 +1016,13 @@ The default is
Specifies the port number to connect on the remote host.
Default is 22.
.It Cm PreferredAuthentications
Specifies the order in which the client should try protocol 2
authentication methods. This allows a client to prefer one method (e.g.
Specifies the order in which the client should try protocol 2
authentication methods. This allows a client to prefer one method (e.g.
.Cm keyboard-interactive )
over another method (e.g.
.Cm password )
The default for this option is:
.Dq publickey, password, keyboard-interactive
.Dq hostbased,publickey,keyboard-interactive,password .
.It Cm Protocol
Specifies the protocol versions
.Nm
@ -960,9 +1074,11 @@ The default is
This option applies to protocol version 2 only.
.It Cm RemoteForward
Specifies that a TCP/IP port on the remote machine be forwarded over
the secure channel to given host:port from the local machine.
the secure channel to the specified host and port from the local machine.
The first argument must be a port number, and the second must be
host:port.
.Ar host:port .
IPv6 addresses can be specified with an alternative syntax:
.Ar host/port .
Multiple forwardings may be specified, and additional
forwardings can be given on the command line.
Only the superuser can forward privileged ports.
@ -975,8 +1091,8 @@ Disabling rhosts authentication may reduce
authentication time on slow connections when rhosts authentication is
not used.
Most servers do not permit RhostsAuthentication because it
is not secure (see
.Cm RhostsRSAAuthentication ).
is not secure (see
.Cm RhostsRSAAuthentication ) .
The argument to this keyword must be
.Dq yes
or
@ -1008,31 +1124,31 @@ The default is
Note that this option applies to protocol version 1 only.
.It Cm ChallengeResponseAuthentication
Specifies whether to use challenge response authentication.
Currently there is only support for
.Xr skey 1
authentication.
The argument to this keyword must be
.Dq yes
or
.Dq no .
The default is
.Dq no .
.Dq yes .
.It Cm SmartcardDevice
Specifies which smartcard device to use. The argument to this keyword is
the device
.Nm
should use to communicate with a smartcard used for storing the user's
private RSA key. By default, no device is specified and smartcard support
is not activated.
.It Cm StrictHostKeyChecking
If this flag is set to
.Dq yes ,
.Nm
will never automatically add host keys to the
.Pa $HOME/.ssh/known_hosts
and
.Pa $HOME/.ssh/known_hosts2
files, and refuses to connect to hosts whose host key has changed.
This provides maximum protection against trojan horse attacks.
However, it can be somewhat annoying if you don't have good
file, and refuses to connect to hosts whose host key has changed.
This provides maximum protection against trojan horse attacks,
however, can be annoying when the
.Pa /etc/ssh/ssh_known_hosts
and
.Pa /etc/ssh/ssh_known_hosts2
files installed and frequently
connect to new hosts.
file is poorly maintained, or connections to new hosts are
frequently made.
This option forces the user to manually
add all new hosts.
If this flag is set to
@ -1064,26 +1180,22 @@ or
.Dq no .
The default is
.Dq no .
Note that you need to set this option to
Note that this option must be set to
.Dq yes
if you want to use
if
.Cm RhostsAuthentication
and
.Cm RhostsRSAAuthentication
with older servers.
authentications are needed with older servers.
.It Cm User
Specifies the user to log in as.
This can be useful if you have a different user name on different machines.
This can be useful when a different user name is used on different machines.
This saves the trouble of
having to remember to give the user name on the command line.
.It Cm UserKnownHostsFile
Specifies a file to use for the protocol version 1 user
Specifies a file to use for the user
host key database instead of
.Pa $HOME/.ssh/known_hosts .
.It Cm UserKnownHostsFile2
Specifies a file to use for the protocol version 2 user
host key database instead of
.Pa $HOME/.ssh/known_hosts2 .
.It Cm UseRsh
Specifies that rlogin/rsh should be used for this host.
It is possible that the host does not at all support the
@ -1136,14 +1248,37 @@ Synonym for
.Ev USER ;
set for compatibility with systems that use this variable.
.It Ev MAIL
Set to point the user's mailbox.
Set to the path of the user's mailbox.
.It Ev PATH
Set to the default
.Ev PATH ,
as specified when compiling
.Nm ssh .
.It Ev SSH_ASKPASS
If
.Nm
needs a passphrase, it will read the passphrase from the current
terminal if it was run from a terminal.
If
.Nm
does not have a terminal associated with it but
.Ev DISPLAY
and
.Ev SSH_ASKPASS
are set, it will execute the program specified by
.Ev SSH_ASKPASS
and open an X11 window to read the passphrase.
This is particularly useful when calling
.Nm
from a
.Pa .Xsession
or related script.
(Note that on some machines it
may be necessary to redirect the input from
.Pa /dev/null
to make this work.)
.It Ev SSH_AUTH_SOCK
indicates the path of a unix-domain socket used to communicate with the
Identifies the path of a unix-domain socket used to communicate with the
agent.
.It Ev SSH_CLIENT
Identifies the client end of the connection.
@ -1176,13 +1311,10 @@ and adds lines of the format
to the environment.
.Sh FILES
.Bl -tag -width Ds
.It Pa $HOME/.ssh/known_hosts, $HOME/.ssh/known_hosts2
Records host keys for all hosts the user has logged into (that are not
.It Pa $HOME/.ssh/known_hosts
Records host keys for all hosts the user has logged into that are not
in
.Pa /etc/ssh/ssh_known_hosts
for protocol version 1 or
.Pa /etc/ssh/ssh_known_hosts2
for protocol version 2).
.Pa /etc/ssh/ssh_known_hosts .
See
.Xr sshd 8 .
.It Pa $HOME/.ssh/identity, $HOME/.ssh/id_dsa, $HOME/.ssh/id_rsa
@ -1205,15 +1337,15 @@ The contents of the
file should be added to
.Pa $HOME/.ssh/authorized_keys
on all machines
where you wish to log in using protocol version 1 RSA authentication.
where the user wishes to log in using protocol version 1 RSA authentication.
The contents of the
.Pa $HOME/.ssh/id_dsa.pub
and
.Pa $HOME/.ssh/id_rsa.pub
file should be added to
.Pa $HOME/.ssh/authorized_keys2
.Pa $HOME/.ssh/authorized_keys
on all machines
where you wish to log in using protocol version 2 DSA/RSA authentication.
where the user wishes to log in using protocol version 2 DSA/RSA authentication.
These files are not
sensitive and can (but need not) be readable by anyone.
These files are
@ -1229,34 +1361,23 @@ This file does not usually contain any sensitive information,
but the recommended permissions are read/write for the user, and not
accessible by others.
.It Pa $HOME/.ssh/authorized_keys
Lists the RSA keys that can be used for logging in as this user.
Lists the public keys (RSA/DSA) that can be used for logging in as this user.
The format of this file is described in the
.Xr sshd 8
manual page.
In the simplest form the format is the same as the .pub
identity files (that is, each line contains the number of bits in
modulus, public exponent, modulus, and comment fields, separated by
spaces).
identity files.
This file is not highly sensitive, but the recommended
permissions are read/write for the user, and not accessible by others.
.It Pa $HOME/.ssh/authorized_keys2
Lists the public keys (RSA/DSA) that can be used for logging in as this user.
This file is not highly sensitive, but the recommended
permissions are read/write for the user, and not accessible by others.
.It Pa /etc/ssh/ssh_known_hosts, /etc/ssh/ssh_known_hosts2
.It Pa /etc/ssh/ssh_known_hosts
Systemwide list of known host keys.
.Pa /etc/ssh/ssh_known_hosts
contains RSA and
.Pa /etc/ssh/ssh_known_hosts2
contains RSA or DSA keys for protocol version 2.
These files should be prepared by the
This file should be prepared by the
system administrator to contain the public host keys of all machines in the
organization.
This file should be world-readable.
This file contains
public keys, one per line, in the following format (fields separated
by spaces): system name, number of bits in modulus, public exponent,
modulus, and optional comment field.
by spaces): system name, public key and optional comment field.
When different names are used
for the same machine, all such names should be listed, separated by
commas.
@ -1277,6 +1398,15 @@ This file provides defaults for those
values that are not specified in the user's configuration file, and
for those users who do not have a configuration file.
This file must be world-readable.
.It Pa /etc/ssh/ssh_host_key, /etc/ssh/ssh_host_dsa_key, /etc/ssh/ssh_host_rsa_key
These three files contain the private parts of the host keys
and are used for
.Cm RhostsRSAAuthentication
and
.Cm HostbasedAuthentication .
Since they are readable only by root
.Nm
must be setuid root if these authentication methods are desired.
.It Pa $HOME/.rhosts
This file is used in
.Pa \&.rhosts
@ -1302,9 +1432,9 @@ Note that by default
.Xr sshd 8
will be installed so that it requires successful RSA host
authentication before permitting \s+2.\s0rhosts authentication.
If your server machine does not have the client's host key in
If the server machine does not have the client's host key in
.Pa /etc/ssh/ssh_known_hosts ,
you can store it in
it can be stored in
.Pa $HOME/.ssh/known_hosts .
The easiest way to do this is to
connect back to the client from the server machine using ssh; this
@ -1361,6 +1491,10 @@ Contains additional definitions for environment variables, see section
.Sx ENVIRONMENT
above.
.El
.Sh DIAGNOSTICS
.Nm
exits with the exit status of the remote command or with 255
if an error occurred.
.Sh AUTHORS
OpenSSH is a derivative of the original and free
ssh 1.2.12 release by Tatu Ylonen.
@ -1387,7 +1521,7 @@ protocol versions 1.5 and 2.0.
.%A T. Rinne
.%A S. Lehtinen
.%T "SSH Protocol Architecture"
.%N draft-ietf-secsh-architecture-07.txt
.%D January 2001
.%N draft-ietf-secsh-architecture-09.txt
.%D July 2001
.%O work in progress material
.Re

View file

@ -39,7 +39,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: ssh.c,v 1.116 2001/04/17 12:55:04 markus Exp $");
RCSID("$OpenBSD: ssh.c,v 1.164 2002/02/14 23:28:00 markus Exp $");
RCSID("$FreeBSD$");
#include <openssl/evp.h>
@ -70,6 +70,11 @@ RCSID("$FreeBSD$");
#include "mac.h"
#include "sshtty.h"
#ifdef SMARTCARD
#include <openssl/engine.h>
#include "scard.h"
#endif
extern char *__progname;
/* Flag indicating whether IPv4 or IPv6. This can be set on the command line.
@ -106,6 +111,9 @@ int fork_after_authentication_flag = 0;
*/
Options options;
/* optional user configfile */
char *config = NULL;
/*
* Name of the host we are connecting to. This is the name given on the
* command line, or the HostName specified for the user-supplied name in a
@ -116,14 +124,6 @@ char *host;
/* socket address the host resolves to */
struct sockaddr_storage hostaddr;
/*
* Flag to indicate that we have received a window change signal which has
* not yet been processed. This will cause a message indicating the new
* window size to be sent to the server a little later. This is volatile
* because this is updated in a signal handler.
*/
volatile int received_window_change_signal = 0;
/* Private host keys. */
struct {
Key **keys;
@ -141,22 +141,27 @@ int subsystem_flag = 0;
/* Prints a help message to the user. This function never returns. */
void
static void
usage(void)
{
fprintf(stderr, "Usage: %s [options] host [command]\n", __progname);
fprintf(stderr, "Options:\n");
fprintf(stderr, " -l user Log in using this user name.\n");
fprintf(stderr, " -n Redirect input from " _PATH_DEVNULL ".\n");
fprintf(stderr, " -F config Config file (default: ~/%s).\n",
_PATH_SSH_USER_CONFFILE);
fprintf(stderr, " -A Enable authentication agent forwarding.\n");
fprintf(stderr, " -a Disable authentication agent forwarding.\n");
fprintf(stderr, " -a Disable authentication agent forwarding (default).\n");
#ifdef AFS
fprintf(stderr, " -k Disable Kerberos ticket and AFS token forwarding.\n");
#endif /* AFS */
fprintf(stderr, " -X Enable X11 connection forwarding.\n");
fprintf(stderr, " -x Disable X11 connection forwarding.\n");
fprintf(stderr, " -x Disable X11 connection forwarding (default).\n");
fprintf(stderr, " -i file Identity for public key authentication "
"(default: ~/.ssh/identity)\n");
#ifdef SMARTCARD
fprintf(stderr, " -I reader Set smartcard reader.\n");
#endif
fprintf(stderr, " -t Tty; allocate a tty even if command is given.\n");
fprintf(stderr, " -T Do not allocate a tty.\n");
fprintf(stderr, " -v Verbose; display verbose debugging messages.\n");
@ -167,14 +172,14 @@ usage(void)
fprintf(stderr, " -f Fork into background after authentication.\n");
fprintf(stderr, " -e char Set escape character; ``none'' = disable (default: ~).\n");
fprintf(stderr, " -c cipher Select encryption algorithm: "
"``3des'', ``blowfish''\n");
fprintf(stderr, " -c cipher Select encryption algorithm\n");
fprintf(stderr, " -m macs Specify MAC algorithms for protocol version 2.\n");
fprintf(stderr, " -p port Connect to this port. Server must be on the same port.\n");
fprintf(stderr, " -L listen-port:host:port Forward local port to remote address\n");
fprintf(stderr, " -R listen-port:host:port Forward remote port to local address\n");
fprintf(stderr, " These cause %s to listen for connections on a port, and\n", __progname);
fprintf(stderr, " forward them to the other side by connecting to host:port.\n");
fprintf(stderr, " -D port Enable dynamic application-level port forwarding.\n");
fprintf(stderr, " -C Enable compression.\n");
fprintf(stderr, " -N Do not execute a shell or command.\n");
fprintf(stderr, " -g Allow remote hosts to connect to forwarded ports.\n");
@ -184,6 +189,7 @@ usage(void)
fprintf(stderr, " -6 Use IPv6 only.\n");
fprintf(stderr, " -o 'option' Process the option as if it was read from a configuration file.\n");
fprintf(stderr, " -s Invoke command (mandatory) as SSH2 subsystem.\n");
fprintf(stderr, " -b addr Local IP address.\n");
exit(1);
}
@ -191,7 +197,7 @@ usage(void)
* Connects to the given host using rsh (or prints an error message and exits
* if rsh is not available). This function never returns.
*/
void
static void
rsh_connect(char *host, char *user, Buffer * command)
{
char *args[10];
@ -228,9 +234,9 @@ rsh_connect(char *host, char *user, Buffer * command)
exit(1);
}
int ssh_session(void);
int ssh_session2(void);
void load_public_identity_files(void);
static int ssh_session(void);
static int ssh_session2(void);
static void load_public_identity_files(void);
/*
* Main program for the ssh client.
@ -238,13 +244,16 @@ void load_public_identity_files(void);
int
main(int ac, char **av)
{
int i, opt, optind, exit_status, ok;
int i, opt, exit_status, cerr;
u_short fwd_port, fwd_host_port;
char *optarg, *cp, buf[256];
char sfwd_port[6], sfwd_host_port[6];
char *p, *cp, buf[256];
struct stat st;
struct passwd *pw;
int dummy;
uid_t original_effective_uid;
extern int optind, optreset;
extern char *optarg;
/*
* Save the original real uid. It will be needed later (uid-swapping
@ -292,35 +301,9 @@ main(int ac, char **av)
/* Parse command-line arguments. */
host = NULL;
for (optind = 1; optind < ac; optind++) {
if (av[optind][0] != '-') {
if (host)
break;
if ((cp = strchr(av[optind], '@'))) {
if(cp == av[optind])
usage();
options.user = av[optind];
*cp = '\0';
host = ++cp;
} else
host = av[optind];
continue;
}
opt = av[optind][1];
if (!opt)
usage();
if (strchr("eilcmpLRDo", opt)) { /* options with arguments */
optarg = av[optind] + 2;
if (strcmp(optarg, "") == 0) {
if (optind >= ac - 1)
usage();
optarg = av[++optind];
}
} else {
if (av[optind][2])
usage();
optarg = NULL;
}
again:
while ((opt = getopt(ac, av,
"1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:NPR:TVX")) != -1) {
switch (opt) {
case '1':
options.protocol = SSH_PROTO_1;
@ -361,23 +344,29 @@ main(int ac, char **av)
break;
#ifdef AFS
case 'k':
options.krb4_tgt_passing = 0;
#ifdef KRB5
options.krb5_tgt_passing = 0;
#endif
options.kerberos_tgt_passing = 0;
options.afs_token_passing = 0;
break;
#endif
case 'i':
if (stat(optarg, &st) < 0) {
fprintf(stderr, "Warning: Identity file %s does not exist.\n",
optarg);
fprintf(stderr, "Warning: Identity file %s "
"does not exist.\n", optarg);
break;
}
if (options.num_identity_files >= SSH_MAX_IDENTITY_FILES)
fatal("Too many identity files specified (max %d)",
SSH_MAX_IDENTITY_FILES);
options.identity_files[options.num_identity_files++] = xstrdup(optarg);
if (options.num_identity_files >=
SSH_MAX_IDENTITY_FILES)
fatal("Too many identity files specified "
"(max %d)", SSH_MAX_IDENTITY_FILES);
options.identity_files[options.num_identity_files++] =
xstrdup(optarg);
break;
case 'I':
#ifdef SMARTCARD
options.smartcard_device = xstrdup(optarg);
#else
fprintf(stderr, "no support for smartcards.\n");
#endif
break;
case 't':
if (tty_flag)
@ -391,9 +380,8 @@ main(int ac, char **av)
} else if (options.log_level < SYSLOG_LEVEL_DEBUG3) {
options.log_level++;
break;
} else {
} else
fatal("Too high debugging level.");
}
/* fallthrough */
case 'V':
fprintf(stderr,
@ -410,14 +398,16 @@ main(int ac, char **av)
break;
case 'e':
if (optarg[0] == '^' && optarg[2] == 0 &&
(u_char) optarg[1] >= 64 && (u_char) optarg[1] < 128)
(u_char) optarg[1] >= 64 &&
(u_char) optarg[1] < 128)
options.escape_char = (u_char) optarg[1] & 31;
else if (strlen(optarg) == 1)
options.escape_char = (u_char) optarg[0];
else if (strcmp(optarg, "none") == 0)
options.escape_char = -2;
options.escape_char = SSH_ESCAPECHAR_NONE;
else {
fprintf(stderr, "Bad escape character '%s'.\n", optarg);
fprintf(stderr, "Bad escape character '%s'.\n",
optarg);
exit(1);
}
break;
@ -430,23 +420,25 @@ main(int ac, char **av)
/* SSH1 only */
options.cipher = cipher_number(optarg);
if (options.cipher == -1) {
fprintf(stderr, "Unknown cipher type '%s'\n", optarg);
fprintf(stderr,
"Unknown cipher type '%s'\n",
optarg);
exit(1);
}
if (options.cipher == SSH_CIPHER_3DES) {
if (options.cipher == SSH_CIPHER_3DES)
options.ciphers = "3des-cbc";
} else if (options.cipher == SSH_CIPHER_BLOWFISH) {
else if (options.cipher == SSH_CIPHER_BLOWFISH)
options.ciphers = "blowfish-cbc";
} else {
else
options.ciphers = (char *)-1;
}
}
break;
case 'm':
if (mac_valid(optarg))
options.macs = xstrdup(optarg);
else {
fprintf(stderr, "Unknown mac type '%s'\n", optarg);
fprintf(stderr, "Unknown mac type '%s'\n",
optarg);
exit(1);
}
break;
@ -460,33 +452,38 @@ main(int ac, char **av)
case 'l':
options.user = optarg;
break;
case 'R':
if (sscanf(optarg, "%hu/%255[^/]/%hu", &fwd_port, buf,
&fwd_host_port) != 3 &&
sscanf(optarg, "%hu:%255[^:]:%hu", &fwd_port, buf,
&fwd_host_port) != 3) {
fprintf(stderr, "Bad forwarding specification '%s'.\n", optarg);
usage();
/* NOTREACHED */
}
add_remote_forward(&options, fwd_port, buf, fwd_host_port);
break;
case 'L':
if (sscanf(optarg, "%hu/%255[^/]/%hu", &fwd_port, buf,
&fwd_host_port) != 3 &&
sscanf(optarg, "%hu:%255[^:]:%hu", &fwd_port, buf,
&fwd_host_port) != 3) {
fprintf(stderr, "Bad forwarding specification '%s'.\n", optarg);
case 'R':
if (sscanf(optarg, "%5[0-9]:%255[^:]:%5[0-9]",
sfwd_port, buf, sfwd_host_port) != 3 &&
sscanf(optarg, "%5[0-9]/%255[^/]/%5[0-9]",
sfwd_port, buf, sfwd_host_port) != 3) {
fprintf(stderr,
"Bad forwarding specification '%s'\n",
optarg);
usage();
/* NOTREACHED */
}
add_local_forward(&options, fwd_port, buf, fwd_host_port);
if ((fwd_port = a2port(sfwd_port)) == 0 ||
(fwd_host_port = a2port(sfwd_host_port)) == 0) {
fprintf(stderr,
"Bad forwarding port(s) '%s'\n", optarg);
exit(1);
}
if (opt == 'L')
add_local_forward(&options, fwd_port, buf,
fwd_host_port);
else if (opt == 'R')
add_remote_forward(&options, fwd_port, buf,
fwd_host_port);
break;
case 'D':
fwd_port = a2port(optarg);
if (fwd_port == 0) {
fprintf(stderr, "Bad dynamic port '%s'\n", optarg);
fprintf(stderr, "Bad dynamic port '%s'\n",
optarg);
exit(1);
}
add_local_forward(&options, fwd_port, "socks4", 0);
@ -504,24 +501,53 @@ main(int ac, char **av)
break;
case 'o':
dummy = 1;
if (process_config_line(&options, host ? host : "", optarg,
"command-line", 0, &dummy) != 0)
if (process_config_line(&options, host ? host : "",
optarg, "command-line", 0, &dummy) != 0)
exit(1);
break;
case 's':
subsystem_flag = 1;
break;
case 'b':
options.bind_address = optarg;
break;
case 'F':
config = optarg;
break;
default:
usage();
}
}
ac -= optind;
av += optind;
if (ac > 0 && !host && **av != '-') {
if (strchr(*av, '@')) {
p = xstrdup(*av);
cp = strchr(p, '@');
if (cp == NULL || cp == p)
usage();
options.user = p;
*cp = '\0';
host = ++cp;
} else
host = *av;
ac--, av++;
if (ac > 0) {
optind = 0;
optreset = 1;
goto again;
}
}
/* Check that we got a host name. */
if (!host)
usage();
SSLeay_add_all_algorithms();
ERR_load_crypto_strings();
channel_set_af(IPv4or6);
/* Initialize the command to execute on remote host. */
buffer_init(&command);
@ -531,18 +557,18 @@ main(int ac, char **av)
* is no limit on the length of the command, except by the maximum
* packet size. Also sets the tty flag if there is no command.
*/
if (optind == ac) {
if (!ac) {
/* No command specified - execute shell on a tty. */
tty_flag = 1;
if (subsystem_flag) {
fprintf(stderr, "You must specify a subsystem to invoke.\n");
fprintf(stderr,
"You must specify a subsystem to invoke.\n");
usage();
}
} else {
/* A command has been specified. Store it into the
buffer. */
for (i = optind; i < ac; i++) {
if (i > optind)
/* A command has been specified. Store it into the buffer. */
for (i = 0; i < ac; i++) {
if (i)
buffer_append(&command, " ", 1);
buffer_append(&command, av[i], strlen(av[i]));
}
@ -573,12 +599,22 @@ main(int ac, char **av)
log_init(av[0], options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level,
SYSLOG_FACILITY_USER, 1);
/* Read per-user configuration file. */
snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, _PATH_SSH_USER_CONFFILE);
read_config_file(buf, host, &options);
/*
* Read per-user configuration file. Ignore the system wide config
* file if the user specifies a config file on the command line.
*/
if (config != NULL) {
if (!read_config_file(config, host, &options))
fatal("Can't open user config file %.100s: "
"%.100s", config, strerror(errno));
} else {
snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir,
_PATH_SSH_USER_CONFFILE);
(void)read_config_file(buf, host, &options);
/* Read systemwide configuration file. */
read_config_file(_PATH_HOST_CONFIG_FILE, host, &options);
/* Read systemwide configuration file after use config. */
(void)read_config_file(_PATH_HOST_CONFIG_FILE, host, &options);
}
/* Fill configuration defaults. */
fill_default_options(&options);
@ -637,7 +673,7 @@ main(int ac, char **av)
/* Open a connection to the remote host. */
ok = ssh_connect(host, &hostaddr, options.port,
cerr = ssh_connect(host, &hostaddr, options.port, IPv4or6,
options.connection_attempts,
original_effective_uid != 0 || !options.use_privileged_port,
pw, options.proxy_command);
@ -650,7 +686,7 @@ main(int ac, char **av)
*/
sensitive_data.nkeys = 0;
sensitive_data.keys = NULL;
if (ok && (options.rhosts_rsa_authentication ||
if (!cerr && (options.rhosts_rsa_authentication ||
options.hostbased_authentication)) {
sensitive_data.nkeys = 3;
sensitive_data.keys = xmalloc(sensitive_data.nkeys*sizeof(Key));
@ -682,26 +718,25 @@ main(int ac, char **av)
* Now that we are back to our own permissions, create ~/.ssh
* directory if it doesn\'t already exist.
*/
snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, _PATH_SSH_USER_DIR);
snprintf(buf, sizeof buf, "%.100s%s%.100s", pw->pw_dir, strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR);
if (stat(buf, &st) < 0)
if (mkdir(buf, 0700) < 0)
error("Could not create directory '%.200s'.", buf);
/* Check if the connection failed, and try "rsh" if appropriate. */
if (!ok) {
if (cerr) {
if (!options.fallback_to_rsh)
exit(1);
if (options.port != 0)
log("Secure connection to %.100s on port %hu refused%.100s.",
host, options.port,
options.fallback_to_rsh ? "; reverting to insecure method" : "");
log("Secure connection to %.100s on port %hu refused; "
"reverting to insecure method",
host, options.port);
else
log("Secure connection to %.100s refused%.100s.", host,
options.fallback_to_rsh ? "; reverting to insecure method" : "");
log("Secure connection to %.100s refused; "
"reverting to insecure method.", host);
if (options.fallback_to_rsh) {
rsh_connect(host, options.user, &command);
fatal("rsh_connect returned");
}
exit(1);
rsh_connect(host, options.user, &command);
fatal("rsh_connect returned");
}
/* load options.identity_files */
load_public_identity_files();
@ -717,6 +752,8 @@ main(int ac, char **av)
options.user_hostfile2 =
tilde_expand_filename(options.user_hostfile2, original_real_uid);
signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */
/* Log into the remote system. This never returns if the login fails. */
ssh_login(sensitive_data.keys, sensitive_data.nkeys,
host, (struct sockaddr *)&hostaddr, pw);
@ -733,26 +770,53 @@ main(int ac, char **av)
}
xfree(sensitive_data.keys);
}
for (i = 0; i < options.num_identity_files; i++) {
if (options.identity_files[i]) {
xfree(options.identity_files[i]);
options.identity_files[i] = NULL;
}
if (options.identity_keys[i]) {
key_free(options.identity_keys[i]);
options.identity_keys[i] = NULL;
}
}
exit_status = compat20 ? ssh_session2() : ssh_session();
packet_close();
return exit_status;
}
void
x11_get_proto(char *proto, int proto_len, char *data, int data_len)
static void
x11_get_proto(char **_proto, char **_data)
{
char line[512];
static char proto[512], data[512];
FILE *f;
int got_data = 0, i;
char *display;
if (options.xauth_location) {
*_proto = proto;
*_data = data;
proto[0] = data[0] = '\0';
if (options.xauth_location && (display = getenv("DISPLAY"))) {
/* Try to get Xauthority information for the display. */
snprintf(line, sizeof line, "%.100s list %.200s 2>" _PATH_DEVNULL,
options.xauth_location, getenv("DISPLAY"));
if (strncmp(display, "localhost:", 10) == 0)
/*
* Handle FamilyLocal case where $DISPLAY does
* not match an authorization entry. For this we
* just try "xauth list unix:displaynum.screennum".
* XXX: "localhost" match to determine FamilyLocal
* is not perfect.
*/
snprintf(line, sizeof line, "%.100s list unix:%s 2>"
_PATH_DEVNULL, options.xauth_location, display+10);
else
snprintf(line, sizeof line, "%.100s list %.200s 2>"
_PATH_DEVNULL, options.xauth_location, display);
debug2("x11_get_proto %s", line);
f = popen(line, "r");
if (f && fgets(line, sizeof(line), f) &&
sscanf(line, "%*s %s %s", proto, data) == 2)
sscanf(line, "%*s %511s %511s", proto, data) == 2)
got_data = 1;
if (f)
pclose(f);
@ -768,17 +832,17 @@ x11_get_proto(char *proto, int proto_len, char *data, int data_len)
if (!got_data) {
u_int32_t rand = 0;
strlcpy(proto, "MIT-MAGIC-COOKIE-1", proto_len);
strlcpy(proto, "MIT-MAGIC-COOKIE-1", sizeof proto);
for (i = 0; i < 16; i++) {
if (i % 4 == 0)
rand = arc4random();
snprintf(data + 2 * i, data_len - 2 * i, "%02x", rand & 0xff);
snprintf(data + 2 * i, sizeof data - 2 * i, "%02x", rand & 0xff);
rand >>= 8;
}
}
}
void
static void
ssh_init_forwarding(void)
{
int success = 0;
@ -790,7 +854,7 @@ ssh_init_forwarding(void)
options.local_forwards[i].port,
options.local_forwards[i].host,
options.local_forwards[i].host_port);
success += channel_request_local_forwarding(
success += channel_setup_local_fwd_listener(
options.local_forwards[i].port,
options.local_forwards[i].host,
options.local_forwards[i].host_port,
@ -812,7 +876,7 @@ ssh_init_forwarding(void)
}
}
void
static void
check_agent_present(void)
{
if (options.forward_agent) {
@ -825,11 +889,10 @@ check_agent_present(void)
}
}
int
static int
ssh_session(void)
{
int type;
int plen;
int interactive = 0;
int have_tty = 0;
struct winsize ws;
@ -847,7 +910,7 @@ ssh_session(void)
packet_put_int(options.compression_level);
packet_send();
packet_write_wait();
type = packet_read(&plen);
type = packet_read();
if (type == SSH_SMSG_SUCCESS)
packet_start_compression(options.compression_level);
else if (type == SSH_SMSG_FAILURE)
@ -867,7 +930,7 @@ ssh_session(void)
cp = getenv("TERM");
if (!cp)
cp = "";
packet_put_string(cp, strlen(cp));
packet_put_cstring(cp);
/* Store window size in the packet. */
if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
@ -885,7 +948,7 @@ ssh_session(void)
packet_write_wait();
/* Read response from the server. */
type = packet_read(&plen);
type = packet_read();
if (type == SSH_SMSG_SUCCESS) {
interactive = 1;
have_tty = 1;
@ -896,15 +959,15 @@ ssh_session(void)
}
/* Request X11 forwarding if enabled and DISPLAY is set. */
if (options.forward_x11 && getenv("DISPLAY") != NULL) {
char proto[512], data[512];
char *proto, *data;
/* Get reasonable local authentication information. */
x11_get_proto(proto, sizeof proto, data, sizeof data);
x11_get_proto(&proto, &data);
/* Request forwarding with authentication spoofing. */
debug("Requesting X11 forwarding with authentication spoofing.");
x11_request_forwarding_with_spoofing(0, proto, data);
/* Read response from the server. */
type = packet_read(&plen);
type = packet_read();
if (type == SSH_SMSG_SUCCESS) {
interactive = 1;
} else if (type == SSH_SMSG_FAILURE) {
@ -924,8 +987,8 @@ ssh_session(void)
auth_request_forwarding();
/* Read response from the server. */
type = packet_read(&plen);
packet_integrity_check(plen, 0, type);
type = packet_read();
packet_check_eom();
if (type != SSH_SMSG_SUCCESS)
log("Warning: Remote host denied authentication agent forwarding.");
}
@ -946,7 +1009,7 @@ ssh_session(void)
int len = buffer_len(&command);
if (len > 900)
len = 900;
debug("Sending command: %.*s", len, buffer_ptr(&command));
debug("Sending command: %.*s", len, (u_char *)buffer_ptr(&command));
packet_start(SSH_CMSG_EXEC_CMD);
packet_put_string(buffer_ptr(&command), buffer_len(&command));
packet_send();
@ -959,11 +1022,12 @@ ssh_session(void)
}
/* Enter the interactive session. */
return client_loop(have_tty, tty_flag ? options.escape_char : -1, 0);
return client_loop(have_tty, tty_flag ?
options.escape_char : SSH_ESCAPECHAR_NONE, 0);
}
void
client_subsystem_reply(int type, int plen, void *ctxt)
static void
client_subsystem_reply(int type, u_int32_t seq, void *ctxt)
{
int id, len;
@ -971,20 +1035,21 @@ client_subsystem_reply(int type, int plen, void *ctxt)
len = buffer_len(&command);
if (len > 900)
len = 900;
packet_done();
packet_check_eom();
if (type == SSH2_MSG_CHANNEL_FAILURE)
fatal("Request for subsystem '%.*s' failed on channel %d",
len, buffer_ptr(&command), id);
len, (u_char *)buffer_ptr(&command), id);
}
void
ssh_session2_callback(int id, void *arg)
/* request pty/x11/agent/tcpfwd/shell for channel */
static void
ssh_session2_setup(int id, void *arg)
{
int len;
int interactive = 0;
struct termios tio;
debug("client_init id %d arg %ld", id, (long)arg);
debug("ssh_session2_setup: id %d", id);
if (tty_flag) {
struct winsize ws;
@ -1010,9 +1075,9 @@ ssh_session2_callback(int id, void *arg)
}
if (options.forward_x11 &&
getenv("DISPLAY") != NULL) {
char proto[512], data[512];
char *proto, *data;
/* Get reasonable local authentication information. */
x11_get_proto(proto, sizeof proto, data, sizeof data);
x11_get_proto(&proto, &data);
/* Request forwarding with authentication spoofing. */
debug("Requesting X11 forwarding with authentication spoofing.");
x11_request_forwarding_with_spoofing(id, proto, data);
@ -1032,32 +1097,32 @@ ssh_session2_callback(int id, void *arg)
if (len > 900)
len = 900;
if (subsystem_flag) {
debug("Sending subsystem: %.*s", len, buffer_ptr(&command));
debug("Sending subsystem: %.*s", len, (u_char *)buffer_ptr(&command));
channel_request_start(id, "subsystem", /*want reply*/ 1);
/* register callback for reply */
/* XXX we asume that client_loop has already been called */
dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &client_subsystem_reply);
dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, &client_subsystem_reply);
} else {
debug("Sending command: %.*s", len, buffer_ptr(&command));
debug("Sending command: %.*s", len, (u_char *)buffer_ptr(&command));
channel_request_start(id, "exec", 0);
}
packet_put_string(buffer_ptr(&command), buffer_len(&command));
packet_send();
} else {
channel_request(id, "shell", 0);
channel_request_start(id, "shell", 0);
packet_send();
}
/* channel_callback(id, SSH2_MSG_OPEN_CONFIGMATION, client_init, 0); */
/* register different callback, etc. XXX */
packet_set_interactive(interactive);
}
int
ssh_session2_command(void)
/* open new channel for a session */
static int
ssh_session2_open(void)
{
int id, window, packetmax;
int in, out, err;
Channel *c;
int window, packetmax, in, out, err;
if (stdin_null_flag) {
in = open(_PATH_DEVNULL, O_RDONLY);
@ -1080,50 +1145,85 @@ ssh_session2_command(void)
window = CHAN_SES_WINDOW_DEFAULT;
packetmax = CHAN_SES_PACKET_DEFAULT;
if (!tty_flag) {
window *= 2;
packetmax *=2;
if (tty_flag) {
window >>= 1;
packetmax >>= 1;
}
id = channel_new(
c = channel_new(
"session", SSH_CHANNEL_OPENING, in, out, err,
window, packetmax, CHAN_EXTENDED_WRITE,
xstrdup("client-session"), /*nonblock*/0);
debug("channel_new: %d", id);
debug3("ssh_session2_open: channel_new: %d", c->self);
channel_open(id);
channel_register_callback(id, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION,
ssh_session2_callback, (void *)0);
channel_send_open(c->self);
if (!no_shell_flag)
channel_register_confirm(c->self, ssh_session2_setup);
return id;
return c->self;
}
int
static int
ssh_session2(void)
{
int id;
int id = -1;
/* XXX should be pre-session */
ssh_init_forwarding();
id = no_shell_flag ? -1 : ssh_session2_command();
if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN))
id = ssh_session2_open();
/* If requested, let ssh continue in the background. */
if (fork_after_authentication_flag)
if (daemon(1, 1) < 0)
fatal("daemon() failed: %.200s", strerror(errno));
return client_loop(tty_flag, tty_flag ? options.escape_char : -1, id);
return client_loop(tty_flag, tty_flag ?
options.escape_char : SSH_ESCAPECHAR_NONE, id);
}
void
static void
load_public_identity_files(void)
{
char *filename;
Key *public;
int i;
int i = 0;
for (i = 0; i < options.num_identity_files; i++) {
#ifdef SMARTCARD
if (options.smartcard_device != NULL &&
options.num_identity_files + 1 < SSH_MAX_IDENTITY_FILES &&
(public = sc_get_key(options.smartcard_device)) != NULL ) {
Key *new;
if (options.num_identity_files + 2 > SSH_MAX_IDENTITY_FILES)
options.num_identity_files = SSH_MAX_IDENTITY_FILES - 2;
memmove(&options.identity_files[2], &options.identity_files[0],
sizeof(char *) * options.num_identity_files);
options.num_identity_files += 2;
i = 2;
/* XXX ssh1 vs ssh2 */
new = key_new(KEY_RSA);
new->flags = KEY_FLAG_EXT;
BN_copy(new->rsa->n, public->rsa->n);
BN_copy(new->rsa->e, public->rsa->e);
RSA_set_method(new->rsa, sc_get_engine());
options.identity_keys[0] = new;
options.identity_files[0] = xstrdup("smartcard rsa key");;
new = key_new(KEY_RSA1);
new->flags = KEY_FLAG_EXT;
BN_copy(new->rsa->n, public->rsa->n);
BN_copy(new->rsa->e, public->rsa->e);
RSA_set_method(new->rsa, sc_get_engine());
options.identity_keys[1] = new;
options.identity_files[1] = xstrdup("smartcard rsa1 key");
key_free(public);
}
#endif /* SMARTCARD */
for (; i < options.num_identity_files; i++) {
filename = tilde_expand_filename(options.identity_files[i],
original_real_uid);
public = key_load_public(filename, NULL);

View file

@ -1,3 +1,6 @@
/* $OpenBSD: ssh.h,v 1.64 2002/03/04 17:27:39 stevesk Exp $ */
/* $FreeBSD$ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -10,9 +13,6 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/* RCSID("$OpenBSD: ssh.h,v 1.62 2001/01/23 10:45:10 markus Exp $"); */
/* RCSID("$FreeBSD$"); */
#ifndef SSH_H
#define SSH_H
@ -83,8 +83,8 @@
/* Name of Kerberos service for SSH to use. */
#define KRB4_SERVICE_NAME "rcmd"
/* Kerberos IV tickets can't be forwarded. This is an AFS hack! */
#define SSH_CMSG_HAVE_KRB4_TGT SSH_CMSG_HAVE_KERBEROS_TGT /* credentials (s) */
/* Used to identify ``EscapeChar none'' */
#define SSH_ESCAPECHAR_NONE -2
#ifdef USE_PAM
#include "auth-pam.h"

View file

@ -1,13 +1,10 @@
# This is ssh client systemwide configuration file. This file provides
# defaults for users, and the values can be changed in per-user configuration
# files or on the command line.
#
# $OpenBSD: ssh_config,v 1.10 2001/04/03 21:19:38 todd Exp $
# $FreeBSD$
# $OpenBSD: ssh_config,v 1.12 2002/01/16 17:55:33 stevesk Exp $
# $FreeBSD$
# This is ssh client systemwide configuration file. See ssh(1) for more
# information. This file provides defaults for users, and the values can
# be changed in per-user configuration files or on the command line.
# This is the ssh client system-wide configuration file. See ssh(1)
# for more information. This file provides defaults for users, and
# the values can be changed in per-user configuration files or on the
# command line.
# Configuration data is parsed as follows:
# 1. command line options
@ -22,7 +19,7 @@
# Host *
# ForwardAgent no
# ForwardX11 no
# RhostsAuthentication no
# RhostsAuthentication yes
# RhostsRSAAuthentication yes
# RSAAuthentication yes
# PasswordAuthentication yes
@ -30,11 +27,12 @@
# UseRsh no
# BatchMode no
# CheckHostIP yes
# StrictHostKeyChecking yes
# StrictHostKeyChecking ask
# IdentityFile ~/.ssh/identity
# IdentityFile ~/.ssh/id_dsa
# IdentityFile ~/.ssh/id_rsa
# IdentityFile ~/.ssh/id_dsa
# Port 22
# Protocol 2,1
# Cipher blowfish
# Cipher 3des
# Ciphers aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour,aes192-cbc,aes256-cbc
# EscapeChar ~

View file

@ -13,7 +13,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: sshconnect.c,v 1.104 2001/04/12 19:15:25 markus Exp $");
RCSID("$OpenBSD: sshconnect.c,v 1.119 2002/01/21 15:13:51 markus Exp $");
RCSID("$FreeBSD$");
#include <openssl/bn.h>
@ -32,9 +32,7 @@ RCSID("$FreeBSD$");
#include "readconf.h"
#include "atomicio.h"
#include "misc.h"
#include "auth.h"
#include "ssh1.h"
#include "canohost.h"
#include "readpass.h"
char *client_version_string = NULL;
char *server_version_string = NULL;
@ -42,13 +40,31 @@ char *server_version_string = NULL;
extern Options options;
extern char *__progname;
/* AF_UNSPEC or AF_INET or AF_INET6 */
extern int IPv4or6;
static const char *
sockaddr_ntop(struct sockaddr *sa)
{
void *addr;
static char addrbuf[INET6_ADDRSTRLEN];
switch (sa->sa_family) {
case AF_INET:
addr = &((struct sockaddr_in *)sa)->sin_addr;
break;
case AF_INET6:
addr = &((struct sockaddr_in6 *)sa)->sin6_addr;
break;
default:
/* This case should be protected against elsewhere */
abort(); /* XXX abort is bad -- do something else */
}
inet_ntop(sa->sa_family, addr, addrbuf, sizeof(addrbuf));
return addrbuf;
}
/*
* Connect to the given ssh server using a proxy command.
*/
int
static int
ssh_proxy_connect(const char *host, u_short port, struct passwd *pw,
const char *proxy_command)
{
@ -91,7 +107,7 @@ ssh_proxy_connect(const char *host, u_short port, struct passwd *pw,
/* Create pipes for communicating with the proxy. */
if (pipe(pin) < 0 || pipe(pout) < 0)
fatal("Could not create pipes to communicate with the proxy: %.100s",
strerror(errno));
strerror(errno));
debug("Executing proxy command: %.500s", command_string);
@ -142,16 +158,18 @@ ssh_proxy_connect(const char *host, u_short port, struct passwd *pw,
/* Set the connection file descriptors. */
packet_set_connection(pout[0], pin[1]);
return 1;
/* Indicate OK return */
return 0;
}
/*
* Creates a (possibly privileged) socket for use as the ssh connection.
*/
int
static int
ssh_create_socket(struct passwd *pw, int privileged, int family)
{
int sock;
int sock, gaierr;
struct addrinfo hints, *res;
/*
* If we are running as root and want to connect to a privileged
@ -164,17 +182,40 @@ ssh_create_socket(struct passwd *pw, int privileged, int family)
error("rresvport: af=%d %.100s", family, strerror(errno));
else
debug("Allocated local port %d.", p);
} else {
/*
* Just create an ordinary socket on arbitrary port. We use
* the user's uid to create the socket.
*/
temporarily_use_uid(pw);
sock = socket(family, SOCK_STREAM, 0);
if (sock < 0)
error("socket: %.100s", strerror(errno));
restore_uid();
return sock;
}
/*
* Just create an ordinary socket on arbitrary port. We use
* the user's uid to create the socket.
*/
temporarily_use_uid(pw);
sock = socket(family, SOCK_STREAM, 0);
if (sock < 0)
error("socket: %.100s", strerror(errno));
restore_uid();
/* Bind the socket to an alternative local IP address */
if (options.bind_address == NULL)
return sock;
memset(&hints, 0, sizeof(hints));
hints.ai_family = family;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
gaierr = getaddrinfo(options.bind_address, "0", &hints, &res);
if (gaierr) {
error("getaddrinfo: %s: %s", options.bind_address,
gai_strerror(gaierr));
close(sock);
return -1;
}
if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
error("bind: %s: %s", options.bind_address, strerror(errno));
close(sock);
freeaddrinfo(res);
return -1;
}
freeaddrinfo(res);
return sock;
}
@ -188,12 +229,17 @@ ssh_create_socket(struct passwd *pw, int privileged, int family)
* second). If proxy_command is non-NULL, it specifies the command (with %h
* and %p substituted for host and port, respectively) to use to contact
* the daemon.
* Return values:
* 0 for OK
* ECONNREFUSED if we got a "Connection Refused" by the peer on any address
* ECONNABORTED if we failed without a "Connection refused"
* Suitable error messages for the connection failure will already have been
* printed.
*/
int
ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
u_short port, int connection_attempts,
int anonymous, struct passwd *pw,
const char *proxy_command)
u_short port, int family, int connection_attempts,
int anonymous, struct passwd *pw, const char *proxy_command)
{
int gaierr;
int on = 1;
@ -202,9 +248,15 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
struct addrinfo hints, *ai, *aitop;
struct linger linger;
struct servent *sp;
/*
* Did we get only other errors than "Connection refused" (which
* should block fallback to rsh and similar), or did we get at least
* one "Connection refused"?
*/
int full_failure = 1;
debug("ssh_connect: getuid %u geteuid %u anon %d",
(u_int) getuid(), (u_int) geteuid(), anonymous);
(u_int) getuid(), (u_int) geteuid(), anonymous);
/* Get default port if port has not been set. */
if (port == 0) {
@ -221,7 +273,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
/* No proxy command. */
memset(&hints, 0, sizeof(hints));
hints.ai_family = IPv4or6;
hints.ai_family = family;
hints.ai_socktype = SOCK_STREAM;
snprintf(strport, sizeof strport, "%d", port);
if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)
@ -232,8 +284,8 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
* Try to connect several times. On some machines, the first time
* will sometimes fail. In general socket code appears to behave
* quite magically on many machines.
*/
for (attempt = 0; attempt < connection_attempts; attempt++) {
*/
for (attempt = 0; ;) {
if (attempt > 0)
debug("Trying again...");
@ -256,6 +308,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
!anonymous && geteuid() == 0,
ai->ai_family);
if (sock < 0)
/* Any error is already output */
continue;
/* Connect to the host. We use the user's uid in the
@ -269,7 +322,11 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
restore_uid();
break;
} else {
debug("connect: %.100s", strerror(errno));
if (errno == ECONNREFUSED)
full_failure = 0;
log("ssh: connect to address %s port %s: %s",
sockaddr_ntop(ai->ai_addr), strport,
strerror(errno));
restore_uid();
/*
* Close the failed socket; there appear to
@ -277,13 +334,15 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
* which connect() has already returned an
* error.
*/
shutdown(sock, SHUT_RDWR);
close(sock);
}
}
if (ai)
break; /* Successful connection. */
attempt++;
if (attempt >= connection_attempts)
break;
/* Sleep a moment before retrying. */
sleep(1);
}
@ -292,7 +351,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
/* Return failure if we didn't get a successful connection. */
if (attempt >= connection_attempts)
return 0;
return full_failure ? ECONNABORTED : ECONNREFUSED;
debug("Connection established.");
@ -314,14 +373,14 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
/* Set the connection. */
packet_set_connection(sock, sock);
return 1;
return 0;
}
/*
* Waits for the server identification string, and sends our own
* identification string.
*/
void
static void
ssh_exchange_identification(void)
{
char buf[256], remote_version[256]; /* must be same size! */
@ -363,12 +422,12 @@ ssh_exchange_identification(void)
&remote_major, &remote_minor, remote_version) != 3)
fatal("Bad remote protocol version identification: '%.100s'", buf);
debug("Remote protocol version %d.%d, remote software version %.100s",
remote_major, remote_minor, remote_version);
remote_major, remote_minor, remote_version);
compat_datafellows(remote_version);
mismatch = 0;
switch(remote_major) {
switch (remote_major) {
case 1:
if (remote_minor == 99 &&
(options.protocol & SSH_PROTO_2) &&
@ -406,8 +465,6 @@ ssh_exchange_identification(void)
fatal("Protocol major versions differ: %d vs. %d",
(options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
remote_major);
if (compat20)
packet_set_ssh2_format();
/* Send our own protocol version identification. */
snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
@ -422,61 +479,38 @@ ssh_exchange_identification(void)
}
/* defaults to 'no' */
int
read_yes_or_no(const char *prompt, int defval)
static int
confirm(const char *prompt)
{
char buf[1024];
FILE *f;
int retval = -1;
const char *msg, *again = "Please type 'yes' or 'no': ";
char *p;
int ret = -1;
if (options.batch_mode)
return 0;
if (isatty(STDIN_FILENO))
f = stdin;
else
f = fopen(_PATH_TTY, "rw");
if (f == NULL)
return 0;
fflush(stdout);
while (1) {
fprintf(stderr, "%s", prompt);
if (fgets(buf, sizeof(buf), f) == NULL) {
/* Print a newline (the prompt probably didn\'t have one). */
fprintf(stderr, "\n");
strlcpy(buf, "no", sizeof buf);
}
/* Remove newline from response. */
if (strchr(buf, '\n'))
*strchr(buf, '\n') = 0;
if (buf[0] == 0)
retval = defval;
if (strcmp(buf, "yes") == 0)
retval = 1;
else if (strcmp(buf, "no") == 0)
retval = 0;
else
fprintf(stderr, "Please type 'yes' or 'no'.\n");
if (retval != -1) {
if (f != stdin)
fclose(f);
return retval;
}
for (msg = prompt;;msg = again) {
p = read_passphrase(msg, RP_ECHO);
if (p == NULL ||
(p[0] == '\0') || (p[0] == '\n') ||
strncasecmp(p, "no", 2) == 0)
ret = 0;
if (strncasecmp(p, "yes", 3) == 0)
ret = 1;
if (p)
xfree(p);
if (ret != -1)
return ret;
}
}
/*
* check whether the supplied host key is valid, return only if ok.
* check whether the supplied host key is valid, return -1 if the key
* is not valid. the user_hostfile will not be updated if 'readonly' is true.
*/
void
static int
check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
const char *user_hostfile, const char *system_hostfile)
int readonly, const char *user_hostfile, const char *system_hostfile)
{
Key *file_key;
char *type = key_type(host_key);
@ -486,7 +520,8 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
HostStatus ip_status;
int local = 0, host_ip_differ = 0;
char ntop[NI_MAXHOST];
int host_line, ip_line;
char msg[1024];
int len, host_line, ip_line;
const char *host_file = NULL, *ip_file = NULL;
/*
@ -500,19 +535,22 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
/** hostaddr == 0! */
switch (hostaddr->sa_family) {
case AF_INET:
local = (ntohl(((struct sockaddr_in *)hostaddr)->sin_addr.s_addr) >> 24) == IN_LOOPBACKNET;
local = (ntohl(((struct sockaddr_in *)hostaddr)->
sin_addr.s_addr) >> 24) == IN_LOOPBACKNET;
break;
case AF_INET6:
local = IN6_IS_ADDR_LOOPBACK(&(((struct sockaddr_in6 *)hostaddr)->sin6_addr));
local = IN6_IS_ADDR_LOOPBACK(
&(((struct sockaddr_in6 *)hostaddr)->sin6_addr));
break;
default:
local = 0;
break;
}
if (local && options.host_key_alias == NULL) {
if (options.no_host_authentication_for_localhost == 1 && local &&
options.host_key_alias == NULL) {
debug("Forcing accepting of host key for "
"loopback/localhost.");
return;
return 0;
}
/*
@ -556,10 +594,12 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
* hosts or in the systemwide list.
*/
host_file = user_hostfile;
host_status = check_host_in_hostfile(host_file, host, host_key, file_key, &host_line);
host_status = check_host_in_hostfile(host_file, host, host_key,
file_key, &host_line);
if (host_status == HOST_NEW) {
host_file = system_hostfile;
host_status = check_host_in_hostfile(host_file, host, host_key, file_key, &host_line);
host_status = check_host_in_hostfile(host_file, host, host_key,
file_key, &host_line);
}
/*
* Also perform check for the ip address, skip the check if we are
@ -569,10 +609,12 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
Key *ip_key = key_new(host_key->type);
ip_file = user_hostfile;
ip_status = check_host_in_hostfile(ip_file, ip, host_key, ip_key, &ip_line);
ip_status = check_host_in_hostfile(ip_file, ip, host_key,
ip_key, &ip_line);
if (ip_status == HOST_NEW) {
ip_file = system_hostfile;
ip_status = check_host_in_hostfile(ip_file, ip, host_key, ip_key, &ip_line);
ip_status = check_host_in_hostfile(ip_file, ip,
host_key, ip_key, &ip_line);
}
if (host_status == HOST_CHANGED &&
(ip_status != HOST_CHANGED || !key_equal(ip_key, file_key)))
@ -591,32 +633,46 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
host, type);
debug("Found key in %s:%d", host_file, host_line);
if (options.check_host_ip && ip_status == HOST_NEW) {
if (!add_host_to_hostfile(user_hostfile, ip, host_key))
log("Failed to add the %s host key for IP address '%.128s' to the list of known hosts (%.30s).",
type, ip, user_hostfile);
else
log("Warning: Permanently added the %s host key for IP address '%.128s' to the list of known hosts.",
if (readonly)
log("%s host key for IP address "
"'%.128s' not in list of known hosts.",
type, ip);
else if (!add_host_to_hostfile(user_hostfile, ip,
host_key))
log("Failed to add the %s host key for IP "
"address '%.128s' to the list of known "
"hosts (%.30s).", type, ip, user_hostfile);
else
log("Warning: Permanently added the %s host "
"key for IP address '%.128s' to the list "
"of known hosts.", type, ip);
}
break;
case HOST_NEW:
if (readonly)
goto fail;
/* The host is new. */
if (options.strict_host_key_checking == 1) {
/* User has requested strict host key checking. We will not add the host key
automatically. The only alternative left is to abort. */
fatal("No %s host key is known for %.200s and you have requested strict checking.", type, host);
/*
* User has requested strict host key checking. We
* will not add the host key automatically. The only
* alternative left is to abort.
*/
error("No %s host key is known for %.200s and you "
"have requested strict checking.", type, host);
goto fail;
} else if (options.strict_host_key_checking == 2) {
/* The default */
char prompt[1024];
fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
snprintf(prompt, sizeof(prompt),
"The authenticity of host '%.200s (%s)' can't be established.\n"
snprintf(msg, sizeof(msg),
"The authenticity of host '%.200s (%s)' can't be "
"established.\n"
"%s key fingerprint is %s.\n"
"Are you sure you want to continue connecting (yes/no)? ",
host, ip, type, fp);
"Are you sure you want to continue connecting "
"(yes/no)? ", host, ip, type, fp);
xfree(fp);
if (!read_yes_or_no(prompt, -1))
fatal("Aborted by user!");
if (!confirm(msg))
goto fail;
}
if (options.check_host_ip && ip_status == HOST_NEW) {
snprintf(hostline, sizeof(hostline), "%s,%s", host, ip);
@ -624,13 +680,16 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
} else
hostp = host;
/* If not in strict mode, add the key automatically to the local known_hosts file. */
/*
* If not in strict mode, add the key automatically to the
* local known_hosts file.
*/
if (!add_host_to_hostfile(user_hostfile, hostp, host_key))
log("Failed to add the host to the list of known hosts (%.500s).",
user_hostfile);
log("Failed to add the host to the list of known "
"hosts (%.500s).", user_hostfile);
else
log("Warning: Permanently added '%.200s' (%s) to the list of known hosts.",
hostp, type);
log("Warning: Permanently added '%.200s' (%s) to the "
"list of known hosts.", hostp, type);
break;
case HOST_CHANGED:
if (options.check_host_ip && host_ip_differ) {
@ -672,8 +731,11 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
* If strict host key checking is in use, the user will have
* to edit the key manually and we can only abort.
*/
if (options.strict_host_key_checking)
fatal("%s host key for %.200s has changed and you have requested strict checking.", type, host);
if (options.strict_host_key_checking) {
error("%s host key for %.200s has changed and you have "
"requested strict checking.", type, host);
goto fail;
}
/*
* If strict host key checking has not been requested, allow
@ -681,20 +743,26 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
* agent forwarding.
*/
if (options.password_authentication) {
error("Password authentication is disabled to avoid trojan horses.");
error("Password authentication is disabled to avoid "
"man-in-the-middle attacks.");
options.password_authentication = 0;
}
if (options.forward_agent) {
error("Agent forwarding is disabled to avoid trojan horses.");
error("Agent forwarding is disabled to avoid "
"man-in-the-middle attacks.");
options.forward_agent = 0;
}
if (options.forward_x11) {
error("X11 forwarding is disabled to avoid trojan horses.");
error("X11 forwarding is disabled to avoid "
"man-in-the-middle attacks.");
options.forward_x11 = 0;
}
if (options.num_local_forwards > 0 || options.num_remote_forwards > 0) {
error("Port forwarding is disabled to avoid trojan horses.");
options.num_local_forwards = options.num_remote_forwards = 0;
if (options.num_local_forwards > 0 ||
options.num_remote_forwards > 0) {
error("Port forwarding is disabled to avoid "
"man-in-the-middle attacks.");
options.num_local_forwards =
options.num_remote_forwards = 0;
}
/*
* XXX Should permit the user to change to use the new id.
@ -708,223 +776,55 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
if (options.check_host_ip && host_status != HOST_CHANGED &&
ip_status == HOST_CHANGED) {
log("Warning: the %s host key for '%.200s' "
"differs from the key for the IP address '%.128s'",
type, host, ip);
if (host_status == HOST_OK)
log("Matching host key in %s:%d", host_file, host_line);
log("Offending key for IP in %s:%d", ip_file, ip_line);
snprintf(msg, sizeof(msg),
"Warning: the %s host key for '%.200s' "
"differs from the key for the IP address '%.128s'"
"\nOffending key for IP in %s:%d",
type, host, ip, ip_file, ip_line);
if (host_status == HOST_OK) {
len = strlen(msg);
snprintf(msg + len, sizeof(msg) - len,
"\nMatching host key in %s:%d",
host_file, host_line);
}
if (options.strict_host_key_checking == 1) {
fatal("Exiting, you have requested strict checking.");
log(msg);
error("Exiting, you have requested strict checking.");
goto fail;
} else if (options.strict_host_key_checking == 2) {
if (!read_yes_or_no("Are you sure you want " \
"to continue connecting (yes/no)? ", -1))
fatal("Aborted by user!");
strlcat(msg, "\nAre you sure you want "
"to continue connecting (yes/no)? ", sizeof(msg));
if (!confirm(msg))
goto fail;
} else {
log(msg);
}
}
xfree(ip);
return 0;
fail:
xfree(ip);
return -1;
}
#ifdef KRB5
int
try_krb5_authentication(krb5_context *context, krb5_auth_context *auth_context)
verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
{
krb5_error_code problem;
const char *tkfile;
struct stat buf;
krb5_ccache ccache = NULL;
const char *remotehost;
krb5_data ap;
int type, payload_len;
krb5_ap_rep_enc_part *reply = NULL;
int ret;
struct stat st;
memset(&ap, 0, sizeof(ap));
problem = krb5_init_context(context);
if (problem) {
ret = 0;
goto out;
}
tkfile = krb5_cc_default_name(*context);
if (strncmp(tkfile, "FILE:", 5) == 0)
tkfile += 5;
if (stat(tkfile, &buf) == 0 && getuid() != buf.st_uid) {
debug("Kerberos V5: could not get default ccache (permission denied).");
ret = 0;
goto out;
}
problem = krb5_cc_default(*context, &ccache);
if (problem) {
ret = 0;
goto out;
}
remotehost = get_canonical_hostname(1);
problem = krb5_mk_req(*context, auth_context, AP_OPTS_MUTUAL_REQUIRED,
"host", remotehost, NULL, ccache, &ap);
if (problem) {
ret = 0;
goto out;
}
packet_start(SSH_CMSG_AUTH_KERBEROS);
packet_put_string((char *) ap.data, ap.length);
packet_send();
packet_write_wait();
xfree(ap.data);
ap.length = 0;
type = packet_read(&payload_len);
switch (type) {
case SSH_SMSG_FAILURE:
/* Should really be SSH_SMSG_AUTH_KERBEROS_FAILURE */
debug("Kerberos V5 authentication failed.");
ret = 0;
break;
case SSH_SMSG_AUTH_KERBEROS_RESPONSE:
/* SSH_SMSG_AUTH_KERBEROS_SUCCESS */
debug("Kerberos V5 authentication accepted.");
/* Get server's response. */
ap.data = packet_get_string((unsigned int *) &ap.length);
packet_integrity_check(payload_len, 4 + ap.length, type);
/* XXX je to dobre? */
problem = krb5_rd_rep(*context, *auth_context, &ap, &reply);
if (problem) {
ret = 0;
goto out;
}
ret = 1;
break;
default:
packet_disconnect("Protocol error on Kerberos V5 response: %d", type);
ret = 0;
break;
}
out:
if (ccache != NULL)
krb5_cc_close(*context, ccache);
if (reply != NULL)
krb5_free_ap_rep_enc_part(*context, reply);
if (ap.length > 0)
krb5_data_free(&ap);
return ret;
/* return ok if the key can be found in an old keyfile */
if (stat(options.system_hostfile2, &st) == 0 ||
stat(options.user_hostfile2, &st) == 0) {
if (check_host_key(host, hostaddr, host_key, /*readonly*/ 1,
options.user_hostfile2, options.system_hostfile2) == 0)
return 0;
}
return check_host_key(host, hostaddr, host_key, /*readonly*/ 0,
options.user_hostfile, options.system_hostfile);
}
void
send_krb5_tgt(krb5_context context, krb5_auth_context auth_context)
{
int fd;
int type, payload_len;
krb5_error_code problem;
krb5_data outbuf;
krb5_ccache ccache = NULL;
krb5_creds creds;
krb5_kdc_flags flags;
const char *remotehost = get_canonical_hostname(1);
memset(&creds, 0, sizeof(creds));
memset(&outbuf, 0, sizeof(outbuf));
fd = packet_get_connection_in();
problem = krb5_auth_con_setaddrs_from_fd(context, auth_context, &fd);
if (problem) {
goto out;
}
#if 0
tkfile = krb5_cc_default_name(context);
if (strncmp(tkfile, "FILE:", 5) == 0)
tkfile += 5;
if (stat(tkfile, &buf) == 0 && getuid() != buf.st_uid) {
debug("Kerberos V5: could not get default ccache (permission denied).");
goto out;
}
#endif
problem = krb5_cc_default(context, &ccache);
if (problem) {
goto out;
}
problem = krb5_cc_get_principal(context, ccache, &creds.client);
if (problem) {
goto out;
}
problem = krb5_build_principal(context, &creds.server,
strlen(creds.client->realm),
creds.client->realm,
"krbtgt",
creds.client->realm,
NULL);
if (problem) {
goto out;
}
creds.times.endtime = 0;
flags.i = 0;
flags.b.forwarded = 1;
flags.b.forwardable = krb5_config_get_bool(context, NULL,
"libdefaults", "forwardable", NULL);
problem = krb5_get_forwarded_creds (context,
auth_context,
ccache,
flags.i,
remotehost,
&creds,
&outbuf);
if (problem) {
goto out;
}
packet_start(SSH_CMSG_HAVE_KERBEROS_TGT);
packet_put_string((char *)outbuf.data, outbuf.length);
packet_send();
packet_write_wait();
type = packet_read(&payload_len);
switch (type) {
case SSH_SMSG_SUCCESS:
break;
case SSH_SMSG_FAILURE:
break;
default:
break;
}
out:
if (creds.client)
krb5_free_principal(context, creds.client);
if (creds.server)
krb5_free_principal(context, creds.server);
if (ccache)
krb5_cc_close(context, ccache);
if (outbuf.data)
xfree(outbuf.data);
return;
}
#endif /* KRB5 */
/*
* Starts a dialog with the server, and authenticates the current user on the
* server. This does not need any extra privileges. The basic connection
@ -972,7 +872,7 @@ ssh_put_password(char *password)
char *padded;
if (datafellows & SSH_BUG_PASSWORDPAD) {
packet_put_string(password, strlen(password));
packet_put_cstring(password);
return;
}
size = roundup(strlen(password) + 1, 32);

View file

@ -1,4 +1,4 @@
/* $OpenBSD: sshconnect.h,v 1.9 2001/04/12 19:15:25 markus Exp $ */
/* $OpenBSD: sshconnect.h,v 1.13 2001/10/08 19:05:05 markus Exp $ */
/* $FreeBSD$ */
/*
@ -28,29 +28,20 @@
#define SSHCONNECT_H
int
ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
u_short port, int connection_attempts,
int anonymous, struct passwd *pw,
const char *proxy_command);
ssh_connect(const char *, struct sockaddr_storage *, u_short, int, int,
int, struct passwd *, const char *);
void
ssh_login(Key **keys, int nkeys, const char *orighost,
struct sockaddr *hostaddr, struct passwd *pw);
ssh_login(Key **, int, const char *, struct sockaddr *, struct passwd *);
void
check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
const char *user_hostfile, const char *system_hostfile);
int verify_host_key(char *, struct sockaddr *, Key *);
void ssh_kex(char *host, struct sockaddr *hostaddr);
void ssh_kex2(char *host, struct sockaddr *hostaddr);
void ssh_kex(char *, struct sockaddr *);
void ssh_kex2(char *, struct sockaddr *);
void
ssh_userauth1(const char *local_user, const char *server_user, char *host,
Key **keys, int nkeys);
void
ssh_userauth2(const char *local_user, const char *server_user, char *host,
Key **keys, int nkeys);
void ssh_userauth1(const char *, const char *, char *, Key **, int);
void ssh_userauth2(const char *, const char *, char *, Key **, int);
void ssh_put_password(char *password);
void ssh_put_password(char *);
#endif

File diff suppressed because it is too large Load diff

View file

@ -23,30 +23,21 @@
*/
#include "includes.h"
RCSID("$OpenBSD: sshconnect2.c,v 1.97 2002/02/25 16:33:27 markus Exp $");
RCSID("$FreeBSD$");
RCSID("$OpenBSD: sshconnect2.c,v 1.72 2001/04/18 23:43:26 markus Exp $");
#include <openssl/bn.h>
#include <openssl/md5.h>
#include <openssl/dh.h>
#include <openssl/hmac.h>
#include "ssh.h"
#include "ssh2.h"
#include "xmalloc.h"
#include "rsa.h"
#include "buffer.h"
#include "packet.h"
#include "uidswap.h"
#include "compat.h"
#include "bufaux.h"
#include "cipher.h"
#include "kex.h"
#include "myproposal.h"
#include "key.h"
#include "sshconnect.h"
#include "authfile.h"
#include "cli.h"
#include "dh.h"
#include "authfd.h"
#include "log.h"
@ -73,11 +64,11 @@ struct sockaddr *xxx_hostaddr;
Kex *xxx_kex = NULL;
int
check_host_key_callback(Key *hostkey)
static int
verify_host_key_callback(Key *hostkey)
{
check_host_key(xxx_host, xxx_hostaddr, hostkey,
options.user_hostfile2, options.system_hostfile2);
if (verify_host_key(xxx_host, xxx_hostaddr, hostkey) == -1)
fatal("Host key verification failed.");
return 0;
}
@ -113,14 +104,14 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs;
}
if (options.hostkeyalgorithms != NULL)
myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
options.hostkeyalgorithms;
/* start key exchange */
kex = kex_setup(myproposal);
kex->client_version_string=client_version_string;
kex->server_version_string=server_version_string;
kex->check_host_key=&check_host_key_callback;
kex->verify_host_key=&verify_host_key_callback;
xxx_kex = kex;
@ -148,7 +139,7 @@ typedef struct Authmethod Authmethod;
typedef int sign_cb_fn(
Authctxt *authctxt, Key *key,
u_char **sigp, int *lenp, u_char *data, int datalen);
u_char **sigp, u_int *lenp, u_char *data, u_int datalen);
struct Authctxt {
const char *server_user;
@ -166,6 +157,8 @@ struct Authctxt {
/* hostbased */
Key **keys;
int nkeys;
/* kbd-interactive */
int info_req_seen;
};
struct Authmethod {
char *name; /* string to compare against server's list */
@ -174,47 +167,45 @@ struct Authmethod {
int *batch_flag; /* flag in option struct that disables method */
};
void input_userauth_success(int type, int plen, void *ctxt);
void input_userauth_failure(int type, int plen, void *ctxt);
void input_userauth_banner(int type, int plen, void *ctxt);
void input_userauth_error(int type, int plen, void *ctxt);
void input_userauth_info_req(int type, int plen, void *ctxt);
void input_userauth_pk_ok(int type, int plen, void *ctxt);
void input_userauth_success(int, u_int32_t, void *);
void input_userauth_failure(int, u_int32_t, void *);
void input_userauth_banner(int, u_int32_t, void *);
void input_userauth_error(int, u_int32_t, void *);
void input_userauth_info_req(int, u_int32_t, void *);
void input_userauth_pk_ok(int, u_int32_t, void *);
int userauth_none(Authctxt *authctxt);
int userauth_pubkey(Authctxt *authctxt);
int userauth_passwd(Authctxt *authctxt);
int userauth_kbdint(Authctxt *authctxt);
int userauth_hostbased(Authctxt *authctxt);
int userauth_none(Authctxt *);
int userauth_pubkey(Authctxt *);
int userauth_passwd(Authctxt *);
int userauth_kbdint(Authctxt *);
int userauth_hostbased(Authctxt *);
void userauth(Authctxt *authctxt, char *authlist);
void userauth(Authctxt *, char *);
int
sign_and_send_pubkey(Authctxt *authctxt, Key *k,
sign_cb_fn *sign_callback);
void clear_auth_state(Authctxt *authctxt);
static int sign_and_send_pubkey(Authctxt *, Key *, sign_cb_fn *);
static void clear_auth_state(Authctxt *);
Authmethod *authmethod_get(char *authlist);
Authmethod *authmethod_lookup(const char *name);
char *authmethods_get(void);
static Authmethod *authmethod_get(char *authlist);
static Authmethod *authmethod_lookup(const char *name);
static char *authmethods_get(void);
Authmethod authmethods[] = {
{"publickey",
userauth_pubkey,
&options.pubkey_authentication,
NULL},
{"password",
userauth_passwd,
&options.password_authentication,
&options.batch_mode},
{"keyboard-interactive",
userauth_kbdint,
&options.kbd_interactive_authentication,
&options.batch_mode},
{"hostbased",
userauth_hostbased,
&options.hostbased_authentication,
NULL},
{"publickey",
userauth_pubkey,
&options.pubkey_authentication,
NULL},
{"keyboard-interactive",
userauth_kbdint,
&options.kbd_interactive_authentication,
&options.batch_mode},
{"password",
userauth_passwd,
&options.password_authentication,
&options.batch_mode},
{"none",
userauth_none,
NULL,
@ -228,9 +219,8 @@ ssh_userauth2(const char *local_user, const char *server_user, char *host,
{
Authctxt authctxt;
int type;
int plen;
if (options.challenge_reponse_authentication)
if (options.challenge_response_authentication)
options.kbd_interactive_authentication = 1;
debug("send SSH2_MSG_SERVICE_REQUEST");
@ -238,24 +228,25 @@ ssh_userauth2(const char *local_user, const char *server_user, char *host,
packet_put_cstring("ssh-userauth");
packet_send();
packet_write_wait();
type = packet_read(&plen);
type = packet_read();
if (type != SSH2_MSG_SERVICE_ACCEPT) {
fatal("denied SSH2_MSG_SERVICE_ACCEPT: %d", type);
}
if (packet_remaining() > 0) {
char *reply = packet_get_string(&plen);
char *reply = packet_get_string(NULL);
debug("service_accept: %s", reply);
xfree(reply);
} else {
debug("buggy server: service_accept w/o service");
}
packet_done();
packet_check_eom();
debug("got SSH2_MSG_SERVICE_ACCEPT");
if (options.preferred_authentications == NULL)
options.preferred_authentications = authmethods_get();
/* setup authentication context */
memset(&authctxt, 0, sizeof(authctxt));
authctxt.agent = ssh_get_authentication_connection();
authctxt.server_user = server_user;
authctxt.local_user = local_user;
@ -266,6 +257,7 @@ ssh_userauth2(const char *local_user, const char *server_user, char *host,
authctxt.authlist = NULL;
authctxt.keys = keys;
authctxt.nkeys = nkeys;
authctxt.info_req_seen = 0;
if (authctxt.method == NULL)
fatal("ssh_userauth2: internal error: cannot send userauth none request");
@ -308,13 +300,13 @@ userauth(Authctxt *authctxt, char *authlist)
}
}
void
input_userauth_error(int type, int plen, void *ctxt)
input_userauth_error(int type, u_int32_t seq, void *ctxt)
{
fatal("input_userauth_error: bad message during authentication: "
"type %d", type);
}
void
input_userauth_banner(int type, int plen, void *ctxt)
input_userauth_banner(int type, u_int32_t seq, void *ctxt)
{
char *msg, *lang;
debug3("input_userauth_banner");
@ -325,7 +317,7 @@ input_userauth_banner(int type, int plen, void *ctxt)
xfree(lang);
}
void
input_userauth_success(int type, int plen, void *ctxt)
input_userauth_success(int type, u_int32_t seq, void *ctxt)
{
Authctxt *authctxt = ctxt;
if (authctxt == NULL)
@ -336,7 +328,7 @@ input_userauth_success(int type, int plen, void *ctxt)
authctxt->success = 1; /* break out */
}
void
input_userauth_failure(int type, int plen, void *ctxt)
input_userauth_failure(int type, u_int32_t seq, void *ctxt)
{
Authctxt *authctxt = ctxt;
char *authlist = NULL;
@ -347,7 +339,7 @@ input_userauth_failure(int type, int plen, void *ctxt)
authlist = packet_get_string(NULL);
partial = packet_get_char();
packet_done();
packet_check_eom();
if (partial != 0)
log("Authenticated with partial success.");
@ -357,13 +349,15 @@ input_userauth_failure(int type, int plen, void *ctxt)
userauth(authctxt, authlist);
}
void
input_userauth_pk_ok(int type, int plen, void *ctxt)
input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt)
{
Authctxt *authctxt = ctxt;
Key *key = NULL;
Buffer b;
int alen, blen, sent = 0;
char *pkalg, *pkblob, *fp;
int pktype, sent = 0;
u_int alen, blen;
char *pkalg, *fp;
u_char *pkblob;
if (authctxt == NULL)
fatal("input_userauth_pk_ok: no authentication context");
@ -379,7 +373,7 @@ input_userauth_pk_ok(int type, int plen, void *ctxt)
pkalg = packet_get_string(&alen);
pkblob = packet_get_string(&blen);
}
packet_done();
packet_check_eom();
debug("input_userauth_pk_ok: pkalg %s blen %d lastkey %p hint %d",
pkalg, blen, authctxt->last_key, authctxt->last_key_hint);
@ -390,7 +384,7 @@ input_userauth_pk_ok(int type, int plen, void *ctxt)
debug("no last key or no sign cb");
break;
}
if (key_type_from_name(pkalg) == KEY_UNSPEC) {
if ((pktype = key_type_from_name(pkalg)) == KEY_UNSPEC) {
debug("unknown pkalg %s", pkalg);
break;
}
@ -398,6 +392,12 @@ input_userauth_pk_ok(int type, int plen, void *ctxt)
debug("no key from blob. pkalg %s", pkalg);
break;
}
if (key->type != pktype) {
error("input_userauth_pk_ok: type mismatch "
"for decoded key (received %d, expected %d)",
key->type, pktype);
break;
}
fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
debug2("input_userauth_pk_ok: fp %s", fp);
xfree(fp);
@ -407,7 +407,7 @@ input_userauth_pk_ok(int type, int plen, void *ctxt)
}
sent = sign_and_send_pubkey(authctxt, key,
authctxt->last_key_sign);
} while(0);
} while (0);
if (key != NULL)
key_free(key);
@ -446,7 +446,7 @@ userauth_passwd(Authctxt *authctxt)
if (attempt++ >= options.number_of_password_prompts)
return 0;
if(attempt != 1)
if (attempt != 1)
error("Permission denied, please try again.");
snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ",
@ -460,12 +460,12 @@ userauth_passwd(Authctxt *authctxt)
ssh_put_password(password);
memset(password, 0, strlen(password));
xfree(password);
packet_inject_ignore(64);
packet_add_padding(64);
packet_send();
return 1;
}
void
static void
clear_auth_state(Authctxt *authctxt)
{
/* XXX clear authentication state */
@ -478,12 +478,12 @@ clear_auth_state(Authctxt *authctxt)
authctxt->last_key_sign = NULL;
}
int
static int
sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
{
Buffer b;
u_char *blob, *signature;
int bloblen, slen;
u_int bloblen, slen;
int skip = 0;
int ret = -1;
int have_sig = 1;
@ -563,12 +563,12 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
return 1;
}
int
static int
send_pubkey_test(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback,
int hint)
{
u_char *blob;
int bloblen, have_sig = 0;
u_int bloblen, have_sig = 0;
debug3("send_pubkey_test");
@ -596,7 +596,7 @@ send_pubkey_test(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback,
return 1;
}
Key *
static Key *
load_identity_file(char *filename)
{
Key *private;
@ -613,7 +613,7 @@ load_identity_file(char *filename)
if (options.batch_mode)
return NULL;
snprintf(prompt, sizeof prompt,
"Enter passphrase for key '%.100s': ", filename);
"Enter passphrase for key '%.100s': ", filename);
for (i = 0; i < options.number_of_password_prompts; i++) {
passphrase = read_passphrase(prompt, 0);
if (strcmp(passphrase, "") != 0) {
@ -634,9 +634,9 @@ load_identity_file(char *filename)
return private;
}
int
identity_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp,
u_char *data, int datalen)
static int
identity_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp,
u_char *data, u_int datalen)
{
Key *private;
int idx, ret;
@ -644,6 +644,11 @@ identity_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp,
idx = authctxt->last_key_hint;
if (idx < 0)
return -1;
/* private key is stored in external hardware */
if (options.identity_keys[idx]->flags & KEY_FLAG_EXT)
return key_sign(options.identity_keys[idx], sigp, lenp, data, datalen);
private = load_identity_file(options.identity_files[idx]);
if (private == NULL)
return -1;
@ -652,19 +657,21 @@ identity_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp,
return ret;
}
int agent_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp,
u_char *data, int datalen)
static int
agent_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp,
u_char *data, u_int datalen)
{
return ssh_agent_sign(authctxt->agent, key, sigp, lenp, data, datalen);
}
int key_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp,
u_char *data, int datalen)
static int
key_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp,
u_char *data, u_int datalen)
{
return key_sign(key, sigp, lenp, data, datalen);
}
int
static int
userauth_pubkey_agent(Authctxt *authctxt)
{
static int called = 0;
@ -703,7 +710,7 @@ userauth_pubkey(Authctxt *authctxt)
if (authctxt->agent != NULL) {
do {
sent = userauth_pubkey_agent(authctxt);
} while(!sent && authctxt->agent->howmany > 0);
} while (!sent && authctxt->agent->howmany > 0);
}
while (!sent && idx < options.num_identity_files) {
key = options.identity_keys[idx];
@ -736,6 +743,12 @@ userauth_kbdint(Authctxt *authctxt)
if (attempt++ >= options.number_of_password_prompts)
return 0;
/* disable if no SSH2_MSG_USERAUTH_INFO_REQUEST has been seen */
if (attempt > 1 && !authctxt->info_req_seen) {
debug3("userauth_kbdint: disable: no info_req_seen");
dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, NULL);
return 0;
}
debug2("userauth_kbdint");
packet_start(SSH2_MSG_USERAUTH_REQUEST);
@ -755,7 +768,7 @@ userauth_kbdint(Authctxt *authctxt)
* parse INFO_REQUEST, prompt user and send INFO_RESPONSE
*/
void
input_userauth_info_req(int type, int plen, void *ctxt)
input_userauth_info_req(int type, u_int32_t seq, void *ctxt)
{
Authctxt *authctxt = ctxt;
char *name, *inst, *lang, *prompt, *response;
@ -767,13 +780,15 @@ input_userauth_info_req(int type, int plen, void *ctxt)
if (authctxt == NULL)
fatal("input_userauth_info_req: no authentication context");
authctxt->info_req_seen = 1;
name = packet_get_string(NULL);
inst = packet_get_string(NULL);
lang = packet_get_string(NULL);
if (strlen(name) > 0)
cli_mesg(name);
log("%s", name);
if (strlen(inst) > 0)
cli_mesg(inst);
log("%s", inst);
xfree(name);
xfree(inst);
xfree(lang);
@ -788,20 +803,21 @@ input_userauth_info_req(int type, int plen, void *ctxt)
packet_start(SSH2_MSG_USERAUTH_INFO_RESPONSE);
packet_put_int(num_prompts);
debug2("input_userauth_info_req: num_prompts %d", num_prompts);
for (i = 0; i < num_prompts; i++) {
prompt = packet_get_string(NULL);
echo = packet_get_char();
response = cli_prompt(prompt, echo);
response = read_passphrase(prompt, echo ? RP_ECHO : 0);
ssh_put_password(response);
memset(response, 0, strlen(response));
xfree(response);
xfree(prompt);
}
packet_done(); /* done with parsing incoming message. */
packet_check_eom(); /* done with parsing incoming message. */
packet_inject_ignore(64);
packet_add_padding(64);
packet_send();
}
@ -820,16 +836,6 @@ userauth_hostbased(Authctxt *authctxt)
u_int blen, slen;
int ok, i, len, found = 0;
p = get_local_name(packet_get_connection_in());
if (p == NULL) {
error("userauth_hostbased: cannot get local ipaddr/name");
return 0;
}
len = strlen(p) + 2;
chost = xmalloc(len);
strlcpy(chost, p, len);
strlcat(chost, ".", len);
debug2("userauth_hostbased: chost %s", chost);
/* check for a useful key */
for (i = 0; i < authctxt->nkeys; i++) {
private = authctxt->keys[i];
@ -841,14 +847,26 @@ userauth_hostbased(Authctxt *authctxt)
}
}
if (!found) {
xfree(chost);
debug("userauth_hostbased: no more client hostkeys");
return 0;
}
if (key_to_blob(private, &blob, &blen) == 0) {
key_free(private);
xfree(chost);
return 0;
}
/* figure out a name for the client host */
p = get_local_name(packet_get_connection_in());
if (p == NULL) {
error("userauth_hostbased: cannot get local ipaddr/name");
key_free(private);
return 0;
}
len = strlen(p) + 2;
chost = xmalloc(len);
strlcpy(chost, p, len);
strlcat(chost, ".", len);
debug2("userauth_hostbased: chost %s", chost);
service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" :
authctxt->service;
pkalg = xstrdup(key_ssh_name(private));
@ -866,7 +884,6 @@ userauth_hostbased(Authctxt *authctxt)
#ifdef DEBUG_PK
buffer_dump(&b);
#endif
debug2("xxx: chost %s", chost);
ok = key_sign(private, &signature, &slen, buffer_ptr(&b), buffer_len(&b));
key_free(private);
buffer_free(&b);
@ -900,7 +917,7 @@ userauth_hostbased(Authctxt *authctxt)
* given auth method name, if configurable options permit this method fill
* in auth_ident field and return true, otherwise return false.
*/
int
static int
authmethod_is_enabled(Authmethod *method)
{
if (method == NULL)
@ -914,7 +931,7 @@ authmethod_is_enabled(Authmethod *method)
return 1;
}
Authmethod *
static Authmethod *
authmethod_lookup(const char *name)
{
Authmethod *method = NULL;
@ -935,12 +952,12 @@ static char *preferred = NULL;
* next method we should try. If the server initially sends a nil list,
* use a built-in default list.
*/
Authmethod *
static Authmethod *
authmethod_get(char *authlist)
{
char *name = NULL;
int next;
u_int next;
/* Use a suitable default if we're passed a nil list. */
if (authlist == NULL || strlen(authlist) == 0)
@ -975,21 +992,23 @@ authmethod_get(char *authlist)
}
}
#define DELIM ","
char *
static char *
authmethods_get(void)
{
Authmethod *method = NULL;
char buf[1024];
Buffer b;
char *list;
buf[0] = '\0';
buffer_init(&b);
for (method = authmethods; method->name != NULL; method++) {
if (authmethod_is_enabled(method)) {
if (buf[0] != '\0')
strlcat(buf, DELIM, sizeof buf);
strlcat(buf, method->name, sizeof buf);
if (buffer_len(&b) > 0)
buffer_append(&b, ",", 1);
buffer_append(&b, method->name, strlen(method->name));
}
}
return xstrdup(buf);
buffer_append(&b, "\0", 1);
list = xstrdup(buffer_ptr(&b));
buffer_free(&b);
return list;
}

View file

@ -34,10 +34,9 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" $OpenBSD: sshd.8,v 1.120 2001/04/22 23:58:36 markus Exp $
.\" $OpenBSD: sshd.8,v 1.170 2002/02/28 20:46:10 stevesk Exp $
.\" $FreeBSD$
.\"
.Dd September 25, 1999
.Dd March 18, 2002
.Dt SSHD 8
.Os
.Sh NAME
@ -45,15 +44,15 @@
.Nd OpenSSH SSH daemon
.Sh SYNOPSIS
.Nm sshd
.Op Fl deiqD46
.Op Fl deiqtD46
.Op Fl b Ar bits
.Op Fl f Ar config_file
.Op Fl g Ar login_grace_time
.Op Fl h Ar host_key_file
.Op Fl k Ar key_gen_time
.Op Fl o Ar option
.Op Fl p Ar port
.Op Fl u Ar len
.Op Fl V Ar client_protocol_id
.Sh DESCRIPTION
.Nm
(SSH Daemon) is the daemon program for
@ -66,7 +65,7 @@ install and use as possible.
.Pp
.Nm
is the daemon that listens for connections from clients.
It is normally started at boot from
It is normally started at boot from
.Pa /etc/rc.network .
It forks a new
daemon for each incoming connection.
@ -120,9 +119,8 @@ configuration file if desired.
System security is not improved unless
.Xr rshd 8 ,
.Xr rlogind 8 ,
.Xr rexecd 8 ,
and
.Xr rexd 8
.Xr rexecd 8
are disabled (thus completely disabling
.Xr rlogin 1
and
@ -132,7 +130,7 @@ into the machine).
.Ss SSH protocol version 2
.Pp
Version 2 works similarly:
Each host has a host-specific DSA key used to identify the host.
Each host has a host-specific key (RSA or DSA) used to identify the host.
However, when the daemon starts, it does not generate a server key.
Forward security is provided through a Diffie-Hellman key agreement.
This key agreement results in a shared session key.
@ -178,7 +176,7 @@ configuration file.
.Nm
rereads its configuration file when it receives a hangup signal,
.Dv SIGHUP ,
by executing itself with the name it was started as, ie.
by executing itself with the name it was started as, i.e.,
.Pa /usr/sbin/sshd .
.Pp
The options are as follows:
@ -186,7 +184,6 @@ The options are as follows:
.It Fl b Ar bits
Specifies the number of bits in the ephemeral protocol version 1
server key (default 768).
.Pp
.It Fl d
Debug mode.
The server sends verbose debug output to the system
@ -212,12 +209,18 @@ If the client fails to authenticate the user within
this many seconds, the server disconnects and exits.
A value of zero indicates no limit.
.It Fl h Ar host_key_file
Specifies the file from which the host key is read (default
.Pa /etc/ssh/ssh_host_key ) .
Specifies a file from which a host key is read.
This option must be given if
.Nm
is not run as root (as the normal
host file is normally not readable by anyone but root).
host key files are normally not readable by anyone but root).
The default is
.Pa /etc/ssh/ssh_host_key
for protocol version 1, and
.Pa /etc/ssh/ssh_host_rsa_key
and
.Pa /etc/ssh/ssh_host_dsa_key
for protocol version 2.
It is possible to have multiple host key files for
the different protocol versions and host key algorithms.
.It Fl i
@ -242,14 +245,27 @@ it becomes impossible to recover the key for decrypting intercepted
communications even if the machine is cracked into or physically
seized.
A value of zero indicates that the key will never be regenerated.
.It Fl o Ar option
Can be used to give options in the format used in the configuration file.
This is useful for specifying options for which there is no separate
command-line flag.
.It Fl p Ar port
Specifies the port on which the server listens for connections
(default 22).
Multiple port options are permitted.
Ports specified in the configuration file are ignored when a
command-line port is specified.
.It Fl q
Quiet mode.
Nothing is sent to the system log.
Normally the beginning,
authentication, and termination of each connection is logged.
.It Fl t
Test mode.
Only check the validity of the configuration file and sanity of the keys.
This is useful for updating
.Nm
reliably as configuration options may change.
.It Fl u Ar len
This option is used to specify the size of the field
in the
@ -266,6 +282,23 @@ indicates that only dotted decimal addresses
should be put into the
.Pa utmp
file.
.Fl u0
is also be used to prevent
.Nm
from making DNS requests unless the authentication
mechanism or configuration requires it.
Authentication mechanisms that may require DNS include
.Cm RhostsAuthentication ,
.Cm RhostsRSAAuthentication ,
.Cm HostbasedAuthentication
and using a
.Cm from="pattern-list"
option in a key file.
Configuration options that require DNS include using a
USER@HOST pattern in
.Cm AllowUsers
or
.Cm DenyUsers .
.It Fl D
When this option is specified
.Nm
@ -288,19 +321,21 @@ reads configuration data from
(or the file specified with
.Fl f
on the command line).
The file contains keyword-value pairs, one per line.
The file contains keyword-argument pairs, one per line.
Lines starting with
.Ql #
and empty lines are interpreted as comments.
.Pp
The following keywords are possible.
The possible
keywords and their meanings are as follows (note that
keywords are case-insensitive and arguments are case-sensitive):
.Bl -tag -width Ds
.It Cm AFSTokenPassing
Specifies whether an AFS token may be forwarded to the server.
Default is
.Dq yes .
.It Cm AllowGroups
This keyword can be followed by a list of group names, separated
This keyword can be followed by a list of group name patterns, separated
by spaces.
If specified, login is allowed only for users whose primary
group or supplementary group list matches one of the patterns.
@ -309,8 +344,8 @@ and
.Ql ?
can be used as
wildcards in the patterns.
Only group names are valid; a numerical group ID isn't recognized.
By default login is allowed regardless of the group list.
Only group names are valid; a numerical group ID is not recognized.
By default, login is allowed for all groups.
.Pp
.It Cm AllowTcpForwarding
Specifies whether TCP forwarding is permitted.
@ -321,7 +356,7 @@ users are also denied shell access, as they can always install their
own forwarders.
.Pp
.It Cm AllowUsers
This keyword can be followed by a list of user names, separated
This keyword can be followed by a list of user name patterns, separated
by spaces.
If specified, login is allowed only for users names that
match one of the patterns.
@ -330,9 +365,26 @@ and
.Ql ?
can be used as
wildcards in the patterns.
Only user names are valid; a numerical user ID isn't recognized.
By default login is allowed regardless of the user name.
Only user names are valid; a numerical user ID is not recognized.
By default, login is allowed for all users.
If the pattern takes the form USER@HOST then USER and HOST
are separately checked, restricting logins to particular
users from particular hosts.
.Pp
.It Cm AuthorizedKeysFile
Specifies the file that contains the public keys that can be used
for user authentication.
.Cm AuthorizedKeysFile
may contain tokens of the form %T which are substituted during connection
set-up. The following tokens are defined: %% is replaced by a literal '%',
%h is replaced by the home directory of the user being authenticated and
%u is replaced by the username of that user.
After expansion,
.Cm AuthorizedKeysFile
is taken to be an absolute path or one relative to the user's home
directory.
The default is
.Dq .ssh/authorized_keys .
.It Cm Banner
In some jurisdictions, sending a warning message before authentication
may be relevant for getting legal protection.
@ -341,28 +393,33 @@ authentication is allowed.
This option is only available for protocol version 2.
.Pp
.It Cm ChallengeResponseAuthentication
Specifies whether
challenge response
authentication is allowed.
Currently there is only support for
.Xr skey 1
authentication.
Specifies whether challenge response authentication is allowed.
All authentication styles from
.Xr login.conf 5
are supported.
The default is
.Dq yes .
Note that OPIE authentication is enabled only if
.Cm PasswordAuthentication
is allowed, too.
.It Cm Ciphers
Specifies the ciphers allowed for protocol version 2.
Multiple ciphers must be comma-separated.
The default is
.Dq aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour.
.Pp
.Bd -literal
``aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour,
aes192-cbc,aes256-cbc''
.Ed
.It Cm CheckMail
Specifies whether
.Nm
should check for new mail for interactive logins.
should notify the user of new mail for interactive logins.
The default is
.Dq yes .
.It Cm ClientAliveInterval
Sets a timeout interval in seconds after which if no data has been received
from the client,
from the client,
.Nm
will send a message through the encrypted
channel to request a response from the client.
@ -374,49 +431,62 @@ Sets the number of client alive messages (see above) which may be
sent without
.Nm
receiving any messages back from the client. If this threshold is
reached while client alive messages are being sent,
reached while client alive messages are being sent,
.Nm
will disconnect the client, terminating the session. It is important
to note that the use of client alive messages is very different from
.Cm Keepalive
to note that the use of client alive messages is very different from
.Cm KeepAlive
(below). The client alive messages are sent through the
encrypted channel and therefore will not be spoofable. The TCP keepalive
option enabled by
.Cm Keepalive
is spoofable. You want to use the client
alive mechanism when you are basing something important on
clients having an active connection to the server.
.Cm KeepAlive
is spoofable. The client alive mechanism is valuable when the client or
server depend on knowing when a connection has become inactive.
.Pp
The default value is 3. If you set
The default value is 3. If
.Cm ClientAliveInterval
(above) to 15, and leave this value at the default, unresponsive ssh clients
will be disconnected after approximately 45 seconds.
(above) is set to 15, and
.Cm ClientAliveCountMax
is left at the default, unresponsive ssh clients
will be disconnected after approximately 45 seconds.
.It Cm DenyGroups
This keyword can be followed by a number of group names, separated
This keyword can be followed by a list of group name patterns, separated
by spaces.
Users whose primary group or supplementary group list matches
one of the patterns aren't allowed to log in.
Login is disallowed for users whose primary group or supplementary
group list matches one of the patterns.
.Ql \&*
and
.Ql ?
can be used as
wildcards in the patterns.
Only group names are valid; a numerical group ID isn't recognized.
By default login is allowed regardless of the group list.
Only group names are valid; a numerical group ID is not recognized.
By default, login is allowed for all groups.
.Pp
.It Cm DenyUsers
This keyword can be followed by a number of user names, separated
This keyword can be followed by a list of user name patterns, separated
by spaces.
Login is disallowed for user names that match one of the patterns.
.Ql \&*
and
.Ql ?
can be used as wildcards in the patterns.
Only user names are valid; a numerical user ID isn't recognized.
By default login is allowed regardless of the user name.
Only user names are valid; a numerical user ID is not recognized.
By default, login is allowed for all users.
If the pattern takes the form USER@HOST then USER and HOST
are separately checked, restricting logins to particular
users from particular hosts.
.It Cm GatewayPorts
Specifies whether remote hosts are allowed to connect to ports
forwarded for the client.
By default,
.Nm
binds remote port forwardings to the loopback addresss. This
prevents other remote hosts from connecting to forwarded ports.
.Cm GatewayPorts
can be used to specify that
.Nm
should bind remote port forwardings to the wildcard address,
thus allowing remote hosts to connect to forwarded ports.
The argument must be
.Dq yes
or
@ -433,9 +503,15 @@ and applies to protocol version 2 only.
The default is
.Dq no .
.It Cm HostKey
Specifies the file containing the private host keys (default
.Pa /etc/ssh/ssh_host_key )
used by SSH protocol versions 1 and 2.
Specifies a file containing a private host key
used by SSH.
The default is
.Pa /etc/ssh/ssh_host_key
for protocol version 1, and
.Pa /etc/ssh/ssh_host_rsa_key
and
.Pa /etc/ssh/ssh_host_dsa_key
for protocol version 2.
Note that
.Nm
will refuse to use a file if it is group/world-accessible.
@ -475,7 +551,7 @@ or
The default is
.Dq no .
.It Cm KeepAlive
Specifies whether the system should send keepalive messages to the
Specifies whether the system should send TCP keepalive messages to the
other side.
If they are sent, death of the connection or crash of one
of the machines will be properly noticed.
@ -490,12 +566,11 @@ users and consuming server resources.
The default is
.Dq yes
(to send keepalives), and the server will notice
if the network goes down or the client host reboots.
if the network goes down or the client host crashes.
This avoids infinitely hanging sessions.
.Pp
To disable keepalives, the value should be set to
.Dq no
in both the server and the client configuration files.
.Dq no .
.It Cm KerberosAuthentication
Specifies whether Kerberos authentication is allowed.
This can be in the form of a Kerberos ticket, or if
@ -578,9 +653,10 @@ The default is 120 (seconds).
Gives the verbosity level that is used when logging messages from
.Nm sshd .
The possible values are:
QUIET, FATAL, ERROR, INFO, VERBOSE and DEBUG.
The default is INFO.
Logging with level DEBUG violates the privacy of users
QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG, DEBUG1, DEBUG2 and DEBUG3.
The default is INFO. DEBUG and DEBUG1 are equivalent. DEBUG2
and DEBUG3 each specify higher levels of debugging output.
Logging with a DEBUG level violates the privacy of users
and is not recommended.
.It Cm MACs
Specifies the available MAC (message authentication code) algorithms.
@ -588,11 +664,7 @@ The MAC algorithm is used in protocol version 2
for data integrity protection.
Multiple algorithms must be comma-separated.
The default is
.Pp
.Bd -literal
``hmac-md5,hmac-sha1,hmac-ripemd160,hmac-ripemd160@openssh.com,
hmac-sha1-96,hmac-md5-96''
.Ed
.Dq hmac-md5,hmac-sha1,hmac-ripemd160,hmac-sha1-96,hmac-md5-96 .
.It Cm MaxStartups
Specifies the maximum number of concurrent unauthenticated connections to the
.Nm
@ -703,14 +775,6 @@ Specifies whether public key authentication is allowed.
The default is
.Dq yes .
Note that this option applies to protocol version 2 only.
.It Cm ReverseMappingCheck
Specifies whether
.Nm
should try to verify the remote host name and check that
the resolved host name for the remote IP address maps back to the
very same IP address.
The default is
.Dq no .
.It Cm RhostsAuthentication
Specifies whether authentication using rhosts or
.Pa /etc/hosts.equiv
@ -742,14 +806,8 @@ This option applies to protocol version 1 only.
Defines the number of bits in the ephemeral protocol version 1 server key.
The minimum value is 512, and the default is 768.
.It Cm SkeyAuthentication
Specifies whether
.Xr skey 1
authentication is allowed.
The default is
.Dq yes .
Note that OPIE authentication is enabled only if
.Cm PasswordAuthentication
is allowed, too.
Backward-compatibility alias for
.Cm ChallengeResponseAuthentication .
.It Cm StrictModes
Specifies whether
.Nm
@ -780,9 +838,24 @@ The default is AUTH.
Specifies whether
.Xr login 1
is used for interactive login sessions.
The default is
.Dq no .
Note that
.Xr login 1
is never used for remote command execution.
Note also, that if this is enabled,
.Cm X11Forwarding
will be disabled because
.Xr login 1
does not know how to handle
.Xr xauth 1
cookies.
.It Cm VerifyReverseMapping
Specifies whether
.Nm
should try to verify the remote host name and check that
the resolved host name for the remote IP address maps back to the
very same IP address.
The default is
.Dq no .
.It Cm X11DisplayOffset
@ -799,6 +872,34 @@ The default is
.Dq no .
Note that disabling X11 forwarding does not improve security in any
way, as users can always install their own forwarders.
X11 forwarding is automatically disabled if
.Cm UseLogin
is enabled.
.It Cm X11UseLocalhost
Specifies whether
.Nm
should bind the X11 forwarding server to the loopback address or to
the wildcard address. By default,
.Nm
binds the forwarding server to the loopback address and sets the
hostname part of the
.Ev DISPLAY
environment variable to
.Dq localhost .
This prevents remote hosts from connecting to the fake display.
However, some older X11 clients may not function with this
configuration.
.Cm X11UseLocalhost
may be set to
.Dq no
to specify that the forwarding server should be bound to the wildcard
address.
The argument must be
.Dq yes
or
.Dq no .
The default is
.Dq yes .
.It Cm XAuthLocation
Specifies the location of the
.Xr xauth 1
@ -806,6 +907,48 @@ program.
The default is
.Pa /usr/X11R6/bin/xauth .
.El
.Ss Time Formats
.Pp
.Nm
command-line arguments and configuration file options that specify time
may be expressed using a sequence of the form:
.Sm off
.Ar time Oo Ar qualifier Oc ,
.Sm on
where
.Ar time
is a positive integer value and
.Ar qualifier
is one of the following:
.Pp
.Bl -tag -width Ds -compact -offset indent
.It Cm <none>
seconds
.It Cm s | Cm S
seconds
.It Cm m | Cm M
minutes
.It Cm h | Cm H
hours
.It Cm d | Cm D
days
.It Cm w | Cm W
weeks
.El
.Pp
Each member of the sequence is added together to calculate
the total time value.
.Pp
Time format examples:
.Pp
.Bl -tag -width Ds -compact -offset indent
.It 600
600 seconds (10 minutes)
.It 10m
10 minutes
.It 1h30m
1 hour 30 minutes (90 minutes)
.El
.Sh LOGIN PROCESS
When a user successfully logs in,
.Nm
@ -854,15 +997,13 @@ authentication protocol and cookie (if applicable) in standard input.
Runs user's shell or command.
.El
.Sh AUTHORIZED_KEYS FILE FORMAT
The
.Pa $HOME/.ssh/authorized_keys
file lists the RSA keys that are
is the default file that lists the public keys that are
permitted for RSA authentication in protocol version 1
Similarly, the
.Pa $HOME/.ssh/authorized_keys2
file lists the DSA and RSA keys that are
permitted for public key authentication (PubkeyAuthentication)
and for public key authentication (PubkeyAuthentication)
in protocol version 2.
.Cm AuthorizedKeysFile
may be used to specify an alternative file.
.Pp
Each line of the file contains one
key (empty lines and lines starting with a
@ -897,7 +1038,8 @@ file and edit it.
The options (if present) consist of comma-separated option
specifications.
No spaces are permitted, except within double quotes.
The following option specifications are supported:
The following option specifications are supported (note
that option keywords are case-insensitive):
.Bl -tag -width Ds
.It Cm from="pattern-list"
Specifies that in addition to RSA authentication, the canonical name
@ -923,10 +1065,10 @@ just the key).
Specifies that the command is executed whenever this key is used for
authentication.
The command supplied by the user (if any) is ignored.
The command is run on a pty if the connection requests a pty;
The command is run on a pty if the client requests a pty;
otherwise it is run without a tty.
Note that if you want a 8-bit clean channel,
you must not request a pty or should specify
If a 8-bit clean channel is required,
one must not request a pty or should specify
.Cm no-pty .
A quote may be included in the command by quoting it with a backslash.
This option might be useful
@ -934,12 +1076,16 @@ to restrict certain RSA keys to perform just a specific operation.
An example might be a key that permits remote backups but nothing else.
Note that the client may specify TCP/IP and/or X11
forwarding unless they are explicitly prohibited.
Note that this option applies to shell, command or subsystem execution.
.It Cm environment="NAME=value"
Specifies that the string is to be added to the environment when
logging in using this key.
Environment variables set this way
override other default environment values.
Multiple options of this type are permitted.
This option is automatically disabled if
.Cm UseLogin
is enabled.
.It Cm no-port-forwarding
Forbids TCP/IP forwarding when this key is used for authentication.
Any port forward requests by the client will return an error.
@ -955,13 +1101,16 @@ authentication.
.It Cm no-pty
Prevents tty allocation (a request to allocate a pty will fail).
.It Cm permitopen="host:port"
Limit local
Limit local
.Li ``ssh -L''
port forwarding such that it may only connect to the specified host and
port. Multiple
port.
IPv6 addresses can be specified with an alternative syntax:
.Ar host/port .
Multiple
.Cm permitopen
options may be applied separated by commas. No pattern matching is
performed on the specified hostnames, they must be literal domains or
options may be applied separated by commas. No pattern matching is
performed on the specified hostnames, they must be literal domains or
addresses.
.El
.Ss Examples
@ -974,11 +1123,9 @@ command="dump /home",no-pty,no-port-forwarding 1024 33 23.\|.\|.\|2323 backup.hu
permitopen="10.2.1.55:80",permitopen="10.2.1.56:25" 1024 33 23.\|.\|.\|2323
.Sh SSH_KNOWN_HOSTS FILE FORMAT
The
.Pa /etc/ssh/ssh_known_hosts ,
.Pa /etc/ssh/ssh_known_hosts2 ,
.Pa $HOME/.ssh/known_hosts ,
.Pa /etc/ssh/ssh_known_hosts
and
.Pa $HOME/.ssh/known_hosts2
.Pa $HOME/.ssh/known_hosts
files contain host public keys for all known hosts.
The global file should
be prepared by the administrator (optional), and the per-user file is
@ -1054,7 +1201,7 @@ really used for anything; they are provided for the convenience of
the user so their contents can be copied to known hosts files.
These files are created using
.Xr ssh-keygen 1 .
.It Pa /etc/primes
.It Pa /etc/moduli
Contains Diffie-Hellman groups used for the "Diffie-Hellman Group Exchange".
.It Pa /var/run/sshd.pid
Contains the process ID of the
@ -1064,17 +1211,6 @@ concurrently for different ports, this contains the pid of the one
started last).
The content of this file is not sensitive; it can be world-readable.
.It Pa $HOME/.ssh/authorized_keys
Lists the RSA keys that can be used to log into the user's account.
This file must be readable by root (which may on some machines imply
it being world-readable if the user's home directory resides on an NFS
volume).
It is recommended that it not be accessible by others.
The format of this file is described above.
Users will place the contents of their
.Pa identity.pub
files into this file, as described in
.Xr ssh-keygen 1 .
.It Pa $HOME/.ssh/authorized_keys2
Lists the public keys (RSA or DSA) that can be used to log into the user's account.
This file must be readable by root (which may on some machines imply
it being world-readable if the user's home directory resides on an NFS
@ -1082,6 +1218,7 @@ volume).
It is recommended that it not be accessible by others.
The format of this file is described above.
Users will place the contents of their
.Pa identity.pub ,
.Pa id_dsa.pub
and/or
.Pa id_rsa.pub
@ -1089,7 +1226,8 @@ files into this file, as described in
.Xr ssh-keygen 1 .
.It Pa "/etc/ssh/ssh_known_hosts" and "$HOME/.ssh/known_hosts"
These files are consulted when using rhosts with RSA host
authentication to check the public key of the host.
authentication or protocol version 2 hostbased authentication
to check the public key of the host.
The key must be listed in one of these files to be accepted.
The client uses the same files
to verify that it is connecting to the correct remote host.
@ -1098,17 +1236,6 @@ These files should be writable only by root/the owner.
should be world-readable, and
.Pa $HOME/.ssh/known_hosts
can but need not be world-readable.
.It Pa "/etc/ssh_known_hosts2" and "$HOME/.ssh/known_hosts2"
These files are consulted when using protocol version 2 hostbased
authentication to check the public key of the host.
The key must be listed in one of these files to be accepted.
The client uses the same files
to verify that it is connecting to the correct remote host.
These files should be writable only by root/the owner.
.Pa /etc/ssh_known_hosts2
should be world-readable, and
.Pa $HOME/.ssh/known_hosts2
can but need not be world-readable.
.It Pa /etc/nologin
If this file exists,
.Nm
@ -1117,10 +1244,9 @@ The contents of the file
are displayed to anyone trying to log in, and non-root connections are
refused.
The file should be world-readable.
.It Pa /etc/hosts.allow
If compiled with
.Sy LIBWRAP
support, tcp-wrappers access controls may be defined here as described in
.It Pa /etc/hosts.allow, /etc/hosts.deny
Access controls that should be enforced by tcp-wrappers are defined here.
Further details are described in
.Xr hosts_access 5 .
.It Pa $HOME/.rhosts
This file contains host-username pairs, separated by a space, one per
@ -1243,13 +1369,13 @@ protocol versions 1.5 and 2.0.
.Sh SEE ALSO
.Xr scp 1 ,
.Xr sftp 1 ,
.Xr sftp-server 8 ,
.Xr ssh 1 ,
.Xr ssh-add 1 ,
.Xr ssh-agent 1 ,
.Xr ssh-keygen 1 ,
.Xr rlogin 1 ,
.Xr rsh 1
.Xr login.conf 5 ,
.Xr moduli 5 ,
.Xr sftp-server 8
.Rs
.%A T. Ylonen
.%A T. Kivinen
@ -1257,8 +1383,8 @@ protocol versions 1.5 and 2.0.
.%A T. Rinne
.%A S. Lehtinen
.%T "SSH Protocol Architecture"
.%N draft-ietf-secsh-architecture-07.txt
.%D January 2001
.%N draft-ietf-secsh-architecture-09.txt
.%D July 2001
.%O work in progress material
.Re
.Rs
@ -1266,7 +1392,7 @@ protocol versions 1.5 and 2.0.
.%A N. Provos
.%A W. A. Simpson
.%T "Diffie-Hellman Group Exchange for the SSH Transport Layer Protocol"
.%N draft-ietf-secsh-dh-group-exchange-00.txt
.%D January 2001
.%N draft-ietf-secsh-dh-group-exchange-01.txt
.%D April 2001
.%O work in progress material
.Re

View file

@ -40,12 +40,12 @@
*/
#include "includes.h"
RCSID("$OpenBSD: sshd.c,v 1.195 2001/04/15 16:58:03 markus Exp $");
RCSID("$OpenBSD: sshd.c,v 1.228 2002/02/27 21:23:13 stevesk Exp $");
RCSID("$FreeBSD$");
#include <openssl/dh.h>
#include <openssl/bn.h>
#include <openssl/hmac.h>
#include <openssl/md5.h>
#include "ssh.h"
#include "ssh1.h"
@ -75,6 +75,7 @@ RCSID("$FreeBSD$");
#include "auth.h"
#include "misc.h"
#include "dispatch.h"
#include "channels.h"
#ifdef LIBWRAP
#include <tcpd.h>
@ -87,10 +88,6 @@ int deny_severity = LOG_WARNING;
#define O_NOCTTY 0
#endif
#ifdef KRB5
#include <krb5.h>
#endif /* KRB5 */
extern char *__progname;
/* Server configuration options. */
@ -113,6 +110,9 @@ extern int IPv4or6;
*/
int debug_flag = 0;
/* Flag indicating that the daemon should only test the configuration and keys. */
int test_flag = 0;
/* Flag indicating that the daemon is being started from inetd. */
int inetd_flag = 0;
@ -164,10 +164,11 @@ struct {
* Flag indicating whether the RSA server key needs to be regenerated.
* Is set in the SIGALRM handler and cleared when the key is regenerated.
*/
int key_do_regen = 0;
static volatile sig_atomic_t key_do_regen = 0;
/* This is set to true when SIGHUP is received. */
int received_sighup = 0;
/* This is set to true when a signal is received. */
static volatile sig_atomic_t received_sighup = 0;
static volatile sig_atomic_t received_sigterm = 0;
/* session identifier, used by RSA-auth */
u_char session_id[16];
@ -179,17 +180,20 @@ int session_id2_len = 0;
/* record remote hostname or ip */
u_int utmp_len = MAXHOSTNAMELEN;
/* Prototypes for various functions defined later in this file. */
void do_ssh1_kex(void);
void do_ssh2_kex(void);
/* options.max_startup sized array of fd ints */
int *startup_pipes = NULL;
int startup_pipe; /* in child */
void ssh_dh1_server(Kex *, Buffer *_kexinit, Buffer *);
void ssh_dhgex_server(Kex *, Buffer *_kexinit, Buffer *);
/* Prototypes for various functions defined later in this file. */
void destroy_sensitive_data(void);
static void do_ssh1_kex(void);
static void do_ssh2_kex(void);
/*
* Close all listening sockets
*/
void
static void
close_listen_socks(void)
{
int i;
@ -198,27 +202,41 @@ close_listen_socks(void)
num_listen_socks = -1;
}
static void
close_startup_pipes(void)
{
int i;
if (startup_pipes)
for (i = 0; i < options.max_startups; i++)
if (startup_pipes[i] != -1)
close(startup_pipes[i]);
}
/*
* Signal handler for SIGHUP. Sshd execs itself when it receives SIGHUP;
* the effect is to reread the configuration file (and to regenerate
* the server key).
*/
void
static void
sighup_handler(int sig)
{
int save_errno = errno;
received_sighup = 1;
signal(SIGHUP, sighup_handler);
errno = save_errno;
}
/*
* Called from the main program after receiving SIGHUP.
* Restarts the server.
*/
void
static void
sighup_restart(void)
{
log("Received SIGHUP; restarting.");
close_listen_socks();
close_startup_pipes();
execv(saved_argv[0], saved_argv);
log("RESTART FAILED: av[0]='%.100s', error: %.100s.", saved_argv[0], strerror(errno));
exit(1);
@ -226,23 +244,18 @@ sighup_restart(void)
/*
* Generic signal handler for terminating signals in the master daemon.
* These close the listen socket; not closing it seems to cause "Address
* already in use" problems on some machines, which is inconvenient.
*/
void
static void
sigterm_handler(int sig)
{
log("Received signal %d; terminating.", sig);
close_listen_socks();
unlink(options.pid_file);
exit(255);
received_sigterm = sig;
}
/*
* SIGCHLD handler. This is called whenever a child dies. This will then
* reap any zombies left by exited c.
* reap any zombies left by exited children.
*/
void
static void
main_sigchld_handler(int sig)
{
int save_errno = errno;
@ -258,9 +271,11 @@ main_sigchld_handler(int sig)
/*
* Signal handler for the alarm after the login grace period has expired.
*/
void
static void
grace_alarm_handler(int sig)
{
/* XXX no idea how fix this signal handler */
/* Close the connection. */
packet_close();
@ -275,7 +290,7 @@ grace_alarm_handler(int sig)
* Thus there should be no concurrency control/asynchronous execution
* problems.
*/
void
static void
generate_ephemeral_server_key(void)
{
u_int32_t rand = 0;
@ -298,7 +313,7 @@ generate_ephemeral_server_key(void)
arc4random_stir();
}
void
static void
key_regeneration_alarm(int sig)
{
int save_errno = errno;
@ -307,7 +322,7 @@ key_regeneration_alarm(int sig)
key_do_regen = 1;
}
void
static void
sshd_exchange_identification(int sock_in, int sock_out)
{
int i, mismatch;
@ -335,7 +350,7 @@ sshd_exchange_identification(int sock_in, int sock_out)
/* Send our protocol version identification. */
if (atomicio(write, sock_out, server_version_string, strlen(server_version_string))
!= strlen(server_version_string)) {
log("Could not write ident string to %s.", get_remote_ipaddr());
log("Could not write ident string to %s", get_remote_ipaddr());
fatal_cleanup();
}
@ -343,7 +358,7 @@ sshd_exchange_identification(int sock_in, int sock_out)
memset(buf, 0, sizeof(buf));
for (i = 0; i < sizeof(buf) - 1; i++) {
if (atomicio(read, sock_in, &buf[i], 1) != 1) {
log("Did not receive identification string from %s.",
log("Did not receive identification string from %s",
get_remote_ipaddr());
fatal_cleanup();
}
@ -379,7 +394,7 @@ sshd_exchange_identification(int sock_in, int sock_out)
fatal_cleanup();
}
debug("Client protocol version %d.%d; client software version %.100s",
remote_major, remote_minor, remote_version);
remote_major, remote_minor, remote_version);
compat_datafellows(remote_version);
@ -390,7 +405,7 @@ sshd_exchange_identification(int sock_in, int sock_out)
}
mismatch = 0;
switch(remote_major) {
switch (remote_major) {
case 1:
if (remote_minor == 99) {
if (options.protocol & SSH_PROTO_2)
@ -434,8 +449,6 @@ sshd_exchange_identification(int sock_in, int sock_out)
server_version_string, client_version_string);
fatal_cleanup();
}
if (compat20)
packet_set_ssh2_format();
}
@ -449,7 +462,7 @@ destroy_sensitive_data(void)
key_free(sensitive_data.server_key);
sensitive_data.server_key = NULL;
}
for(i = 0; i < options.num_host_key_files; i++) {
for (i = 0; i < options.num_host_key_files; i++) {
if (sensitive_data.host_keys[i]) {
key_free(sensitive_data.host_keys[i]);
sensitive_data.host_keys[i] = NULL;
@ -459,36 +472,40 @@ destroy_sensitive_data(void)
memset(sensitive_data.ssh1_cookie, 0, SSH_SESSION_KEY_LENGTH);
}
char *
static char *
list_hostkey_types(void)
{
static char buf[1024];
Buffer b;
char *p;
int i;
buf[0] = '\0';
for(i = 0; i < options.num_host_key_files; i++) {
buffer_init(&b);
for (i = 0; i < options.num_host_key_files; i++) {
Key *key = sensitive_data.host_keys[i];
if (key == NULL)
continue;
switch(key->type) {
switch (key->type) {
case KEY_RSA:
case KEY_DSA:
strlcat(buf, key_ssh_name(key), sizeof buf);
strlcat(buf, ",", sizeof buf);
if (buffer_len(&b) > 0)
buffer_append(&b, ",", 1);
p = key_ssh_name(key);
buffer_append(&b, p, strlen(p));
break;
}
}
i = strlen(buf);
if (i > 0 && buf[i-1] == ',')
buf[i-1] = '\0';
debug("list_hostkey_types: %s", buf);
return buf;
buffer_append(&b, "\0", 1);
p = xstrdup(buffer_ptr(&b));
buffer_free(&b);
debug("list_hostkey_types: %s", p);
return p;
}
Key *
static Key *
get_hostkey_by_type(int type)
{
int i;
for(i = 0; i < options.num_host_key_files; i++) {
for (i = 0; i < options.num_host_key_files; i++) {
Key *key = sensitive_data.host_keys[i];
if (key != NULL && key->type == type)
return key;
@ -502,7 +519,7 @@ get_hostkey_by_type(int type)
* of (max_startups_rate/100). the probability increases linearly until
* all connections are dropped for startups > max_startups
*/
int
static int
drop_connection(int startups)
{
double p, r;
@ -525,8 +542,30 @@ drop_connection(int startups)
return (r < p) ? 1 : 0;
}
int *startup_pipes = NULL; /* options.max_startup sized array of fd ints */
int startup_pipe; /* in child */
static void
usage(void)
{
fprintf(stderr, "sshd version %s\n", SSH_VERSION);
fprintf(stderr, "Usage: %s [options]\n", __progname);
fprintf(stderr, "Options:\n");
fprintf(stderr, " -f file Configuration file (default %s)\n", _PATH_SERVER_CONFIG_FILE);
fprintf(stderr, " -d Debugging mode (multiple -d means more debugging)\n");
fprintf(stderr, " -i Started from inetd\n");
fprintf(stderr, " -D Do not fork into daemon mode\n");
fprintf(stderr, " -t Only test configuration file and keys\n");
fprintf(stderr, " -q Quiet (no logging)\n");
fprintf(stderr, " -p port Listen on the specified port (default: 22)\n");
fprintf(stderr, " -k seconds Regenerate server key every this many seconds (default: 3600)\n");
fprintf(stderr, " -g seconds Grace period for authentication (default: 600)\n");
fprintf(stderr, " -b bits Size of server RSA key (default: 768 bits)\n");
fprintf(stderr, " -h file File from which to read host key (default: %s)\n",
_PATH_HOST_KEY_FILE);
fprintf(stderr, " -u len Maximum hostname length for utmp recording\n");
fprintf(stderr, " -4 Use IPv4 only\n");
fprintf(stderr, " -6 Use IPv6 only\n");
fprintf(stderr, " -o option Process the option as if it was read from a configuration file.\n");
exit(1);
}
/*
* Main program for the daemon.
@ -560,7 +599,7 @@ main(int ac, char **av)
initialize_server_options(&options);
/* Parse command-line arguments. */
while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:u:dDeiqQ46")) != -1) {
while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:u:o:dDeiqtQ46")) != -1) {
switch (opt) {
case '4':
IPv4or6 = AF_INET;
@ -613,10 +652,16 @@ main(int ac, char **av)
}
break;
case 'g':
options.login_grace_time = atoi(optarg);
if ((options.login_grace_time = convtime(optarg)) == -1) {
fprintf(stderr, "Invalid login grace time.\n");
exit(1);
}
break;
case 'k':
options.key_regeneration_time = atoi(optarg);
if ((options.key_regeneration_time = convtime(optarg)) == -1) {
fprintf(stderr, "Invalid key regeneration interval.\n");
exit(1);
}
break;
case 'h':
if (options.num_host_key_files >= MAX_HOSTKEYS) {
@ -630,40 +675,35 @@ main(int ac, char **av)
/* only makes sense with inetd_flag, i.e. no listen() */
inetd_flag = 1;
break;
case 't':
test_flag = 1;
break;
case 'u':
utmp_len = atoi(optarg);
break;
case 'o':
if (process_server_config_line(&options, optarg,
"command-line", 0) != 0)
exit(1);
break;
case '?':
default:
fprintf(stderr, "sshd version %s\n", SSH_VERSION);
fprintf(stderr, "Usage: %s [options]\n", __progname);
fprintf(stderr, "Options:\n");
fprintf(stderr, " -f file Configuration file (default %s)\n", _PATH_SERVER_CONFIG_FILE);
fprintf(stderr, " -d Debugging mode (multiple -d means more debugging)\n");
fprintf(stderr, " -i Started from inetd\n");
fprintf(stderr, " -D Do not fork into daemon mode\n");
fprintf(stderr, " -q Quiet (no logging)\n");
fprintf(stderr, " -p port Listen on the specified port (default: 22)\n");
fprintf(stderr, " -k seconds Regenerate server key every this many seconds (default: 3600)\n");
fprintf(stderr, " -g seconds Grace period for authentication (default: 600)\n");
fprintf(stderr, " -b bits Size of server RSA key (default: 768 bits)\n");
fprintf(stderr, " -h file File from which to read host key (default: %s)\n",
_PATH_HOST_KEY_FILE);
fprintf(stderr, " -u len Maximum hostname length for utmp recording\n");
fprintf(stderr, " -4 Use IPv4 only\n");
fprintf(stderr, " -6 Use IPv6 only\n");
exit(1);
usage();
break;
}
}
SSLeay_add_all_algorithms();
channel_set_af(IPv4or6);
/*
* Force logging to stderr until we have loaded the private host
* key (unless started from inetd)
*/
log_init(__progname,
options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level,
options.log_facility == -1 ? SYSLOG_FACILITY_AUTH : options.log_facility,
options.log_level == SYSLOG_LEVEL_NOT_SET ?
SYSLOG_LEVEL_INFO : options.log_level,
options.log_facility == SYSLOG_FACILITY_NOT_SET ?
SYSLOG_FACILITY_AUTH : options.log_facility,
!inetd_flag);
/* Read server configuration options from the configuration file. */
@ -682,14 +722,14 @@ main(int ac, char **av)
/* load private host keys */
sensitive_data.host_keys = xmalloc(options.num_host_key_files*sizeof(Key*));
for(i = 0; i < options.num_host_key_files; i++)
for (i = 0; i < options.num_host_key_files; i++)
sensitive_data.host_keys[i] = NULL;
sensitive_data.server_key = NULL;
sensitive_data.ssh1_host_key = NULL;
sensitive_data.have_ssh1_key = 0;
sensitive_data.have_ssh2_key = 0;
for(i = 0; i < options.num_host_key_files; i++) {
for (i = 0; i < options.num_host_key_files; i++) {
key = key_load_private(options.host_key_files[i], "", NULL);
sensitive_data.host_keys[i] = key;
if (key == NULL) {
@ -698,7 +738,7 @@ main(int ac, char **av)
sensitive_data.host_keys[i] = NULL;
continue;
}
switch(key->type){
switch (key->type) {
case KEY_RSA1:
sensitive_data.ssh1_host_key = key;
sensitive_data.have_ssh1_key = 1;
@ -747,6 +787,10 @@ main(int ac, char **av)
}
}
/* Configuration looks good, so exit if in test mode. */
if (test_flag)
exit(0);
/* Initialize the log (it is reinitialized below in case we forked). */
if (debug_flag && !inetd_flag)
log_stderr = 1;
@ -782,7 +826,7 @@ main(int ac, char **av)
/* Chdir to the root directory so that the current disk can be
unmounted if desired. */
chdir("/");
/* ignore SIGPIPE */
signal(SIGPIPE, SIG_IGN);
@ -834,11 +878,11 @@ main(int ac, char **av)
* close.
*/
setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR,
(void *) &on, sizeof(on));
&on, sizeof(on));
linger.l_onoff = 1;
linger.l_linger = 5;
setsockopt(listen_sock, SOL_SOCKET, SO_LINGER,
(void *) &linger, sizeof(linger));
&linger, sizeof(linger));
debug("Bind to port %s on %s.", strport, ntop);
@ -863,6 +907,22 @@ main(int ac, char **av)
if (!num_listen_socks)
fatal("Cannot bind any address.");
if (options.protocol & SSH_PROTO_1)
generate_ephemeral_server_key();
/*
* Arrange to restart on SIGHUP. The handler needs
* listen_sock.
*/
signal(SIGHUP, sighup_handler);
signal(SIGTERM, sigterm_handler);
signal(SIGQUIT, sigterm_handler);
/* Arrange SIGCHLD to be caught. */
signal(SIGCHLD, main_sigchld_handler);
/* Write out the pid file after the sigterm handler is setup */
if (!debug_flag) {
/*
* Record our pid in /var/run/sshd.pid to make it
@ -877,17 +937,6 @@ main(int ac, char **av)
fclose(f);
}
}
if (options.protocol & SSH_PROTO_1)
generate_ephemeral_server_key();
/* Arrange to restart on SIGHUP. The handler needs listen_sock. */
signal(SIGHUP, sighup_handler);
signal(SIGTERM, sigterm_handler);
signal(SIGQUIT, sigterm_handler);
/* Arrange SIGCHLD to be caught. */
signal(SIGCHLD, main_sigchld_handler);
/* setup fd set for listen */
fdset = NULL;
@ -923,6 +972,13 @@ main(int ac, char **av)
ret = select(maxfd+1, fdset, NULL, NULL, NULL);
if (ret < 0 && errno != EINTR)
error("select: %.100s", strerror(errno));
if (received_sigterm) {
log("Received signal %d; terminating.",
(int) received_sigterm);
close_listen_socks();
unlink(options.pid_file);
exit(255);
}
if (key_used && key_do_regen) {
generate_ephemeral_server_key();
key_used = 0;
@ -957,6 +1013,7 @@ main(int ac, char **av)
}
if (fcntl(newsock, F_SETFL, 0) < 0) {
error("newsock del O_NONBLOCK: %s", strerror(errno));
close(newsock);
continue;
}
if (drop_connection(startups) == 1) {
@ -1010,9 +1067,7 @@ main(int ac, char **av)
* the connection.
*/
startup_pipe = startup_p[1];
for (j = 0; j < options.max_startups; j++)
if (startup_pipes[j] != -1)
close(startup_pipes[j]);
close_startup_pipes();
close_listen_socks();
sock_in = newsock;
sock_out = newsock;
@ -1072,11 +1127,11 @@ main(int ac, char **av)
/* setsockopt(sock_in, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */
linger.l_onoff = 1;
linger.l_linger = 5;
setsockopt(sock_in, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof(linger));
setsockopt(sock_in, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger));
/* Set keepalives if requested. */
if (options.keepalives &&
setsockopt(sock_in, SOL_SOCKET, SO_KEEPALIVE, (void *)&on,
setsockopt(sock_in, SOL_SOCKET, SO_KEEPALIVE, &on,
sizeof(on)) < 0)
error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
@ -1089,22 +1144,23 @@ main(int ac, char **av)
remote_port = get_remote_port();
remote_ip = get_remote_ipaddr();
/* Check whether logins are denied from this host. */
#ifdef LIBWRAP
/* Check whether logins are denied from this host. */
{
struct request_info req;
request_init(&req, RQ_DAEMON, __progname, RQ_FILE, sock_in, NULL);
request_init(&req, RQ_DAEMON, __progname, RQ_FILE, sock_in, 0);
fromhost(&req);
if (!hosts_access(&req)) {
debug("Connection refused by tcp wrapper");
refuse(&req);
close(sock_in);
close(sock_out);
/* NOTREACHED */
fatal("libwrap refuse returns");
}
verbose("Connection from %.500s port %d", eval_client(&req), remote_port);
}
#endif /* LIBWRAP */
/* Log the connection. */
verbose("Connection from %.500s port %d", remote_ip, remote_port);
@ -1128,10 +1184,11 @@ main(int ac, char **av)
* machine, he can connect from any port. So do not use these
* authentication methods from machines that you do not trust.
*/
if (remote_port >= IPPORT_RESERVED ||
remote_port < IPPORT_RESERVED / 2) {
if (options.rhosts_authentication &&
(remote_port >= IPPORT_RESERVED ||
remote_port < IPPORT_RESERVED / 2)) {
debug("Rhosts Authentication disabled, "
"originating port not trusted.");
"originating port %d not trusted.", remote_port);
options.rhosts_authentication = 0;
}
#if defined(KRB4) && !defined(KRB5)
@ -1140,7 +1197,7 @@ main(int ac, char **av)
debug("Kerberos Authentication disabled, only available for IPv4.");
options.kerberos_authentication = 0;
}
#endif /* KRB4 */
#endif /* KRB4 && !KRB5 */
#ifdef AFS
/* If machine has AFS, set process authentication group. */
if (k_hasafs()) {
@ -1160,13 +1217,6 @@ main(int ac, char **av)
do_ssh1_kex();
do_authentication();
}
#ifdef KRB4
/* Cleanup user's ticket cache file. */
if (options.krb4_ticket_cleanup)
(void) dest_tkt();
#endif /* KRB4 */
/* The connection has been terminated. */
verbose("Closing connection to %.100s", remote_ip);
@ -1181,11 +1231,10 @@ main(int ac, char **av)
/*
* SSH1 key exchange
*/
void
static void
do_ssh1_kex(void)
{
int i, len;
int plen, slen;
int rsafail = 0;
BIGNUM *session_key_int;
u_char session_key[SSH_SESSION_KEY_LENGTH];
@ -1246,18 +1295,15 @@ do_ssh1_kex(void)
if (options.kerberos_authentication)
auth_mask |= 1 << SSH_AUTH_KERBEROS;
#endif
#ifdef KRB5
if (options.krb5_tgt_passing)
auth_mask |= 1 << SSH_PASS_KERBEROS_TGT;
#endif /* KRB5 */
#ifdef AFS
if (options.krb4_tgt_passing)
#if defined(AFS) || defined(KRB5)
if (options.kerberos_tgt_passing)
auth_mask |= 1 << SSH_PASS_KERBEROS_TGT;
#endif
#ifdef AFS
if (options.afs_token_passing)
auth_mask |= 1 << SSH_PASS_AFS_TOKEN;
#endif
if (options.challenge_reponse_authentication == 1)
if (options.challenge_response_authentication == 1)
auth_mask |= 1 << SSH_AUTH_TIS;
if (options.password_authentication)
auth_mask |= 1 << SSH_AUTH_PASSWORD;
@ -1272,7 +1318,7 @@ do_ssh1_kex(void)
BN_num_bits(sensitive_data.ssh1_host_key->rsa->n));
/* Read clients reply (cipher type and session key). */
packet_read_expect(&plen, SSH_CMSG_SESSION_KEY);
packet_read_expect(SSH_CMSG_SESSION_KEY);
/* Get cipher type and check whether we accept this. */
cipher_type = packet_get_char();
@ -1289,13 +1335,13 @@ do_ssh1_kex(void)
debug("Encryption type: %.200s", cipher_name(cipher_type));
/* Get the encrypted integer. */
session_key_int = BN_new();
packet_get_bignum(session_key_int, &slen);
if ((session_key_int = BN_new()) == NULL)
fatal("do_ssh1_kex: BN_new failed");
packet_get_bignum(session_key_int);
protocol_flags = packet_get_int();
packet_set_protocol_flags(protocol_flags);
packet_integrity_check(plen, 1 + 8 + slen + 4, SSH_CMSG_SESSION_KEY);
packet_check_eom();
/*
* Decrypt it using our private server key and private host key (key
@ -1365,7 +1411,7 @@ do_ssh1_kex(void)
}
if (rsafail) {
int bytes = BN_num_bytes(session_key_int);
char *buf = xmalloc(bytes);
u_char *buf = xmalloc(bytes);
MD5_CTX md;
log("do_connection: generating a fake encryption key");
@ -1407,7 +1453,7 @@ do_ssh1_kex(void)
/*
* SSH2 key exchange: diffie-hellman-group1-sha1
*/
void
static void
do_ssh2_kex(void)
{
Kex *kex;

View file

@ -1,70 +1,93 @@
# $OpenBSD: sshd_config,v 1.38 2001/04/15 21:41:29 deraadt Exp $
# $FreeBSD$
# $OpenBSD: src/usr.bin/ssh/sshd_config,v 1.48 2002/02/19 02:50:59 deraadt Exp $
# $FreeBSD$
# This is the sshd server system-wide configuration file. See sshd(8)
# for more information.
Port 22
# The strategy used for options in the default sshd_config shipped with
# OpenSSH is to specify options with their default value where
# possible, but leave them commented. Uncommented options change a
# default value.
# Note that some of FreeBSD's defaults differ from OpenBSD's, and
# FreeBSD has a few additional options.
#VersionAddendum FreeBSD localisations 20020318
#Port 22
#Protocol 2,1
#ListenAddress 0.0.0.0
#ListenAddress ::
HostKey /etc/ssh/ssh_host_key
HostKey /etc/ssh/ssh_host_dsa_key
ServerKeyBits 768
LoginGraceTime 120
KeyRegenerationInterval 3600
PermitRootLogin no
# ConnectionsPerPeriod has been deprecated completely
# After 10 unauthenticated connections, refuse 30% of the new ones, and
# refuse any more than 60 total.
MaxStartups 10:30:60
# Don't read ~/.rhosts and ~/.shosts files
IgnoreRhosts yes
# Uncomment if you don't trust ~/.ssh/known_hosts for RhostsRSAAuthentication
#IgnoreUserKnownHosts yes
StrictModes yes
X11Forwarding yes
X11DisplayOffset 10
PrintMotd yes
#PrintLastLog no
KeepAlive yes
# HostKey for protocol version 1
#HostKey /etc/ssh/ssh_host_key
# HostKeys for protocol version 2
#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_dsa_key
# Lifetime and size of ephemeral version 1 server key
#KeyRegenerationInterval 3600
#ServerKeyBits 768
# Logging
SyslogFacility AUTH
LogLevel INFO
#obsoletes QuietMode and FascistLogging
#SyslogFacility AUTH
#LogLevel INFO
RhostsAuthentication no
#
# For this to work you will also need host keys in /etc/ssh_known_hosts
RhostsRSAAuthentication no
# Authentication:
#LoginGraceTime 120
#PermitRootLogin no
#StrictModes yes
#RSAAuthentication yes
#PubkeyAuthentication yes
#AuthorizedKeysFile .ssh/authorized_keys
# rhosts authentication should not be used
#RhostsAuthentication no
# Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes
# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
#RhostsRSAAuthentication no
# similar for protocol version 2
HostbasedAuthentication no
#
RSAAuthentication yes
#HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# RhostsRSAAuthentication and HostbasedAuthentication
#IgnoreUserKnownHosts no
# To disable tunneled clear text passwords, change to no here!
PasswordAuthentication yes
PermitEmptyPasswords no
#PasswordAuthentication yes
#PermitEmptyPasswords no
# Uncomment to disable s/key passwords
#ChallengeResponseAuthentication no
# Change to no to disable s/key passwords
#ChallengeResponseAuthentication yes
# To change Kerberos options
#KerberosAuthentication no
# Kerberos options
# KerberosAuthentication automatically enabled if keyfile exists
#KerberosAuthentication yes
#KerberosOrLocalPasswd yes
#AFSTokenPassing no
#KerberosTicketCleanup no
#KerberosTicketCleanup yes
# Kerberos TGT Passing does only work with the AFS kaserver
#KerberosTgtPassing yes
# AFSTokenPassing automatically enabled if k_hasafs() is true
#AFSTokenPassing yes
CheckMail yes
# Kerberos TGT Passing only works with the AFS kaserver
#KerberosTgtPassing no
#X11Forwarding yes
#X11DisplayOffset 10
#X11UseLocalhost yes
#PrintMotd yes
#PrintLastLog yes
#KeepAlive yes
#UseLogin no
#CheckMail yes
#MaxStartups 10:30:60
#Banner /etc/issue.net
#ReverseMappingCheck yes
#MaxStartups 10
# no default banner path
#Banner /some/path
#VerifyReverseMapping no
# override default of no subsystems
Subsystem sftp /usr/libexec/sftp-server

View file

@ -39,7 +39,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: sshlogin.c,v 1.2 2001/03/24 16:43:27 stevesk Exp $");
RCSID("$OpenBSD: sshlogin.c,v 1.3 2001/12/19 07:18:56 deraadt Exp $");
RCSID("$FreeBSD$");
#include <libutil.h>
@ -87,7 +87,7 @@ get_last_login_time(uid_t uid, const char *logname,
void
record_login(pid_t pid, const char *ttyname, const char *user, uid_t uid,
const char *host, struct sockaddr * addr)
const char *host, struct sockaddr * addr)
{
int fd;
struct lastlog ll;
@ -99,7 +99,7 @@ record_login(pid_t pid, const char *ttyname, const char *user, uid_t uid,
strncpy(u.ut_line, ttyname + 5, sizeof(u.ut_line));
u.ut_time = time(NULL);
strncpy(u.ut_name, user, sizeof(u.ut_name));
realhostname_sa(u.ut_host, sizeof(u.ut_host), addr, addr->sa_len);
strncpy(u.ut_host, host, sizeof(u.ut_host));
login(&u);
lastlog = _PATH_LASTLOG;

View file

@ -12,7 +12,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: sshpty.c,v 1.1 2001/03/04 01:46:30 djm Exp $");
RCSID("$OpenBSD: sshpty.c,v 1.4 2001/12/19 07:18:56 deraadt Exp $");
RCSID("$FreeBSD$");
#include <libutil.h>
@ -132,7 +132,7 @@ pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen)
*ttyfd = open(name, O_RDWR | O_NOCTTY);
if (*ttyfd < 0) {
error("Could not open pty slave side %.100s: %.100s",
name, strerror(errno));
name, strerror(errno));
close(*ptyfd);
return 0;
}
@ -225,7 +225,7 @@ pty_make_controlling_tty(int *ttyfd, const char *ttyname)
fd = open(_PATH_TTY, O_WRONLY);
if (fd < 0)
error("open /dev/tty failed - could not set controlling tty: %.100s",
strerror(errno));
strerror(errno));
else {
close(fd);
}
@ -235,7 +235,7 @@ pty_make_controlling_tty(int *ttyfd, const char *ttyname)
void
pty_change_window_size(int ptyfd, int row, int col,
int xpixel, int ypixel)
int xpixel, int ypixel)
{
struct winsize w;
w.ws_row = row;
@ -265,7 +265,8 @@ pty_setowner(struct passwd *pw, const char *ttyname)
/*
* Change owner and mode of the tty as required.
* Warn but continue if filesystem is read-only and the uids match.
* Warn but continue if filesystem is read-only and the uids match/
* tty is owned by root.
*/
if (stat(ttyname, &st))
fatal("stat(%.100s) failed: %.100s", ttyname,
@ -273,14 +274,15 @@ pty_setowner(struct passwd *pw, const char *ttyname)
if (st.st_uid != pw->pw_uid || st.st_gid != gid) {
if (chown(ttyname, pw->pw_uid, gid) < 0) {
if (errno == EROFS && st.st_uid == pw->pw_uid)
if (errno == EROFS &&
(st.st_uid == pw->pw_uid || st.st_uid == 0))
error("chown(%.100s, %d, %d) failed: %.100s",
ttyname, pw->pw_uid, gid,
strerror(errno));
ttyname, pw->pw_uid, gid,
strerror(errno));
else
fatal("chown(%.100s, %d, %d) failed: %.100s",
ttyname, pw->pw_uid, gid,
strerror(errno));
ttyname, pw->pw_uid, gid,
strerror(errno));
}
}
@ -289,10 +291,10 @@ pty_setowner(struct passwd *pw, const char *ttyname)
if (errno == EROFS &&
(st.st_mode & (S_IRGRP | S_IROTH)) == 0)
error("chmod(%.100s, 0%o) failed: %.100s",
ttyname, mode, strerror(errno));
ttyname, mode, strerror(errno));
else
fatal("chmod(%.100s, 0%o) failed: %.100s",
ttyname, mode, strerror(errno));
ttyname, mode, strerror(errno));
}
}
}

View file

@ -1,11 +1,11 @@
/* $OpenBSD: version.h,v 1.28 2002/03/06 00:25:55 markus Exp $ */
/* $FreeBSD$ */
/* $OpenBSD: version.h,v 1.23 2001/04/24 16:43:16 markus Exp $ */
#ifndef SSH_VERSION
#ifndef SSH_VERSION
#define SSH_VERSION (ssh_version_get())
#define SSH_VERSION_BASE "OpenSSH_2.9"
#define SSH_VERSION_ADDENDUM "FreeBSD localisations 20020307"
#define SSH_VERSION (ssh_version_get())
#define SSH_VERSION_BASE "OpenSSH_3.1"
#define SSH_VERSION_ADDENDUM "FreeBSD localisations 20020318"
const char *ssh_version_get(void);
void ssh_version_set_addendum(const char *add);