Fix conflicts.
This commit is contained in:
+45
-67
@@ -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
|
||||
|
||||
+152
-170
@@ -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 */
|
||||
|
||||
+230
-208
@@ -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 */
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
+47
-60
@@ -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.");
|
||||
|
||||
+222
-8
@@ -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;
|
||||
}
|
||||
|
||||
+84
-84
@@ -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"
|
||||
|
||||
+87
-171
@@ -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;
|
||||
|
||||
+215
-267
@@ -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);
|
||||
}
|
||||
|
||||
+35
-16
@@ -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:
|
||||
|
||||
+58
-60
@@ -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':
|
||||
|
||||
+11
-14
@@ -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)
|
||||
|
||||
+24
-24
@@ -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);
|
||||
}
|
||||
|
||||
+911
-873
File diff suppressed because it is too large
Load Diff
+105
-195
@@ -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
|
||||
|
||||
+330
-385
@@ -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);
|
||||
}
|
||||
|
||||
+23
-56
@@ -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 */
|
||||
|
||||
+80
-58
@@ -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(®, check[i].pat, REG_EXTENDED|REG_NOSUB);
|
||||
if (ret != 0) {
|
||||
regerror(ret, ®, ebuf, sizeof(ebuf));
|
||||
ebuf[sizeof(ebuf)-1] = '\0';
|
||||
error("regerror: %s", ebuf);
|
||||
continue;
|
||||
}
|
||||
ret = regexec(®, version, 0, NULL, 0);
|
||||
regfree(®);
|
||||
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);
|
||||
|
||||
+30
-25
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
+83
-63
@@ -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;
|
||||
|
||||
+52
-187
@@ -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 */
|
||||
|
||||
+25
-12
@@ -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"
|
||||
|
||||
|
||||
+124
-101
@@ -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 */
|
||||
|
||||
+19
-58
@@ -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 */
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
+561
-531
File diff suppressed because it is too large
Load Diff
+28
-40
@@ -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 */
|
||||
|
||||
+255
-185
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
+619
-738
File diff suppressed because it is too large
Load Diff
+151
-60
@@ -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;
|
||||
}
|
||||
|
||||
+259
-127
@@ -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);
|
||||
}
|
||||
|
||||
+277
-143
@@ -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
|
||||
|
||||
+272
-172
@@ -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);
|
||||
|
||||
@@ -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"
|
||||
|
||||
+11
-13
@@ -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 ~
|
||||
|
||||
+223
-323
@@ -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);
|
||||
|
||||
+10
-19
@@ -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
|
||||
|
||||
+470
-289
File diff suppressed because it is too large
Load Diff
+133
-114
@@ -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;
|
||||
}
|
||||
|
||||
+259
-133
@@ -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
|
||||
|
||||
+178
-132
@@ -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;
|
||||
|
||||
+69
-46
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
+14
-12
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user