зеркало из https://github.com/Azure/sonic-openssh.git
- Merged very large OpenBSD source code reformat
- OpenBSD CVS updates - [channels.c cipher.c compat.c log-client.c scp.c serverloop.c] [ssh.h sshd.8 sshd.c] syslog changes: * Unified Logmessage for all auth-types, for success and for failed * Standard connections get only ONE line in the LOG when level==LOG: Auth-attempts are logged only, if authentication is: a) successfull or b) with passwd or c) we had more than AUTH_FAIL_LOG failues * many log() became verbose() * old behaviour with level=VERBOSE - [readconf.c readconf.h ssh.1 ssh.h sshconnect.c sshd.c] tranfer s/key challenge/response data in SSH_SMSG_AUTH_TIS_CHALLENGE messages. allows use of s/key in windows (ttssh, securecrt) and ssh-1.2.27 clients without 'ssh -v', ok: niels@ - [sshd.8] -V, for fallback to openssh in SSH2 compatibility mode - [sshd.c] fix sigchld race; cjc5@po.cwru.edu
This commit is contained in:
Родитель
4d2f15f895
Коммит
95def09838
23
ChangeLog
23
ChangeLog
|
@ -1,3 +1,26 @@
|
|||
19991124
|
||||
- Merged very large OpenBSD source code reformat
|
||||
- OpenBSD CVS updates
|
||||
- [channels.c cipher.c compat.c log-client.c scp.c serverloop.c]
|
||||
[ssh.h sshd.8 sshd.c]
|
||||
syslog changes:
|
||||
* Unified Logmessage for all auth-types, for success and for failed
|
||||
* Standard connections get only ONE line in the LOG when level==LOG:
|
||||
Auth-attempts are logged only, if authentication is:
|
||||
a) successfull or
|
||||
b) with passwd or
|
||||
c) we had more than AUTH_FAIL_LOG failues
|
||||
* many log() became verbose()
|
||||
* old behaviour with level=VERBOSE
|
||||
- [readconf.c readconf.h ssh.1 ssh.h sshconnect.c sshd.c]
|
||||
tranfer s/key challenge/response data in SSH_SMSG_AUTH_TIS_CHALLENGE
|
||||
messages. allows use of s/key in windows (ttssh, securecrt) and
|
||||
ssh-1.2.27 clients without 'ssh -v', ok: niels@
|
||||
- [sshd.8]
|
||||
-V, for fallback to openssh in SSH2 compatibility mode
|
||||
- [sshd.c]
|
||||
fix sigchld race; cjc5@po.cwru.edu
|
||||
|
||||
19991123
|
||||
- Added SuSE package files from Chris Saia <csaia@wtower.com>
|
||||
- Restructured package-related files under packages/*
|
||||
|
|
400
auth-krb4.c
400
auth-krb4.c
|
@ -1,13 +1,7 @@
|
|||
/*
|
||||
|
||||
auth-kerberos.c
|
||||
|
||||
Dug Song <dugsong@UMICH.EDU>
|
||||
|
||||
Kerberos v4 authentication and ticket-passing routines.
|
||||
|
||||
$Id: auth-krb4.c,v 1.4 1999/11/15 04:25:10 damien Exp $
|
||||
*/
|
||||
* Dug Song <dugsong@UMICH.EDU>
|
||||
* Kerberos v4 authentication and ticket-passing routines.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "packet.h"
|
||||
|
@ -20,216 +14,222 @@ char *ticket = NULL;
|
|||
void
|
||||
krb4_cleanup_proc(void *ignore)
|
||||
{
|
||||
debug("krb4_cleanup_proc called");
|
||||
|
||||
if (ticket) {
|
||||
(void) dest_tkt();
|
||||
xfree(ticket);
|
||||
ticket = NULL;
|
||||
}
|
||||
debug("krb4_cleanup_proc called");
|
||||
if (ticket) {
|
||||
(void) dest_tkt();
|
||||
xfree(ticket);
|
||||
ticket = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int krb4_init(uid_t uid)
|
||||
int
|
||||
krb4_init(uid_t uid)
|
||||
{
|
||||
static int cleanup_registered = 0;
|
||||
char *tkt_root = TKT_ROOT;
|
||||
struct stat st;
|
||||
int fd;
|
||||
static int cleanup_registered = 0;
|
||||
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);
|
||||
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/";
|
||||
if (lstat("/ticket", &st) != -1)
|
||||
tkt_root = "/ticket/";
|
||||
#endif /* AFS */
|
||||
snprintf(ticket, MAXPATHLEN, "%s%d_%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;
|
||||
snprintf(ticket, MAXPATHLEN, "%s%d_%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)
|
||||
int
|
||||
auth_krb4(const char *server_user, KTEXT auth, char **client)
|
||||
{
|
||||
AUTH_DAT adat = { 0 };
|
||||
KTEXT_ST reply;
|
||||
char instance[INST_SZ];
|
||||
int r, s;
|
||||
u_int cksum;
|
||||
Key_schedule schedule;
|
||||
struct sockaddr_in local, foreign;
|
||||
|
||||
s = packet_get_connection_in();
|
||||
|
||||
r = sizeof(local);
|
||||
memset(&local, 0, sizeof(local));
|
||||
if (getsockname(s, (struct sockaddr *) &local, &r) < 0)
|
||||
debug("getsockname failed: %.100s", strerror(errno));
|
||||
r = sizeof(foreign);
|
||||
memset(&foreign, 0, sizeof(foreign));
|
||||
if (getpeername(s, (struct sockaddr *)&foreign, &r) < 0) {
|
||||
debug("getpeername failed: %.100s", strerror(errno));
|
||||
fatal_cleanup();
|
||||
}
|
||||
|
||||
instance[0] = '*'; 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;
|
||||
}
|
||||
des_key_sched((des_cblock *)adat.session, schedule);
|
||||
|
||||
*client = xmalloc(MAX_K_NAME_SZ);
|
||||
(void) snprintf(*client, MAX_K_NAME_SZ, "%s%s%s@%s", adat.pname,
|
||||
*adat.pinst ? "." : "", adat.pinst, adat.prealm);
|
||||
AUTH_DAT adat = {0};
|
||||
KTEXT_ST reply;
|
||||
char instance[INST_SZ];
|
||||
int r, s;
|
||||
u_int cksum;
|
||||
Key_schedule schedule;
|
||||
struct sockaddr_in local, foreign;
|
||||
|
||||
/* 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);
|
||||
xfree(*client);
|
||||
return 0;
|
||||
}
|
||||
/* Increment the checksum, and return it encrypted with the session key. */
|
||||
cksum = adat.checksum + 1;
|
||||
cksum = htonl(cksum);
|
||||
|
||||
/* If we can't successfully encrypt the checksum, we send back an 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]);
|
||||
reply.dat[0] = 0;
|
||||
reply.length = 0;
|
||||
}
|
||||
else reply.length = r;
|
||||
|
||||
/* Clear session key. */
|
||||
memset(&adat.session, 0, sizeof(&adat.session));
|
||||
|
||||
packet_start(SSH_SMSG_AUTH_KERBEROS_RESPONSE);
|
||||
packet_put_string((char *) reply.dat, reply.length);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
return 1;
|
||||
s = packet_get_connection_in();
|
||||
|
||||
r = sizeof(local);
|
||||
memset(&local, 0, sizeof(local));
|
||||
if (getsockname(s, (struct sockaddr *) & local, &r) < 0)
|
||||
debug("getsockname failed: %.100s", strerror(errno));
|
||||
r = sizeof(foreign);
|
||||
memset(&foreign, 0, sizeof(foreign));
|
||||
if (getpeername(s, (struct sockaddr *) & foreign, &r) < 0) {
|
||||
debug("getpeername failed: %.100s", strerror(errno));
|
||||
fatal_cleanup();
|
||||
}
|
||||
instance[0] = '*';
|
||||
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;
|
||||
}
|
||||
des_key_sched((des_cblock *) adat.session, schedule);
|
||||
|
||||
*client = xmalloc(MAX_K_NAME_SZ);
|
||||
(void) snprintf(*client, MAX_K_NAME_SZ, "%s%s%s@%s", adat.pname,
|
||||
*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);
|
||||
xfree(*client);
|
||||
return 0;
|
||||
}
|
||||
/* Increment the checksum, and return it encrypted with the
|
||||
session key. */
|
||||
cksum = adat.checksum + 1;
|
||||
cksum = htonl(cksum);
|
||||
|
||||
/* If we can't successfully encrypt the checksum, we send back an
|
||||
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]);
|
||||
reply.dat[0] = 0;
|
||||
reply.length = 0;
|
||||
} else
|
||||
reply.length = r;
|
||||
|
||||
/* Clear session key. */
|
||||
memset(&adat.session, 0, sizeof(&adat.session));
|
||||
|
||||
packet_start(SSH_SMSG_AUTH_KERBEROS_RESPONSE);
|
||||
packet_put_string((char *) reply.dat, reply.length);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
return 1;
|
||||
}
|
||||
#endif /* KRB4 */
|
||||
|
||||
#ifdef AFS
|
||||
int auth_kerberos_tgt(struct passwd *pw, const char *string)
|
||||
int
|
||||
auth_kerberos_tgt(struct passwd *pw, const char *string)
|
||||
{
|
||||
CREDENTIALS creds;
|
||||
|
||||
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;
|
||||
}
|
||||
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",
|
||||
creds.pname, creds.pinst[0] ? "." : "", creds.pinst,
|
||||
creds.realm, pw->pw_name);
|
||||
goto auth_kerberos_tgt_failure;
|
||||
}
|
||||
if (!krb4_init(pw->pw_uid))
|
||||
goto auth_kerberos_tgt_failure;
|
||||
CREDENTIALS creds;
|
||||
|
||||
if (in_tkt(creds.pname, creds.pinst) != KSUCCESS)
|
||||
goto auth_kerberos_tgt_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;
|
||||
}
|
||||
/* 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);
|
||||
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);
|
||||
memset(&creds, 0, sizeof(creds));
|
||||
packet_start(SSH_SMSG_FAILURE);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
return 0;
|
||||
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;
|
||||
}
|
||||
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",
|
||||
creds.pname, creds.pinst[0] ? "." : "", creds.pinst,
|
||||
creds.realm, pw->pw_name);
|
||||
goto auth_kerberos_tgt_failure;
|
||||
}
|
||||
if (!krb4_init(pw->pw_uid))
|
||||
goto auth_kerberos_tgt_failure;
|
||||
|
||||
if (in_tkt(creds.pname, creds.pinst) != KSUCCESS)
|
||||
goto auth_kerberos_tgt_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;
|
||||
}
|
||||
/* 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);
|
||||
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);
|
||||
memset(&creds, 0, sizeof(creds));
|
||||
packet_start(SSH_SMSG_FAILURE);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int auth_afs_token(struct passwd *pw, const char *token_string)
|
||||
int
|
||||
auth_afs_token(struct passwd *pw, const char *token_string)
|
||||
{
|
||||
CREDENTIALS creds;
|
||||
uid_t uid = pw->pw_uid;
|
||||
CREDENTIALS creds;
|
||||
uid_t uid = pw->pw_uid;
|
||||
|
||||
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;
|
||||
}
|
||||
if (strncmp(creds.service, "", 1) == 0) /* backward compatibility */
|
||||
strlcpy(creds.service, "afs", sizeof creds.service);
|
||||
|
||||
if (strncmp(creds.pname, "AFS ID ", 7) == 0)
|
||||
uid = atoi(creds.pname + 7);
|
||||
|
||||
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);
|
||||
memset(&creds, 0, sizeof(creds));
|
||||
packet_start(SSH_SMSG_FAILURE);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
return 0;
|
||||
}
|
||||
packet_send_debug("AFS token accepted (%s@%s, %s@%s)", creds.service,
|
||||
creds.realm, creds.pname, creds.realm);
|
||||
memset(&creds, 0, sizeof(creds));
|
||||
packet_start(SSH_SMSG_SUCCESS);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
return 1;
|
||||
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;
|
||||
}
|
||||
if (strncmp(creds.service, "", 1) == 0) /* backward compatibility */
|
||||
strlcpy(creds.service, "afs", sizeof creds.service);
|
||||
|
||||
if (strncmp(creds.pname, "AFS ID ", 7) == 0)
|
||||
uid = atoi(creds.pname + 7);
|
||||
|
||||
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);
|
||||
memset(&creds, 0, sizeof(creds));
|
||||
packet_start(SSH_SMSG_FAILURE);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
return 0;
|
||||
}
|
||||
packet_send_debug("AFS token accepted (%s@%s, %s@%s)", creds.service,
|
||||
creds.realm, creds.pname, creds.realm);
|
||||
memset(&creds, 0, sizeof(creds));
|
||||
packet_start(SSH_SMSG_SUCCESS);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
return 1;
|
||||
}
|
||||
#endif /* AFS */
|
||||
|
|
338
auth-passwd.c
338
auth-passwd.c
|
@ -1,30 +1,22 @@
|
|||
/*
|
||||
|
||||
auth-passwd.c
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Sat Mar 18 05:11:38 1995 ylo
|
||||
|
||||
Password authentication. This file contains the functions to check whether
|
||||
the password is valid for the user.
|
||||
|
||||
*/
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Created: Sat Mar 18 05:11:38 1995 ylo
|
||||
* Password authentication. This file contains the functions to check whether
|
||||
* the password is valid for the user.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#ifndef HAVE_PAM
|
||||
|
||||
RCSID("$Id: auth-passwd.c,v 1.5 1999/11/19 04:53:20 damien Exp $");
|
||||
RCSID("$Id: auth-passwd.c,v 1.6 1999/11/24 13:26:21 damien Exp $");
|
||||
|
||||
#include "packet.h"
|
||||
#include "ssh.h"
|
||||
#include "servconf.h"
|
||||
#include "xmalloc.h"
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_SHADOW_H
|
||||
#include <shadow.h>
|
||||
|
@ -34,185 +26,189 @@ RCSID("$Id: auth-passwd.c,v 1.5 1999/11/19 04:53:20 damien Exp $");
|
|||
#include "md5crypt.h"
|
||||
#endif
|
||||
|
||||
/* Don't need anything from here if we are using PAM */
|
||||
|
||||
/* Tries to authenticate the user using password. Returns true if
|
||||
authentication succeeds. */
|
||||
|
||||
int auth_password(struct passwd *pw, const char *password)
|
||||
/*
|
||||
* Tries to authenticate the user using password. Returns true if
|
||||
* authentication succeeds.
|
||||
*/
|
||||
int
|
||||
auth_password(struct passwd * pw, const char *password)
|
||||
{
|
||||
extern ServerOptions options;
|
||||
char *encrypted_password;
|
||||
extern ServerOptions options;
|
||||
char *encrypted_password;
|
||||
#ifdef HAVE_SHADOW_H
|
||||
struct spwd *spw;
|
||||
struct spwd *spw;
|
||||
#endif
|
||||
|
||||
if (pw->pw_uid == 0 && options.permit_root_login == 2)
|
||||
{
|
||||
/*packet_send_debug("Server does not permit root login with password.");*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*password == '\0' && options.permit_empty_passwd == 0)
|
||||
{
|
||||
/*packet_send_debug("Server does not permit empty password login.");*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* deny if no user. */
|
||||
if (pw == NULL)
|
||||
return 0;
|
||||
if (pw->pw_uid == 0 && options.permit_root_login == 2) {
|
||||
/* Server does not permit root login with password */
|
||||
return 0;
|
||||
}
|
||||
if (*password == '\0' && options.permit_empty_passwd == 0) {
|
||||
/* Server does not permit empty password login */
|
||||
return 0;
|
||||
}
|
||||
/* deny if no user. */
|
||||
if (pw == NULL)
|
||||
return 0;
|
||||
|
||||
#ifdef SKEY
|
||||
if (options.skey_authentication == 1) {
|
||||
if (strncasecmp(password, "s/key", 5) == 0) {
|
||||
char *skeyinfo = skey_keyinfo(pw->pw_name);
|
||||
if(skeyinfo == NULL){
|
||||
debug("generating fake skeyinfo for %.100s.", pw->pw_name);
|
||||
skeyinfo = skey_fake_keyinfo(pw->pw_name);
|
||||
}
|
||||
if(skeyinfo != NULL)
|
||||
packet_send_debug(skeyinfo);
|
||||
/* Try again. */
|
||||
return 0;
|
||||
}
|
||||
else if (skey_haskey(pw->pw_name) == 0 &&
|
||||
skey_passcheck(pw->pw_name, (char *)password) != -1) {
|
||||
/* Authentication succeeded. */
|
||||
return 1;
|
||||
}
|
||||
/* Fall back to ordinary passwd authentication. */
|
||||
}
|
||||
if (options.skey_authentication == 1) {
|
||||
if (strncasecmp(password, "s/key", 5) == 0) {
|
||||
char *skeyinfo = skey_keyinfo(pw->pw_name);
|
||||
if (skeyinfo == NULL) {
|
||||
debug("generating fake skeyinfo for %.100s.",
|
||||
pw->pw_name);
|
||||
skeyinfo = skey_fake_keyinfo(pw->pw_name);
|
||||
}
|
||||
if (skeyinfo != NULL)
|
||||
packet_send_debug(skeyinfo);
|
||||
/* Try again. */
|
||||
return 0;
|
||||
} else if (skey_haskey(pw->pw_name) == 0 &&
|
||||
skey_passcheck(pw->pw_name, (char *) password) != -1) {
|
||||
/* Authentication succeeded. */
|
||||
return 1;
|
||||
}
|
||||
/* Fall back to ordinary passwd authentication. */
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(KRB4)
|
||||
/* Support for Kerberos v4 authentication - Dug Song <dugsong@UMICH.EDU> */
|
||||
if (options.kerberos_authentication)
|
||||
{
|
||||
AUTH_DAT adata;
|
||||
KTEXT_ST tkt;
|
||||
struct hostent *hp;
|
||||
unsigned long faddr;
|
||||
char localhost[MAXHOSTNAMELEN];
|
||||
char phost[INST_SZ];
|
||||
char realm[REALM_SZ];
|
||||
int r;
|
||||
|
||||
/* 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) {
|
||||
/* Support for Kerberos v4 authentication - Dug Song
|
||||
<dugsong@UMICH.EDU> */
|
||||
if (options.kerberos_authentication) {
|
||||
AUTH_DAT adata;
|
||||
KTEXT_ST tkt;
|
||||
struct hostent *hp;
|
||||
unsigned long faddr;
|
||||
char localhost[MAXHOSTNAMELEN];
|
||||
char phost[INST_SZ];
|
||||
char realm[REALM_SZ];
|
||||
int r;
|
||||
|
||||
/* Set up our ticket file. */
|
||||
if (!krb4_init(pw->pw_uid)) {
|
||||
log("Couldn't initialize Kerberos ticket file for %s!", pw->pw_name);
|
||||
goto kerberos_auth_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);
|
||||
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;
|
||||
}
|
||||
/* Successful authentication. */
|
||||
chown(tkt_string(), pw->pw_uid, pw->pw_gid);
|
||||
|
||||
/* Now that we have a TGT, try to get a local "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);
|
||||
r = krb_mk_req(&tkt, KRB4_SERVICE_NAME, phost, realm, 33);
|
||||
/* 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) {
|
||||
|
||||
if (r == KSUCCESS) {
|
||||
if (!(hp = gethostbyname(localhost))) {
|
||||
log("Couldn't get local host address!");
|
||||
goto kerberos_auth_failure;
|
||||
}
|
||||
memmove((void *)&faddr, (void *)hp->h_addr, sizeof(faddr));
|
||||
/* Set up our ticket file. */
|
||||
if (!krb4_init(pw->pw_uid)) {
|
||||
log("Couldn't initialize Kerberos ticket file for %s!",
|
||||
pw->pw_name);
|
||||
goto kerberos_auth_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);
|
||||
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;
|
||||
}
|
||||
/* Successful authentication. */
|
||||
chown(tkt_string(), pw->pw_uid, pw->pw_gid);
|
||||
|
||||
/* Verify our "rcmd" ticket. */
|
||||
r = krb_rd_req(&tkt, KRB4_SERVICE_NAME, phost, faddr, &adata, "");
|
||||
if (r == RD_AP_UNDEC) {
|
||||
/* Probably didn't have a srvtab on localhost. Allow login. */
|
||||
log("Kerberos V4 TGT for %s unverifiable, no srvtab installed? "
|
||||
"krb_rd_req: %s", pw->pw_name, krb_err_txt[r]);
|
||||
}
|
||||
else if (r != KSUCCESS) {
|
||||
log("Kerberos V4 %s ticket unverifiable: %s",
|
||||
KRB4_SERVICE_NAME, krb_err_txt[r]);
|
||||
goto kerberos_auth_failure;
|
||||
}
|
||||
/*
|
||||
* Now that we have a TGT, try to get a local
|
||||
* "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);
|
||||
r = krb_mk_req(&tkt, KRB4_SERVICE_NAME, phost, realm, 33);
|
||||
|
||||
if (r == KSUCCESS) {
|
||||
if (!(hp = gethostbyname(localhost))) {
|
||||
log("Couldn't get local host address!");
|
||||
goto kerberos_auth_failure;
|
||||
}
|
||||
memmove((void *) &faddr, (void *) hp->h_addr,
|
||||
sizeof(faddr));
|
||||
|
||||
/* Verify our "rcmd" ticket. */
|
||||
r = krb_rd_req(&tkt, KRB4_SERVICE_NAME, phost,
|
||||
faddr, &adata, "");
|
||||
if (r == RD_AP_UNDEC) {
|
||||
/*
|
||||
* Probably didn't have a srvtab on
|
||||
* localhost. Allow login.
|
||||
*/
|
||||
log("Kerberos V4 TGT for %s unverifiable, "
|
||||
"no srvtab installed? krb_rd_req: %s",
|
||||
pw->pw_name, krb_err_txt[r]);
|
||||
} else if (r != KSUCCESS) {
|
||||
log("Kerberos V4 %s ticket unverifiable: %s",
|
||||
KRB4_SERVICE_NAME, krb_err_txt[r]);
|
||||
goto kerberos_auth_failure;
|
||||
}
|
||||
} else if (r == KDC_PR_UNKNOWN) {
|
||||
/* Allow login if no rcmd service exists,
|
||||
but log the error. */
|
||||
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);
|
||||
} 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;
|
||||
}
|
||||
|
||||
/* Authentication succeeded. */
|
||||
return 1;
|
||||
|
||||
kerberos_auth_failure:
|
||||
krb4_cleanup_proc(NULL);
|
||||
|
||||
if (!options.kerberos_or_local_passwd)
|
||||
return 0;
|
||||
} else {
|
||||
/* Logging in as root or no local Kerberos realm. */
|
||||
packet_send_debug("Unable to authenticate to Kerberos.");
|
||||
}
|
||||
/* Fall back to ordinary passwd authentication. */
|
||||
}
|
||||
else if (r == KDC_PR_UNKNOWN) {
|
||||
/* Allow login if no rcmd service exists, but log the error. */
|
||||
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);
|
||||
#endif /* KRB4 */
|
||||
|
||||
/* Check for users with no password. */
|
||||
if (strcmp(password, "") == 0 && strcmp(pw->pw_passwd, "") == 0) {
|
||||
packet_send_debug("Login permitted without a password "
|
||||
"because the account has no password.");
|
||||
return 1;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/* Authentication succeeded. */
|
||||
return 1;
|
||||
|
||||
kerberos_auth_failure:
|
||||
krb4_cleanup_proc(NULL);
|
||||
|
||||
if (!options.kerberos_or_local_passwd)
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
/* Logging in as root or no local Kerberos realm. */
|
||||
packet_send_debug("Unable to authenticate to Kerberos.");
|
||||
}
|
||||
/* Fall back to ordinary passwd authentication. */
|
||||
}
|
||||
#endif /* KRB4 */
|
||||
|
||||
/* Check for users with no password. */
|
||||
if (strcmp(password, "") == 0 && strcmp(pw->pw_passwd, "") == 0)
|
||||
{
|
||||
packet_send_debug("Login permitted without a password because the account has no password.");
|
||||
return 1; /* The user has no password and an empty password was tried. */
|
||||
}
|
||||
|
||||
#ifdef HAVE_SHADOW_H
|
||||
spw = getspnam(pw->pw_name);
|
||||
if (spw == NULL)
|
||||
return(0);
|
||||
spw = getspnam(pw->pw_name);
|
||||
if (spw == NULL)
|
||||
return(0);
|
||||
|
||||
if ((spw->sp_namp == NULL) || (strcmp(pw->pw_name, spw->sp_namp) != 0))
|
||||
fatal("Shadow lookup returned garbage.");
|
||||
if ((spw->sp_namp == NULL) || (strcmp(pw->pw_name, spw->sp_namp) != 0))
|
||||
fatal("Shadow lookup returned garbage.");
|
||||
|
||||
if (strlen(spw->sp_pwdp) < 3)
|
||||
return(0);
|
||||
if (strlen(spw->sp_pwdp) < 3)
|
||||
return(0);
|
||||
|
||||
/* Encrypt the candidate password using the proper salt. */
|
||||
/* Encrypt the candidate password using the proper salt. */
|
||||
#ifdef HAVE_MD5_PASSWORDS
|
||||
if (is_md5_salt(spw->sp_pwdp))
|
||||
encrypted_password = md5_crypt(password, spw->sp_pwdp);
|
||||
else
|
||||
encrypted_password = crypt(password, spw->sp_pwdp);
|
||||
if (is_md5_salt(spw->sp_pwdp))
|
||||
encrypted_password = md5_crypt(password, spw->sp_pwdp);
|
||||
else
|
||||
encrypted_password = crypt(password, spw->sp_pwdp);
|
||||
#else /* HAVE_MD5_PASSWORDS */
|
||||
encrypted_password = crypt(password, spw->sp_pwdp);
|
||||
encrypted_password = crypt(password, spw->sp_pwdp);
|
||||
#endif /* HAVE_MD5_PASSWORDS */
|
||||
|
||||
/* Authentication is accepted if the encrypted passwords are identical. */
|
||||
return (strcmp(encrypted_password, spw->sp_pwdp) == 0);
|
||||
/* Authentication is accepted if the encrypted passwords are identical. */
|
||||
return (strcmp(encrypted_password, spw->sp_pwdp) == 0);
|
||||
#else /* !HAVE_SHADOW_H */
|
||||
encrypted_password = crypt(password,
|
||||
(pw->pw_passwd[0] && pw->pw_passwd[1]) ? pw->pw_passwd : "xx");
|
||||
|
||||
/* Encrypt the candidate password using the proper salt. */
|
||||
encrypted_password = crypt(password,
|
||||
(pw->pw_passwd[0] && pw->pw_passwd[1]) ?
|
||||
pw->pw_passwd : "xx");
|
||||
/* Authentication is accepted if the encrypted passwords are identical. */
|
||||
return (strcmp(encrypted_password, pw->pw_passwd) == 0);
|
||||
/* Authentication is accepted if the encrypted passwords are identical. */
|
||||
return (strcmp(encrypted_password, pw->pw_passwd) == 0);
|
||||
#endif /* !HAVE_SHADOW_H */
|
||||
}
|
||||
|
||||
#endif /* !HAVE_PAM */
|
||||
|
|
158
auth-rh-rsa.c
158
auth-rh-rsa.c
|
@ -1,21 +1,21 @@
|
|||
/*
|
||||
|
||||
auth-rh-rsa.c
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Sun May 7 03:08:06 1995 ylo
|
||||
|
||||
Rhosts or /etc/hosts.equiv authentication combined with RSA host
|
||||
authentication.
|
||||
|
||||
*/
|
||||
*
|
||||
* auth-rh-rsa.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Sun May 7 03:08:06 1995 ylo
|
||||
*
|
||||
* Rhosts or /etc/hosts.equiv authentication combined with RSA host
|
||||
* authentication.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: auth-rh-rsa.c,v 1.5 1999/11/16 02:37:16 damien Exp $");
|
||||
RCSID("$Id: auth-rh-rsa.c,v 1.6 1999/11/24 13:26:21 damien Exp $");
|
||||
|
||||
#include "packet.h"
|
||||
#include "ssh.h"
|
||||
|
@ -26,78 +26,76 @@ RCSID("$Id: auth-rh-rsa.c,v 1.5 1999/11/16 02:37:16 damien Exp $");
|
|||
/* 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,
|
||||
BIGNUM *client_host_key_e, BIGNUM *client_host_key_n)
|
||||
int
|
||||
auth_rhosts_rsa(struct passwd *pw, const char *client_user,
|
||||
BIGNUM *client_host_key_e, BIGNUM *client_host_key_n)
|
||||
{
|
||||
extern ServerOptions options;
|
||||
const char *canonical_hostname;
|
||||
HostStatus host_status;
|
||||
BIGNUM *ke, *kn;
|
||||
extern ServerOptions options;
|
||||
const char *canonical_hostname;
|
||||
HostStatus host_status;
|
||||
BIGNUM *ke, *kn;
|
||||
|
||||
debug("Trying rhosts with RSA host authentication for %.100s", client_user);
|
||||
debug("Trying rhosts with RSA host authentication for %.100s", client_user);
|
||||
|
||||
/* Check if we would accept it using rhosts authentication. */
|
||||
if (!auth_rhosts(pw, client_user))
|
||||
return 0;
|
||||
/* Check if we would accept it using rhosts authentication. */
|
||||
if (!auth_rhosts(pw, client_user))
|
||||
return 0;
|
||||
|
||||
canonical_hostname = get_canonical_hostname();
|
||||
canonical_hostname = get_canonical_hostname();
|
||||
|
||||
debug("Rhosts RSA authentication: canonical host %.900s",
|
||||
canonical_hostname);
|
||||
|
||||
/* Check if we know the host and its host key. */
|
||||
/* Check system-wide host file. */
|
||||
ke = BN_new();
|
||||
kn = BN_new();
|
||||
host_status = check_host_in_hostfile(SSH_SYSTEM_HOSTFILE, canonical_hostname,
|
||||
client_host_key_e, client_host_key_n, ke, kn);
|
||||
debug("Rhosts RSA authentication: canonical host %.900s",
|
||||
canonical_hostname);
|
||||
|
||||
/* 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(SSH_USER_HOSTFILE, pw->pw_uid);
|
||||
/* Check file permissions of 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->pw_uid);
|
||||
host_status = check_host_in_hostfile(user_hostfile, canonical_hostname,
|
||||
client_host_key_e, client_host_key_n, ke, kn);
|
||||
restore_uid();
|
||||
}
|
||||
xfree(user_hostfile);
|
||||
}
|
||||
BN_free(ke);
|
||||
BN_free(kn);
|
||||
/* Check if we know the host and its host key. */
|
||||
ke = BN_new();
|
||||
kn = BN_new();
|
||||
host_status = check_host_in_hostfile(SSH_SYSTEM_HOSTFILE, canonical_hostname,
|
||||
client_host_key_e, client_host_key_n,
|
||||
ke, kn);
|
||||
|
||||
if (host_status != HOST_OK) {
|
||||
/* The host key was not found. */
|
||||
debug("Rhosts with RSA host authentication denied: unknown or invalid host key");
|
||||
packet_send_debug("Your host key cannot be verified: unknown or invalid host key.");
|
||||
return 0;
|
||||
}
|
||||
/* 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(SSH_USER_HOSTFILE, pw->pw_uid);
|
||||
/* Check file permissions of 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->pw_uid);
|
||||
host_status = check_host_in_hostfile(user_hostfile, canonical_hostname,
|
||||
client_host_key_e, client_host_key_n,
|
||||
ke, kn);
|
||||
restore_uid();
|
||||
}
|
||||
xfree(user_hostfile);
|
||||
}
|
||||
BN_free(ke);
|
||||
BN_free(kn);
|
||||
|
||||
/* 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_e, client_host_key_n))
|
||||
{
|
||||
log("Client on %.800s failed to respond correctly to host authentication.",
|
||||
canonical_hostname);
|
||||
return 0;
|
||||
}
|
||||
if (host_status != HOST_OK) {
|
||||
debug("Rhosts with RSA host authentication denied: unknown or invalid host key");
|
||||
packet_send_debug("Your host key cannot be verified: unknown or invalid host key.");
|
||||
return 0;
|
||||
}
|
||||
/* A matching host key was found and is known. */
|
||||
|
||||
/* We have authenticated the user using .rhosts or /etc/hosts.equiv, and
|
||||
the host using RSA. We accept the authentication. */
|
||||
|
||||
log("Rhosts with RSA host authentication accepted for %.100s, %.100s on %.700s.",
|
||||
pw->pw_name, client_user, canonical_hostname);
|
||||
packet_send_debug("Rhosts with RSA host authentication accepted.");
|
||||
return 1;
|
||||
/* Perform the challenge-response dialog with the client for the host key. */
|
||||
if (!auth_rsa_challenge_dialog(client_host_key_e, client_host_key_n)) {
|
||||
log("Client on %.800s failed to respond correctly to host authentication.",
|
||||
canonical_hostname);
|
||||
return 0;
|
||||
}
|
||||
/* We have authenticated the user using .rhosts or /etc/hosts.equiv, and the host using RSA.
|
||||
We accept the authentication. */
|
||||
|
||||
verbose("Rhosts with RSA host authentication accepted for %.100s, %.100s on %.700s.",
|
||||
pw->pw_name, client_user, canonical_hostname);
|
||||
packet_send_debug("Rhosts with RSA host authentication accepted.");
|
||||
return 1;
|
||||
}
|
||||
|
|
468
auth-rhosts.c
468
auth-rhosts.c
|
@ -1,22 +1,22 @@
|
|||
/*
|
||||
|
||||
auth-rhosts.c
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Fri Mar 17 05:12:18 1995 ylo
|
||||
|
||||
Rhosts authentication. This file contains code to check whether to admit
|
||||
the login based on rhosts authentication. This file also processes
|
||||
/etc/hosts.equiv.
|
||||
|
||||
*/
|
||||
*
|
||||
* auth-rhosts.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Fri Mar 17 05:12:18 1995 ylo
|
||||
*
|
||||
* Rhosts authentication. This file contains code to check whether to admit
|
||||
* the login based on rhosts authentication. This file also processes
|
||||
* /etc/hosts.equiv.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: auth-rhosts.c,v 1.4 1999/11/18 21:25:48 damien Exp $");
|
||||
RCSID("$Id: auth-rhosts.c,v 1.5 1999/11/24 13:26:21 damien Exp $");
|
||||
|
||||
#include "packet.h"
|
||||
#include "ssh.h"
|
||||
|
@ -28,256 +28,228 @@ RCSID("$Id: auth-rhosts.c,v 1.4 1999/11/18 21:25:48 damien Exp $");
|
|||
/etc/hosts.equiv). This returns true if authentication can be granted
|
||||
based on the file, and returns zero otherwise. */
|
||||
|
||||
int check_rhosts_file(const char *filename, const char *hostname,
|
||||
const char *ipaddr, const char *client_user,
|
||||
const char *server_user)
|
||||
int
|
||||
check_rhosts_file(const char *filename, const char *hostname,
|
||||
const char *ipaddr, const char *client_user,
|
||||
const char *server_user)
|
||||
{
|
||||
FILE *f;
|
||||
char buf[1024]; /* Must not be larger than host, user, dummy below. */
|
||||
|
||||
/* Open the .rhosts file. */
|
||||
f = fopen(filename, "r");
|
||||
if (!f)
|
||||
return 0; /* Cannot read the .rhosts - deny access. */
|
||||
FILE *f;
|
||||
char buf[1024]; /* Must not be larger than host, user, dummy below. */
|
||||
|
||||
/* Go through the file, checking every entry. */
|
||||
while (fgets(buf, sizeof(buf), f))
|
||||
{
|
||||
/* All three must be at least as big as buf to avoid overflows. */
|
||||
char hostbuf[1024], userbuf[1024], dummy[1024], *host, *user, *cp;
|
||||
int negated;
|
||||
|
||||
for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
if (*cp == '#' || *cp == '\n' || !*cp)
|
||||
continue;
|
||||
/* Open the .rhosts file, deny if unreadable */
|
||||
f = fopen(filename, "r");
|
||||
if (!f)
|
||||
return 0;
|
||||
|
||||
/* NO_PLUS is supported at least on OSF/1. We skip it (we don't ever
|
||||
support the plus syntax). */
|
||||
if (strncmp(cp, "NO_PLUS", 7) == 0)
|
||||
continue;
|
||||
/* Go through the file, checking every entry. */
|
||||
while (fgets(buf, sizeof(buf), f)) {
|
||||
/* All three must be at least as big as buf to avoid overflows. */
|
||||
char hostbuf[1024], userbuf[1024], dummy[1024], *host, *user, *cp;
|
||||
int negated;
|
||||
|
||||
/* This should be safe because each buffer is as big as the whole
|
||||
string, and thus cannot be overwritten. */
|
||||
switch (sscanf(buf, "%s %s %s", hostbuf, userbuf, dummy))
|
||||
{
|
||||
case 0:
|
||||
packet_send_debug("Found empty line in %.100s.", filename);
|
||||
continue; /* Empty line? */
|
||||
case 1:
|
||||
/* Host name only. */
|
||||
strlcpy(userbuf, server_user, sizeof(userbuf));
|
||||
break;
|
||||
case 2:
|
||||
/* Got both host and user name. */
|
||||
break;
|
||||
case 3:
|
||||
packet_send_debug("Found garbage in %.100s.", filename);
|
||||
continue; /* Extra garbage */
|
||||
default:
|
||||
continue; /* Weird... */
|
||||
for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
if (*cp == '#' || *cp == '\n' || !*cp)
|
||||
continue;
|
||||
|
||||
/* NO_PLUS is supported at least on OSF/1. We skip it (we
|
||||
don't ever support the plus syntax). */
|
||||
if (strncmp(cp, "NO_PLUS", 7) == 0)
|
||||
continue;
|
||||
|
||||
/* This should be safe because each buffer is as big as
|
||||
the whole string, and thus cannot be overwritten. */
|
||||
switch (sscanf(buf, "%s %s %s", hostbuf, userbuf, dummy)) {
|
||||
case 0:
|
||||
packet_send_debug("Found empty line in %.100s.", filename);
|
||||
continue;
|
||||
case 1:
|
||||
/* Host name only. */
|
||||
strlcpy(userbuf, server_user, sizeof(userbuf));
|
||||
break;
|
||||
case 2:
|
||||
/* Got both host and user name. */
|
||||
break;
|
||||
case 3:
|
||||
packet_send_debug("Found garbage in %.100s.", filename);
|
||||
continue;
|
||||
default:
|
||||
/* Weird... */
|
||||
continue;
|
||||
}
|
||||
|
||||
host = hostbuf;
|
||||
user = userbuf;
|
||||
negated = 0;
|
||||
|
||||
/* Process negated host names, or positive netgroups. */
|
||||
if (host[0] == '-') {
|
||||
negated = 1;
|
||||
host++;
|
||||
} else if (host[0] == '+')
|
||||
host++;
|
||||
|
||||
if (user[0] == '-') {
|
||||
negated = 1;
|
||||
user++;
|
||||
} else if (user[0] == '+')
|
||||
user++;
|
||||
|
||||
/* Check for empty host/user names (particularly '+'). */
|
||||
if (!host[0] || !user[0]) {
|
||||
/* We come here if either was '+' or '-'. */
|
||||
packet_send_debug("Ignoring wild host/user names in %.100s.",
|
||||
filename);
|
||||
continue;
|
||||
}
|
||||
/* Verify that host name matches. */
|
||||
if (host[0] == '@') {
|
||||
if (!innetgr(host + 1, hostname, NULL, NULL) &&
|
||||
!innetgr(host + 1, ipaddr, NULL, NULL))
|
||||
continue;
|
||||
} else if (strcasecmp(host, hostname) && strcmp(host, ipaddr) != 0)
|
||||
continue; /* Different hostname. */
|
||||
|
||||
/* Verify that user name matches. */
|
||||
if (user[0] == '@') {
|
||||
if (!innetgr(user + 1, NULL, client_user, NULL))
|
||||
continue;
|
||||
} else if (strcmp(user, client_user) != 0)
|
||||
continue; /* Different username. */
|
||||
|
||||
/* Found the user and host. */
|
||||
fclose(f);
|
||||
|
||||
/* If the entry was negated, deny access. */
|
||||
if (negated) {
|
||||
packet_send_debug("Matched negative entry in %.100s.",
|
||||
filename);
|
||||
return 0;
|
||||
}
|
||||
/* Accept authentication. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
host = hostbuf;
|
||||
user = userbuf;
|
||||
negated = 0;
|
||||
|
||||
/* Process negated host names, or positive netgroups. */
|
||||
if (host[0] == '-')
|
||||
{
|
||||
negated = 1;
|
||||
host++;
|
||||
}
|
||||
else
|
||||
if (host[0] == '+')
|
||||
host++;
|
||||
|
||||
if (user[0] == '-')
|
||||
{
|
||||
negated = 1;
|
||||
user++;
|
||||
}
|
||||
else
|
||||
if (user[0] == '+')
|
||||
user++;
|
||||
|
||||
/* Check for empty host/user names (particularly '+'). */
|
||||
if (!host[0] || !user[0])
|
||||
{
|
||||
/* We come here if either was '+' or '-'. */
|
||||
packet_send_debug("Ignoring wild host/user names in %.100s.",
|
||||
filename);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Verify that host name matches. */
|
||||
if (host[0] == '@')
|
||||
{
|
||||
if (!innetgr(host + 1, hostname, NULL, NULL) &&
|
||||
!innetgr(host + 1, ipaddr, NULL, NULL))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
if (strcasecmp(host, hostname) && strcmp(host, ipaddr) != 0)
|
||||
continue; /* Different hostname. */
|
||||
|
||||
/* Verify that user name matches. */
|
||||
if (user[0] == '@')
|
||||
{
|
||||
if (!innetgr(user + 1, NULL, client_user, NULL))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
if (strcmp(user, client_user) != 0)
|
||||
continue; /* Different username. */
|
||||
|
||||
/* Found the user and host. */
|
||||
fclose(f);
|
||||
|
||||
/* If the entry was negated, deny access. */
|
||||
if (negated)
|
||||
{
|
||||
packet_send_debug("Matched negative entry in %.100s.",
|
||||
filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Accept authentication. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Authentication using this file denied. */
|
||||
fclose(f);
|
||||
return 0;
|
||||
/* Authentication using this file denied. */
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Tries to authenticate the user using the .shosts or .rhosts file.
|
||||
/* Tries to authenticate the user using the .shosts or .rhosts file.
|
||||
Returns true if authentication succeeds. If ignore_rhosts is
|
||||
true, only /etc/hosts.equiv will be considered (.rhosts and .shosts
|
||||
are ignored). */
|
||||
|
||||
int auth_rhosts(struct passwd *pw, const char *client_user)
|
||||
int
|
||||
auth_rhosts(struct passwd *pw, const char *client_user)
|
||||
{
|
||||
extern ServerOptions options;
|
||||
char buf[1024];
|
||||
const char *hostname, *ipaddr;
|
||||
struct stat st;
|
||||
static const char *rhosts_files[] = { ".shosts", ".rhosts", NULL };
|
||||
unsigned int rhosts_file_index;
|
||||
extern ServerOptions options;
|
||||
char buf[1024];
|
||||
const char *hostname, *ipaddr;
|
||||
struct stat st;
|
||||
static const char *rhosts_files[] = {".shosts", ".rhosts", NULL};
|
||||
unsigned int rhosts_file_index;
|
||||
|
||||
/* Quick check: if the user has no .shosts or .rhosts files, return failure
|
||||
immediately without doing costly lookups from name servers. */
|
||||
/* Switch to the user's uid. */
|
||||
temporarily_use_uid(pw->pw_uid);
|
||||
for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];
|
||||
rhosts_file_index++)
|
||||
{
|
||||
/* Check users .rhosts or .shosts. */
|
||||
snprintf(buf, sizeof buf, "%.500s/%.100s",
|
||||
pw->pw_dir, rhosts_files[rhosts_file_index]);
|
||||
if (stat(buf, &st) >= 0)
|
||||
break;
|
||||
}
|
||||
/* Switch back to privileged uid. */
|
||||
restore_uid();
|
||||
|
||||
if (!rhosts_files[rhosts_file_index] && stat("/etc/hosts.equiv", &st) < 0 &&
|
||||
stat(SSH_HOSTS_EQUIV, &st) < 0)
|
||||
return 0; /* The user has no .shosts or .rhosts file and there are no
|
||||
system-wide files. */
|
||||
|
||||
/* Get the name, address, and port of the remote host. */
|
||||
hostname = get_canonical_hostname();
|
||||
ipaddr = get_remote_ipaddr();
|
||||
|
||||
/* If not logging in as superuser, try /etc/hosts.equiv and shosts.equiv. */
|
||||
if (pw->pw_uid != 0)
|
||||
{
|
||||
if (check_rhosts_file("/etc/hosts.equiv", hostname, ipaddr, client_user,
|
||||
pw->pw_name))
|
||||
{
|
||||
packet_send_debug("Accepted for %.100s [%.100s] by /etc/hosts.equiv.",
|
||||
hostname, ipaddr);
|
||||
return 1;
|
||||
/* Quick check: if the user has no .shosts or .rhosts files,
|
||||
return failure immediately without doing costly lookups from
|
||||
name servers. */
|
||||
/* Switch to the user's uid. */
|
||||
temporarily_use_uid(pw->pw_uid);
|
||||
for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];
|
||||
rhosts_file_index++) {
|
||||
/* Check users .rhosts or .shosts. */
|
||||
snprintf(buf, sizeof buf, "%.500s/%.100s",
|
||||
pw->pw_dir, rhosts_files[rhosts_file_index]);
|
||||
if (stat(buf, &st) >= 0)
|
||||
break;
|
||||
}
|
||||
if (check_rhosts_file(SSH_HOSTS_EQUIV, hostname, ipaddr, client_user,
|
||||
pw->pw_name))
|
||||
{
|
||||
packet_send_debug("Accepted for %.100s [%.100s] by %.100s.",
|
||||
hostname, ipaddr, SSH_HOSTS_EQUIV);
|
||||
return 1;
|
||||
/* Switch back to privileged uid. */
|
||||
restore_uid();
|
||||
|
||||
/* Deny if The user has no .shosts or .rhosts file and there are no system-wide files. */
|
||||
if (!rhosts_files[rhosts_file_index] &&
|
||||
stat("/etc/hosts.equiv", &st) < 0 &&
|
||||
stat(SSH_HOSTS_EQUIV, &st) < 0)
|
||||
return 0;
|
||||
|
||||
/* Get the name, address, and port of the remote host. */
|
||||
hostname = get_canonical_hostname();
|
||||
ipaddr = get_remote_ipaddr();
|
||||
|
||||
/* If not logging in as superuser, try /etc/hosts.equiv and shosts.equiv. */
|
||||
if (pw->pw_uid != 0) {
|
||||
if (check_rhosts_file("/etc/hosts.equiv", hostname, ipaddr, client_user,
|
||||
pw->pw_name)) {
|
||||
packet_send_debug("Accepted for %.100s [%.100s] by /etc/hosts.equiv.",
|
||||
hostname, ipaddr);
|
||||
return 1;
|
||||
}
|
||||
if (check_rhosts_file(SSH_HOSTS_EQUIV, hostname, ipaddr, client_user,
|
||||
pw->pw_name)) {
|
||||
packet_send_debug("Accepted for %.100s [%.100s] by %.100s.",
|
||||
hostname, ipaddr, SSH_HOSTS_EQUIV);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Check that the home directory is owned by root or the user, and
|
||||
is not group or world writable. */
|
||||
if (stat(pw->pw_dir, &st) < 0) {
|
||||
log("Rhosts authentication refused for %.100s: no home directory %.200s",
|
||||
pw->pw_name, pw->pw_dir);
|
||||
packet_send_debug("Rhosts authentication refused for %.100: no home directory %.200s",
|
||||
pw->pw_name, pw->pw_dir);
|
||||
return 0;
|
||||
}
|
||||
if (options.strict_modes &&
|
||||
((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
|
||||
(st.st_mode & 022) != 0)) {
|
||||
log("Rhosts authentication refused for %.100s: bad ownership or modes for home directory.",
|
||||
pw->pw_name);
|
||||
packet_send_debug("Rhosts authentication refused for %.100s: bad ownership or modes for home directory.",
|
||||
pw->pw_name);
|
||||
return 0;
|
||||
}
|
||||
/* Temporarily use the user's uid. */
|
||||
temporarily_use_uid(pw->pw_uid);
|
||||
|
||||
/* Check that the home directory is owned by root or the user, and is not
|
||||
group or world writable. */
|
||||
if (stat(pw->pw_dir, &st) < 0)
|
||||
{
|
||||
log("Rhosts authentication refused for %.100s: no home directory %.200s",
|
||||
pw->pw_name, pw->pw_dir);
|
||||
packet_send_debug("Rhosts authentication refused for %.100: no home directory %.200s",
|
||||
pw->pw_name, pw->pw_dir);
|
||||
return 0;
|
||||
}
|
||||
if (options.strict_modes &&
|
||||
((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
|
||||
(st.st_mode & 022) != 0))
|
||||
{
|
||||
log("Rhosts authentication refused for %.100s: bad ownership or modes for home directory.",
|
||||
pw->pw_name);
|
||||
packet_send_debug("Rhosts authentication refused for %.100s: bad ownership or modes for home directory.",
|
||||
pw->pw_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check all .rhosts files (currently .shosts and .rhosts). */
|
||||
/* Temporarily use the user's uid. */
|
||||
temporarily_use_uid(pw->pw_uid);
|
||||
for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];
|
||||
rhosts_file_index++)
|
||||
{
|
||||
/* Check users .rhosts or .shosts. */
|
||||
snprintf(buf, sizeof buf, "%.500s/%.100s",
|
||||
pw->pw_dir, rhosts_files[rhosts_file_index]);
|
||||
if (stat(buf, &st) < 0)
|
||||
continue; /* No such file. */
|
||||
/* Check all .rhosts files (currently .shosts and .rhosts). */
|
||||
for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];
|
||||
rhosts_file_index++) {
|
||||
/* Check users .rhosts or .shosts. */
|
||||
snprintf(buf, sizeof buf, "%.500s/%.100s",
|
||||
pw->pw_dir, rhosts_files[rhosts_file_index]);
|
||||
if (stat(buf, &st) < 0)
|
||||
continue;
|
||||
|
||||
/* Make sure that the file is either owned by the user or by root,
|
||||
and make sure it is not writable by anyone but the owner. This is
|
||||
to help avoid novices accidentally allowing access to their account
|
||||
by anyone. */
|
||||
if (options.strict_modes &&
|
||||
((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
|
||||
(st.st_mode & 022) != 0))
|
||||
{
|
||||
log("Rhosts authentication refused for %.100s: bad modes for %.200s",
|
||||
pw->pw_name, buf);
|
||||
packet_send_debug("Bad file modes for %.200s", buf);
|
||||
continue;
|
||||
/* Make sure that the file is either owned by the user or
|
||||
by root, and make sure it is not writable by anyone but
|
||||
the owner. This is to help avoid novices accidentally
|
||||
allowing access to their account by anyone. */
|
||||
if (options.strict_modes &&
|
||||
((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
|
||||
(st.st_mode & 022) != 0)) {
|
||||
log("Rhosts authentication refused for %.100s: bad modes for %.200s",
|
||||
pw->pw_name, buf);
|
||||
packet_send_debug("Bad file modes for %.200s", buf);
|
||||
continue;
|
||||
}
|
||||
/* Check if we have been configured to ignore .rhosts and .shosts files. */
|
||||
if (options.ignore_rhosts) {
|
||||
packet_send_debug("Server has been configured to ignore %.100s.",
|
||||
rhosts_files[rhosts_file_index]);
|
||||
continue;
|
||||
}
|
||||
/* Check if authentication is permitted by the file. */
|
||||
if (check_rhosts_file(buf, hostname, ipaddr, client_user, pw->pw_name)) {
|
||||
packet_send_debug("Accepted by %.100s.",
|
||||
rhosts_files[rhosts_file_index]);
|
||||
/* Restore the privileged uid. */
|
||||
restore_uid();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if we have been configured to ignore .rhosts and .shosts
|
||||
files. */
|
||||
if (options.ignore_rhosts)
|
||||
{
|
||||
packet_send_debug("Server has been configured to ignore %.100s.",
|
||||
rhosts_files[rhosts_file_index]);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check if authentication is permitted by the file. */
|
||||
if (check_rhosts_file(buf, hostname, ipaddr, client_user, pw->pw_name))
|
||||
{
|
||||
packet_send_debug("Accepted by %.100s.",
|
||||
rhosts_files[rhosts_file_index]);
|
||||
/* Restore the privileged uid. */
|
||||
restore_uid();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Rhosts authentication denied. */
|
||||
/* Restore the privileged uid. */
|
||||
restore_uid();
|
||||
return 0;
|
||||
/* Restore the privileged uid. */
|
||||
restore_uid();
|
||||
return 0;
|
||||
}
|
||||
|
|
789
auth-rsa.c
789
auth-rsa.c
|
@ -1,22 +1,22 @@
|
|||
/*
|
||||
|
||||
auth-rsa.c
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Mon Mar 27 01:46:52 1995 ylo
|
||||
|
||||
RSA-based authentication. This code determines whether to admit a login
|
||||
based on RSA authentication. This file also contains functions to check
|
||||
validity of the host key.
|
||||
|
||||
*/
|
||||
*
|
||||
* auth-rsa.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Mon Mar 27 01:46:52 1995 ylo
|
||||
*
|
||||
* RSA-based authentication. This code determines whether to admit a login
|
||||
* based on RSA authentication. This file also contains functions to check
|
||||
* validity of the host key.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: auth-rsa.c,v 1.8 1999/11/18 21:25:48 damien Exp $");
|
||||
RCSID("$Id: auth-rsa.c,v 1.9 1999/11/24 13:26:21 damien Exp $");
|
||||
|
||||
#include "rsa.h"
|
||||
#include "packet.h"
|
||||
|
@ -50,7 +50,7 @@ extern unsigned char session_id[16];
|
|||
/* The .ssh/authorized_keys file contains public keys, one per line, in the
|
||||
following format:
|
||||
options bits e n comment
|
||||
where bits, e and n are decimal numbers,
|
||||
where bits, e and n are decimal numbers,
|
||||
and comment is any string of characters up to newline. The maximum
|
||||
length of a line is 8000 characters. See the documentation for a
|
||||
description of the options.
|
||||
|
@ -63,71 +63,69 @@ extern unsigned char session_id[16];
|
|||
int
|
||||
auth_rsa_challenge_dialog(BIGNUM *e, BIGNUM *n)
|
||||
{
|
||||
BIGNUM *challenge, *encrypted_challenge, *aux;
|
||||
RSA *pk;
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
unsigned char buf[32], mdbuf[16], response[16];
|
||||
MD5_CTX md;
|
||||
unsigned int i;
|
||||
int plen, len;
|
||||
BIGNUM *challenge, *encrypted_challenge, *aux;
|
||||
RSA *pk;
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
unsigned char buf[32], mdbuf[16], response[16];
|
||||
MD5_CTX md;
|
||||
unsigned int i;
|
||||
int plen, len;
|
||||
|
||||
encrypted_challenge = BN_new();
|
||||
challenge = BN_new();
|
||||
aux = BN_new();
|
||||
encrypted_challenge = BN_new();
|
||||
challenge = BN_new();
|
||||
aux = BN_new();
|
||||
|
||||
/* Generate a random challenge. */
|
||||
BN_rand(challenge, 256, 0, 0);
|
||||
BN_mod(challenge, challenge, n, ctx);
|
||||
|
||||
/* Create the public key data structure. */
|
||||
pk = RSA_new();
|
||||
pk->e = BN_new();
|
||||
BN_copy(pk->e, e);
|
||||
pk->n = BN_new();
|
||||
BN_copy(pk->n, n);
|
||||
/* Generate a random challenge. */
|
||||
BN_rand(challenge, 256, 0, 0);
|
||||
BN_mod(challenge, challenge, n, ctx);
|
||||
|
||||
/* Encrypt the challenge with the public key. */
|
||||
rsa_public_encrypt(encrypted_challenge, challenge, pk);
|
||||
RSA_free(pk);
|
||||
/* Create the public key data structure. */
|
||||
pk = RSA_new();
|
||||
pk->e = BN_new();
|
||||
BN_copy(pk->e, e);
|
||||
pk->n = BN_new();
|
||||
BN_copy(pk->n, n);
|
||||
|
||||
/* Send the encrypted challenge to the client. */
|
||||
packet_start(SSH_SMSG_AUTH_RSA_CHALLENGE);
|
||||
packet_put_bignum(encrypted_challenge);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
/* Encrypt the challenge with the public key. */
|
||||
rsa_public_encrypt(encrypted_challenge, challenge, pk);
|
||||
RSA_free(pk);
|
||||
|
||||
/* The response is MD5 of decrypted challenge plus session id. */
|
||||
len = BN_num_bytes(challenge);
|
||||
if (len <= 0 || len > 32)
|
||||
fatal("auth_rsa_challenge_dialog: bad challenge length %d", len);
|
||||
memset(buf, 0, 32);
|
||||
BN_bn2bin(challenge, buf + 32 - len);
|
||||
MD5_Init(&md);
|
||||
MD5_Update(&md, buf, 32);
|
||||
MD5_Update(&md, session_id, 16);
|
||||
MD5_Final(mdbuf, &md);
|
||||
/* Send the encrypted challenge to the client. */
|
||||
packet_start(SSH_SMSG_AUTH_RSA_CHALLENGE);
|
||||
packet_put_bignum(encrypted_challenge);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
|
||||
/* We will no longer need these. */
|
||||
BN_clear_free(encrypted_challenge);
|
||||
BN_clear_free(challenge);
|
||||
BN_clear_free(aux);
|
||||
BN_CTX_free(ctx);
|
||||
|
||||
/* Wait for a response. */
|
||||
packet_read_expect(&plen, SSH_CMSG_AUTH_RSA_RESPONSE);
|
||||
packet_integrity_check(plen, 16, SSH_CMSG_AUTH_RSA_RESPONSE);
|
||||
for (i = 0; i < 16; i++)
|
||||
response[i] = packet_get_char();
|
||||
/* The response is MD5 of decrypted challenge plus session id. */
|
||||
len = BN_num_bytes(challenge);
|
||||
if (len <= 0 || len > 32)
|
||||
fatal("auth_rsa_challenge_dialog: bad challenge length %d", len);
|
||||
memset(buf, 0, 32);
|
||||
BN_bn2bin(challenge, buf + 32 - len);
|
||||
MD5_Init(&md);
|
||||
MD5_Update(&md, buf, 32);
|
||||
MD5_Update(&md, session_id, 16);
|
||||
MD5_Final(mdbuf, &md);
|
||||
|
||||
/* Verify that the response is the original challenge. */
|
||||
if (memcmp(response, mdbuf, 16) != 0)
|
||||
{
|
||||
/* Wrong answer. */
|
||||
return 0;
|
||||
}
|
||||
/* We will no longer need these. */
|
||||
BN_clear_free(encrypted_challenge);
|
||||
BN_clear_free(challenge);
|
||||
BN_clear_free(aux);
|
||||
BN_CTX_free(ctx);
|
||||
|
||||
/* Correct answer. */
|
||||
return 1;
|
||||
/* Wait for a response. */
|
||||
packet_read_expect(&plen, SSH_CMSG_AUTH_RSA_RESPONSE);
|
||||
packet_integrity_check(plen, 16, SSH_CMSG_AUTH_RSA_RESPONSE);
|
||||
for (i = 0; i < 16; i++)
|
||||
response[i] = packet_get_char();
|
||||
|
||||
/* Verify that the response is the original challenge. */
|
||||
if (memcmp(response, mdbuf, 16) != 0) {
|
||||
/* Wrong answer. */
|
||||
return 0;
|
||||
}
|
||||
/* Correct answer. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Performs the RSA authentication dialog with the client. This returns
|
||||
|
@ -137,357 +135,324 @@ auth_rsa_challenge_dialog(BIGNUM *e, BIGNUM *n)
|
|||
int
|
||||
auth_rsa(struct passwd *pw, BIGNUM *client_n)
|
||||
{
|
||||
extern ServerOptions options;
|
||||
char line[8192], file[1024];
|
||||
int authenticated;
|
||||
unsigned int bits;
|
||||
FILE *f;
|
||||
unsigned long linenum = 0;
|
||||
struct stat st;
|
||||
BIGNUM *e, *n;
|
||||
extern ServerOptions options;
|
||||
char line[8192], file[1024];
|
||||
int authenticated;
|
||||
unsigned int bits;
|
||||
FILE *f;
|
||||
unsigned long linenum = 0;
|
||||
struct stat st;
|
||||
BIGNUM *e, *n;
|
||||
|
||||
/* Temporarily use the user's uid. */
|
||||
temporarily_use_uid(pw->pw_uid);
|
||||
/* Temporarily use the user's uid. */
|
||||
temporarily_use_uid(pw->pw_uid);
|
||||
|
||||
/* The authorized keys. */
|
||||
snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
|
||||
SSH_USER_PERMITTED_KEYS);
|
||||
|
||||
/* Fail quietly if file does not exist */
|
||||
if (stat(file, &st) < 0)
|
||||
{
|
||||
/* Restore the privileged uid. */
|
||||
restore_uid();
|
||||
return 0;
|
||||
}
|
||||
/* The authorized keys. */
|
||||
snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
|
||||
SSH_USER_PERMITTED_KEYS);
|
||||
|
||||
/* Open the file containing the authorized keys. */
|
||||
f = fopen(file, "r");
|
||||
if (!f)
|
||||
{
|
||||
/* Restore the privileged uid. */
|
||||
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.");
|
||||
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 SSH_USER_PERMITTED_KEYS */
|
||||
int i;
|
||||
static const char *check[] = {
|
||||
"", 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) {
|
||||
log(buf);
|
||||
packet_send_debug(buf);
|
||||
restore_uid();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Flag indicating whether authentication has succeeded. */
|
||||
authenticated = 0;
|
||||
|
||||
/* Initialize mp-int variables. */
|
||||
e = BN_new();
|
||||
n = BN_new();
|
||||
|
||||
/* Go though the accepted keys, looking for the current key. If found,
|
||||
perform a challenge-response dialog to verify that the user really has
|
||||
the corresponding private key. */
|
||||
while (fgets(line, sizeof(line), f))
|
||||
{
|
||||
char *cp;
|
||||
char *options;
|
||||
|
||||
linenum++;
|
||||
|
||||
/* Skip leading whitespace. */
|
||||
for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
|
||||
/* Skip empty and comment lines. */
|
||||
if (!*cp || *cp == '\n' || *cp == '#')
|
||||
continue;
|
||||
|
||||
/* Check if there are options for this key, and if so, save their
|
||||
starting address and skip the option part for now. If there are no
|
||||
options, set the starting address to NULL. */
|
||||
if (*cp < '0' || *cp > '9')
|
||||
{
|
||||
int quoted = 0;
|
||||
options = cp;
|
||||
for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++)
|
||||
{
|
||||
if (*cp == '\\' && cp[1] == '"')
|
||||
cp++; /* Skip both */
|
||||
else
|
||||
if (*cp == '"')
|
||||
quoted = !quoted;
|
||||
}
|
||||
/* Fail quietly if file does not exist */
|
||||
if (stat(file, &st) < 0) {
|
||||
/* Restore the privileged uid. */
|
||||
restore_uid();
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
options = NULL;
|
||||
|
||||
/* Parse the key from the line. */
|
||||
if (!auth_rsa_read_key(&cp, &bits, e, n))
|
||||
{
|
||||
debug("%.100s, line %lu: bad key syntax",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
packet_send_debug("%.100s, line %lu: bad key syntax",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
continue;
|
||||
/* Open the file containing the authorized keys. */
|
||||
f = fopen(file, "r");
|
||||
if (!f) {
|
||||
/* Restore the privileged uid. */
|
||||
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.");
|
||||
return 0;
|
||||
}
|
||||
/* cp now points to the comment part. */
|
||||
|
||||
/* check the real bits */
|
||||
if (bits != BN_num_bits(n))
|
||||
error("Warning: error in %s, line %ld: keysize mismatch: "
|
||||
"actual size %d vs. announced %d.",
|
||||
file, linenum, BN_num_bits(n), bits);
|
||||
|
||||
/* Check if the we have found the desired key (identified by its
|
||||
modulus). */
|
||||
if (BN_cmp(n, client_n) != 0)
|
||||
continue; /* Wrong key. */
|
||||
|
||||
/* We have found the desired key. */
|
||||
|
||||
/* Perform the challenge-response dialog for this key. */
|
||||
if (!auth_rsa_challenge_dialog(e, n))
|
||||
{
|
||||
/* Wrong response. */
|
||||
log("Wrong response to RSA authentication challenge.");
|
||||
packet_send_debug("Wrong response to RSA authentication challenge.");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Correct response. The client has been successfully authenticated.
|
||||
Note that we have not yet processed the options; this will be reset
|
||||
if the options cause the authentication to be rejected. */
|
||||
authenticated = 1;
|
||||
|
||||
/* RSA part of authentication was accepted. Now process the options. */
|
||||
if (options)
|
||||
{
|
||||
while (*options && *options != ' ' && *options != '\t')
|
||||
{
|
||||
cp = "no-port-forwarding";
|
||||
if (strncmp(options, cp, strlen(cp)) == 0)
|
||||
{
|
||||
packet_send_debug("Port forwarding disabled.");
|
||||
no_port_forwarding_flag = 1;
|
||||
options += strlen(cp);
|
||||
goto next_option;
|
||||
}
|
||||
cp = "no-agent-forwarding";
|
||||
if (strncmp(options, cp, strlen(cp)) == 0)
|
||||
{
|
||||
packet_send_debug("Agent forwarding disabled.");
|
||||
no_agent_forwarding_flag = 1;
|
||||
options += strlen(cp);
|
||||
goto next_option;
|
||||
}
|
||||
cp = "no-X11-forwarding";
|
||||
if (strncmp(options, cp, strlen(cp)) == 0)
|
||||
{
|
||||
packet_send_debug("X11 forwarding disabled.");
|
||||
no_x11_forwarding_flag = 1;
|
||||
options += strlen(cp);
|
||||
goto next_option;
|
||||
}
|
||||
cp = "no-pty";
|
||||
if (strncmp(options, cp, strlen(cp)) == 0)
|
||||
{
|
||||
packet_send_debug("Pty allocation disabled.");
|
||||
no_pty_flag = 1;
|
||||
options += strlen(cp);
|
||||
goto next_option;
|
||||
}
|
||||
cp = "command=\"";
|
||||
if (strncmp(options, cp, strlen(cp)) == 0)
|
||||
{
|
||||
int i;
|
||||
options += strlen(cp);
|
||||
forced_command = xmalloc(strlen(options) + 1);
|
||||
i = 0;
|
||||
while (*options)
|
||||
{
|
||||
if (*options == '"')
|
||||
break;
|
||||
if (*options == '\\' && options[1] == '"')
|
||||
{
|
||||
options += 2;
|
||||
forced_command[i++] = '"';
|
||||
continue;
|
||||
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 SSH_USER_PERMITTED_KEYS */
|
||||
int i;
|
||||
static const char *check[] = {
|
||||
"", 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;
|
||||
}
|
||||
}
|
||||
forced_command[i++] = *options++;
|
||||
}
|
||||
if (!*options)
|
||||
{
|
||||
debug("%.100s, line %lu: missing end quote",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
packet_send_debug("%.100s, line %lu: missing end quote",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
continue;
|
||||
}
|
||||
forced_command[i] = 0;
|
||||
packet_send_debug("Forced command: %.900s", forced_command);
|
||||
options++;
|
||||
goto next_option;
|
||||
}
|
||||
cp = "environment=\"";
|
||||
if (strncmp(options, cp, strlen(cp)) == 0)
|
||||
{
|
||||
int i;
|
||||
char *s;
|
||||
struct envstring *new_envstring;
|
||||
options += strlen(cp);
|
||||
s = xmalloc(strlen(options) + 1);
|
||||
i = 0;
|
||||
while (*options)
|
||||
{
|
||||
if (*options == '"')
|
||||
break;
|
||||
if (*options == '\\' && options[1] == '"')
|
||||
{
|
||||
options += 2;
|
||||
s[i++] = '"';
|
||||
continue;
|
||||
}
|
||||
s[i++] = *options++;
|
||||
}
|
||||
if (!*options)
|
||||
{
|
||||
debug("%.100s, line %lu: missing end quote",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
packet_send_debug("%.100s, line %lu: missing end quote",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
continue;
|
||||
}
|
||||
s[i] = 0;
|
||||
packet_send_debug("Adding to environment: %.900s", s);
|
||||
debug("Adding to environment: %.900s", s);
|
||||
options++;
|
||||
new_envstring = xmalloc(sizeof(struct envstring));
|
||||
new_envstring->s = s;
|
||||
new_envstring->next = custom_environment;
|
||||
custom_environment = new_envstring;
|
||||
goto next_option;
|
||||
if (fail) {
|
||||
log(buf);
|
||||
packet_send_debug(buf);
|
||||
restore_uid();
|
||||
return 0;
|
||||
}
|
||||
cp = "from=\"";
|
||||
if (strncmp(options, cp, strlen(cp)) == 0)
|
||||
{
|
||||
char *patterns = xmalloc(strlen(options) + 1);
|
||||
int i;
|
||||
options += strlen(cp);
|
||||
i = 0;
|
||||
while (*options)
|
||||
{
|
||||
if (*options == '"')
|
||||
break;
|
||||
if (*options == '\\' && options[1] == '"')
|
||||
{
|
||||
options += 2;
|
||||
patterns[i++] = '"';
|
||||
continue;
|
||||
}
|
||||
patterns[i++] = *options++;
|
||||
}
|
||||
if (!*options)
|
||||
{
|
||||
debug("%.100s, line %lu: missing end quote",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
packet_send_debug("%.100s, line %lu: missing end quote",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
continue;
|
||||
}
|
||||
patterns[i] = 0;
|
||||
options++;
|
||||
if (!match_hostname(get_canonical_hostname(), patterns,
|
||||
strlen(patterns)) &&
|
||||
!match_hostname(get_remote_ipaddr(), patterns,
|
||||
strlen(patterns)))
|
||||
{
|
||||
log("RSA authentication tried for %.100s with correct key but not from a permitted host (host=%.200s, ip=%.200s).",
|
||||
pw->pw_name, get_canonical_hostname(),
|
||||
get_remote_ipaddr());
|
||||
packet_send_debug("Your host '%.200s' is not permitted to use this key for login.",
|
||||
get_canonical_hostname());
|
||||
xfree(patterns);
|
||||
authenticated = 0;
|
||||
break;
|
||||
}
|
||||
xfree(patterns);
|
||||
/* Host name matches. */
|
||||
goto next_option;
|
||||
}
|
||||
bad_option:
|
||||
/* Unknown option. */
|
||||
log("Bad options in %.100s file, line %lu: %.50s",
|
||||
SSH_USER_PERMITTED_KEYS, linenum, options);
|
||||
packet_send_debug("Bad options in %.100s file, line %lu: %.50s",
|
||||
SSH_USER_PERMITTED_KEYS, linenum, options);
|
||||
authenticated = 0;
|
||||
break;
|
||||
}
|
||||
/* Flag indicating whether authentication has succeeded. */
|
||||
authenticated = 0;
|
||||
|
||||
next_option:
|
||||
/* Skip the comma, and move to the next option (or break out
|
||||
if there are no more). */
|
||||
if (!*options)
|
||||
fatal("Bugs in auth-rsa.c option processing.");
|
||||
if (*options == ' ' || *options == '\t')
|
||||
break; /* End of options. */
|
||||
if (*options != ',')
|
||||
goto bad_option;
|
||||
options++;
|
||||
/* Process the next option. */
|
||||
continue;
|
||||
}
|
||||
/* Initialize mp-int variables. */
|
||||
e = BN_new();
|
||||
n = BN_new();
|
||||
|
||||
/* Go though the accepted keys, looking for the current key. If
|
||||
found, perform a challenge-response dialog to verify that the
|
||||
user really has the corresponding private key. */
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
char *cp;
|
||||
char *options;
|
||||
|
||||
linenum++;
|
||||
|
||||
/* Skip leading whitespace. */
|
||||
for (cp = line; *cp == ' ' || *cp == '\t'; cp++);
|
||||
|
||||
/* Skip empty and comment lines. */
|
||||
if (!*cp || *cp == '\n' || *cp == '#')
|
||||
continue;
|
||||
|
||||
/* Check if there are options for this key, and if so,
|
||||
save their starting address and skip the option part
|
||||
for now. If there are no options, set the starting
|
||||
address to NULL. */
|
||||
if (*cp < '0' || *cp > '9') {
|
||||
int quoted = 0;
|
||||
options = cp;
|
||||
for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
|
||||
if (*cp == '\\' && cp[1] == '"')
|
||||
cp++; /* Skip both */
|
||||
else if (*cp == '"')
|
||||
quoted = !quoted;
|
||||
}
|
||||
} else
|
||||
options = NULL;
|
||||
|
||||
/* Parse the key from the line. */
|
||||
if (!auth_rsa_read_key(&cp, &bits, e, n)) {
|
||||
debug("%.100s, line %lu: bad key syntax",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
packet_send_debug("%.100s, line %lu: bad key syntax",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
continue;
|
||||
}
|
||||
/* cp now points to the comment part. */
|
||||
|
||||
/* check the real bits */
|
||||
if (bits != BN_num_bits(n))
|
||||
error("Warning: error in %s, line %ld: keysize mismatch: "
|
||||
"actual size %d vs. announced %d.",
|
||||
file, linenum, BN_num_bits(n), bits);
|
||||
|
||||
/* Check if the we have found the desired key (identified by its modulus). */
|
||||
if (BN_cmp(n, client_n) != 0)
|
||||
continue; /* Wrong key. */
|
||||
|
||||
/* We have found the desired key. */
|
||||
|
||||
/* Perform the challenge-response dialog for this key. */
|
||||
if (!auth_rsa_challenge_dialog(e, n)) {
|
||||
/* Wrong response. */
|
||||
verbose("Wrong response to RSA authentication challenge.");
|
||||
packet_send_debug("Wrong response to RSA authentication challenge.");
|
||||
continue;
|
||||
}
|
||||
/* Correct response. The client has been successfully
|
||||
authenticated. Note that we have not yet processed the
|
||||
options; this will be reset if the options cause the
|
||||
authentication to be rejected. */
|
||||
authenticated = 1;
|
||||
|
||||
/* RSA part of authentication was accepted. Now process the options. */
|
||||
if (options) {
|
||||
while (*options && *options != ' ' && *options != '\t') {
|
||||
cp = "no-port-forwarding";
|
||||
if (strncmp(options, cp, strlen(cp)) == 0) {
|
||||
packet_send_debug("Port forwarding disabled.");
|
||||
no_port_forwarding_flag = 1;
|
||||
options += strlen(cp);
|
||||
goto next_option;
|
||||
}
|
||||
cp = "no-agent-forwarding";
|
||||
if (strncmp(options, cp, strlen(cp)) == 0) {
|
||||
packet_send_debug("Agent forwarding disabled.");
|
||||
no_agent_forwarding_flag = 1;
|
||||
options += strlen(cp);
|
||||
goto next_option;
|
||||
}
|
||||
cp = "no-X11-forwarding";
|
||||
if (strncmp(options, cp, strlen(cp)) == 0) {
|
||||
packet_send_debug("X11 forwarding disabled.");
|
||||
no_x11_forwarding_flag = 1;
|
||||
options += strlen(cp);
|
||||
goto next_option;
|
||||
}
|
||||
cp = "no-pty";
|
||||
if (strncmp(options, cp, strlen(cp)) == 0) {
|
||||
packet_send_debug("Pty allocation disabled.");
|
||||
no_pty_flag = 1;
|
||||
options += strlen(cp);
|
||||
goto next_option;
|
||||
}
|
||||
cp = "command=\"";
|
||||
if (strncmp(options, cp, strlen(cp)) == 0) {
|
||||
int i;
|
||||
options += strlen(cp);
|
||||
forced_command = xmalloc(strlen(options) + 1);
|
||||
i = 0;
|
||||
while (*options) {
|
||||
if (*options == '"')
|
||||
break;
|
||||
if (*options == '\\' && options[1] == '"') {
|
||||
options += 2;
|
||||
forced_command[i++] = '"';
|
||||
continue;
|
||||
}
|
||||
forced_command[i++] = *options++;
|
||||
}
|
||||
if (!*options) {
|
||||
debug("%.100s, line %lu: missing end quote",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
packet_send_debug("%.100s, line %lu: missing end quote",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
continue;
|
||||
}
|
||||
forced_command[i] = 0;
|
||||
packet_send_debug("Forced command: %.900s", forced_command);
|
||||
options++;
|
||||
goto next_option;
|
||||
}
|
||||
cp = "environment=\"";
|
||||
if (strncmp(options, cp, strlen(cp)) == 0) {
|
||||
int i;
|
||||
char *s;
|
||||
struct envstring *new_envstring;
|
||||
options += strlen(cp);
|
||||
s = xmalloc(strlen(options) + 1);
|
||||
i = 0;
|
||||
while (*options) {
|
||||
if (*options == '"')
|
||||
break;
|
||||
if (*options == '\\' && options[1] == '"') {
|
||||
options += 2;
|
||||
s[i++] = '"';
|
||||
continue;
|
||||
}
|
||||
s[i++] = *options++;
|
||||
}
|
||||
if (!*options) {
|
||||
debug("%.100s, line %lu: missing end quote",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
packet_send_debug("%.100s, line %lu: missing end quote",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
continue;
|
||||
}
|
||||
s[i] = 0;
|
||||
packet_send_debug("Adding to environment: %.900s", s);
|
||||
debug("Adding to environment: %.900s", s);
|
||||
options++;
|
||||
new_envstring = xmalloc(sizeof(struct envstring));
|
||||
new_envstring->s = s;
|
||||
new_envstring->next = custom_environment;
|
||||
custom_environment = new_envstring;
|
||||
goto next_option;
|
||||
}
|
||||
cp = "from=\"";
|
||||
if (strncmp(options, cp, strlen(cp)) == 0) {
|
||||
char *patterns = xmalloc(strlen(options) + 1);
|
||||
int i;
|
||||
options += strlen(cp);
|
||||
i = 0;
|
||||
while (*options) {
|
||||
if (*options == '"')
|
||||
break;
|
||||
if (*options == '\\' && options[1] == '"') {
|
||||
options += 2;
|
||||
patterns[i++] = '"';
|
||||
continue;
|
||||
}
|
||||
patterns[i++] = *options++;
|
||||
}
|
||||
if (!*options) {
|
||||
debug("%.100s, line %lu: missing end quote",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
packet_send_debug("%.100s, line %lu: missing end quote",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
continue;
|
||||
}
|
||||
patterns[i] = 0;
|
||||
options++;
|
||||
if (!match_hostname(get_canonical_hostname(), patterns,
|
||||
strlen(patterns)) &&
|
||||
!match_hostname(get_remote_ipaddr(), patterns,
|
||||
strlen(patterns))) {
|
||||
log("RSA authentication tried for %.100s with correct key but not from a permitted host (host=%.200s, ip=%.200s).",
|
||||
pw->pw_name, get_canonical_hostname(),
|
||||
get_remote_ipaddr());
|
||||
packet_send_debug("Your host '%.200s' is not permitted to use this key for login.",
|
||||
get_canonical_hostname());
|
||||
xfree(patterns);
|
||||
authenticated = 0;
|
||||
break;
|
||||
}
|
||||
xfree(patterns);
|
||||
/* Host name matches. */
|
||||
goto next_option;
|
||||
}
|
||||
bad_option:
|
||||
/* Unknown option. */
|
||||
log("Bad options in %.100s file, line %lu: %.50s",
|
||||
SSH_USER_PERMITTED_KEYS, linenum, options);
|
||||
packet_send_debug("Bad options in %.100s file, line %lu: %.50s",
|
||||
SSH_USER_PERMITTED_KEYS, linenum, options);
|
||||
authenticated = 0;
|
||||
break;
|
||||
|
||||
next_option:
|
||||
/* Skip the comma, and move to the next option
|
||||
(or break out if there are no more). */
|
||||
if (!*options)
|
||||
fatal("Bugs in auth-rsa.c option processing.");
|
||||
if (*options == ' ' || *options == '\t')
|
||||
break; /* End of options. */
|
||||
if (*options != ',')
|
||||
goto bad_option;
|
||||
options++;
|
||||
/* Process the next option. */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/* Break out of the loop if authentication was successful;
|
||||
otherwise continue searching. */
|
||||
if (authenticated)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Break out of the loop if authentication was successful; otherwise
|
||||
continue searching. */
|
||||
if (authenticated)
|
||||
break;
|
||||
}
|
||||
/* Restore the privileged uid. */
|
||||
restore_uid();
|
||||
|
||||
/* Restore the privileged uid. */
|
||||
restore_uid();
|
||||
/* Close the file. */
|
||||
fclose(f);
|
||||
|
||||
/* Close the file. */
|
||||
fclose(f);
|
||||
|
||||
/* Clear any mp-int variables. */
|
||||
BN_clear_free(n);
|
||||
BN_clear_free(e);
|
||||
/* Clear any mp-int variables. */
|
||||
BN_clear_free(n);
|
||||
BN_clear_free(e);
|
||||
|
||||
if (authenticated)
|
||||
packet_send_debug("RSA authentication accepted.");
|
||||
if (authenticated)
|
||||
packet_send_debug("RSA authentication accepted.");
|
||||
|
||||
/* Return authentication result. */
|
||||
return authenticated;
|
||||
/* Return authentication result. */
|
||||
return authenticated;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
#include "includes.h"
|
||||
|
||||
#ifdef SKEY
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: auth-skey.c,v 1.2 1999/10/16 20:57:52 deraadt Exp $");
|
||||
RCSID("$Id: auth-skey.c,v 1.3 1999/11/23 22:25:52 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include <sha1.h>
|
||||
|
@ -32,6 +33,7 @@ hash_collapse(s)
|
|||
|
||||
return i;
|
||||
}
|
||||
|
||||
char *
|
||||
skey_fake_keyinfo(char *username)
|
||||
{
|
||||
|
@ -150,4 +152,4 @@ skey_fake_keyinfo(char *username)
|
|||
return skeyprompt;
|
||||
}
|
||||
|
||||
#endif SKEY
|
||||
#endif /* SKEY */
|
||||
|
|
855
authfd.c
855
authfd.c
|
@ -1,20 +1,20 @@
|
|||
/*
|
||||
|
||||
authfd.c
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Wed Mar 29 01:30:28 1995 ylo
|
||||
|
||||
Functions for connecting the local authentication agent.
|
||||
|
||||
*/
|
||||
*
|
||||
* authfd.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Wed Mar 29 01:30:28 1995 ylo
|
||||
*
|
||||
* Functions for connecting the local authentication agent.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: authfd.c,v 1.6 1999/11/18 21:25:48 damien Exp $");
|
||||
RCSID("$Id: authfd.c,v 1.7 1999/11/24 13:26:21 damien Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "rsa.h"
|
||||
|
@ -36,45 +36,42 @@ RCSID("$Id: authfd.c,v 1.6 1999/11/18 21:25:48 damien Exp $");
|
|||
int
|
||||
ssh_get_authentication_socket()
|
||||
{
|
||||
const char *authsocket;
|
||||
int sock;
|
||||
struct sockaddr_un sunaddr;
|
||||
const char *authsocket;
|
||||
int sock;
|
||||
struct sockaddr_un sunaddr;
|
||||
|
||||
authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME);
|
||||
if (!authsocket)
|
||||
return -1;
|
||||
authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME);
|
||||
if (!authsocket)
|
||||
return -1;
|
||||
|
||||
sunaddr.sun_family = AF_UNIX;
|
||||
strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
|
||||
|
||||
sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (sock < 0)
|
||||
return -1;
|
||||
sunaddr.sun_family = AF_UNIX;
|
||||
strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
|
||||
|
||||
/* close on exec */
|
||||
if (fcntl(sock, F_SETFD, 1) == -1)
|
||||
{
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (connect(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0)
|
||||
{
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (sock < 0)
|
||||
return -1;
|
||||
|
||||
return sock;
|
||||
/* close on exec */
|
||||
if (fcntl(sock, F_SETFD, 1) == -1) {
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
if (connect(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) {
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
return sock;
|
||||
}
|
||||
|
||||
/* Closes the agent socket if it should be closed (depends on how it was
|
||||
obtained). The argument must have been returned by
|
||||
obtained). The argument must have been returned by
|
||||
ssh_get_authentication_socket(). */
|
||||
|
||||
void ssh_close_authentication_socket(int sock)
|
||||
void
|
||||
ssh_close_authentication_socket(int sock)
|
||||
{
|
||||
if (getenv(SSH_AUTHSOCKET_ENV_NAME))
|
||||
close(sock);
|
||||
if (getenv(SSH_AUTHSOCKET_ENV_NAME))
|
||||
close(sock);
|
||||
}
|
||||
|
||||
/* Opens and connects a private socket for communication with the
|
||||
|
@ -83,38 +80,39 @@ void ssh_close_authentication_socket(int sock)
|
|||
Returns NULL if an error occurred and the connection could not be
|
||||
opened. */
|
||||
|
||||
AuthenticationConnection *ssh_get_authentication_connection()
|
||||
AuthenticationConnection *
|
||||
ssh_get_authentication_connection()
|
||||
{
|
||||
AuthenticationConnection *auth;
|
||||
int sock;
|
||||
|
||||
sock = ssh_get_authentication_socket();
|
||||
AuthenticationConnection *auth;
|
||||
int sock;
|
||||
|
||||
/* Fail if we couldn't obtain a connection. This happens if we exited
|
||||
due to a timeout. */
|
||||
if (sock < 0)
|
||||
return NULL;
|
||||
sock = ssh_get_authentication_socket();
|
||||
|
||||
/* Applocate the connection structure and initialize it. */
|
||||
auth = xmalloc(sizeof(*auth));
|
||||
auth->fd = sock;
|
||||
buffer_init(&auth->packet);
|
||||
buffer_init(&auth->identities);
|
||||
auth->howmany = 0;
|
||||
/* Fail if we couldn't obtain a connection. This happens if we
|
||||
exited due to a timeout. */
|
||||
if (sock < 0)
|
||||
return NULL;
|
||||
|
||||
return auth;
|
||||
/* Applocate the connection structure and initialize it. */
|
||||
auth = xmalloc(sizeof(*auth));
|
||||
auth->fd = sock;
|
||||
buffer_init(&auth->packet);
|
||||
buffer_init(&auth->identities);
|
||||
auth->howmany = 0;
|
||||
|
||||
return auth;
|
||||
}
|
||||
|
||||
/* Closes the connection to the authentication agent and frees any associated
|
||||
memory. */
|
||||
|
||||
void ssh_close_authentication_connection(AuthenticationConnection *ac)
|
||||
void
|
||||
ssh_close_authentication_connection(AuthenticationConnection *ac)
|
||||
{
|
||||
buffer_free(&ac->packet);
|
||||
buffer_free(&ac->identities);
|
||||
close(ac->fd);
|
||||
/* Free the connection data structure. */
|
||||
xfree(ac);
|
||||
buffer_free(&ac->packet);
|
||||
buffer_free(&ac->identities);
|
||||
close(ac->fd);
|
||||
xfree(ac);
|
||||
}
|
||||
|
||||
/* Returns the first authentication identity held by the agent.
|
||||
|
@ -126,67 +124,62 @@ int
|
|||
ssh_get_first_identity(AuthenticationConnection *auth,
|
||||
BIGNUM *e, BIGNUM *n, char **comment)
|
||||
{
|
||||
unsigned char msg[8192];
|
||||
int len, l;
|
||||
unsigned char msg[8192];
|
||||
int len, l;
|
||||
|
||||
/* Send a message to the agent requesting for a list of the identities
|
||||
it can represent. */
|
||||
msg[0] = 0;
|
||||
msg[1] = 0;
|
||||
msg[2] = 0;
|
||||
msg[3] = 1;
|
||||
msg[4] = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
|
||||
if (write(auth->fd, msg, 5) != 5)
|
||||
{
|
||||
error("write auth->fd: %.100s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read the length of the response. XXX implement timeouts here. */
|
||||
len = 4;
|
||||
while (len > 0)
|
||||
{
|
||||
l = read(auth->fd, msg + 4 - len, len);
|
||||
if (l <= 0)
|
||||
{
|
||||
error("read auth->fd: %.100s", strerror(errno));
|
||||
return 0;
|
||||
/* Send a message to the agent requesting for a list of the
|
||||
identities it can represent. */
|
||||
msg[0] = 0;
|
||||
msg[1] = 0;
|
||||
msg[2] = 0;
|
||||
msg[3] = 1;
|
||||
msg[4] = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
|
||||
if (write(auth->fd, msg, 5) != 5) {
|
||||
error("write auth->fd: %.100s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
/* Read the length of the response. XXX implement timeouts here. */
|
||||
len = 4;
|
||||
while (len > 0) {
|
||||
l = read(auth->fd, msg + 4 - len, len);
|
||||
if (l <= 0) {
|
||||
error("read auth->fd: %.100s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
len -= l;
|
||||
}
|
||||
len -= l;
|
||||
}
|
||||
|
||||
/* Extract the length, and check it for sanity. (We cannot trust
|
||||
authentication agents). */
|
||||
len = GET_32BIT(msg);
|
||||
if (len < 1 || len > 256*1024)
|
||||
fatal("Authentication reply message too long: %d\n", len);
|
||||
/* Extract the length, and check it for sanity. (We cannot trust
|
||||
authentication agents). */
|
||||
len = GET_32BIT(msg);
|
||||
if (len < 1 || len > 256 * 1024)
|
||||
fatal("Authentication reply message too long: %d\n", len);
|
||||
|
||||
/* Read the packet itself. */
|
||||
buffer_clear(&auth->identities);
|
||||
while (len > 0)
|
||||
{
|
||||
l = len;
|
||||
if (l > sizeof(msg))
|
||||
l = sizeof(msg);
|
||||
l = read(auth->fd, msg, l);
|
||||
if (l <= 0)
|
||||
fatal("Incomplete authentication reply.");
|
||||
buffer_append(&auth->identities, (char *)msg, l);
|
||||
len -= l;
|
||||
}
|
||||
|
||||
/* Get message type, and verify that we got a proper answer. */
|
||||
buffer_get(&auth->identities, (char *)msg, 1);
|
||||
if (msg[0] != SSH_AGENT_RSA_IDENTITIES_ANSWER)
|
||||
fatal("Bad authentication reply message type: %d", msg[0]);
|
||||
|
||||
/* Get the number of entries in the response and check it for sanity. */
|
||||
auth->howmany = buffer_get_int(&auth->identities);
|
||||
if (auth->howmany > 1024)
|
||||
fatal("Too many identities in authentication reply: %d\n", auth->howmany);
|
||||
/* Read the packet itself. */
|
||||
buffer_clear(&auth->identities);
|
||||
while (len > 0) {
|
||||
l = len;
|
||||
if (l > sizeof(msg))
|
||||
l = sizeof(msg);
|
||||
l = read(auth->fd, msg, l);
|
||||
if (l <= 0)
|
||||
fatal("Incomplete authentication reply.");
|
||||
buffer_append(&auth->identities, (char *) msg, l);
|
||||
len -= l;
|
||||
}
|
||||
|
||||
/* Return the first entry (if any). */
|
||||
return ssh_get_next_identity(auth, e, n, comment);
|
||||
/* Get message type, and verify that we got a proper answer. */
|
||||
buffer_get(&auth->identities, (char *) msg, 1);
|
||||
if (msg[0] != SSH_AGENT_RSA_IDENTITIES_ANSWER)
|
||||
fatal("Bad authentication reply message type: %d", msg[0]);
|
||||
|
||||
/* Get the number of entries in the response and check it for sanity. */
|
||||
auth->howmany = buffer_get_int(&auth->identities);
|
||||
if (auth->howmany > 1024)
|
||||
fatal("Too many identities in authentication reply: %d\n", auth->howmany);
|
||||
|
||||
/* Return the first entry (if any). */
|
||||
return ssh_get_next_identity(auth, e, n, comment);
|
||||
}
|
||||
|
||||
/* Returns the next authentication identity for the agent. Other functions
|
||||
|
@ -198,27 +191,27 @@ int
|
|||
ssh_get_next_identity(AuthenticationConnection *auth,
|
||||
BIGNUM *e, BIGNUM *n, char **comment)
|
||||
{
|
||||
unsigned int bits;
|
||||
unsigned int bits;
|
||||
|
||||
/* Return failure if no more entries. */
|
||||
if (auth->howmany <= 0)
|
||||
return 0;
|
||||
/* Return failure if no more entries. */
|
||||
if (auth->howmany <= 0)
|
||||
return 0;
|
||||
|
||||
/* Get the next entry from the packet. These will abort with a fatal
|
||||
error if the packet is too short or contains corrupt data. */
|
||||
bits = buffer_get_int(&auth->identities);
|
||||
buffer_get_bignum(&auth->identities, e);
|
||||
buffer_get_bignum(&auth->identities, n);
|
||||
*comment = buffer_get_string(&auth->identities, NULL);
|
||||
/* Get the next entry from the packet. These will abort with a
|
||||
fatal error if the packet is too short or contains corrupt data. */
|
||||
bits = buffer_get_int(&auth->identities);
|
||||
buffer_get_bignum(&auth->identities, e);
|
||||
buffer_get_bignum(&auth->identities, n);
|
||||
*comment = buffer_get_string(&auth->identities, NULL);
|
||||
|
||||
if (bits != BN_num_bits(n))
|
||||
error("Warning: keysize mismatch: actual %d, announced %u",
|
||||
BN_num_bits(n), bits);
|
||||
if (bits != BN_num_bits(n))
|
||||
error("Warning: keysize mismatch: actual %d, announced %u",
|
||||
BN_num_bits(n), bits);
|
||||
|
||||
/* Decrement the number of remaining entries. */
|
||||
auth->howmany--;
|
||||
/* Decrement the number of remaining entries. */
|
||||
auth->howmany--;
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Generates a random challenge, sends it to the agent, and waits for response
|
||||
|
@ -229,355 +222,329 @@ ssh_get_next_identity(AuthenticationConnection *auth,
|
|||
|
||||
int
|
||||
ssh_decrypt_challenge(AuthenticationConnection *auth,
|
||||
BIGNUM *e, BIGNUM *n, BIGNUM *challenge,
|
||||
BIGNUM* e, BIGNUM *n, BIGNUM *challenge,
|
||||
unsigned char session_id[16],
|
||||
unsigned int response_type,
|
||||
unsigned char response[16])
|
||||
{
|
||||
Buffer buffer;
|
||||
unsigned char buf[8192];
|
||||
int len, l, i;
|
||||
Buffer buffer;
|
||||
unsigned char buf[8192];
|
||||
int len, l, i;
|
||||
|
||||
/* Response type 0 is no longer supported. */
|
||||
if (response_type == 0)
|
||||
fatal("Compatibility with ssh protocol version 1.0 no longer supported.");
|
||||
/* Response type 0 is no longer supported. */
|
||||
if (response_type == 0)
|
||||
fatal("Compatibility with ssh protocol version 1.0 no longer supported.");
|
||||
|
||||
/* Format a message to the agent. */
|
||||
buf[0] = SSH_AGENTC_RSA_CHALLENGE;
|
||||
buffer_init(&buffer);
|
||||
buffer_append(&buffer, (char *)buf, 1);
|
||||
buffer_put_int(&buffer, BN_num_bits(n));
|
||||
buffer_put_bignum(&buffer, e);
|
||||
buffer_put_bignum(&buffer, n);
|
||||
buffer_put_bignum(&buffer, challenge);
|
||||
buffer_append(&buffer, (char *)session_id, 16);
|
||||
buffer_put_int(&buffer, response_type);
|
||||
/* Format a message to the agent. */
|
||||
buf[0] = SSH_AGENTC_RSA_CHALLENGE;
|
||||
buffer_init(&buffer);
|
||||
buffer_append(&buffer, (char *) buf, 1);
|
||||
buffer_put_int(&buffer, BN_num_bits(n));
|
||||
buffer_put_bignum(&buffer, e);
|
||||
buffer_put_bignum(&buffer, n);
|
||||
buffer_put_bignum(&buffer, challenge);
|
||||
buffer_append(&buffer, (char *) session_id, 16);
|
||||
buffer_put_int(&buffer, response_type);
|
||||
|
||||
/* Get the length of the message, and format it in the buffer. */
|
||||
len = buffer_len(&buffer);
|
||||
PUT_32BIT(buf, len);
|
||||
/* Get the length of the message, and format it in the buffer. */
|
||||
len = buffer_len(&buffer);
|
||||
PUT_32BIT(buf, len);
|
||||
|
||||
/* Send the length and then the packet to the agent. */
|
||||
if (write(auth->fd, buf, 4) != 4 ||
|
||||
write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
|
||||
buffer_len(&buffer))
|
||||
{
|
||||
error("Error writing to authentication socket.");
|
||||
error_cleanup:
|
||||
buffer_free(&buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Wait for response from the agent. First read the length of the
|
||||
response packet. */
|
||||
len = 4;
|
||||
while (len > 0)
|
||||
{
|
||||
l = read(auth->fd, buf + 4 - len, len);
|
||||
if (l <= 0)
|
||||
{
|
||||
error("Error reading response length from authentication socket.");
|
||||
goto error_cleanup;
|
||||
/* Send the length and then the packet to the agent. */
|
||||
if (write(auth->fd, buf, 4) != 4 ||
|
||||
write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
|
||||
buffer_len(&buffer)) {
|
||||
error("Error writing to authentication socket.");
|
||||
error_cleanup:
|
||||
buffer_free(&buffer);
|
||||
return 0;
|
||||
}
|
||||
len -= l;
|
||||
}
|
||||
|
||||
/* Extract the length, and check it for sanity. */
|
||||
len = GET_32BIT(buf);
|
||||
if (len > 256*1024)
|
||||
fatal("Authentication response too long: %d", len);
|
||||
|
||||
/* Read the rest of the response in tothe buffer. */
|
||||
buffer_clear(&buffer);
|
||||
while (len > 0)
|
||||
{
|
||||
l = len;
|
||||
if (l > sizeof(buf))
|
||||
l = sizeof(buf);
|
||||
l = read(auth->fd, buf, l);
|
||||
if (l <= 0)
|
||||
{
|
||||
error("Error reading response from authentication socket.");
|
||||
goto error_cleanup;
|
||||
/* Wait for response from the agent. First read the length of the
|
||||
response packet. */
|
||||
len = 4;
|
||||
while (len > 0) {
|
||||
l = read(auth->fd, buf + 4 - len, len);
|
||||
if (l <= 0) {
|
||||
error("Error reading response length from authentication socket.");
|
||||
goto error_cleanup;
|
||||
}
|
||||
len -= l;
|
||||
}
|
||||
buffer_append(&buffer, (char *)buf, l);
|
||||
len -= l;
|
||||
}
|
||||
|
||||
/* Get the type of the packet. */
|
||||
buffer_get(&buffer, (char *)buf, 1);
|
||||
/* Extract the length, and check it for sanity. */
|
||||
len = GET_32BIT(buf);
|
||||
if (len > 256 * 1024)
|
||||
fatal("Authentication response too long: %d", len);
|
||||
|
||||
/* Check for agent failure message. */
|
||||
if (buf[0] == SSH_AGENT_FAILURE)
|
||||
{
|
||||
log("Agent admitted failure to authenticate using the key.");
|
||||
goto error_cleanup;
|
||||
}
|
||||
|
||||
/* Now it must be an authentication response packet. */
|
||||
if (buf[0] != SSH_AGENT_RSA_RESPONSE)
|
||||
fatal("Bad authentication response: %d", buf[0]);
|
||||
/* Read the rest of the response in tothe buffer. */
|
||||
buffer_clear(&buffer);
|
||||
while (len > 0) {
|
||||
l = len;
|
||||
if (l > sizeof(buf))
|
||||
l = sizeof(buf);
|
||||
l = read(auth->fd, buf, l);
|
||||
if (l <= 0) {
|
||||
error("Error reading response from authentication socket.");
|
||||
goto error_cleanup;
|
||||
}
|
||||
buffer_append(&buffer, (char *) buf, l);
|
||||
len -= l;
|
||||
}
|
||||
|
||||
/* Get the response from the packet. This will abort with a fatal error
|
||||
if the packet is corrupt. */
|
||||
for (i = 0; i < 16; i++)
|
||||
response[i] = buffer_get_char(&buffer);
|
||||
/* Get the type of the packet. */
|
||||
buffer_get(&buffer, (char *) buf, 1);
|
||||
|
||||
/* The buffer containing the packet is no longer needed. */
|
||||
buffer_free(&buffer);
|
||||
/* Check for agent failure message. */
|
||||
if (buf[0] == SSH_AGENT_FAILURE) {
|
||||
log("Agent admitted failure to authenticate using the key.");
|
||||
goto error_cleanup;
|
||||
}
|
||||
/* Now it must be an authentication response packet. */
|
||||
if (buf[0] != SSH_AGENT_RSA_RESPONSE)
|
||||
fatal("Bad authentication response: %d", buf[0]);
|
||||
|
||||
/* Correct answer. */
|
||||
return 1;
|
||||
}
|
||||
/* Get the response from the packet. This will abort with a fatal
|
||||
error if the packet is corrupt. */
|
||||
for (i = 0; i < 16; i++)
|
||||
response[i] = buffer_get_char(&buffer);
|
||||
|
||||
/* The buffer containing the packet is no longer needed. */
|
||||
buffer_free(&buffer);
|
||||
|
||||
/* Correct answer. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Adds an identity to the authentication server. This call is not meant to
|
||||
be used by normal applications. */
|
||||
|
||||
int ssh_add_identity(AuthenticationConnection *auth,
|
||||
RSA *key, const char *comment)
|
||||
int
|
||||
ssh_add_identity(AuthenticationConnection *auth,
|
||||
RSA * key, const char *comment)
|
||||
{
|
||||
Buffer buffer;
|
||||
unsigned char buf[8192];
|
||||
int len, l, type;
|
||||
Buffer buffer;
|
||||
unsigned char buf[8192];
|
||||
int len, l, type;
|
||||
|
||||
/* Format a message to the agent. */
|
||||
buffer_init(&buffer);
|
||||
buffer_put_char(&buffer, SSH_AGENTC_ADD_RSA_IDENTITY);
|
||||
buffer_put_int(&buffer, BN_num_bits(key->n));
|
||||
buffer_put_bignum(&buffer, key->n);
|
||||
buffer_put_bignum(&buffer, key->e);
|
||||
buffer_put_bignum(&buffer, key->d);
|
||||
/* To keep within the protocol: p < q for ssh. in SSL p > q */
|
||||
buffer_put_bignum(&buffer, key->iqmp); /* ssh key->u */
|
||||
buffer_put_bignum(&buffer, key->q); /* ssh key->p, SSL key->q */
|
||||
buffer_put_bignum(&buffer, key->p); /* ssh key->q, SSL key->p */
|
||||
buffer_put_string(&buffer, comment, strlen(comment));
|
||||
/* Format a message to the agent. */
|
||||
buffer_init(&buffer);
|
||||
buffer_put_char(&buffer, SSH_AGENTC_ADD_RSA_IDENTITY);
|
||||
buffer_put_int(&buffer, BN_num_bits(key->n));
|
||||
buffer_put_bignum(&buffer, key->n);
|
||||
buffer_put_bignum(&buffer, key->e);
|
||||
buffer_put_bignum(&buffer, key->d);
|
||||
/* To keep within the protocol: p < q for ssh. in SSL p > q */
|
||||
buffer_put_bignum(&buffer, key->iqmp); /* ssh key->u */
|
||||
buffer_put_bignum(&buffer, key->q); /* ssh key->p, SSL key->q */
|
||||
buffer_put_bignum(&buffer, key->p); /* ssh key->q, SSL key->p */
|
||||
buffer_put_string(&buffer, comment, strlen(comment));
|
||||
|
||||
/* Get the length of the message, and format it in the buffer. */
|
||||
len = buffer_len(&buffer);
|
||||
PUT_32BIT(buf, len);
|
||||
/* Get the length of the message, and format it in the buffer. */
|
||||
len = buffer_len(&buffer);
|
||||
PUT_32BIT(buf, len);
|
||||
|
||||
/* Send the length and then the packet to the agent. */
|
||||
if (write(auth->fd, buf, 4) != 4 ||
|
||||
write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
|
||||
buffer_len(&buffer))
|
||||
{
|
||||
error("Error writing to authentication socket.");
|
||||
error_cleanup:
|
||||
buffer_free(&buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Wait for response from the agent. First read the length of the
|
||||
response packet. */
|
||||
len = 4;
|
||||
while (len > 0)
|
||||
{
|
||||
l = read(auth->fd, buf + 4 - len, len);
|
||||
if (l <= 0)
|
||||
{
|
||||
error("Error reading response length from authentication socket.");
|
||||
goto error_cleanup;
|
||||
/* Send the length and then the packet to the agent. */
|
||||
if (write(auth->fd, buf, 4) != 4 ||
|
||||
write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
|
||||
buffer_len(&buffer)) {
|
||||
error("Error writing to authentication socket.");
|
||||
error_cleanup:
|
||||
buffer_free(&buffer);
|
||||
return 0;
|
||||
}
|
||||
len -= l;
|
||||
}
|
||||
|
||||
/* Extract the length, and check it for sanity. */
|
||||
len = GET_32BIT(buf);
|
||||
if (len > 256*1024)
|
||||
fatal("Add identity response too long: %d", len);
|
||||
|
||||
/* Read the rest of the response in tothe buffer. */
|
||||
buffer_clear(&buffer);
|
||||
while (len > 0)
|
||||
{
|
||||
l = len;
|
||||
if (l > sizeof(buf))
|
||||
l = sizeof(buf);
|
||||
l = read(auth->fd, buf, l);
|
||||
if (l <= 0)
|
||||
{
|
||||
error("Error reading response from authentication socket.");
|
||||
goto error_cleanup;
|
||||
/* Wait for response from the agent. First read the length of the
|
||||
response packet. */
|
||||
len = 4;
|
||||
while (len > 0) {
|
||||
l = read(auth->fd, buf + 4 - len, len);
|
||||
if (l <= 0) {
|
||||
error("Error reading response length from authentication socket.");
|
||||
goto error_cleanup;
|
||||
}
|
||||
len -= l;
|
||||
}
|
||||
buffer_append(&buffer, (char *)buf, l);
|
||||
len -= l;
|
||||
}
|
||||
|
||||
/* Get the type of the packet. */
|
||||
type = buffer_get_char(&buffer);
|
||||
switch (type)
|
||||
{
|
||||
case SSH_AGENT_FAILURE:
|
||||
buffer_free(&buffer);
|
||||
return 0;
|
||||
case SSH_AGENT_SUCCESS:
|
||||
buffer_free(&buffer);
|
||||
return 1;
|
||||
default:
|
||||
fatal("Bad response to add identity from authentication agent: %d",
|
||||
type);
|
||||
}
|
||||
/*NOTREACHED*/
|
||||
return 0;
|
||||
}
|
||||
/* Extract the length, and check it for sanity. */
|
||||
len = GET_32BIT(buf);
|
||||
if (len > 256 * 1024)
|
||||
fatal("Add identity response too long: %d", len);
|
||||
|
||||
/* Removes an identity from the authentication server. This call is not meant
|
||||
/* Read the rest of the response in tothe buffer. */
|
||||
buffer_clear(&buffer);
|
||||
while (len > 0) {
|
||||
l = len;
|
||||
if (l > sizeof(buf))
|
||||
l = sizeof(buf);
|
||||
l = read(auth->fd, buf, l);
|
||||
if (l <= 0) {
|
||||
error("Error reading response from authentication socket.");
|
||||
goto error_cleanup;
|
||||
}
|
||||
buffer_append(&buffer, (char *) buf, l);
|
||||
len -= l;
|
||||
}
|
||||
|
||||
/* Get the type of the packet. */
|
||||
type = buffer_get_char(&buffer);
|
||||
switch (type) {
|
||||
case SSH_AGENT_FAILURE:
|
||||
buffer_free(&buffer);
|
||||
return 0;
|
||||
case SSH_AGENT_SUCCESS:
|
||||
buffer_free(&buffer);
|
||||
return 1;
|
||||
default:
|
||||
fatal("Bad response to add identity from authentication agent: %d",
|
||||
type);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Removes an identity from the authentication server. This call is not meant
|
||||
to be used by normal applications. */
|
||||
|
||||
int ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
|
||||
int
|
||||
ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
|
||||
{
|
||||
Buffer buffer;
|
||||
unsigned char buf[8192];
|
||||
int len, l, type;
|
||||
Buffer buffer;
|
||||
unsigned char buf[8192];
|
||||
int len, l, type;
|
||||
|
||||
/* Format a message to the agent. */
|
||||
buffer_init(&buffer);
|
||||
buffer_put_char(&buffer, SSH_AGENTC_REMOVE_RSA_IDENTITY);
|
||||
buffer_put_int(&buffer, BN_num_bits(key->n));
|
||||
buffer_put_bignum(&buffer, key->e);
|
||||
buffer_put_bignum(&buffer, key->n);
|
||||
/* Format a message to the agent. */
|
||||
buffer_init(&buffer);
|
||||
buffer_put_char(&buffer, SSH_AGENTC_REMOVE_RSA_IDENTITY);
|
||||
buffer_put_int(&buffer, BN_num_bits(key->n));
|
||||
buffer_put_bignum(&buffer, key->e);
|
||||
buffer_put_bignum(&buffer, key->n);
|
||||
|
||||
/* Get the length of the message, and format it in the buffer. */
|
||||
len = buffer_len(&buffer);
|
||||
PUT_32BIT(buf, len);
|
||||
/* Get the length of the message, and format it in the buffer. */
|
||||
len = buffer_len(&buffer);
|
||||
PUT_32BIT(buf, len);
|
||||
|
||||
/* Send the length and then the packet to the agent. */
|
||||
if (write(auth->fd, buf, 4) != 4 ||
|
||||
write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
|
||||
buffer_len(&buffer))
|
||||
{
|
||||
error("Error writing to authentication socket.");
|
||||
error_cleanup:
|
||||
buffer_free(&buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Wait for response from the agent. First read the length of the
|
||||
response packet. */
|
||||
len = 4;
|
||||
while (len > 0)
|
||||
{
|
||||
l = read(auth->fd, buf + 4 - len, len);
|
||||
if (l <= 0)
|
||||
{
|
||||
error("Error reading response length from authentication socket.");
|
||||
goto error_cleanup;
|
||||
/* Send the length and then the packet to the agent. */
|
||||
if (write(auth->fd, buf, 4) != 4 ||
|
||||
write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
|
||||
buffer_len(&buffer)) {
|
||||
error("Error writing to authentication socket.");
|
||||
error_cleanup:
|
||||
buffer_free(&buffer);
|
||||
return 0;
|
||||
}
|
||||
len -= l;
|
||||
}
|
||||
|
||||
/* Extract the length, and check it for sanity. */
|
||||
len = GET_32BIT(buf);
|
||||
if (len > 256*1024)
|
||||
fatal("Remove identity response too long: %d", len);
|
||||
|
||||
/* Read the rest of the response in tothe buffer. */
|
||||
buffer_clear(&buffer);
|
||||
while (len > 0)
|
||||
{
|
||||
l = len;
|
||||
if (l > sizeof(buf))
|
||||
l = sizeof(buf);
|
||||
l = read(auth->fd, buf, l);
|
||||
if (l <= 0)
|
||||
{
|
||||
error("Error reading response from authentication socket.");
|
||||
goto error_cleanup;
|
||||
/* Wait for response from the agent. First read the length of the
|
||||
response packet. */
|
||||
len = 4;
|
||||
while (len > 0) {
|
||||
l = read(auth->fd, buf + 4 - len, len);
|
||||
if (l <= 0) {
|
||||
error("Error reading response length from authentication socket.");
|
||||
goto error_cleanup;
|
||||
}
|
||||
len -= l;
|
||||
}
|
||||
buffer_append(&buffer, (char *)buf, l);
|
||||
len -= l;
|
||||
}
|
||||
|
||||
/* Get the type of the packet. */
|
||||
type = buffer_get_char(&buffer);
|
||||
switch (type)
|
||||
{
|
||||
case SSH_AGENT_FAILURE:
|
||||
buffer_free(&buffer);
|
||||
return 0;
|
||||
case SSH_AGENT_SUCCESS:
|
||||
buffer_free(&buffer);
|
||||
return 1;
|
||||
default:
|
||||
fatal("Bad response to remove identity from authentication agent: %d",
|
||||
type);
|
||||
}
|
||||
/*NOTREACHED*/
|
||||
return 0;
|
||||
}
|
||||
/* Extract the length, and check it for sanity. */
|
||||
len = GET_32BIT(buf);
|
||||
if (len > 256 * 1024)
|
||||
fatal("Remove identity response too long: %d", len);
|
||||
|
||||
/* Removes all identities from the agent. This call is not meant
|
||||
/* Read the rest of the response in tothe buffer. */
|
||||
buffer_clear(&buffer);
|
||||
while (len > 0) {
|
||||
l = len;
|
||||
if (l > sizeof(buf))
|
||||
l = sizeof(buf);
|
||||
l = read(auth->fd, buf, l);
|
||||
if (l <= 0) {
|
||||
error("Error reading response from authentication socket.");
|
||||
goto error_cleanup;
|
||||
}
|
||||
buffer_append(&buffer, (char *) buf, l);
|
||||
len -= l;
|
||||
}
|
||||
|
||||
/* Get the type of the packet. */
|
||||
type = buffer_get_char(&buffer);
|
||||
switch (type) {
|
||||
case SSH_AGENT_FAILURE:
|
||||
buffer_free(&buffer);
|
||||
return 0;
|
||||
case SSH_AGENT_SUCCESS:
|
||||
buffer_free(&buffer);
|
||||
return 1;
|
||||
default:
|
||||
fatal("Bad response to remove identity from authentication agent: %d",
|
||||
type);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Removes all identities from the agent. This call is not meant
|
||||
to be used by normal applications. */
|
||||
|
||||
int ssh_remove_all_identities(AuthenticationConnection *auth)
|
||||
int
|
||||
ssh_remove_all_identities(AuthenticationConnection *auth)
|
||||
{
|
||||
Buffer buffer;
|
||||
unsigned char buf[8192];
|
||||
int len, l, type;
|
||||
Buffer buffer;
|
||||
unsigned char buf[8192];
|
||||
int len, l, type;
|
||||
|
||||
/* Get the length of the message, and format it in the buffer. */
|
||||
PUT_32BIT(buf, 1);
|
||||
buf[4] = SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES;
|
||||
/* Get the length of the message, and format it in the buffer. */
|
||||
PUT_32BIT(buf, 1);
|
||||
buf[4] = SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES;
|
||||
|
||||
/* Send the length and then the packet to the agent. */
|
||||
if (write(auth->fd, buf, 5) != 5)
|
||||
{
|
||||
error("Error writing to authentication socket.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Wait for response from the agent. First read the length of the
|
||||
response packet. */
|
||||
len = 4;
|
||||
while (len > 0)
|
||||
{
|
||||
l = read(auth->fd, buf + 4 - len, len);
|
||||
if (l <= 0)
|
||||
{
|
||||
error("Error reading response length from authentication socket.");
|
||||
return 0;
|
||||
/* Send the length and then the packet to the agent. */
|
||||
if (write(auth->fd, buf, 5) != 5) {
|
||||
error("Error writing to authentication socket.");
|
||||
return 0;
|
||||
}
|
||||
len -= l;
|
||||
}
|
||||
|
||||
/* Extract the length, and check it for sanity. */
|
||||
len = GET_32BIT(buf);
|
||||
if (len > 256*1024)
|
||||
fatal("Remove identity response too long: %d", len);
|
||||
|
||||
/* Read the rest of the response into the buffer. */
|
||||
buffer_init(&buffer);
|
||||
while (len > 0)
|
||||
{
|
||||
l = len;
|
||||
if (l > sizeof(buf))
|
||||
l = sizeof(buf);
|
||||
l = read(auth->fd, buf, l);
|
||||
if (l <= 0)
|
||||
{
|
||||
error("Error reading response from authentication socket.");
|
||||
buffer_free(&buffer);
|
||||
return 0;
|
||||
/* Wait for response from the agent. First read the length of the
|
||||
response packet. */
|
||||
len = 4;
|
||||
while (len > 0) {
|
||||
l = read(auth->fd, buf + 4 - len, len);
|
||||
if (l <= 0) {
|
||||
error("Error reading response length from authentication socket.");
|
||||
return 0;
|
||||
}
|
||||
len -= l;
|
||||
}
|
||||
buffer_append(&buffer, (char *)buf, l);
|
||||
len -= l;
|
||||
}
|
||||
|
||||
/* Get the type of the packet. */
|
||||
type = buffer_get_char(&buffer);
|
||||
switch (type)
|
||||
{
|
||||
case SSH_AGENT_FAILURE:
|
||||
buffer_free(&buffer);
|
||||
return 0;
|
||||
case SSH_AGENT_SUCCESS:
|
||||
buffer_free(&buffer);
|
||||
return 1;
|
||||
default:
|
||||
fatal("Bad response to remove identity from authentication agent: %d",
|
||||
type);
|
||||
}
|
||||
/*NOTREACHED*/
|
||||
return 0;
|
||||
}
|
||||
/* Extract the length, and check it for sanity. */
|
||||
len = GET_32BIT(buf);
|
||||
if (len > 256 * 1024)
|
||||
fatal("Remove identity response too long: %d", len);
|
||||
|
||||
/* Read the rest of the response into the buffer. */
|
||||
buffer_init(&buffer);
|
||||
while (len > 0) {
|
||||
l = len;
|
||||
if (l > sizeof(buf))
|
||||
l = sizeof(buf);
|
||||
l = read(auth->fd, buf, l);
|
||||
if (l <= 0) {
|
||||
error("Error reading response from authentication socket.");
|
||||
buffer_free(&buffer);
|
||||
return 0;
|
||||
}
|
||||
buffer_append(&buffer, (char *) buf, l);
|
||||
len -= l;
|
||||
}
|
||||
|
||||
/* Get the type of the packet. */
|
||||
type = buffer_get_char(&buffer);
|
||||
switch (type) {
|
||||
case SSH_AGENT_FAILURE:
|
||||
buffer_free(&buffer);
|
||||
return 0;
|
||||
case SSH_AGENT_SUCCESS:
|
||||
buffer_free(&buffer);
|
||||
return 1;
|
||||
default:
|
||||
fatal("Bad response to remove identity from authentication agent: %d",
|
||||
type);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
return 0;
|
||||
}
|
||||
|
|
87
authfd.h
87
authfd.h
|
@ -1,19 +1,19 @@
|
|||
/*
|
||||
*
|
||||
* authfd.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Wed Mar 29 01:17:41 1995 ylo
|
||||
*
|
||||
* Functions to interface with the SSH_AUTHENTICATION_FD socket.
|
||||
*
|
||||
*/
|
||||
|
||||
authfd.h
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Wed Mar 29 01:17:41 1995 ylo
|
||||
|
||||
Functions to interface with the SSH_AUTHENTICATION_FD socket.
|
||||
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: authfd.h,v 1.2 1999/11/16 02:37:16 damien Exp $"); */
|
||||
/* RCSID("$Id: authfd.h,v 1.3 1999/11/24 13:26:22 damien Exp $"); */
|
||||
|
||||
#ifndef AUTHFD_H
|
||||
#define AUTHFD_H
|
||||
|
@ -31,72 +31,73 @@ Functions to interface with the SSH_AUTHENTICATION_FD socket.
|
|||
#define SSH_AGENTC_REMOVE_RSA_IDENTITY 8
|
||||
#define SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES 9
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int fd;
|
||||
Buffer packet;
|
||||
Buffer identities;
|
||||
int howmany;
|
||||
} AuthenticationConnection;
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
Buffer packet;
|
||||
Buffer identities;
|
||||
int howmany;
|
||||
} AuthenticationConnection;
|
||||
/* Returns the number of the authentication fd, or -1 if there is none. */
|
||||
int ssh_get_authentication_socket();
|
||||
int ssh_get_authentication_socket();
|
||||
|
||||
/* This should be called for any descriptor returned by
|
||||
/* This should be called for any descriptor returned by
|
||||
ssh_get_authentication_socket(). Depending on the way the descriptor was
|
||||
obtained, this may close the descriptor. */
|
||||
void ssh_close_authentication_socket(int authfd);
|
||||
void ssh_close_authentication_socket(int authfd);
|
||||
|
||||
/* Opens and connects a private socket for communication with the
|
||||
authentication agent. Returns NULL if an error occurred and the
|
||||
authentication agent. Returns NULL if an error occurred and the
|
||||
connection could not be opened. The connection should be closed by
|
||||
the caller by calling ssh_close_authentication_connection(). */
|
||||
AuthenticationConnection *ssh_get_authentication_connection();
|
||||
|
||||
/* Closes the connection to the authentication agent and frees any associated
|
||||
memory. */
|
||||
void ssh_close_authentication_connection(AuthenticationConnection *ac);
|
||||
void ssh_close_authentication_connection(AuthenticationConnection * ac);
|
||||
|
||||
/* Returns the first authentication identity held by the agent.
|
||||
Returns true if an identity is available, 0 otherwise.
|
||||
The caller must initialize the integers before the call, and free the
|
||||
comment after a successful call (before calling ssh_get_next_identity). */
|
||||
int ssh_get_first_identity(AuthenticationConnection *connection,
|
||||
BIGNUM *e, BIGNUM *n, char **comment);
|
||||
int
|
||||
ssh_get_first_identity(AuthenticationConnection * connection,
|
||||
BIGNUM * e, BIGNUM * n, char **comment);
|
||||
|
||||
/* Returns the next authentication identity for the agent. Other functions
|
||||
can be called between this and ssh_get_first_identity or two calls of this
|
||||
function. This returns 0 if there are no more identities. The caller
|
||||
must free comment after a successful return. */
|
||||
int ssh_get_next_identity(AuthenticationConnection *connection,
|
||||
BIGNUM *e, BIGNUM *n, char **comment);
|
||||
int
|
||||
ssh_get_next_identity(AuthenticationConnection * connection,
|
||||
BIGNUM * e, BIGNUM * n, char **comment);
|
||||
|
||||
/* Requests the agent to decrypt the given challenge. Returns true if
|
||||
the agent claims it was able to decrypt it. */
|
||||
int ssh_decrypt_challenge(AuthenticationConnection *auth,
|
||||
BIGNUM *e, BIGNUM *n, BIGNUM *challenge,
|
||||
unsigned char session_id[16],
|
||||
unsigned int response_type,
|
||||
unsigned char response[16]);
|
||||
int
|
||||
ssh_decrypt_challenge(AuthenticationConnection * auth,
|
||||
BIGNUM * e, BIGNUM * n, BIGNUM * challenge,
|
||||
unsigned char session_id[16],
|
||||
unsigned int response_type,
|
||||
unsigned char response[16]);
|
||||
|
||||
/* Adds an identity to the authentication server. This call is not meant to
|
||||
be used by normal applications. This returns true if the identity
|
||||
was successfully added. */
|
||||
int ssh_add_identity(AuthenticationConnection *connection,
|
||||
RSA *key, const char *comment);
|
||||
int ssh_add_identity(AuthenticationConnection * connection,
|
||||
RSA * key, const char *comment);
|
||||
|
||||
/* Removes the identity from the authentication server. This call is
|
||||
not meant to be used by normal applications. This returns true if the
|
||||
identity was successfully added. */
|
||||
int ssh_remove_identity(AuthenticationConnection *connection,
|
||||
RSA *key);
|
||||
int ssh_remove_identity(AuthenticationConnection * connection,
|
||||
RSA * key);
|
||||
|
||||
/* Removes all identities from the authentication agent. This call is not
|
||||
meant to be used by normal applications. This returns true if the
|
||||
operation was successful. */
|
||||
int ssh_remove_all_identities(AuthenticationConnection *connection);
|
||||
int ssh_remove_all_identities(AuthenticationConnection * connection);
|
||||
|
||||
/* Closes the connection to the authentication agent. */
|
||||
void ssh_close_authentication(AuthenticationConnection *connection);
|
||||
void ssh_close_authentication(AuthenticationConnection * connection);
|
||||
|
||||
#endif /* AUTHFD_H */
|
||||
#endif /* AUTHFD_H */
|
||||
|
|
533
authfile.c
533
authfile.c
|
@ -1,21 +1,21 @@
|
|||
/*
|
||||
|
||||
authfile.c
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Mon Mar 27 03:52:05 1995 ylo
|
||||
|
||||
This file contains functions for reading and writing identity files, and
|
||||
for reading the passphrase from the user.
|
||||
|
||||
*/
|
||||
*
|
||||
* authfile.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Mon Mar 27 03:52:05 1995 ylo
|
||||
*
|
||||
* This file contains functions for reading and writing identity files, and
|
||||
* for reading the passphrase from the user.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: authfile.c,v 1.3 1999/11/13 02:07:45 damien Exp $");
|
||||
RCSID("$Id: authfile.c,v 1.4 1999/11/24 13:26:22 damien Exp $");
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
#include <openssl/bn.h>
|
||||
|
@ -42,93 +42,93 @@ int
|
|||
save_private_key(const char *filename, const char *passphrase,
|
||||
RSA *key, const char *comment)
|
||||
{
|
||||
Buffer buffer, encrypted;
|
||||
char buf[100], *cp;
|
||||
int f, i;
|
||||
CipherContext cipher;
|
||||
int cipher_type;
|
||||
u_int32_t rand;
|
||||
Buffer buffer, encrypted;
|
||||
char buf[100], *cp;
|
||||
int f, i;
|
||||
CipherContext cipher;
|
||||
int cipher_type;
|
||||
u_int32_t rand;
|
||||
|
||||
/* 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_type = SSH_CIPHER_NONE;
|
||||
else
|
||||
cipher_type = SSH_AUTHFILE_CIPHER;
|
||||
/* 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_type = SSH_CIPHER_NONE;
|
||||
else
|
||||
cipher_type = SSH_AUTHFILE_CIPHER;
|
||||
|
||||
/* This buffer is used to built the secret part of the private key. */
|
||||
buffer_init(&buffer);
|
||||
|
||||
/* Put checkbytes for checking passphrase validity. */
|
||||
rand = arc4random();
|
||||
buf[0] = rand & 0xff;
|
||||
buf[1] = (rand >> 8) & 0xff;
|
||||
buf[2] = buf[0];
|
||||
buf[3] = buf[1];
|
||||
buffer_append(&buffer, buf, 4);
|
||||
/* This buffer is used to built the secret part of the private key. */
|
||||
buffer_init(&buffer);
|
||||
|
||||
/* Store the private key (n and e will not be stored because they will
|
||||
be stored in plain text, and storing them also in encrypted format
|
||||
would just give known plaintext). */
|
||||
buffer_put_bignum(&buffer, key->d);
|
||||
buffer_put_bignum(&buffer, key->iqmp);
|
||||
buffer_put_bignum(&buffer, key->q); /* reverse from SSL p */
|
||||
buffer_put_bignum(&buffer, key->p); /* reverse from SSL q */
|
||||
/* Put checkbytes for checking passphrase validity. */
|
||||
rand = arc4random();
|
||||
buf[0] = rand & 0xff;
|
||||
buf[1] = (rand >> 8) & 0xff;
|
||||
buf[2] = buf[0];
|
||||
buf[3] = buf[1];
|
||||
buffer_append(&buffer, buf, 4);
|
||||
|
||||
/* Pad the part to be encrypted until its size is a multiple of 8. */
|
||||
while (buffer_len(&buffer) % 8 != 0)
|
||||
buffer_put_char(&buffer, 0);
|
||||
/* Store the private key (n and e will not be stored because they
|
||||
will be stored in plain text, and storing them also in
|
||||
encrypted format would just give known plaintext). */
|
||||
buffer_put_bignum(&buffer, key->d);
|
||||
buffer_put_bignum(&buffer, key->iqmp);
|
||||
buffer_put_bignum(&buffer, key->q); /* reverse from SSL p */
|
||||
buffer_put_bignum(&buffer, key->p); /* reverse from SSL q */
|
||||
|
||||
/* This buffer will be used to contain the data in the file. */
|
||||
buffer_init(&encrypted);
|
||||
/* Pad the part to be encrypted until its size is a multiple of 8. */
|
||||
while (buffer_len(&buffer) % 8 != 0)
|
||||
buffer_put_char(&buffer, 0);
|
||||
|
||||
/* First store keyfile id string. */
|
||||
cp = AUTHFILE_ID_STRING;
|
||||
for (i = 0; cp[i]; i++)
|
||||
buffer_put_char(&encrypted, cp[i]);
|
||||
buffer_put_char(&encrypted, 0);
|
||||
/* This buffer will be used to contain the data in the file. */
|
||||
buffer_init(&encrypted);
|
||||
|
||||
/* Store cipher type. */
|
||||
buffer_put_char(&encrypted, cipher_type);
|
||||
buffer_put_int(&encrypted, 0); /* For future extension */
|
||||
/* First store keyfile id string. */
|
||||
cp = AUTHFILE_ID_STRING;
|
||||
for (i = 0; cp[i]; i++)
|
||||
buffer_put_char(&encrypted, cp[i]);
|
||||
buffer_put_char(&encrypted, 0);
|
||||
|
||||
/* Store public key. This will be in plain text. */
|
||||
buffer_put_int(&encrypted, BN_num_bits(key->n));
|
||||
buffer_put_bignum(&encrypted, key->n);
|
||||
buffer_put_bignum(&encrypted, key->e);
|
||||
buffer_put_string(&encrypted, comment, strlen(comment));
|
||||
/* Store cipher type. */
|
||||
buffer_put_char(&encrypted, cipher_type);
|
||||
buffer_put_int(&encrypted, 0); /* For future extension */
|
||||
|
||||
/* Allocate space for the private part of the key in the buffer. */
|
||||
buffer_append_space(&encrypted, &cp, buffer_len(&buffer));
|
||||
/* Store public key. This will be in plain text. */
|
||||
buffer_put_int(&encrypted, BN_num_bits(key->n));
|
||||
buffer_put_bignum(&encrypted, key->n);
|
||||
buffer_put_bignum(&encrypted, key->e);
|
||||
buffer_put_string(&encrypted, comment, strlen(comment));
|
||||
|
||||
cipher_set_key_string(&cipher, cipher_type, passphrase, 1);
|
||||
cipher_encrypt(&cipher, (unsigned char *)cp,
|
||||
(unsigned char *)buffer_ptr(&buffer),
|
||||
buffer_len(&buffer));
|
||||
memset(&cipher, 0, sizeof(cipher));
|
||||
/* Allocate space for the private part of the key in the buffer. */
|
||||
buffer_append_space(&encrypted, &cp, buffer_len(&buffer));
|
||||
|
||||
/* Destroy temporary data. */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
buffer_free(&buffer);
|
||||
cipher_set_key_string(&cipher, cipher_type, passphrase, 1);
|
||||
cipher_encrypt(&cipher, (unsigned char *) cp,
|
||||
(unsigned char *) buffer_ptr(&buffer),
|
||||
buffer_len(&buffer));
|
||||
memset(&cipher, 0, sizeof(cipher));
|
||||
|
||||
/* Write to a file. */
|
||||
f = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0600);
|
||||
if (f < 0)
|
||||
return 0;
|
||||
/* Destroy temporary data. */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
buffer_free(&buffer);
|
||||
|
||||
if (write(f, buffer_ptr(&encrypted), buffer_len(&encrypted)) !=
|
||||
buffer_len(&encrypted))
|
||||
{
|
||||
debug("Write to key file %.200s failed: %.100s", filename,
|
||||
strerror(errno));
|
||||
buffer_free(&encrypted);
|
||||
close(f);
|
||||
remove(filename);
|
||||
return 0;
|
||||
}
|
||||
close(f);
|
||||
buffer_free(&encrypted);
|
||||
return 1;
|
||||
/* Write to a file. */
|
||||
f = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
|
||||
if (f < 0)
|
||||
return 0;
|
||||
|
||||
if (write(f, buffer_ptr(&encrypted), buffer_len(&encrypted)) !=
|
||||
buffer_len(&encrypted)) {
|
||||
debug("Write to key file %.200s failed: %.100s", filename,
|
||||
strerror(errno));
|
||||
buffer_free(&encrypted);
|
||||
close(f);
|
||||
remove(filename);
|
||||
return 0;
|
||||
}
|
||||
close(f);
|
||||
buffer_free(&encrypted);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Loads the public part of the key file. Returns 0 if an error
|
||||
|
@ -136,70 +136,65 @@ save_private_key(const char *filename, const char *passphrase,
|
|||
non-zero otherwise. */
|
||||
|
||||
int
|
||||
load_public_key(const char *filename, RSA *pub,
|
||||
load_public_key(const char *filename, RSA * pub,
|
||||
char **comment_return)
|
||||
{
|
||||
int f, i;
|
||||
off_t len;
|
||||
Buffer buffer;
|
||||
char *cp;
|
||||
int f, i;
|
||||
off_t len;
|
||||
Buffer buffer;
|
||||
char *cp;
|
||||
|
||||
/* Read data from the file into the buffer. */
|
||||
f = open(filename, O_RDONLY);
|
||||
if (f < 0)
|
||||
return 0;
|
||||
/* Read data from the file into the buffer. */
|
||||
f = open(filename, O_RDONLY);
|
||||
if (f < 0)
|
||||
return 0;
|
||||
|
||||
len = lseek(f, (off_t)0, SEEK_END);
|
||||
lseek(f, (off_t)0, SEEK_SET);
|
||||
|
||||
buffer_init(&buffer);
|
||||
buffer_append_space(&buffer, &cp, len);
|
||||
len = lseek(f, (off_t) 0, SEEK_END);
|
||||
lseek(f, (off_t) 0, SEEK_SET);
|
||||
|
||||
if (read(f, cp, (size_t)len) != (size_t)len)
|
||||
{
|
||||
debug("Read from key file %.200s failed: %.100s", filename,
|
||||
strerror(errno));
|
||||
buffer_free(&buffer);
|
||||
close(f);
|
||||
return 0;
|
||||
}
|
||||
close(f);
|
||||
buffer_init(&buffer);
|
||||
buffer_append_space(&buffer, &cp, len);
|
||||
|
||||
/* Check that it is at least big enought to contain the ID string. */
|
||||
if (len < strlen(AUTHFILE_ID_STRING) + 1)
|
||||
{
|
||||
debug("Bad key file %.200s.", filename);
|
||||
buffer_free(&buffer);
|
||||
return 0;
|
||||
}
|
||||
if (read(f, cp, (size_t) len) != (size_t) len) {
|
||||
debug("Read from key file %.200s failed: %.100s", filename,
|
||||
strerror(errno));
|
||||
buffer_free(&buffer);
|
||||
close(f);
|
||||
return 0;
|
||||
}
|
||||
close(f);
|
||||
|
||||
/* Check that it is at least big enought to contain the ID string. */
|
||||
if (len < strlen(AUTHFILE_ID_STRING) + 1) {
|
||||
debug("Bad key file %.200s.", filename);
|
||||
buffer_free(&buffer);
|
||||
return 0;
|
||||
}
|
||||
/* Make sure it begins with the id string. Consume the id string
|
||||
from the buffer. */
|
||||
for (i = 0; i < (unsigned int) strlen(AUTHFILE_ID_STRING) + 1; i++)
|
||||
if (buffer_get_char(&buffer) != (unsigned char) AUTHFILE_ID_STRING[i]) {
|
||||
debug("Bad key file %.200s.", filename);
|
||||
buffer_free(&buffer);
|
||||
return 0;
|
||||
}
|
||||
/* Skip cipher type and reserved data. */
|
||||
(void) buffer_get_char(&buffer); /* cipher type */
|
||||
(void) buffer_get_int(&buffer); /* reserved */
|
||||
|
||||
/* Read the public key from the buffer. */
|
||||
buffer_get_int(&buffer);
|
||||
pub->n = BN_new();
|
||||
buffer_get_bignum(&buffer, pub->n);
|
||||
pub->e = BN_new();
|
||||
buffer_get_bignum(&buffer, pub->e);
|
||||
if (comment_return)
|
||||
*comment_return = buffer_get_string(&buffer, NULL);
|
||||
/* The encrypted private part is not parsed by this function. */
|
||||
|
||||
/* Make sure it begins with the id string. Consume the id string from
|
||||
the buffer. */
|
||||
for (i = 0; i < (unsigned int)strlen(AUTHFILE_ID_STRING) + 1; i++)
|
||||
if (buffer_get_char(&buffer) != (unsigned char)AUTHFILE_ID_STRING[i])
|
||||
{
|
||||
debug("Bad key file %.200s.", filename);
|
||||
buffer_free(&buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Skip cipher type and reserved data. */
|
||||
(void)buffer_get_char(&buffer); /* cipher type */
|
||||
(void)buffer_get_int(&buffer); /* reserved */
|
||||
|
||||
/* Read the public key from the buffer. */
|
||||
buffer_get_int(&buffer);
|
||||
pub->n = BN_new();
|
||||
buffer_get_bignum(&buffer, pub->n);
|
||||
pub->e = BN_new();
|
||||
buffer_get_bignum(&buffer, pub->e);
|
||||
if (comment_return)
|
||||
*comment_return = buffer_get_string(&buffer, NULL);
|
||||
/* The encrypted private part is not parsed by this function. */
|
||||
|
||||
buffer_free(&buffer);
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Loads the private key from the file. Returns 0 if an error is encountered
|
||||
|
@ -208,149 +203,139 @@ load_public_key(const char *filename, RSA *pub,
|
|||
|
||||
int
|
||||
load_private_key(const char *filename, const char *passphrase,
|
||||
RSA *prv, char **comment_return)
|
||||
RSA * prv, char **comment_return)
|
||||
{
|
||||
int f, i, check1, check2, cipher_type;
|
||||
off_t len;
|
||||
Buffer buffer, decrypted;
|
||||
char *cp;
|
||||
CipherContext cipher;
|
||||
BN_CTX *ctx;
|
||||
BIGNUM *aux;
|
||||
struct stat st;
|
||||
int f, i, check1, check2, cipher_type;
|
||||
off_t len;
|
||||
Buffer buffer, decrypted;
|
||||
char *cp;
|
||||
CipherContext cipher;
|
||||
BN_CTX *ctx;
|
||||
BIGNUM *aux;
|
||||
struct stat st;
|
||||
|
||||
/* Read the file into the buffer. */
|
||||
f = open(filename, O_RDONLY);
|
||||
if (f < 0)
|
||||
return 0;
|
||||
/* Read the file into the buffer. */
|
||||
f = open(filename, O_RDONLY);
|
||||
if (f < 0)
|
||||
return 0;
|
||||
|
||||
/* We assume we are called under uid of the owner of the file */
|
||||
if (fstat(f, &st) < 0 ||
|
||||
(st.st_uid != 0 && 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'.",
|
||||
st.st_mode & 0777, filename);
|
||||
error("It is recommended that your private key files are NOT accessible by others.");
|
||||
return 0;
|
||||
}
|
||||
/* We assume we are called under uid of the owner of the file */
|
||||
if (fstat(f, &st) < 0 ||
|
||||
(st.st_uid != 0 && 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'.",
|
||||
st.st_mode & 0777, filename);
|
||||
error("It is recommended that your private key files are NOT accessible by others.");
|
||||
return 0;
|
||||
}
|
||||
len = lseek(f, (off_t) 0, SEEK_END);
|
||||
lseek(f, (off_t) 0, SEEK_SET);
|
||||
|
||||
len = lseek(f, (off_t)0, SEEK_END);
|
||||
lseek(f, (off_t)0, SEEK_SET);
|
||||
|
||||
buffer_init(&buffer);
|
||||
buffer_append_space(&buffer, &cp, len);
|
||||
buffer_init(&buffer);
|
||||
buffer_append_space(&buffer, &cp, len);
|
||||
|
||||
if (read(f, cp, (size_t)len) != (size_t)len)
|
||||
{
|
||||
debug("Read from key file %.200s failed: %.100s", filename,
|
||||
strerror(errno));
|
||||
buffer_free(&buffer);
|
||||
close(f);
|
||||
return 0;
|
||||
}
|
||||
close(f);
|
||||
if (read(f, cp, (size_t) len) != (size_t) len) {
|
||||
debug("Read from key file %.200s failed: %.100s", filename,
|
||||
strerror(errno));
|
||||
buffer_free(&buffer);
|
||||
close(f);
|
||||
return 0;
|
||||
}
|
||||
close(f);
|
||||
|
||||
/* Check that it is at least big enought to contain the ID string. */
|
||||
if (len < strlen(AUTHFILE_ID_STRING) + 1)
|
||||
{
|
||||
debug("Bad key file %.200s.", filename);
|
||||
buffer_free(&buffer);
|
||||
return 0;
|
||||
}
|
||||
/* Check that it is at least big enought to contain the ID string. */
|
||||
if (len < strlen(AUTHFILE_ID_STRING) + 1) {
|
||||
debug("Bad key file %.200s.", filename);
|
||||
buffer_free(&buffer);
|
||||
return 0;
|
||||
}
|
||||
/* Make sure it begins with the id string. Consume the id string
|
||||
from the buffer. */
|
||||
for (i = 0; i < (unsigned int) strlen(AUTHFILE_ID_STRING) + 1; i++)
|
||||
if (buffer_get_char(&buffer) != (unsigned char) AUTHFILE_ID_STRING[i]) {
|
||||
debug("Bad key file %.200s.", filename);
|
||||
buffer_free(&buffer);
|
||||
return 0;
|
||||
}
|
||||
/* Read cipher type. */
|
||||
cipher_type = buffer_get_char(&buffer);
|
||||
(void) buffer_get_int(&buffer); /* Reserved data. */
|
||||
|
||||
/* Read the public key from the buffer. */
|
||||
buffer_get_int(&buffer);
|
||||
prv->n = BN_new();
|
||||
buffer_get_bignum(&buffer, prv->n);
|
||||
prv->e = BN_new();
|
||||
buffer_get_bignum(&buffer, prv->e);
|
||||
if (comment_return)
|
||||
*comment_return = buffer_get_string(&buffer, NULL);
|
||||
else
|
||||
xfree(buffer_get_string(&buffer, NULL));
|
||||
|
||||
/* Check that it is a supported cipher. */
|
||||
if (((cipher_mask() | SSH_CIPHER_NONE | SSH_AUTHFILE_CIPHER) &
|
||||
(1 << cipher_type)) == 0) {
|
||||
debug("Unsupported cipher %.100s used in key file %.200s.",
|
||||
cipher_name(cipher_type), filename);
|
||||
buffer_free(&buffer);
|
||||
goto fail;
|
||||
}
|
||||
/* Initialize space for decrypted data. */
|
||||
buffer_init(&decrypted);
|
||||
buffer_append_space(&decrypted, &cp, buffer_len(&buffer));
|
||||
|
||||
/* Rest of the buffer is encrypted. Decrypt it using the passphrase. */
|
||||
cipher_set_key_string(&cipher, cipher_type, passphrase, 0);
|
||||
cipher_decrypt(&cipher, (unsigned char *) cp,
|
||||
(unsigned char *) buffer_ptr(&buffer),
|
||||
buffer_len(&buffer));
|
||||
|
||||
/* Make sure it begins with the id string. Consume the id string from
|
||||
the buffer. */
|
||||
for (i = 0; i < (unsigned int)strlen(AUTHFILE_ID_STRING) + 1; i++)
|
||||
if (buffer_get_char(&buffer) != (unsigned char)AUTHFILE_ID_STRING[i])
|
||||
{
|
||||
debug("Bad key file %.200s.", filename);
|
||||
buffer_free(&buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read cipher type. */
|
||||
cipher_type = buffer_get_char(&buffer);
|
||||
(void)buffer_get_int(&buffer); /* Reserved data. */
|
||||
check1 = buffer_get_char(&decrypted);
|
||||
check2 = buffer_get_char(&decrypted);
|
||||
if (check1 != buffer_get_char(&decrypted) ||
|
||||
check2 != buffer_get_char(&decrypted)) {
|
||||
if (strcmp(passphrase, "") != 0)
|
||||
debug("Bad passphrase supplied for key file %.200s.", filename);
|
||||
/* Bad passphrase. */
|
||||
buffer_free(&decrypted);
|
||||
fail:
|
||||
BN_clear_free(prv->n);
|
||||
BN_clear_free(prv->e);
|
||||
if (comment_return)
|
||||
xfree(*comment_return);
|
||||
return 0;
|
||||
}
|
||||
/* Read the rest of the private key. */
|
||||
prv->d = BN_new();
|
||||
buffer_get_bignum(&decrypted, prv->d);
|
||||
prv->iqmp = BN_new();
|
||||
buffer_get_bignum(&decrypted, prv->iqmp); /* u */
|
||||
/* in SSL and SSH p and q are exchanged */
|
||||
prv->q = BN_new();
|
||||
buffer_get_bignum(&decrypted, prv->q); /* p */
|
||||
prv->p = BN_new();
|
||||
buffer_get_bignum(&decrypted, prv->p); /* q */
|
||||
|
||||
/* Read the public key from the buffer. */
|
||||
buffer_get_int(&buffer);
|
||||
prv->n = BN_new();
|
||||
buffer_get_bignum(&buffer, prv->n);
|
||||
prv->e = BN_new();
|
||||
buffer_get_bignum(&buffer, prv->e);
|
||||
if (comment_return)
|
||||
*comment_return = buffer_get_string(&buffer, NULL);
|
||||
else
|
||||
xfree(buffer_get_string(&buffer, NULL));
|
||||
ctx = BN_CTX_new();
|
||||
aux = BN_new();
|
||||
|
||||
/* Check that it is a supported cipher. */
|
||||
if (((cipher_mask() | SSH_CIPHER_NONE | SSH_AUTHFILE_CIPHER) &
|
||||
(1 << cipher_type)) == 0)
|
||||
{
|
||||
debug("Unsupported cipher %.100s used in key file %.200s.",
|
||||
cipher_name(cipher_type), filename);
|
||||
buffer_free(&buffer);
|
||||
goto fail;
|
||||
}
|
||||
BN_sub(aux, prv->q, BN_value_one());
|
||||
prv->dmq1 = BN_new();
|
||||
BN_mod(prv->dmq1, prv->d, aux, ctx);
|
||||
|
||||
/* Initialize space for decrypted data. */
|
||||
buffer_init(&decrypted);
|
||||
buffer_append_space(&decrypted, &cp, buffer_len(&buffer));
|
||||
|
||||
/* Rest of the buffer is encrypted. Decrypt it using the passphrase. */
|
||||
cipher_set_key_string(&cipher, cipher_type, passphrase, 0);
|
||||
cipher_decrypt(&cipher, (unsigned char *)cp,
|
||||
(unsigned char *)buffer_ptr(&buffer),
|
||||
buffer_len(&buffer));
|
||||
BN_sub(aux, prv->p, BN_value_one());
|
||||
prv->dmp1 = BN_new();
|
||||
BN_mod(prv->dmp1, prv->d, aux, ctx);
|
||||
|
||||
buffer_free(&buffer);
|
||||
BN_clear_free(aux);
|
||||
BN_CTX_free(ctx);
|
||||
|
||||
check1 = buffer_get_char(&decrypted);
|
||||
check2 = buffer_get_char(&decrypted);
|
||||
if (check1 != buffer_get_char(&decrypted) ||
|
||||
check2 != buffer_get_char(&decrypted))
|
||||
{
|
||||
if (strcmp(passphrase, "") != 0)
|
||||
debug("Bad passphrase supplied for key file %.200s.", filename);
|
||||
/* Bad passphrase. */
|
||||
buffer_free(&decrypted);
|
||||
fail:
|
||||
BN_clear_free(prv->n);
|
||||
BN_clear_free(prv->e);
|
||||
if (comment_return)
|
||||
xfree(*comment_return);
|
||||
return 0;
|
||||
}
|
||||
buffer_free(&decrypted);
|
||||
|
||||
/* Read the rest of the private key. */
|
||||
prv->d = BN_new();
|
||||
buffer_get_bignum(&decrypted, prv->d);
|
||||
prv->iqmp = BN_new();
|
||||
buffer_get_bignum(&decrypted, prv->iqmp); /* u */
|
||||
/* in SSL and SSH p and q are exchanged */
|
||||
prv->q = BN_new();
|
||||
buffer_get_bignum(&decrypted, prv->q); /* p */
|
||||
prv->p = BN_new();
|
||||
buffer_get_bignum(&decrypted, prv->p); /* q */
|
||||
|
||||
ctx = BN_CTX_new();
|
||||
aux = BN_new();
|
||||
|
||||
BN_sub(aux, prv->q, BN_value_one());
|
||||
prv->dmq1 = BN_new();
|
||||
BN_mod(prv->dmq1, prv->d, aux, ctx);
|
||||
|
||||
BN_sub(aux, prv->p, BN_value_one());
|
||||
prv->dmp1 = BN_new();
|
||||
BN_mod(prv->dmp1, prv->d, aux, ctx);
|
||||
|
||||
BN_clear_free(aux);
|
||||
BN_CTX_free(ctx);
|
||||
|
||||
buffer_free(&decrypted);
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
|
222
bufaux.c
222
bufaux.c
|
@ -1,21 +1,21 @@
|
|||
/*
|
||||
|
||||
bufaux.c
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Wed Mar 29 02:24:47 1995 ylo
|
||||
|
||||
Auxiliary functions for storing and retrieving various data types to/from
|
||||
Buffers.
|
||||
|
||||
*/
|
||||
*
|
||||
* bufaux.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Wed Mar 29 02:24:47 1995 ylo
|
||||
*
|
||||
* Auxiliary functions for storing and retrieving various data types to/from
|
||||
* Buffers.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: bufaux.c,v 1.5 1999/11/13 02:22:46 damien Exp $");
|
||||
RCSID("$Id: bufaux.c,v 1.6 1999/11/24 13:26:22 damien Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
|
||||
|
@ -30,122 +30,136 @@ RCSID("$Id: bufaux.c,v 1.5 1999/11/13 02:22:46 damien Exp $");
|
|||
#include "xmalloc.h"
|
||||
#include "getput.h"
|
||||
|
||||
/* Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed
|
||||
by (bits+7)/8 bytes of binary data, msb first. */
|
||||
|
||||
/*
|
||||
* Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed
|
||||
* by (bits+7)/8 bytes of binary data, msb first.
|
||||
*/
|
||||
void
|
||||
buffer_put_bignum(Buffer *buffer, BIGNUM *value)
|
||||
{
|
||||
int bits = BN_num_bits(value);
|
||||
int bin_size = (bits + 7) / 8;
|
||||
char *buf = xmalloc(bin_size);
|
||||
int oi;
|
||||
char msg[2];
|
||||
|
||||
/* Get the value of in binary */
|
||||
oi = BN_bn2bin(value, buf);
|
||||
if (oi != bin_size)
|
||||
fatal("buffer_put_bignum: BN_bn2bin() failed: oi %d != bin_size %d",
|
||||
oi, bin_size);
|
||||
int bits = BN_num_bits(value);
|
||||
int bin_size = (bits + 7) / 8;
|
||||
char *buf = xmalloc(bin_size);
|
||||
int oi;
|
||||
char msg[2];
|
||||
|
||||
/* Store the number of bits in the buffer in two bytes, msb first. */
|
||||
PUT_16BIT(msg, bits);
|
||||
buffer_append(buffer, msg, 2);
|
||||
/* Store the binary data. */
|
||||
buffer_append(buffer, buf, oi);
|
||||
/* Clear the temporary data. */
|
||||
memset(buf, 0, bin_size);
|
||||
xfree(buf);
|
||||
/* Get the value of in binary */
|
||||
oi = BN_bn2bin(value, buf);
|
||||
if (oi != bin_size)
|
||||
fatal("buffer_put_bignum: BN_bn2bin() failed: oi %d != bin_size %d",
|
||||
oi, bin_size);
|
||||
|
||||
/* Store the number of bits in the buffer in two bytes, msb first. */
|
||||
PUT_16BIT(msg, bits);
|
||||
buffer_append(buffer, msg, 2);
|
||||
/* Store the binary data. */
|
||||
buffer_append(buffer, buf, oi);
|
||||
/* Clear the temporary data. */
|
||||
memset(buf, 0, bin_size);
|
||||
xfree(buf);
|
||||
}
|
||||
|
||||
/* Retrieves an BIGNUM from the buffer. */
|
||||
|
||||
/*
|
||||
* Retrieves an BIGNUM from the buffer.
|
||||
*/
|
||||
int
|
||||
buffer_get_bignum(Buffer *buffer, BIGNUM *value)
|
||||
{
|
||||
int bits, bytes;
|
||||
unsigned char buf[2], *bin;
|
||||
int bits, bytes;
|
||||
unsigned char buf[2], *bin;
|
||||
|
||||
/* Get the number for bits. */
|
||||
buffer_get(buffer, (char *)buf, 2);
|
||||
bits = GET_16BIT(buf);
|
||||
/* Compute the number of binary bytes that follow. */
|
||||
bytes = (bits + 7) / 8;
|
||||
if (buffer_len(buffer) < bytes)
|
||||
fatal("buffer_get_bignum: input buffer too small");
|
||||
bin = buffer_ptr(buffer);
|
||||
BN_bin2bn(bin, bytes, value);
|
||||
buffer_consume(buffer, bytes);
|
||||
/* Get the number for bits. */
|
||||
buffer_get(buffer, (char *) buf, 2);
|
||||
bits = GET_16BIT(buf);
|
||||
/* Compute the number of binary bytes that follow. */
|
||||
bytes = (bits + 7) / 8;
|
||||
if (buffer_len(buffer) < bytes)
|
||||
fatal("buffer_get_bignum: input buffer too small");
|
||||
bin = buffer_ptr(buffer);
|
||||
BN_bin2bn(bin, bytes, value);
|
||||
buffer_consume(buffer, bytes);
|
||||
|
||||
return 2 + bytes;
|
||||
return 2 + bytes;
|
||||
}
|
||||
|
||||
/* Returns an integer from the buffer (4 bytes, msb first). */
|
||||
|
||||
unsigned int buffer_get_int(Buffer *buffer)
|
||||
/*
|
||||
* Returns an integer from the buffer (4 bytes, msb first).
|
||||
*/
|
||||
unsigned int
|
||||
buffer_get_int(Buffer *buffer)
|
||||
{
|
||||
unsigned char buf[4];
|
||||
buffer_get(buffer, (char *)buf, 4);
|
||||
return GET_32BIT(buf);
|
||||
unsigned char buf[4];
|
||||
buffer_get(buffer, (char *) buf, 4);
|
||||
return GET_32BIT(buf);
|
||||
}
|
||||
|
||||
/* Stores an integer in the buffer in 4 bytes, msb first. */
|
||||
|
||||
void buffer_put_int(Buffer *buffer, unsigned int value)
|
||||
/*
|
||||
* Stores an integer in the buffer in 4 bytes, msb first.
|
||||
*/
|
||||
void
|
||||
buffer_put_int(Buffer *buffer, unsigned int value)
|
||||
{
|
||||
char buf[4];
|
||||
PUT_32BIT(buf, value);
|
||||
buffer_append(buffer, buf, 4);
|
||||
char buf[4];
|
||||
PUT_32BIT(buf, value);
|
||||
buffer_append(buffer, buf, 4);
|
||||
}
|
||||
|
||||
/* Returns an arbitrary binary string from the buffer. The string cannot
|
||||
be longer than 256k. The returned value points to memory allocated
|
||||
with xmalloc; it is the responsibility of the calling function to free
|
||||
the data. If length_ptr is non-NULL, the length of the returned data
|
||||
will be stored there. A null character will be automatically appended
|
||||
to the returned string, and is not counted in length. */
|
||||
|
||||
char *buffer_get_string(Buffer *buffer, unsigned int *length_ptr)
|
||||
/*
|
||||
* Returns an arbitrary binary string from the buffer. The string cannot
|
||||
* be longer than 256k. The returned value points to memory allocated
|
||||
* with xmalloc; it is the responsibility of the calling function to free
|
||||
* the data. If length_ptr is non-NULL, the length of the returned data
|
||||
* will be stored there. A null character will be automatically appended
|
||||
* to the returned string, and is not counted in length.
|
||||
*/
|
||||
char *
|
||||
buffer_get_string(Buffer *buffer, unsigned int *length_ptr)
|
||||
{
|
||||
unsigned int len;
|
||||
char *value;
|
||||
/* Get the length. */
|
||||
len = buffer_get_int(buffer);
|
||||
if (len > 256*1024)
|
||||
fatal("Received packet with bad string length %d", len);
|
||||
/* Allocate space for the string. Add one byte for a null character. */
|
||||
value = xmalloc(len + 1);
|
||||
/* Get the string. */
|
||||
buffer_get(buffer, value, len);
|
||||
/* Append a null character to make processing easier. */
|
||||
value[len] = 0;
|
||||
/* Optionally return the length of the string. */
|
||||
if (length_ptr)
|
||||
*length_ptr = len;
|
||||
return value;
|
||||
unsigned int len;
|
||||
char *value;
|
||||
/* Get the length. */
|
||||
len = buffer_get_int(buffer);
|
||||
if (len > 256 * 1024)
|
||||
fatal("Received packet with bad string length %d", len);
|
||||
/* Allocate space for the string. Add one byte for a null character. */
|
||||
value = xmalloc(len + 1);
|
||||
/* Get the string. */
|
||||
buffer_get(buffer, value, len);
|
||||
/* Append a null character to make processing easier. */
|
||||
value[len] = 0;
|
||||
/* Optionally return the length of the string. */
|
||||
if (length_ptr)
|
||||
*length_ptr = len;
|
||||
return value;
|
||||
}
|
||||
|
||||
/* Stores and arbitrary binary string in the buffer. */
|
||||
|
||||
void buffer_put_string(Buffer *buffer, const void *buf, unsigned int len)
|
||||
/*
|
||||
* Stores and arbitrary binary string in the buffer.
|
||||
*/
|
||||
void
|
||||
buffer_put_string(Buffer *buffer, const void *buf, unsigned int len)
|
||||
{
|
||||
buffer_put_int(buffer, len);
|
||||
buffer_append(buffer, buf, len);
|
||||
buffer_put_int(buffer, len);
|
||||
buffer_append(buffer, buf, len);
|
||||
}
|
||||
|
||||
/* Returns a character from the buffer (0 - 255). */
|
||||
|
||||
int buffer_get_char(Buffer *buffer)
|
||||
/*
|
||||
* Returns a character from the buffer (0 - 255).
|
||||
*/
|
||||
int
|
||||
buffer_get_char(Buffer *buffer)
|
||||
{
|
||||
char ch;
|
||||
buffer_get(buffer, &ch, 1);
|
||||
return (unsigned char)ch;
|
||||
char ch;
|
||||
buffer_get(buffer, &ch, 1);
|
||||
return (unsigned char) ch;
|
||||
}
|
||||
|
||||
/* Stores a character in the buffer. */
|
||||
|
||||
void buffer_put_char(Buffer *buffer, int value)
|
||||
/*
|
||||
* Stores a character in the buffer.
|
||||
*/
|
||||
void
|
||||
buffer_put_char(Buffer *buffer, int value)
|
||||
{
|
||||
char ch = value;
|
||||
buffer_append(buffer, &ch, 1);
|
||||
char ch = value;
|
||||
buffer_append(buffer, &ch, 1);
|
||||
}
|
||||
|
|
42
bufaux.h
42
bufaux.h
|
@ -1,17 +1,17 @@
|
|||
/*
|
||||
*
|
||||
* bufaux.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Wed Mar 29 02:18:23 1995 ylo
|
||||
*
|
||||
*/
|
||||
|
||||
bufaux.h
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Wed Mar 29 02:18:23 1995 ylo
|
||||
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: bufaux.h,v 1.1 1999/10/27 03:42:43 damien Exp $"); */
|
||||
/* RCSID("$Id: bufaux.h,v 1.2 1999/11/24 13:26:22 damien Exp $"); */
|
||||
|
||||
#ifndef BUFAUX_H
|
||||
#define BUFAUX_H
|
||||
|
@ -20,22 +20,22 @@ Created: Wed Mar 29 02:18:23 1995 ylo
|
|||
|
||||
/* Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed
|
||||
by (bits+7)/8 bytes of binary data, msb first. */
|
||||
void buffer_put_bignum(Buffer *buffer, BIGNUM *value);
|
||||
void buffer_put_bignum(Buffer * buffer, BIGNUM * value);
|
||||
|
||||
/* Retrieves an BIGNUM from the buffer. */
|
||||
int buffer_get_bignum(Buffer *buffer, BIGNUM *value);
|
||||
int buffer_get_bignum(Buffer * buffer, BIGNUM * value);
|
||||
|
||||
/* Returns an integer from the buffer (4 bytes, msb first). */
|
||||
unsigned int buffer_get_int(Buffer *buffer);
|
||||
unsigned int buffer_get_int(Buffer * buffer);
|
||||
|
||||
/* Stores an integer in the buffer in 4 bytes, msb first. */
|
||||
void buffer_put_int(Buffer *buffer, unsigned int value);
|
||||
void buffer_put_int(Buffer * buffer, unsigned int value);
|
||||
|
||||
/* Returns a character from the buffer (0 - 255). */
|
||||
int buffer_get_char(Buffer *buffer);
|
||||
int buffer_get_char(Buffer * buffer);
|
||||
|
||||
/* Stores a character in the buffer. */
|
||||
void buffer_put_char(Buffer *buffer, int value);
|
||||
void buffer_put_char(Buffer * buffer, int value);
|
||||
|
||||
/* Returns an arbitrary binary string from the buffer. The string cannot
|
||||
be longer than 256k. The returned value points to memory allocated
|
||||
|
@ -43,9 +43,9 @@ void buffer_put_char(Buffer *buffer, int value);
|
|||
the data. If length_ptr is non-NULL, the length of the returned data
|
||||
will be stored there. A null character will be automatically appended
|
||||
to the returned string, and is not counted in length. */
|
||||
char *buffer_get_string(Buffer *buffer, unsigned int *length_ptr);
|
||||
char *buffer_get_string(Buffer * buffer, unsigned int *length_ptr);
|
||||
|
||||
/* Stores and arbitrary binary string in the buffer. */
|
||||
void buffer_put_string(Buffer *buffer, const void *buf, unsigned int len);
|
||||
void buffer_put_string(Buffer * buffer, const void *buf, unsigned int len);
|
||||
|
||||
#endif /* BUFAUX_H */
|
||||
#endif /* BUFAUX_H */
|
||||
|
|
179
buffer.c
179
buffer.c
|
@ -1,20 +1,20 @@
|
|||
/*
|
||||
|
||||
buffer.c
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Sat Mar 18 04:15:33 1995 ylo
|
||||
|
||||
Functions for manipulating fifo buffers (that can grow if needed).
|
||||
|
||||
*/
|
||||
*
|
||||
* buffer.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Sat Mar 18 04:15:33 1995 ylo
|
||||
*
|
||||
* Functions for manipulating fifo buffers (that can grow if needed).
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: buffer.c,v 1.1 1999/10/27 03:42:43 damien Exp $");
|
||||
RCSID("$Id: buffer.c,v 1.2 1999/11/24 13:26:22 damien Exp $");
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "buffer.h"
|
||||
|
@ -22,129 +22,134 @@ RCSID("$Id: buffer.c,v 1.1 1999/10/27 03:42:43 damien Exp $");
|
|||
|
||||
/* Initializes the buffer structure. */
|
||||
|
||||
void buffer_init(Buffer *buffer)
|
||||
void
|
||||
buffer_init(Buffer *buffer)
|
||||
{
|
||||
buffer->alloc = 4096;
|
||||
buffer->buf = xmalloc(buffer->alloc);
|
||||
buffer->offset = 0;
|
||||
buffer->end = 0;
|
||||
buffer->alloc = 4096;
|
||||
buffer->buf = xmalloc(buffer->alloc);
|
||||
buffer->offset = 0;
|
||||
buffer->end = 0;
|
||||
}
|
||||
|
||||
/* Frees any memory used for the buffer. */
|
||||
|
||||
void buffer_free(Buffer *buffer)
|
||||
void
|
||||
buffer_free(Buffer *buffer)
|
||||
{
|
||||
memset(buffer->buf, 0, buffer->alloc);
|
||||
xfree(buffer->buf);
|
||||
memset(buffer->buf, 0, buffer->alloc);
|
||||
xfree(buffer->buf);
|
||||
}
|
||||
|
||||
/* Clears any data from the buffer, making it empty. This does not actually
|
||||
zero the memory. */
|
||||
|
||||
void buffer_clear(Buffer *buffer)
|
||||
void
|
||||
buffer_clear(Buffer *buffer)
|
||||
{
|
||||
buffer->offset = 0;
|
||||
buffer->end = 0;
|
||||
buffer->offset = 0;
|
||||
buffer->end = 0;
|
||||
}
|
||||
|
||||
/* Appends data to the buffer, expanding it if necessary. */
|
||||
|
||||
void buffer_append(Buffer *buffer, const char *data, unsigned int len)
|
||||
void
|
||||
buffer_append(Buffer *buffer, const char *data, unsigned int len)
|
||||
{
|
||||
char *cp;
|
||||
buffer_append_space(buffer, &cp, len);
|
||||
memcpy(cp, data, len);
|
||||
char *cp;
|
||||
buffer_append_space(buffer, &cp, len);
|
||||
memcpy(cp, data, len);
|
||||
}
|
||||
|
||||
/* Appends space to the buffer, expanding the buffer if necessary.
|
||||
This does not actually copy the data into the buffer, but instead
|
||||
returns a pointer to the allocated region. */
|
||||
|
||||
void buffer_append_space(Buffer *buffer, char **datap, unsigned int len)
|
||||
void
|
||||
buffer_append_space(Buffer *buffer, char **datap, unsigned int len)
|
||||
{
|
||||
/* If the buffer is empty, start using it from the beginning. */
|
||||
if (buffer->offset == buffer->end)
|
||||
{
|
||||
buffer->offset = 0;
|
||||
buffer->end = 0;
|
||||
}
|
||||
|
||||
restart:
|
||||
/* If there is enough space to store all data, store it now. */
|
||||
if (buffer->end + len < buffer->alloc)
|
||||
{
|
||||
*datap = buffer->buf + buffer->end;
|
||||
buffer->end += len;
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the buffer is quite empty, but all data is at the end, move the
|
||||
data to the beginning and retry. */
|
||||
if (buffer->offset > buffer->alloc / 2)
|
||||
{
|
||||
memmove(buffer->buf, buffer->buf + buffer->offset,
|
||||
buffer->end - buffer->offset);
|
||||
buffer->end -= buffer->offset;
|
||||
buffer->offset = 0;
|
||||
goto restart;
|
||||
}
|
||||
|
||||
/* Increase the size of the buffer and retry. */
|
||||
buffer->alloc += len + 32768;
|
||||
buffer->buf = xrealloc(buffer->buf, buffer->alloc);
|
||||
goto restart;
|
||||
/* If the buffer is empty, start using it from the beginning. */
|
||||
if (buffer->offset == buffer->end) {
|
||||
buffer->offset = 0;
|
||||
buffer->end = 0;
|
||||
}
|
||||
restart:
|
||||
/* If there is enough space to store all data, store it now. */
|
||||
if (buffer->end + len < buffer->alloc) {
|
||||
*datap = buffer->buf + buffer->end;
|
||||
buffer->end += len;
|
||||
return;
|
||||
}
|
||||
/* If the buffer is quite empty, but all data is at the end, move
|
||||
the data to the beginning and retry. */
|
||||
if (buffer->offset > buffer->alloc / 2) {
|
||||
memmove(buffer->buf, buffer->buf + buffer->offset,
|
||||
buffer->end - buffer->offset);
|
||||
buffer->end -= buffer->offset;
|
||||
buffer->offset = 0;
|
||||
goto restart;
|
||||
}
|
||||
/* Increase the size of the buffer and retry. */
|
||||
buffer->alloc += len + 32768;
|
||||
buffer->buf = xrealloc(buffer->buf, buffer->alloc);
|
||||
goto restart;
|
||||
}
|
||||
|
||||
/* Returns the number of bytes of data in the buffer. */
|
||||
|
||||
unsigned int buffer_len(Buffer *buffer)
|
||||
unsigned int
|
||||
buffer_len(Buffer *buffer)
|
||||
{
|
||||
return buffer->end - buffer->offset;
|
||||
return buffer->end - buffer->offset;
|
||||
}
|
||||
|
||||
/* Gets data from the beginning of the buffer. */
|
||||
|
||||
void buffer_get(Buffer *buffer, char *buf, unsigned int len)
|
||||
void
|
||||
buffer_get(Buffer *buffer, char *buf, unsigned int len)
|
||||
{
|
||||
if (len > buffer->end - buffer->offset)
|
||||
fatal("buffer_get trying to get more bytes than in buffer");
|
||||
memcpy(buf, buffer->buf + buffer->offset, len);
|
||||
buffer->offset += len;
|
||||
if (len > buffer->end - buffer->offset)
|
||||
fatal("buffer_get trying to get more bytes than in buffer");
|
||||
memcpy(buf, buffer->buf + buffer->offset, len);
|
||||
buffer->offset += len;
|
||||
}
|
||||
|
||||
/* Consumes the given number of bytes from the beginning of the buffer. */
|
||||
|
||||
void buffer_consume(Buffer *buffer, unsigned int bytes)
|
||||
void
|
||||
buffer_consume(Buffer *buffer, unsigned int bytes)
|
||||
{
|
||||
if (bytes > buffer->end - buffer->offset)
|
||||
fatal("buffer_get trying to get more bytes than in buffer");
|
||||
buffer->offset += bytes;
|
||||
}
|
||||
if (bytes > buffer->end - buffer->offset)
|
||||
fatal("buffer_get trying to get more bytes than in buffer");
|
||||
buffer->offset += bytes;
|
||||
}
|
||||
|
||||
/* Consumes the given number of bytes from the end of the buffer. */
|
||||
|
||||
void buffer_consume_end(Buffer *buffer, unsigned int bytes)
|
||||
void
|
||||
buffer_consume_end(Buffer *buffer, unsigned int bytes)
|
||||
{
|
||||
if (bytes > buffer->end - buffer->offset)
|
||||
fatal("buffer_get trying to get more bytes than in buffer");
|
||||
buffer->end -= bytes;
|
||||
}
|
||||
if (bytes > buffer->end - buffer->offset)
|
||||
fatal("buffer_get trying to get more bytes than in buffer");
|
||||
buffer->end -= bytes;
|
||||
}
|
||||
|
||||
/* Returns a pointer to the first used byte in the buffer. */
|
||||
|
||||
char *buffer_ptr(Buffer *buffer)
|
||||
char *
|
||||
buffer_ptr(Buffer *buffer)
|
||||
{
|
||||
return buffer->buf + buffer->offset;
|
||||
return buffer->buf + buffer->offset;
|
||||
}
|
||||
|
||||
/* Dumps the contents of the buffer to stderr. */
|
||||
|
||||
void buffer_dump(Buffer *buffer)
|
||||
void
|
||||
buffer_dump(Buffer *buffer)
|
||||
{
|
||||
int i;
|
||||
unsigned char *ucp = (unsigned char *)buffer->buf;
|
||||
|
||||
for (i = buffer->offset; i < buffer->end; i++)
|
||||
fprintf(stderr, " %02x", ucp[i]);
|
||||
fprintf(stderr, "\n");
|
||||
int i;
|
||||
unsigned char *ucp = (unsigned char *) buffer->buf;
|
||||
|
||||
for (i = buffer->offset; i < buffer->end; i++)
|
||||
fprintf(stderr, " %02x", ucp[i]);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
|
66
buffer.h
66
buffer.h
|
@ -1,66 +1,64 @@
|
|||
/*
|
||||
*
|
||||
* buffer.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Sat Mar 18 04:12:25 1995 ylo
|
||||
*
|
||||
* Code for manipulating FIFO buffers.
|
||||
*
|
||||
*/
|
||||
|
||||
buffer.h
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Sat Mar 18 04:12:25 1995 ylo
|
||||
|
||||
Code for manipulating FIFO buffers.
|
||||
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: buffer.h,v 1.1 1999/10/27 03:42:43 damien Exp $"); */
|
||||
/* RCSID("$Id: buffer.h,v 1.2 1999/11/24 13:26:22 damien Exp $"); */
|
||||
|
||||
#ifndef BUFFER_H
|
||||
#define BUFFER_H
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *buf; /* Buffer for data. */
|
||||
unsigned int alloc; /* Number of bytes allocated for data. */
|
||||
unsigned int offset; /* Offset of first byte containing data. */
|
||||
unsigned int end; /* Offset of last byte containing data. */
|
||||
} Buffer;
|
||||
|
||||
typedef struct {
|
||||
char *buf; /* Buffer for data. */
|
||||
unsigned int alloc; /* Number of bytes allocated for data. */
|
||||
unsigned int offset; /* Offset of first byte containing data. */
|
||||
unsigned int end; /* Offset of last byte containing data. */
|
||||
} Buffer;
|
||||
/* Initializes the buffer structure. */
|
||||
void buffer_init(Buffer *buffer);
|
||||
void buffer_init(Buffer * buffer);
|
||||
|
||||
/* Frees any memory used for the buffer. */
|
||||
void buffer_free(Buffer *buffer);
|
||||
void buffer_free(Buffer * buffer);
|
||||
|
||||
/* Clears any data from the buffer, making it empty. This does not actually
|
||||
zero the memory. */
|
||||
void buffer_clear(Buffer *buffer);
|
||||
void buffer_clear(Buffer * buffer);
|
||||
|
||||
/* Appends data to the buffer, expanding it if necessary. */
|
||||
void buffer_append(Buffer *buffer, const char *data, unsigned int len);
|
||||
void buffer_append(Buffer * buffer, const char *data, unsigned int len);
|
||||
|
||||
/* Appends space to the buffer, expanding the buffer if necessary.
|
||||
This does not actually copy the data into the buffer, but instead
|
||||
returns a pointer to the allocated region. */
|
||||
void buffer_append_space(Buffer *buffer, char **datap, unsigned int len);
|
||||
void buffer_append_space(Buffer * buffer, char **datap, unsigned int len);
|
||||
|
||||
/* Returns the number of bytes of data in the buffer. */
|
||||
unsigned int buffer_len(Buffer *buffer);
|
||||
unsigned int buffer_len(Buffer * buffer);
|
||||
|
||||
/* Gets data from the beginning of the buffer. */
|
||||
void buffer_get(Buffer *buffer, char *buf, unsigned int len);
|
||||
void buffer_get(Buffer * buffer, char *buf, unsigned int len);
|
||||
|
||||
/* Consumes the given number of bytes from the beginning of the buffer. */
|
||||
void buffer_consume(Buffer *buffer, unsigned int bytes);
|
||||
void buffer_consume(Buffer * buffer, unsigned int bytes);
|
||||
|
||||
/* Consumes the given number of bytes from the end of the buffer. */
|
||||
void buffer_consume_end(Buffer *buffer, unsigned int bytes);
|
||||
void buffer_consume_end(Buffer * buffer, unsigned int bytes);
|
||||
|
||||
/* Returns a pointer to the first used byte in the buffer. */
|
||||
char *buffer_ptr(Buffer *buffer);
|
||||
char *buffer_ptr(Buffer * buffer);
|
||||
|
||||
/* Dumps the contents of the buffer to stderr in hex. This intended for
|
||||
debugging purposes only. */
|
||||
void buffer_dump(Buffer *buffer);
|
||||
void buffer_dump(Buffer * buffer);
|
||||
|
||||
#endif /* BUFFER_H */
|
||||
#endif /* BUFFER_H */
|
||||
|
|
357
canohost.c
357
canohost.c
|
@ -1,233 +1,228 @@
|
|||
/*
|
||||
|
||||
canohost.c
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Sun Jul 2 17:52:22 1995 ylo
|
||||
|
||||
Functions for returning the canonical host name of the remote site.
|
||||
|
||||
*/
|
||||
*
|
||||
* canohost.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Sun Jul 2 17:52:22 1995 ylo
|
||||
*
|
||||
* Functions for returning the canonical host name of the remote site.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: canohost.c,v 1.2 1999/11/15 04:25:10 damien Exp $");
|
||||
RCSID("$Id: canohost.c,v 1.3 1999/11/24 13:26:22 damien Exp $");
|
||||
|
||||
#include "packet.h"
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
|
||||
/* Return the canonical name of the host at the other end of the socket.
|
||||
/* 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)
|
||||
char *
|
||||
get_remote_hostname(int socket)
|
||||
{
|
||||
struct sockaddr_in from;
|
||||
int fromlen, i;
|
||||
struct hostent *hp;
|
||||
char name[MAXHOSTNAMELEN];
|
||||
struct sockaddr_in from;
|
||||
int fromlen, i;
|
||||
struct hostent *hp;
|
||||
char name[MAXHOSTNAMELEN];
|
||||
|
||||
/* Get IP address of client. */
|
||||
fromlen = sizeof(from);
|
||||
memset(&from, 0, sizeof(from));
|
||||
if (getpeername(socket, (struct sockaddr *)&from, &fromlen) < 0)
|
||||
{
|
||||
debug("getpeername failed: %.100s", strerror(errno));
|
||||
fatal_cleanup();
|
||||
}
|
||||
|
||||
/* Map the IP address to a host name. */
|
||||
hp = gethostbyaddr((char *)&from.sin_addr, sizeof(struct in_addr),
|
||||
from.sin_family);
|
||||
if (hp)
|
||||
{
|
||||
/* Got host name, find canonic host name. */
|
||||
if (strchr(hp->h_name, '.') != 0)
|
||||
strlcpy(name, hp->h_name, sizeof(name));
|
||||
else if (hp->h_aliases != 0
|
||||
&& hp->h_aliases[0] != 0
|
||||
&& strchr(hp->h_aliases[0], '.') != 0)
|
||||
strlcpy(name, hp->h_aliases[0], sizeof(name));
|
||||
else
|
||||
strlcpy(name, hp->h_name, sizeof(name));
|
||||
|
||||
/* Convert it to all lowercase (which is expected by the rest of this
|
||||
software). */
|
||||
for (i = 0; name[i]; i++)
|
||||
if (isupper(name[i]))
|
||||
name[i] = tolower(name[i]);
|
||||
|
||||
/* Map it back to an IP address and check that the given address actually
|
||||
is an address of this host. This is necessary because anyone with
|
||||
access to a name server can define arbitrary names for an IP address.
|
||||
Mapping from name to IP address can be trusted better (but can still
|
||||
be fooled if the intruder has access to the name server of the
|
||||
domain). */
|
||||
hp = gethostbyname(name);
|
||||
if (!hp)
|
||||
{
|
||||
log("reverse mapping checking gethostbyname for %.700s failed - POSSIBLE BREAKIN ATTEMPT!", name);
|
||||
strlcpy(name, inet_ntoa(from.sin_addr), sizeof name);
|
||||
goto check_ip_options;
|
||||
/* Get IP address of client. */
|
||||
fromlen = sizeof(from);
|
||||
memset(&from, 0, sizeof(from));
|
||||
if (getpeername(socket, (struct sockaddr *) & from, &fromlen) < 0) {
|
||||
debug("getpeername failed: %.100s", strerror(errno));
|
||||
fatal_cleanup();
|
||||
}
|
||||
/* Look for the address from the list of addresses. */
|
||||
for (i = 0; hp->h_addr_list[i]; i++)
|
||||
if (memcmp(hp->h_addr_list[i], &from.sin_addr, sizeof(from.sin_addr))
|
||||
== 0)
|
||||
break;
|
||||
/* If we reached the end of the list, the address was not there. */
|
||||
if (!hp->h_addr_list[i])
|
||||
{
|
||||
/* Address not found for the host name. */
|
||||
log("Address %.100s maps to %.600s, but this does not map back to the address - POSSIBLE BREAKIN ATTEMPT!",
|
||||
inet_ntoa(from.sin_addr), name);
|
||||
strlcpy(name, inet_ntoa(from.sin_addr), sizeof name);
|
||||
goto check_ip_options;
|
||||
/* Map the IP address to a host name. */
|
||||
hp = gethostbyaddr((char *) &from.sin_addr, sizeof(struct in_addr),
|
||||
from.sin_family);
|
||||
if (hp) {
|
||||
/* Got host name, find canonic host name. */
|
||||
if (strchr(hp->h_name, '.') != 0)
|
||||
strlcpy(name, hp->h_name, sizeof(name));
|
||||
else if (hp->h_aliases != 0
|
||||
&& hp->h_aliases[0] != 0
|
||||
&& strchr(hp->h_aliases[0], '.') != 0)
|
||||
strlcpy(name, hp->h_aliases[0], sizeof(name));
|
||||
else
|
||||
strlcpy(name, hp->h_name, sizeof(name));
|
||||
|
||||
/* Convert it to all lowercase (which is expected by the
|
||||
rest of this software). */
|
||||
for (i = 0; name[i]; i++)
|
||||
if (isupper(name[i]))
|
||||
name[i] = tolower(name[i]);
|
||||
|
||||
/* Map it back to an IP address and check that the given
|
||||
address actually is an address of this host. This is
|
||||
necessary because anyone with access to a name server
|
||||
can define arbitrary names for an IP address. Mapping
|
||||
from name to IP address can be trusted better (but can
|
||||
still be fooled if the intruder has access to the name
|
||||
server of the domain). */
|
||||
hp = gethostbyname(name);
|
||||
if (!hp) {
|
||||
log("reverse mapping checking gethostbyname for %.700s failed - POSSIBLE BREAKIN ATTEMPT!", name);
|
||||
strlcpy(name, inet_ntoa(from.sin_addr), sizeof name);
|
||||
goto check_ip_options;
|
||||
}
|
||||
/* Look for the address from the list of addresses. */
|
||||
for (i = 0; hp->h_addr_list[i]; i++)
|
||||
if (memcmp(hp->h_addr_list[i], &from.sin_addr, sizeof(from.sin_addr))
|
||||
== 0)
|
||||
break;
|
||||
/* If we reached the end of the list, the address was not
|
||||
there. */
|
||||
if (!hp->h_addr_list[i]) {
|
||||
/* Address not found for the host name. */
|
||||
log("Address %.100s maps to %.600s, but this does not map back to the address - POSSIBLE BREAKIN ATTEMPT!",
|
||||
inet_ntoa(from.sin_addr), name);
|
||||
strlcpy(name, inet_ntoa(from.sin_addr), sizeof name);
|
||||
goto check_ip_options;
|
||||
}
|
||||
/* Address was found for the host name. We accept the host name. */
|
||||
} else {
|
||||
/* Host name not found. Use ascii representation of the address. */
|
||||
strlcpy(name, inet_ntoa(from.sin_addr), sizeof name);
|
||||
log("Could not reverse map address %.100s.", name);
|
||||
}
|
||||
/* Address was found for the host name. We accept the host name. */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Host name not found. Use ascii representation of the address. */
|
||||
strlcpy(name, inet_ntoa(from.sin_addr), sizeof name);
|
||||
log("Could not reverse map address %.100s.", name);
|
||||
}
|
||||
|
||||
check_ip_options:
|
||||
|
||||
/* If IP options are supported, make sure there are none (log and disconnect
|
||||
them if any are found). Basically we are worried about source routing;
|
||||
it can be used to pretend you are somebody (ip-address) you are not.
|
||||
That itself may be "almost acceptable" under certain circumstances,
|
||||
but rhosts autentication is useless if source routing is accepted.
|
||||
Notice also that if we just dropped source routing here, the other
|
||||
side could use IP spoofing to do rest of the interaction and could still
|
||||
bypass security. So we exit here if we detect any IP options. */
|
||||
{
|
||||
unsigned char options[200], *ucp;
|
||||
char text[1024], *cp;
|
||||
int option_size, ipproto;
|
||||
struct protoent *ip;
|
||||
|
||||
if ((ip = getprotobyname("ip")) != NULL)
|
||||
ipproto = ip->p_proto;
|
||||
else
|
||||
ipproto = IPPROTO_IP;
|
||||
option_size = sizeof(options);
|
||||
if (getsockopt(0, ipproto, IP_OPTIONS, (char *)options,
|
||||
&option_size) >= 0 && option_size != 0)
|
||||
{
|
||||
cp = text;
|
||||
/* Note: "text" buffer must be at least 3x as big as options. */
|
||||
for (ucp = options; option_size > 0; ucp++, option_size--, cp += 3)
|
||||
sprintf(cp, " %2.2x", *ucp);
|
||||
log("Connection from %.100s with IP options:%.800s",
|
||||
inet_ntoa(from.sin_addr), text);
|
||||
packet_disconnect("Connection from %.100s with IP options:%.800s",
|
||||
inet_ntoa(from.sin_addr), text);
|
||||
}
|
||||
}
|
||||
check_ip_options:
|
||||
|
||||
return xstrdup(name);
|
||||
/* If IP options are supported, make sure there are none (log and
|
||||
disconnect them if any are found). Basically we are worried
|
||||
about source routing; it can be used to pretend you are
|
||||
somebody (ip-address) you are not. That itself may be "almost
|
||||
acceptable" under certain circumstances, but rhosts
|
||||
autentication is useless if source routing is accepted. Notice
|
||||
also that if we just dropped source routing here, the other
|
||||
side could use IP spoofing to do rest of the interaction and
|
||||
could still bypass security. So we exit here if we detect any
|
||||
IP options. */
|
||||
{
|
||||
unsigned char options[200], *ucp;
|
||||
char text[1024], *cp;
|
||||
int option_size, ipproto;
|
||||
struct protoent *ip;
|
||||
|
||||
if ((ip = getprotobyname("ip")) != NULL)
|
||||
ipproto = ip->p_proto;
|
||||
else
|
||||
ipproto = IPPROTO_IP;
|
||||
option_size = sizeof(options);
|
||||
if (getsockopt(0, ipproto, IP_OPTIONS, (char *) options,
|
||||
&option_size) >= 0 && option_size != 0) {
|
||||
cp = text;
|
||||
/* Note: "text" buffer must be at least 3x as big as options. */
|
||||
for (ucp = options; option_size > 0; ucp++, option_size--, cp += 3)
|
||||
sprintf(cp, " %2.2x", *ucp);
|
||||
log("Connection from %.100s with IP options:%.800s",
|
||||
inet_ntoa(from.sin_addr), text);
|
||||
packet_disconnect("Connection from %.100s with IP options:%.800s",
|
||||
inet_ntoa(from.sin_addr), text);
|
||||
}
|
||||
}
|
||||
|
||||
return xstrdup(name);
|
||||
}
|
||||
|
||||
static char *canonical_host_name = NULL;
|
||||
static char *canonical_host_ip = NULL;
|
||||
|
||||
/* Return the canonical name of the host in the other side of the current
|
||||
connection. The host name is cached, so it is efficient to call this
|
||||
connection. The host name is cached, so it is efficient to call this
|
||||
several times. */
|
||||
|
||||
const char *get_canonical_hostname()
|
||||
const char *
|
||||
get_canonical_hostname()
|
||||
{
|
||||
/* Check if we have previously retrieved this same name. */
|
||||
if (canonical_host_name != NULL)
|
||||
return canonical_host_name;
|
||||
/* Check if we have previously retrieved this same name. */
|
||||
if (canonical_host_name != NULL)
|
||||
return canonical_host_name;
|
||||
|
||||
/* Get the real hostname if socket; otherwise return UNKNOWN. */
|
||||
if (packet_get_connection_in() == packet_get_connection_out())
|
||||
canonical_host_name = get_remote_hostname(packet_get_connection_in());
|
||||
else
|
||||
canonical_host_name = xstrdup("UNKNOWN");
|
||||
/* Get the real hostname if socket; otherwise return UNKNOWN. */
|
||||
if (packet_get_connection_in() == packet_get_connection_out())
|
||||
canonical_host_name = get_remote_hostname(packet_get_connection_in());
|
||||
else
|
||||
canonical_host_name = xstrdup("UNKNOWN");
|
||||
|
||||
return canonical_host_name;
|
||||
return canonical_host_name;
|
||||
}
|
||||
|
||||
/* Returns the IP-address of the remote host as a string. The returned
|
||||
string need not be freed. */
|
||||
|
||||
const char *get_remote_ipaddr()
|
||||
const char *
|
||||
get_remote_ipaddr()
|
||||
{
|
||||
struct sockaddr_in from;
|
||||
int fromlen, socket;
|
||||
struct sockaddr_in from;
|
||||
int fromlen, socket;
|
||||
|
||||
/* Check if we have previously retrieved this same name. */
|
||||
if (canonical_host_ip != NULL)
|
||||
return canonical_host_ip;
|
||||
/* Check if we have previously retrieved this same name. */
|
||||
if (canonical_host_ip != NULL)
|
||||
return canonical_host_ip;
|
||||
|
||||
/* If not a socket, return UNKNOWN. */
|
||||
if (packet_get_connection_in() != packet_get_connection_out())
|
||||
{
|
||||
canonical_host_ip = xstrdup("UNKNOWN");
|
||||
return canonical_host_ip;
|
||||
}
|
||||
/* If not a socket, return UNKNOWN. */
|
||||
if (packet_get_connection_in() != packet_get_connection_out()) {
|
||||
canonical_host_ip = xstrdup("UNKNOWN");
|
||||
return canonical_host_ip;
|
||||
}
|
||||
/* Get client socket. */
|
||||
socket = packet_get_connection_in();
|
||||
|
||||
/* Get client socket. */
|
||||
socket = packet_get_connection_in();
|
||||
/* Get IP address of client. */
|
||||
fromlen = sizeof(from);
|
||||
memset(&from, 0, sizeof(from));
|
||||
if (getpeername(socket, (struct sockaddr *) & from, &fromlen) < 0) {
|
||||
debug("getpeername failed: %.100s", strerror(errno));
|
||||
fatal_cleanup();
|
||||
}
|
||||
/* Get the IP address in ascii. */
|
||||
canonical_host_ip = xstrdup(inet_ntoa(from.sin_addr));
|
||||
|
||||
/* Get IP address of client. */
|
||||
fromlen = sizeof(from);
|
||||
memset(&from, 0, sizeof(from));
|
||||
if (getpeername(socket, (struct sockaddr *)&from, &fromlen) < 0)
|
||||
{
|
||||
debug("getpeername failed: %.100s", strerror(errno));
|
||||
fatal_cleanup();
|
||||
}
|
||||
|
||||
/* Get the IP address in ascii. */
|
||||
canonical_host_ip = xstrdup(inet_ntoa(from.sin_addr));
|
||||
|
||||
/* Return ip address string. */
|
||||
return canonical_host_ip;
|
||||
/* Return ip address string. */
|
||||
return canonical_host_ip;
|
||||
}
|
||||
|
||||
/* Returns the port of the peer of the socket. */
|
||||
|
||||
int get_peer_port(int sock)
|
||||
int
|
||||
get_peer_port(int sock)
|
||||
{
|
||||
struct sockaddr_in from;
|
||||
int fromlen;
|
||||
struct sockaddr_in from;
|
||||
int fromlen;
|
||||
|
||||
/* Get IP address of client. */
|
||||
fromlen = sizeof(from);
|
||||
memset(&from, 0, sizeof(from));
|
||||
if (getpeername(sock, (struct sockaddr *)&from, &fromlen) < 0)
|
||||
{
|
||||
debug("getpeername failed: %.100s", strerror(errno));
|
||||
fatal_cleanup();
|
||||
}
|
||||
|
||||
/* Return port number. */
|
||||
return ntohs(from.sin_port);
|
||||
/* Get IP address of client. */
|
||||
fromlen = sizeof(from);
|
||||
memset(&from, 0, sizeof(from));
|
||||
if (getpeername(sock, (struct sockaddr *) & from, &fromlen) < 0) {
|
||||
debug("getpeername failed: %.100s", strerror(errno));
|
||||
fatal_cleanup();
|
||||
}
|
||||
/* Return port number. */
|
||||
return ntohs(from.sin_port);
|
||||
}
|
||||
|
||||
/* Returns the port number of the remote host. */
|
||||
|
||||
int get_remote_port()
|
||||
int
|
||||
get_remote_port()
|
||||
{
|
||||
int socket;
|
||||
int socket;
|
||||
|
||||
/* If the connection is not a socket, return 65535. This is intentionally
|
||||
chosen to be an unprivileged port number. */
|
||||
if (packet_get_connection_in() != packet_get_connection_out())
|
||||
return 65535;
|
||||
/* If the connection is not a socket, return 65535. This is
|
||||
intentionally chosen to be an unprivileged port number. */
|
||||
if (packet_get_connection_in() != packet_get_connection_out())
|
||||
return 65535;
|
||||
|
||||
/* Get client socket. */
|
||||
socket = packet_get_connection_in();
|
||||
/* Get client socket. */
|
||||
socket = packet_get_connection_in();
|
||||
|
||||
/* Get and return the peer port number. */
|
||||
return get_peer_port(socket);
|
||||
/* Get and return the peer port number. */
|
||||
return get_peer_port(socket);
|
||||
}
|
||||
|
|
2263
channels.c
2263
channels.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
62
channels.h
62
channels.h
|
@ -1,40 +1,46 @@
|
|||
/* RCSID("$Id: channels.h,v 1.2 1999/10/30 01:39:56 damien Exp $"); */
|
||||
/* RCSID("$Id: channels.h,v 1.3 1999/11/24 13:26:22 damien Exp $"); */
|
||||
|
||||
#ifndef CHANNELS_H
|
||||
#define CHANNELS_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 */
|
||||
#define SSH_CHANNEL_OPEN 4 /* normal open two-way channel */
|
||||
#define SSH_CHANNEL_CLOSED 5 /* waiting for close confirmation */
|
||||
#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 */
|
||||
#define SSH_CHANNEL_OPEN 4 /* normal open two-way channel */
|
||||
#define SSH_CHANNEL_CLOSED 5 /* waiting for close
|
||||
* confirmation */
|
||||
/* SSH_CHANNEL_AUTH_FD 6 authentication fd */
|
||||
#define SSH_CHANNEL_AUTH_SOCKET 7 /* authentication socket */
|
||||
#define SSH_CHANNEL_AUTH_SOCKET 7 /* authentication socket */
|
||||
/* SSH_CHANNEL_AUTH_SOCKET_FD 8 connection to auth socket */
|
||||
#define SSH_CHANNEL_X11_OPEN 9 /* reading first X11 packet */
|
||||
#define SSH_CHANNEL_INPUT_DRAINING 10 /* sending remaining data to conn */
|
||||
#define SSH_CHANNEL_OUTPUT_DRAINING 11 /* sending remaining data to app */
|
||||
#define SSH_CHANNEL_X11_OPEN 9 /* reading first X11 packet */
|
||||
#define SSH_CHANNEL_INPUT_DRAINING 10 /* sending remaining data to
|
||||
* conn */
|
||||
#define SSH_CHANNEL_OUTPUT_DRAINING 11 /* sending remaining data to
|
||||
* app */
|
||||
|
||||
/* Data structure for channel data. This is iniailized in channel_allocate
|
||||
and cleared in channel_free. */
|
||||
|
||||
typedef 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) */
|
||||
int sock; /* data socket, linked to this channel */
|
||||
Buffer input; /* data read from socket, to be sent over encrypted connection */
|
||||
Buffer output; /* data received over encrypted connection for send on socket */
|
||||
char path[200]; /* 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 */
|
||||
} Channel;
|
||||
|
||||
typedef 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) */
|
||||
int sock; /* data socket, linked to this channel */
|
||||
Buffer input; /* data read from socket, to be sent over
|
||||
* encrypted connection */
|
||||
Buffer output; /* data received over encrypted connection for
|
||||
* send on socket */
|
||||
char path[200]; /* 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 */
|
||||
} Channel;
|
||||
#endif
|
||||
|
|
377
cipher.c
377
cipher.c
|
@ -1,18 +1,18 @@
|
|||
/*
|
||||
|
||||
cipher.c
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Wed Apr 19 17:41:39 1995 ylo
|
||||
|
||||
*/
|
||||
*
|
||||
* cipher.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Wed Apr 19 17:41:39 1995 ylo
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: cipher.c,v 1.6 1999/11/16 02:37:16 damien Exp $");
|
||||
RCSID("$Id: cipher.c,v 1.7 1999/11/24 13:26:22 damien Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "cipher.h"
|
||||
|
@ -38,124 +38,124 @@ RCSID("$Id: cipher.c,v 1.6 1999/11/16 02:37:16 damien Exp $");
|
|||
*/
|
||||
void
|
||||
SSH_3CBC_ENCRYPT(des_key_schedule ks1,
|
||||
des_key_schedule ks2, des_cblock *iv2,
|
||||
des_key_schedule ks3, des_cblock *iv3,
|
||||
des_key_schedule ks2, des_cblock * iv2,
|
||||
des_key_schedule ks3, des_cblock * iv3,
|
||||
void *dest, void *src,
|
||||
unsigned int len)
|
||||
{
|
||||
des_cblock iv1;
|
||||
des_cblock iv1;
|
||||
|
||||
memcpy(&iv1, iv2, 8);
|
||||
memcpy(&iv1, iv2, 8);
|
||||
|
||||
des_cbc_encrypt(src, dest, len, ks1, &iv1, DES_ENCRYPT);
|
||||
memcpy(&iv1, dest + len - 8, 8);
|
||||
des_cbc_encrypt(src, dest, len, ks1, &iv1, DES_ENCRYPT);
|
||||
memcpy(&iv1, dest + len - 8, 8);
|
||||
|
||||
des_cbc_encrypt(dest, dest, len, ks2, iv2, DES_DECRYPT);
|
||||
memcpy(iv2, &iv1, 8); /* Note how iv1 == iv2 on entry and exit. */
|
||||
des_cbc_encrypt(dest, dest, len, ks2, iv2, DES_DECRYPT);
|
||||
memcpy(iv2, &iv1, 8); /* Note how iv1 == iv2 on entry and exit. */
|
||||
|
||||
des_cbc_encrypt(dest, dest, len, ks3, iv3, DES_ENCRYPT);
|
||||
memcpy(iv3, dest + len - 8, 8);
|
||||
des_cbc_encrypt(dest, dest, len, ks3, iv3, DES_ENCRYPT);
|
||||
memcpy(iv3, dest + len - 8, 8);
|
||||
}
|
||||
|
||||
void
|
||||
SSH_3CBC_DECRYPT(des_key_schedule ks1,
|
||||
des_key_schedule ks2, des_cblock *iv2,
|
||||
des_key_schedule ks3, des_cblock *iv3,
|
||||
des_key_schedule ks2, des_cblock * iv2,
|
||||
des_key_schedule ks3, des_cblock * iv3,
|
||||
void *dest, void *src,
|
||||
unsigned int len)
|
||||
{
|
||||
des_cblock iv1;
|
||||
des_cblock iv1;
|
||||
|
||||
memcpy(&iv1, iv2, 8);
|
||||
memcpy(&iv1, iv2, 8);
|
||||
|
||||
des_cbc_encrypt(src, dest, len, ks3, iv3, DES_DECRYPT);
|
||||
memcpy(iv3, src + len - 8, 8);
|
||||
des_cbc_encrypt(src, dest, len, ks3, iv3, DES_DECRYPT);
|
||||
memcpy(iv3, src + len - 8, 8);
|
||||
|
||||
des_cbc_encrypt(dest, dest, len, ks2, iv2, DES_ENCRYPT);
|
||||
memcpy(iv2, dest + len - 8, 8);
|
||||
des_cbc_encrypt(dest, dest, len, ks2, iv2, DES_ENCRYPT);
|
||||
memcpy(iv2, dest + len - 8, 8);
|
||||
|
||||
des_cbc_encrypt(dest, dest, len, ks1, &iv1, DES_DECRYPT);
|
||||
/* memcpy(&iv1, iv2, 8); */ /* Note how iv1 == iv2 on entry and exit. */
|
||||
des_cbc_encrypt(dest, dest, len, ks1, &iv1, DES_DECRYPT);
|
||||
/* memcpy(&iv1, iv2, 8); */
|
||||
/* Note how iv1 == iv2 on entry and exit. */
|
||||
}
|
||||
|
||||
/*
|
||||
* SSH uses a variation on Blowfish, all bytes must be swapped before
|
||||
* and after encryption/decryption. Thus the swap_bytes stuff (yuk).
|
||||
*/
|
||||
static
|
||||
void
|
||||
static void
|
||||
swap_bytes(const unsigned char *src, unsigned char *dst_, int n)
|
||||
{
|
||||
u_int32_t *dst = (u_int32_t *)dst_; /* dst must be properly aligned. */
|
||||
union {
|
||||
u_int32_t i;
|
||||
char c[4];
|
||||
} t;
|
||||
/* dst must be properly aligned. */
|
||||
u_int32_t *dst = (u_int32_t *) dst_;
|
||||
union {
|
||||
u_int32_t i;
|
||||
char c[4];
|
||||
} t;
|
||||
|
||||
/* Process 8 bytes every lap. */
|
||||
for (n = n / 8; n > 0; n--)
|
||||
{
|
||||
t.c[3] = *src++;
|
||||
t.c[2] = *src++;
|
||||
t.c[1] = *src++;
|
||||
t.c[0] = *src++;
|
||||
*dst++ = t.i;
|
||||
|
||||
t.c[3] = *src++;
|
||||
t.c[2] = *src++;
|
||||
t.c[1] = *src++;
|
||||
t.c[0] = *src++;
|
||||
*dst++ = t.i;
|
||||
}
|
||||
/* Process 8 bytes every lap. */
|
||||
for (n = n / 8; n > 0; n--) {
|
||||
t.c[3] = *src++;
|
||||
t.c[2] = *src++;
|
||||
t.c[1] = *src++;
|
||||
t.c[0] = *src++;
|
||||
*dst++ = t.i;
|
||||
|
||||
t.c[3] = *src++;
|
||||
t.c[2] = *src++;
|
||||
t.c[1] = *src++;
|
||||
t.c[0] = *src++;
|
||||
*dst++ = t.i;
|
||||
}
|
||||
}
|
||||
|
||||
void (*cipher_attack_detected)(const char *fmt, ...) = fatal;
|
||||
void (*cipher_attack_detected) (const char *fmt,...) = fatal;
|
||||
|
||||
static inline
|
||||
void
|
||||
static inline void
|
||||
detect_cbc_attack(const unsigned char *src,
|
||||
unsigned int len)
|
||||
{
|
||||
return;
|
||||
|
||||
log("CRC-32 CBC insertion attack detected");
|
||||
cipher_attack_detected("CRC-32 CBC insertion attack detected");
|
||||
return;
|
||||
|
||||
log("CRC-32 CBC insertion attack detected");
|
||||
cipher_attack_detected("CRC-32 CBC insertion attack detected");
|
||||
}
|
||||
|
||||
/* Names of all encryption algorithms. These must match the numbers defined
|
||||
int cipher.h. */
|
||||
static char *cipher_names[] =
|
||||
{
|
||||
"none",
|
||||
"idea",
|
||||
"des",
|
||||
"3des",
|
||||
"tss",
|
||||
"rc4",
|
||||
"blowfish"
|
||||
"none",
|
||||
"idea",
|
||||
"des",
|
||||
"3des",
|
||||
"tss",
|
||||
"rc4",
|
||||
"blowfish"
|
||||
};
|
||||
|
||||
/* Returns a bit mask indicating which ciphers are supported by this
|
||||
implementation. The bit mask has the corresponding bit set of each
|
||||
supported cipher. */
|
||||
|
||||
unsigned int cipher_mask()
|
||||
unsigned int
|
||||
cipher_mask()
|
||||
{
|
||||
unsigned int mask = 0;
|
||||
mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */
|
||||
mask |= 1 << SSH_CIPHER_BLOWFISH;
|
||||
return mask;
|
||||
unsigned int mask = 0;
|
||||
mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */
|
||||
mask |= 1 << SSH_CIPHER_BLOWFISH;
|
||||
return mask;
|
||||
}
|
||||
|
||||
/* Returns the name of the cipher. */
|
||||
|
||||
const
|
||||
char *cipher_name(int cipher)
|
||||
const char *
|
||||
cipher_name(int cipher)
|
||||
{
|
||||
if (cipher < 0 || cipher >= sizeof(cipher_names) / sizeof(cipher_names[0]) ||
|
||||
cipher_names[cipher] == NULL)
|
||||
fatal("cipher_name: bad cipher number: %d", cipher);
|
||||
return cipher_names[cipher];
|
||||
if (cipher < 0 || cipher >= sizeof(cipher_names) / sizeof(cipher_names[0]) ||
|
||||
cipher_names[cipher] == NULL)
|
||||
fatal("cipher_name: bad cipher number: %d", cipher);
|
||||
return cipher_names[cipher];
|
||||
}
|
||||
|
||||
/* Parses the name of the cipher. Returns the number of the corresponding
|
||||
|
@ -164,146 +164,151 @@ char *cipher_name(int cipher)
|
|||
int
|
||||
cipher_number(const char *name)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < sizeof(cipher_names) / sizeof(cipher_names[0]); i++)
|
||||
if (strcmp(cipher_names[i], name) == 0 &&
|
||||
(cipher_mask() & (1 << i)))
|
||||
return i;
|
||||
return -1;
|
||||
int i;
|
||||
for (i = 0; i < sizeof(cipher_names) / sizeof(cipher_names[0]); i++)
|
||||
if (strcmp(cipher_names[i], name) == 0 &&
|
||||
(cipher_mask() & (1 << i)))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Selects the cipher, and keys if by computing the MD5 checksum of the
|
||||
passphrase and using the resulting 16 bytes as the key. */
|
||||
|
||||
void cipher_set_key_string(CipherContext *context, int cipher,
|
||||
const char *passphrase, int for_encryption)
|
||||
void
|
||||
cipher_set_key_string(CipherContext *context, int cipher,
|
||||
const char *passphrase, int for_encryption)
|
||||
{
|
||||
MD5_CTX md;
|
||||
unsigned char digest[16];
|
||||
|
||||
MD5_Init(&md);
|
||||
MD5_Update(&md, (const unsigned char *)passphrase, strlen(passphrase));
|
||||
MD5_Final(digest, &md);
|
||||
MD5_CTX md;
|
||||
unsigned char digest[16];
|
||||
|
||||
cipher_set_key(context, cipher, digest, 16, for_encryption);
|
||||
|
||||
memset(digest, 0, sizeof(digest));
|
||||
memset(&md, 0, sizeof(md));
|
||||
MD5_Init(&md);
|
||||
MD5_Update(&md, (const unsigned char *) passphrase, strlen(passphrase));
|
||||
MD5_Final(digest, &md);
|
||||
|
||||
cipher_set_key(context, cipher, digest, 16, for_encryption);
|
||||
|
||||
memset(digest, 0, sizeof(digest));
|
||||
memset(&md, 0, sizeof(md));
|
||||
}
|
||||
|
||||
/* Selects the cipher to use and sets the key. */
|
||||
|
||||
void cipher_set_key(CipherContext *context, int cipher,
|
||||
const unsigned char *key, int keylen, int for_encryption)
|
||||
void
|
||||
cipher_set_key(CipherContext *context, int cipher,
|
||||
const unsigned char *key, int keylen, int for_encryption)
|
||||
{
|
||||
unsigned char padded[32];
|
||||
unsigned char padded[32];
|
||||
|
||||
/* Set cipher type. */
|
||||
context->type = cipher;
|
||||
/* Set cipher type. */
|
||||
context->type = cipher;
|
||||
|
||||
/* Get 32 bytes of key data. Pad if necessary. (So that code below does
|
||||
not need to worry about key size). */
|
||||
memset(padded, 0, sizeof(padded));
|
||||
memcpy(padded, key, keylen < sizeof(padded) ? keylen : sizeof(padded));
|
||||
/* Get 32 bytes of key data. Pad if necessary. (So that code
|
||||
below does not need to worry about key size). */
|
||||
memset(padded, 0, sizeof(padded));
|
||||
memcpy(padded, key, keylen < sizeof(padded) ? keylen : sizeof(padded));
|
||||
|
||||
/* Initialize the initialization vector. */
|
||||
switch (cipher)
|
||||
{
|
||||
case SSH_CIPHER_NONE:
|
||||
/* Has to stay for authfile saving of private key with no passphrase */
|
||||
break;
|
||||
/* Initialize the initialization vector. */
|
||||
switch (cipher) {
|
||||
case SSH_CIPHER_NONE:
|
||||
/* Has to stay for authfile saving of private key with
|
||||
no passphrase */
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_3DES:
|
||||
/* Note: the least significant bit of each byte of key is parity,
|
||||
and must be ignored by the implementation. 16 bytes of key are
|
||||
used (first and last keys are the same). */
|
||||
if (keylen < 16)
|
||||
error("Key length %d is insufficient for 3DES.", keylen);
|
||||
des_set_key((void*)padded, context->u.des3.key1);
|
||||
des_set_key((void*)(padded + 8), context->u.des3.key2);
|
||||
if (keylen <= 16)
|
||||
des_set_key((void*)padded, context->u.des3.key3);
|
||||
else
|
||||
des_set_key((void*)(padded + 16), context->u.des3.key3);
|
||||
memset(context->u.des3.iv2, 0, sizeof(context->u.des3.iv2));
|
||||
memset(context->u.des3.iv3, 0, sizeof(context->u.des3.iv3));
|
||||
break;
|
||||
case SSH_CIPHER_3DES:
|
||||
/* Note: the least significant bit of each byte of key is
|
||||
parity, and must be ignored by the implementation. 16
|
||||
bytes of key are used (first and last keys are the
|
||||
same). */
|
||||
if (keylen < 16)
|
||||
error("Key length %d is insufficient for 3DES.", keylen);
|
||||
des_set_key((void *) padded, context->u.des3.key1);
|
||||
des_set_key((void *) (padded + 8), context->u.des3.key2);
|
||||
if (keylen <= 16)
|
||||
des_set_key((void *) padded, context->u.des3.key3);
|
||||
else
|
||||
des_set_key((void *) (padded + 16), context->u.des3.key3);
|
||||
memset(context->u.des3.iv2, 0, sizeof(context->u.des3.iv2));
|
||||
memset(context->u.des3.iv3, 0, sizeof(context->u.des3.iv3));
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_BLOWFISH:
|
||||
BF_set_key(&context->u.bf.key, keylen, padded);
|
||||
memset(context->u.bf.iv, 0, 8);
|
||||
break;
|
||||
case SSH_CIPHER_BLOWFISH:
|
||||
BF_set_key(&context->u.bf.key, keylen, padded);
|
||||
memset(context->u.bf.iv, 0, 8);
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("cipher_set_key: unknown cipher: %s", cipher_name(cipher));
|
||||
}
|
||||
memset(padded, 0, sizeof(padded));
|
||||
default:
|
||||
fatal("cipher_set_key: unknown cipher: %s", cipher_name(cipher));
|
||||
}
|
||||
memset(padded, 0, sizeof(padded));
|
||||
}
|
||||
|
||||
/* Encrypts data using the cipher. */
|
||||
|
||||
void cipher_encrypt(CipherContext *context, unsigned char *dest,
|
||||
const unsigned char *src, unsigned int len)
|
||||
void
|
||||
cipher_encrypt(CipherContext *context, unsigned char *dest,
|
||||
const unsigned char *src, unsigned int len)
|
||||
{
|
||||
if ((len & 7) != 0)
|
||||
fatal("cipher_encrypt: bad plaintext length %d", len);
|
||||
if ((len & 7) != 0)
|
||||
fatal("cipher_encrypt: bad plaintext length %d", len);
|
||||
|
||||
switch (context->type)
|
||||
{
|
||||
case SSH_CIPHER_NONE:
|
||||
memcpy(dest, src, len);
|
||||
break;
|
||||
switch (context->type) {
|
||||
case SSH_CIPHER_NONE:
|
||||
memcpy(dest, src, len);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_3DES:
|
||||
SSH_3CBC_ENCRYPT(context->u.des3.key1,
|
||||
context->u.des3.key2, &context->u.des3.iv2,
|
||||
context->u.des3.key3, &context->u.des3.iv3,
|
||||
dest, (void*)src, len);
|
||||
break;
|
||||
case SSH_CIPHER_3DES:
|
||||
SSH_3CBC_ENCRYPT(context->u.des3.key1,
|
||||
context->u.des3.key2, &context->u.des3.iv2,
|
||||
context->u.des3.key3, &context->u.des3.iv3,
|
||||
dest, (void *) src, len);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_BLOWFISH:
|
||||
swap_bytes(src, dest, len);
|
||||
BF_cbc_encrypt(dest, dest, len,
|
||||
&context->u.bf.key, context->u.bf.iv, BF_ENCRYPT);
|
||||
swap_bytes(dest, dest, len);
|
||||
break;
|
||||
case SSH_CIPHER_BLOWFISH:
|
||||
swap_bytes(src, dest, len);
|
||||
BF_cbc_encrypt(dest, dest, len,
|
||||
&context->u.bf.key, context->u.bf.iv,
|
||||
BF_ENCRYPT);
|
||||
swap_bytes(dest, dest, len);
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("cipher_encrypt: unknown cipher: %d", context->type);
|
||||
}
|
||||
default:
|
||||
fatal("cipher_encrypt: unknown cipher: %s", cipher_name(context->type));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Decrypts data using the cipher. */
|
||||
|
||||
void cipher_decrypt(CipherContext *context, unsigned char *dest,
|
||||
const unsigned char *src, unsigned int len)
|
||||
void
|
||||
cipher_decrypt(CipherContext *context, unsigned char *dest,
|
||||
const unsigned char *src, unsigned int len)
|
||||
{
|
||||
if ((len & 7) != 0)
|
||||
fatal("cipher_decrypt: bad ciphertext length %d", len);
|
||||
if ((len & 7) != 0)
|
||||
fatal("cipher_decrypt: bad ciphertext length %d", len);
|
||||
|
||||
switch (context->type)
|
||||
{
|
||||
case SSH_CIPHER_NONE:
|
||||
memcpy(dest, src, len);
|
||||
break;
|
||||
switch (context->type) {
|
||||
case SSH_CIPHER_NONE:
|
||||
memcpy(dest, src, len);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_3DES:
|
||||
/* CRC-32 attack? */
|
||||
SSH_3CBC_DECRYPT(context->u.des3.key1,
|
||||
context->u.des3.key2, &context->u.des3.iv2,
|
||||
context->u.des3.key3, &context->u.des3.iv3,
|
||||
dest, (void*)src, len);
|
||||
break;
|
||||
case SSH_CIPHER_3DES:
|
||||
/* CRC-32 attack? */
|
||||
SSH_3CBC_DECRYPT(context->u.des3.key1,
|
||||
context->u.des3.key2, &context->u.des3.iv2,
|
||||
context->u.des3.key3, &context->u.des3.iv3,
|
||||
dest, (void *) src, len);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_BLOWFISH:
|
||||
detect_cbc_attack(src, len);
|
||||
swap_bytes(src, dest, len);
|
||||
BF_cbc_encrypt((void*)dest, dest, len,
|
||||
&context->u.bf.key, context->u.bf.iv, BF_DECRYPT);
|
||||
swap_bytes(dest, dest, len);
|
||||
break;
|
||||
case SSH_CIPHER_BLOWFISH:
|
||||
detect_cbc_attack(src, len);
|
||||
swap_bytes(src, dest, len);
|
||||
BF_cbc_encrypt((void *) dest, dest, len,
|
||||
&context->u.bf.key, context->u.bf.iv,
|
||||
BF_DECRYPT);
|
||||
swap_bytes(dest, dest, len);
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("cipher_decrypt: unknown cipher: %d", context->type);
|
||||
}
|
||||
default:
|
||||
fatal("cipher_decrypt: unknown cipher: %s", cipher_name(context->type));
|
||||
}
|
||||
}
|
||||
|
|
95
cipher.h
95
cipher.h
|
@ -1,17 +1,17 @@
|
|||
/*
|
||||
*
|
||||
* cipher.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Wed Apr 19 16:50:42 1995 ylo
|
||||
*
|
||||
*/
|
||||
|
||||
cipher.h
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Wed Apr 19 16:50:42 1995 ylo
|
||||
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: cipher.h,v 1.3 1999/11/16 02:37:16 damien Exp $"); */
|
||||
/* RCSID("$Id: cipher.h,v 1.4 1999/11/24 13:26:22 damien Exp $"); */
|
||||
|
||||
#ifndef CIPHER_H
|
||||
#define CIPHER_H
|
||||
|
@ -29,32 +29,31 @@ Created: Wed Apr 19 16:50:42 1995 ylo
|
|||
|
||||
/* Cipher types. New types can be added, but old types should not be removed
|
||||
for compatibility. The maximum allowed value is 31. */
|
||||
#define SSH_CIPHER_NOT_SET -1 /* None selected (invalid number). */
|
||||
#define SSH_CIPHER_NONE 0 /* no encryption */
|
||||
#define SSH_CIPHER_IDEA 1 /* IDEA CFB */
|
||||
#define SSH_CIPHER_DES 2 /* DES CBC */
|
||||
#define SSH_CIPHER_3DES 3 /* 3DES CBC */
|
||||
#define SSH_CIPHER_BROKEN_TSS 4 /* TRI's Simple Stream encryption CBC */
|
||||
#define SSH_CIPHER_BROKEN_RC4 5 /* Alleged RC4 */
|
||||
#define SSH_CIPHER_NOT_SET -1 /* None selected (invalid number). */
|
||||
#define SSH_CIPHER_NONE 0 /* no encryption */
|
||||
#define SSH_CIPHER_IDEA 1 /* IDEA CFB */
|
||||
#define SSH_CIPHER_DES 2 /* DES CBC */
|
||||
#define SSH_CIPHER_3DES 3 /* 3DES CBC */
|
||||
#define SSH_CIPHER_BROKEN_TSS 4 /* TRI's Simple Stream encryption CBC */
|
||||
#define SSH_CIPHER_BROKEN_RC4 5 /* Alleged RC4 */
|
||||
#define SSH_CIPHER_BLOWFISH 6
|
||||
|
||||
typedef struct {
|
||||
unsigned int type;
|
||||
union {
|
||||
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;
|
||||
unsigned char iv[8];
|
||||
} bf;
|
||||
} u;
|
||||
} CipherContext;
|
||||
|
||||
unsigned int type;
|
||||
union {
|
||||
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;
|
||||
unsigned char iv[8];
|
||||
} bf;
|
||||
} u;
|
||||
} CipherContext;
|
||||
/* Returns a bit mask indicating which ciphers are supported by this
|
||||
implementation. The bit mask has the corresponding bit set of each
|
||||
supported cipher. */
|
||||
|
@ -65,28 +64,32 @@ const char *cipher_name(int cipher);
|
|||
|
||||
/* Parses the name of the cipher. Returns the number of the corresponding
|
||||
cipher, or -1 on error. */
|
||||
int cipher_number(const char *name);
|
||||
int cipher_number(const char *name);
|
||||
|
||||
/* Selects the cipher to use and sets the key. If for_encryption is true,
|
||||
the key is setup for encryption; otherwise it is setup for decryption. */
|
||||
void cipher_set_key(CipherContext *context, int cipher,
|
||||
const unsigned char *key, int keylen, int for_encryption);
|
||||
void
|
||||
cipher_set_key(CipherContext * context, int cipher,
|
||||
const unsigned char *key, int keylen, int for_encryption);
|
||||
|
||||
/* Sets key for the cipher by computing the MD5 checksum of the passphrase,
|
||||
and using the resulting 16 bytes as the key. */
|
||||
void cipher_set_key_string(CipherContext *context, int cipher,
|
||||
const char *passphrase, int for_encryption);
|
||||
void
|
||||
cipher_set_key_string(CipherContext * context, int cipher,
|
||||
const char *passphrase, int for_encryption);
|
||||
|
||||
/* Encrypts data using the cipher. */
|
||||
void cipher_encrypt(CipherContext *context, unsigned char *dest,
|
||||
const unsigned char *src, unsigned int len);
|
||||
void
|
||||
cipher_encrypt(CipherContext * context, unsigned char *dest,
|
||||
const unsigned char *src, unsigned int len);
|
||||
|
||||
/* Decrypts data using the cipher. */
|
||||
void cipher_decrypt(CipherContext *context, unsigned char *dest,
|
||||
const unsigned char *src, unsigned int len);
|
||||
void
|
||||
cipher_decrypt(CipherContext * context, unsigned char *dest,
|
||||
const unsigned char *src, unsigned int len);
|
||||
|
||||
/* If and CRC-32 attack is detected this function is called. Defaults
|
||||
* to fatal, changed to packet_disconnect in sshd and ssh. */
|
||||
extern void (*cipher_attack_detected)(const char *fmt, ...);
|
||||
extern void (*cipher_attack_detected) (const char *fmt,...);
|
||||
|
||||
#endif /* CIPHER_H */
|
||||
#endif /* CIPHER_H */
|
||||
|
|
1392
clientloop.c
1392
clientloop.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
13
compat.c
13
compat.c
|
@ -1,10 +1,13 @@
|
|||
#include "includes.h"
|
||||
RCSID("$Id: compat.c,v 1.1 1999/10/27 03:42:44 damien Exp $");
|
||||
RCSID("$Id: compat.c,v 1.2 1999/11/24 13:26:22 damien Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
|
||||
int compat13=0;
|
||||
void enable_compat13(void){
|
||||
log("Enabling compatibility mode for protocol 1.3");
|
||||
compat13=1;
|
||||
int compat13 = 0;
|
||||
|
||||
void
|
||||
enable_compat13(void)
|
||||
{
|
||||
verbose("Enabling compatibility mode for protocol 1.3");
|
||||
compat13 = 1;
|
||||
}
|
||||
|
|
4
compat.h
4
compat.h
|
@ -1,7 +1,7 @@
|
|||
/* RCSID("$Id: compat.h,v 1.1 1999/10/27 03:42:44 damien Exp $"); */
|
||||
/* RCSID("$Id: compat.h,v 1.2 1999/11/24 13:26:22 damien Exp $"); */
|
||||
|
||||
#ifndef COMPAT_H
|
||||
#define COMPAT_H
|
||||
void enable_compat13(void);
|
||||
void enable_compat13(void);
|
||||
extern int compat13;
|
||||
#endif
|
||||
|
|
219
compress.c
219
compress.c
|
@ -1,20 +1,20 @@
|
|||
/*
|
||||
|
||||
compress.c
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Wed Oct 25 22:12:46 1995 ylo
|
||||
|
||||
Interface to packet compression for ssh.
|
||||
|
||||
*/
|
||||
*
|
||||
* compress.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Wed Oct 25 22:12:46 1995 ylo
|
||||
*
|
||||
* Interface to packet compression for ssh.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: compress.c,v 1.1 1999/10/27 03:42:44 damien Exp $");
|
||||
RCSID("$Id: compress.c,v 1.2 1999/11/24 13:26:22 damien Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "buffer.h"
|
||||
|
@ -23,32 +23,34 @@ RCSID("$Id: compress.c,v 1.1 1999/10/27 03:42:44 damien Exp $");
|
|||
static z_stream incoming_stream;
|
||||
static z_stream outgoing_stream;
|
||||
|
||||
/* Initializes compression; level is compression level from 1 to 9 (as in
|
||||
gzip). */
|
||||
/* Initializes compression; level is compression level from 1 to 9
|
||||
(as in gzip). */
|
||||
|
||||
void buffer_compress_init(int level)
|
||||
void
|
||||
buffer_compress_init(int level)
|
||||
{
|
||||
debug("Enabling compression at level %d.", level);
|
||||
if (level < 1 || level > 9)
|
||||
fatal("Bad compression level %d.", level);
|
||||
inflateInit(&incoming_stream);
|
||||
deflateInit(&outgoing_stream, level);
|
||||
debug("Enabling compression at level %d.", level);
|
||||
if (level < 1 || level > 9)
|
||||
fatal("Bad compression level %d.", level);
|
||||
inflateInit(&incoming_stream);
|
||||
deflateInit(&outgoing_stream, level);
|
||||
}
|
||||
|
||||
/* Frees any data structures allocated for compression. */
|
||||
|
||||
void buffer_compress_uninit()
|
||||
void
|
||||
buffer_compress_uninit()
|
||||
{
|
||||
debug("compress outgoing: raw data %lu, compressed %lu, factor %.2f",
|
||||
outgoing_stream.total_in, outgoing_stream.total_out,
|
||||
outgoing_stream.total_in == 0 ? 0.0 :
|
||||
(double)outgoing_stream.total_out / outgoing_stream.total_in);
|
||||
debug("compress incoming: raw data %lu, compressed %lu, factor %.2f",
|
||||
incoming_stream.total_out, incoming_stream.total_in,
|
||||
incoming_stream.total_out == 0 ? 0.0 :
|
||||
(double)incoming_stream.total_in / incoming_stream.total_out);
|
||||
inflateEnd(&incoming_stream);
|
||||
deflateEnd(&outgoing_stream);
|
||||
debug("compress outgoing: raw data %lu, compressed %lu, factor %.2f",
|
||||
outgoing_stream.total_in, outgoing_stream.total_out,
|
||||
outgoing_stream.total_in == 0 ? 0.0 :
|
||||
(double) outgoing_stream.total_out / outgoing_stream.total_in);
|
||||
debug("compress incoming: raw data %lu, compressed %lu, factor %.2f",
|
||||
incoming_stream.total_out, incoming_stream.total_in,
|
||||
incoming_stream.total_out == 0 ? 0.0 :
|
||||
(double) incoming_stream.total_in / incoming_stream.total_out);
|
||||
inflateEnd(&incoming_stream);
|
||||
deflateEnd(&outgoing_stream);
|
||||
}
|
||||
|
||||
/* Compresses the contents of input_buffer into output_buffer. All
|
||||
|
@ -59,50 +61,49 @@ void buffer_compress_uninit()
|
|||
form a single compression stream) by the receiver. This appends
|
||||
the compressed data to the output buffer. */
|
||||
|
||||
void buffer_compress(Buffer *input_buffer, Buffer *output_buffer)
|
||||
void
|
||||
buffer_compress(Buffer * input_buffer, Buffer * output_buffer)
|
||||
{
|
||||
char buf[4096];
|
||||
int status;
|
||||
char buf[4096];
|
||||
int status;
|
||||
|
||||
/* This case is not handled below. */
|
||||
if (buffer_len(input_buffer) == 0)
|
||||
return;
|
||||
/* This case is not handled below. */
|
||||
if (buffer_len(input_buffer) == 0)
|
||||
return;
|
||||
|
||||
/* Input is the contents of the input buffer. */
|
||||
outgoing_stream.next_in = buffer_ptr(input_buffer);
|
||||
outgoing_stream.avail_in = buffer_len(input_buffer);
|
||||
/* Input is the contents of the input buffer. */
|
||||
outgoing_stream.next_in = buffer_ptr(input_buffer);
|
||||
outgoing_stream.avail_in = buffer_len(input_buffer);
|
||||
|
||||
/* Loop compressing until deflate() returns with avail_out != 0. */
|
||||
do
|
||||
{
|
||||
/* Set up fixed-size output buffer. */
|
||||
outgoing_stream.next_out = buf;
|
||||
outgoing_stream.avail_out = sizeof(buf);
|
||||
/* Loop compressing until deflate() returns with avail_out != 0. */
|
||||
do {
|
||||
/* Set up fixed-size output buffer. */
|
||||
outgoing_stream.next_out = buf;
|
||||
outgoing_stream.avail_out = sizeof(buf);
|
||||
|
||||
/* Compress as much data into the buffer as possible. */
|
||||
status = deflate(&outgoing_stream, Z_PARTIAL_FLUSH);
|
||||
switch (status)
|
||||
{
|
||||
case Z_OK:
|
||||
/* Append compressed data to output_buffer. */
|
||||
buffer_append(output_buffer, buf,
|
||||
sizeof(buf) - outgoing_stream.avail_out);
|
||||
break;
|
||||
case Z_STREAM_END:
|
||||
fatal("buffer_compress: deflate returned Z_STREAM_END");
|
||||
/*NOTREACHED*/
|
||||
case Z_STREAM_ERROR:
|
||||
fatal("buffer_compress: deflate returned Z_STREAM_ERROR");
|
||||
/*NOTREACHED*/
|
||||
case Z_BUF_ERROR:
|
||||
fatal("buffer_compress: deflate returned Z_BUF_ERROR");
|
||||
/*NOTREACHED*/
|
||||
default:
|
||||
fatal("buffer_compress: deflate returned %d", status);
|
||||
/*NOTREACHED*/
|
||||
/* Compress as much data into the buffer as possible. */
|
||||
status = deflate(&outgoing_stream, Z_PARTIAL_FLUSH);
|
||||
switch (status) {
|
||||
case Z_OK:
|
||||
/* Append compressed data to output_buffer. */
|
||||
buffer_append(output_buffer, buf,
|
||||
sizeof(buf) - outgoing_stream.avail_out);
|
||||
break;
|
||||
case Z_STREAM_END:
|
||||
fatal("buffer_compress: deflate returned Z_STREAM_END");
|
||||
/* NOTREACHED */
|
||||
case Z_STREAM_ERROR:
|
||||
fatal("buffer_compress: deflate returned Z_STREAM_ERROR");
|
||||
/* NOTREACHED */
|
||||
case Z_BUF_ERROR:
|
||||
fatal("buffer_compress: deflate returned Z_BUF_ERROR");
|
||||
/* NOTREACHED */
|
||||
default:
|
||||
fatal("buffer_compress: deflate returned %d", status);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
}
|
||||
while (outgoing_stream.avail_out == 0);
|
||||
while (outgoing_stream.avail_out == 0);
|
||||
}
|
||||
|
||||
/* Uncompresses the contents of input_buffer into output_buffer. All
|
||||
|
@ -113,48 +114,46 @@ void buffer_compress(Buffer *input_buffer, Buffer *output_buffer)
|
|||
same order that buffers compressed with that. This appends the
|
||||
uncompressed data to the output buffer. */
|
||||
|
||||
void buffer_uncompress(Buffer *input_buffer, Buffer *output_buffer)
|
||||
void
|
||||
buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer)
|
||||
{
|
||||
char buf[4096];
|
||||
int status;
|
||||
char buf[4096];
|
||||
int status;
|
||||
|
||||
incoming_stream.next_in = buffer_ptr(input_buffer);
|
||||
incoming_stream.avail_in = buffer_len(input_buffer);
|
||||
incoming_stream.next_in = buffer_ptr(input_buffer);
|
||||
incoming_stream.avail_in = buffer_len(input_buffer);
|
||||
|
||||
incoming_stream.next_out = buf;
|
||||
incoming_stream.avail_out = sizeof(buf);
|
||||
incoming_stream.next_out = buf;
|
||||
incoming_stream.avail_out = sizeof(buf);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
status = inflate(&incoming_stream, Z_PARTIAL_FLUSH);
|
||||
switch (status)
|
||||
{
|
||||
case Z_OK:
|
||||
buffer_append(output_buffer, buf,
|
||||
sizeof(buf) - incoming_stream.avail_out);
|
||||
incoming_stream.next_out = buf;
|
||||
incoming_stream.avail_out = sizeof(buf);
|
||||
break;
|
||||
case Z_STREAM_END:
|
||||
fatal("buffer_uncompress: inflate returned Z_STREAM_END");
|
||||
/*NOTREACHED*/
|
||||
case Z_DATA_ERROR:
|
||||
fatal("buffer_uncompress: inflate returned Z_DATA_ERROR");
|
||||
/*NOTREACHED*/
|
||||
case Z_STREAM_ERROR:
|
||||
fatal("buffer_uncompress: inflate returned Z_STREAM_ERROR");
|
||||
/*NOTREACHED*/
|
||||
case Z_BUF_ERROR:
|
||||
/* Comments in zlib.h say that we should keep calling inflate()
|
||||
until we get an error. This appears to be the error that we
|
||||
get. */
|
||||
return;
|
||||
case Z_MEM_ERROR:
|
||||
fatal("buffer_uncompress: inflate returned Z_MEM_ERROR");
|
||||
/*NOTREACHED*/
|
||||
default:
|
||||
fatal("buffer_uncompress: inflate returned %d", status);
|
||||
for (;;) {
|
||||
status = inflate(&incoming_stream, Z_PARTIAL_FLUSH);
|
||||
switch (status) {
|
||||
case Z_OK:
|
||||
buffer_append(output_buffer, buf,
|
||||
sizeof(buf) - incoming_stream.avail_out);
|
||||
incoming_stream.next_out = buf;
|
||||
incoming_stream.avail_out = sizeof(buf);
|
||||
break;
|
||||
case Z_STREAM_END:
|
||||
fatal("buffer_uncompress: inflate returned Z_STREAM_END");
|
||||
/* NOTREACHED */
|
||||
case Z_DATA_ERROR:
|
||||
fatal("buffer_uncompress: inflate returned Z_DATA_ERROR");
|
||||
/* NOTREACHED */
|
||||
case Z_STREAM_ERROR:
|
||||
fatal("buffer_uncompress: inflate returned Z_STREAM_ERROR");
|
||||
/* NOTREACHED */
|
||||
case Z_BUF_ERROR:
|
||||
/* Comments in zlib.h say that we should keep
|
||||
calling inflate() until we get an error. This
|
||||
appears to be the error that we get. */
|
||||
return;
|
||||
case Z_MEM_ERROR:
|
||||
fatal("buffer_uncompress: inflate returned Z_MEM_ERROR");
|
||||
/* NOTREACHED */
|
||||
default:
|
||||
fatal("buffer_uncompress: inflate returned %d", status);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
38
compress.h
38
compress.h
|
@ -1,29 +1,29 @@
|
|||
/*
|
||||
*
|
||||
* compress.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Wed Oct 25 22:12:46 1995 ylo
|
||||
*
|
||||
* Interface to packet compression for ssh.
|
||||
*
|
||||
*/
|
||||
|
||||
compress.h
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Wed Oct 25 22:12:46 1995 ylo
|
||||
|
||||
Interface to packet compression for ssh.
|
||||
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: compress.h,v 1.1 1999/10/27 03:42:44 damien Exp $"); */
|
||||
/* RCSID("$Id: compress.h,v 1.2 1999/11/24 13:26:22 damien Exp $"); */
|
||||
|
||||
#ifndef COMPRESS_H
|
||||
#define COMPRESS_H
|
||||
|
||||
/* Initializes compression; level is compression level from 1 to 9 (as in
|
||||
gzip). */
|
||||
void buffer_compress_init(int level);
|
||||
void buffer_compress_init(int level);
|
||||
|
||||
/* Frees any data structures allocated by buffer_compress_init. */
|
||||
void buffer_compress_uninit();
|
||||
void buffer_compress_uninit();
|
||||
|
||||
/* Compresses the contents of input_buffer into output_buffer. All
|
||||
packets compressed using this function will form a single
|
||||
|
@ -32,7 +32,7 @@ void buffer_compress_uninit();
|
|||
independently (but in the appropriate order since they together
|
||||
form a single compression stream) by the receiver. This appends
|
||||
the compressed data to the output buffer. */
|
||||
void buffer_compress(Buffer *input_buffer, Buffer *output_buffer);
|
||||
void buffer_compress(Buffer * input_buffer, Buffer * output_buffer);
|
||||
|
||||
/* Uncompresses the contents of input_buffer into output_buffer. All
|
||||
packets uncompressed using this function will form a single
|
||||
|
@ -41,6 +41,6 @@ void buffer_compress(Buffer *input_buffer, Buffer *output_buffer);
|
|||
same size units that the buffer_compress was called, and in the
|
||||
same order that buffers compressed with that. This appends the
|
||||
uncompressed data to the output buffer. */
|
||||
void buffer_uncompress(Buffer *input_buffer, Buffer *output_buffer);
|
||||
void buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer);
|
||||
|
||||
#endif /* COMPRESS_H */
|
||||
#endif /* COMPRESS_H */
|
||||
|
|
|
@ -55,7 +55,7 @@ AC_CHECK_LIB(dl, dlopen, , )
|
|||
AC_CHECK_LIB(pam, pam_authenticate, , )
|
||||
|
||||
dnl Checks for header files.
|
||||
AC_CHECK_HEADERS(pty.h endian.h paths.h lastlog.h shadow.h netgroup.h maillock.h utmp.h sys/select.h sys/time.h)
|
||||
AC_CHECK_HEADERS(pty.h endian.h paths.h lastlog.h shadow.h netgroup.h maillock.h utmp.h util.h sys/select.h sys/time.h)
|
||||
|
||||
dnl Checks for library functions.
|
||||
AC_CHECK_FUNCS(openpty strlcpy strlcat mkdtemp arc4random setproctitle setlogin setenv)
|
||||
|
|
139
crc32.c
139
crc32.c
|
@ -1,9 +1,12 @@
|
|||
/* The implementation here was originally done by Gary S. Brown. I have
|
||||
borrowed the tables directly, and made some minor changes to the
|
||||
crc32-function (including changing the interface). //ylo */
|
||||
/*
|
||||
* The implementation here was originally done by Gary S. Brown.
|
||||
* I have borrowed the tables directly, and made some minor changes
|
||||
* to the crc32-function (including changing the interface).
|
||||
* //ylo
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: crc32.c,v 1.1 1999/10/27 03:42:44 damien Exp $");
|
||||
RCSID("$Id: crc32.c,v 1.2 1999/11/24 13:26:22 damien Exp $");
|
||||
|
||||
#include "crc32.h"
|
||||
|
||||
|
@ -48,73 +51,71 @@ RCSID("$Id: crc32.c,v 1.1 1999/10/27 03:42:44 damien Exp $");
|
|||
/* -------------------------------------------------------------------- */
|
||||
|
||||
static unsigned int crc32_tab[] = {
|
||||
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
|
||||
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
|
||||
0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
|
||||
0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
|
||||
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
|
||||
0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
|
||||
0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
|
||||
0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
|
||||
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
|
||||
0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
|
||||
0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
|
||||
0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
|
||||
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
|
||||
0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
|
||||
0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
|
||||
0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
|
||||
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
|
||||
0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
|
||||
0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
|
||||
0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
|
||||
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
|
||||
0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
|
||||
0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
|
||||
0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
|
||||
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
|
||||
0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
|
||||
0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
|
||||
0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
|
||||
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
|
||||
0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
|
||||
0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
|
||||
0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
|
||||
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
|
||||
0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
|
||||
0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
|
||||
0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
|
||||
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
|
||||
0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
|
||||
0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
|
||||
0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
|
||||
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
|
||||
0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
|
||||
0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
|
||||
0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
|
||||
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
|
||||
0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
|
||||
0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
|
||||
0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
|
||||
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
|
||||
0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
|
||||
0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
|
||||
0x2d02ef8dL
|
||||
};
|
||||
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
|
||||
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
|
||||
0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
|
||||
0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
|
||||
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
|
||||
0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
|
||||
0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
|
||||
0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
|
||||
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
|
||||
0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
|
||||
0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
|
||||
0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
|
||||
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
|
||||
0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
|
||||
0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
|
||||
0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
|
||||
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
|
||||
0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
|
||||
0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
|
||||
0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
|
||||
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
|
||||
0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
|
||||
0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
|
||||
0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
|
||||
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
|
||||
0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
|
||||
0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
|
||||
0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
|
||||
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
|
||||
0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
|
||||
0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
|
||||
0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
|
||||
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
|
||||
0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
|
||||
0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
|
||||
0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
|
||||
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
|
||||
0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
|
||||
0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
|
||||
0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
|
||||
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
|
||||
0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
|
||||
0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
|
||||
0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
|
||||
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
|
||||
0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
|
||||
0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
|
||||
0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
|
||||
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
|
||||
0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
|
||||
0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
|
||||
0x2d02ef8dL
|
||||
};
|
||||
|
||||
/* Return a 32-bit CRC of the contents of the buffer. */
|
||||
|
||||
unsigned int crc32(const unsigned char *s, unsigned int len)
|
||||
unsigned int
|
||||
crc32(const unsigned char *s, unsigned int len)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int crc32val;
|
||||
|
||||
crc32val = 0;
|
||||
for (i = 0; i < len; i ++)
|
||||
{
|
||||
crc32val =
|
||||
crc32_tab[(crc32val ^ s[i]) & 0xff] ^
|
||||
(crc32val >> 8);
|
||||
}
|
||||
return crc32val;
|
||||
unsigned int i;
|
||||
unsigned int crc32val;
|
||||
|
||||
crc32val = 0;
|
||||
for (i = 0; i < len; i ++) {
|
||||
crc32val = crc32_tab[(crc32val ^ s[i]) & 0xff] ^ (crc32val >> 8);
|
||||
}
|
||||
return crc32val;
|
||||
}
|
||||
|
|
30
crc32.h
30
crc32.h
|
@ -1,19 +1,19 @@
|
|||
/*
|
||||
*
|
||||
* crc32.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1992 Tatu Ylonen, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Tue Feb 11 14:37:27 1992 ylo
|
||||
*
|
||||
* Functions for computing 32-bit CRC.
|
||||
*
|
||||
*/
|
||||
|
||||
crc32.h
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1992 Tatu Ylonen, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Tue Feb 11 14:37:27 1992 ylo
|
||||
|
||||
Functions for computing 32-bit CRC.
|
||||
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: crc32.h,v 1.1 1999/10/27 03:42:44 damien Exp $"); */
|
||||
/* RCSID("$Id: crc32.h,v 1.2 1999/11/24 13:26:22 damien Exp $"); */
|
||||
|
||||
#ifndef CRC32_H
|
||||
#define CRC32_H
|
||||
|
@ -22,4 +22,4 @@ Functions for computing 32-bit CRC.
|
|||
CRC. The polynomial used is 0xedb88320. */
|
||||
unsigned int crc32(const unsigned char *buf, unsigned int len);
|
||||
|
||||
#endif /* CRC32_H */
|
||||
#endif /* CRC32_H */
|
||||
|
|
230
deattack.c
230
deattack.c
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* $Id: deattack.c,v 1.2 1999/11/08 05:15:55 damien Exp $
|
||||
* $Id: deattack.c,v 1.3 1999/11/24 13:26:22 damien Exp $
|
||||
* Cryptographic attack detector for ssh - source code
|
||||
*
|
||||
* Copyright (c) 1998 CORE SDI S.A., Buenos Aires, Argentina.
|
||||
|
@ -15,7 +15,8 @@
|
|||
* SOFTWARE.
|
||||
*
|
||||
* Ariel Futoransky <futo@core-sdi.com>
|
||||
* <http://www.core-sdi.com> */
|
||||
* <http://www.core-sdi.com>
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "deattack.h"
|
||||
|
@ -25,157 +26,130 @@
|
|||
#include "xmalloc.h"
|
||||
|
||||
/* SSH Constants */
|
||||
#define SSH_MAXBLOCKS (32 * 1024)
|
||||
#define SSH_BLOCKSIZE (8)
|
||||
#define SSH_MAXBLOCKS (32 * 1024)
|
||||
#define SSH_BLOCKSIZE (8)
|
||||
|
||||
/* Hashing constants */
|
||||
#define HASH_MINSIZE (8 * 1024)
|
||||
#define HASH_ENTRYSIZE (2)
|
||||
#define HASH_FACTOR(x) ((x)*3/2)
|
||||
#define HASH_UNUSEDCHAR (0xff)
|
||||
#define HASH_UNUSED (0xffff)
|
||||
#define HASH_IV (0xfffe)
|
||||
#define HASH_MINSIZE (8 * 1024)
|
||||
#define HASH_ENTRYSIZE (2)
|
||||
#define HASH_FACTOR(x) ((x)*3/2)
|
||||
#define HASH_UNUSEDCHAR (0xff)
|
||||
#define HASH_UNUSED (0xffff)
|
||||
#define HASH_IV (0xfffe)
|
||||
|
||||
#define HASH_MINBLOCKS (7*SSH_BLOCKSIZE)
|
||||
#define HASH_MINBLOCKS (7*SSH_BLOCKSIZE)
|
||||
|
||||
|
||||
/* Hash function (Input keys are cipher results) */
|
||||
#define HASH(x) GET_32BIT(x)
|
||||
#define HASH(x) GET_32BIT(x)
|
||||
|
||||
#define CMP(a,b) (memcmp(a, b, SSH_BLOCKSIZE))
|
||||
#define CMP(a,b) (memcmp(a, b, SSH_BLOCKSIZE))
|
||||
|
||||
|
||||
void
|
||||
crc_update(u_int32_t * a, u_int32_t b)
|
||||
crc_update(u_int32_t *a, u_int32_t b)
|
||||
{
|
||||
b ^= *a;
|
||||
*a = crc32((unsigned char *) &b, sizeof(b));
|
||||
b ^= *a;
|
||||
*a = crc32((unsigned char *) &b, sizeof(b));
|
||||
}
|
||||
|
||||
/*
|
||||
check_crc
|
||||
detects if a block is used in a particular pattern
|
||||
*/
|
||||
|
||||
/* detect if a block is used in a particular pattern */
|
||||
int
|
||||
check_crc(unsigned char *S, unsigned char *buf, u_int32_t len, unsigned char *IV)
|
||||
check_crc(unsigned char *S, unsigned char *buf, u_int32_t len,
|
||||
unsigned char *IV)
|
||||
{
|
||||
u_int32_t crc;
|
||||
unsigned char *c;
|
||||
u_int32_t crc;
|
||||
unsigned char *c;
|
||||
|
||||
crc = 0;
|
||||
if (IV && !CMP(S, IV))
|
||||
{
|
||||
crc_update(&crc, 1);
|
||||
crc_update(&crc, 0);
|
||||
}
|
||||
for (c = buf; c < buf + len; c += SSH_BLOCKSIZE)
|
||||
{
|
||||
if (!CMP(S, c))
|
||||
{
|
||||
crc_update(&crc, 1);
|
||||
crc_update(&crc, 0);
|
||||
} else
|
||||
{
|
||||
crc_update(&crc, 0);
|
||||
crc_update(&crc, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return (crc == 0);
|
||||
crc = 0;
|
||||
if (IV && !CMP(S, IV)) {
|
||||
crc_update(&crc, 1);
|
||||
crc_update(&crc, 0);
|
||||
}
|
||||
for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) {
|
||||
if (!CMP(S, c)) {
|
||||
crc_update(&crc, 1);
|
||||
crc_update(&crc, 0);
|
||||
} else {
|
||||
crc_update(&crc, 0);
|
||||
crc_update(&crc, 0);
|
||||
}
|
||||
}
|
||||
return (crc == 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
detect_attack
|
||||
Detects a crc32 compensation attack on a packet
|
||||
*/
|
||||
/* Detect a crc32 compensation attack on a packet */
|
||||
int
|
||||
detect_attack(unsigned char *buf, u_int32_t len, unsigned char *IV)
|
||||
{
|
||||
static u_int16_t *h = (u_int16_t *) NULL;
|
||||
static u_int16_t n = HASH_MINSIZE / HASH_ENTRYSIZE;
|
||||
register u_int32_t i, j;
|
||||
u_int32_t l;
|
||||
register unsigned char *c;
|
||||
unsigned char *d;
|
||||
static u_int16_t *h = (u_int16_t *) NULL;
|
||||
static u_int16_t n = HASH_MINSIZE / HASH_ENTRYSIZE;
|
||||
register u_int32_t i, j;
|
||||
u_int32_t l;
|
||||
register unsigned char *c;
|
||||
unsigned char *d;
|
||||
|
||||
if (len > (SSH_MAXBLOCKS * SSH_BLOCKSIZE) ||
|
||||
len % SSH_BLOCKSIZE != 0) {
|
||||
fatal("detect_attack: bad length %d", len);
|
||||
}
|
||||
|
||||
for (l = n; l < HASH_FACTOR(len / SSH_BLOCKSIZE); l = l << 2);
|
||||
|
||||
if (h == NULL)
|
||||
{
|
||||
debug("Installing crc compensation attack detector.");
|
||||
n = l;
|
||||
h = (u_int16_t *) xmalloc(n * HASH_ENTRYSIZE);
|
||||
} else
|
||||
{
|
||||
if (l > n)
|
||||
{
|
||||
n = l;
|
||||
h = (u_int16_t *) xrealloc(h, n * HASH_ENTRYSIZE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (len <= HASH_MINBLOCKS)
|
||||
{
|
||||
for (c = buf; c < buf + len; c += SSH_BLOCKSIZE)
|
||||
{
|
||||
if (IV && (!CMP(c, IV)))
|
||||
{
|
||||
if ((check_crc(c, buf, len, IV)))
|
||||
return (DEATTACK_DETECTED);
|
||||
else
|
||||
break;
|
||||
}
|
||||
for (d = buf; d < c; d += SSH_BLOCKSIZE)
|
||||
{
|
||||
if (!CMP(c, d))
|
||||
{
|
||||
if ((check_crc(c, buf, len, IV)))
|
||||
return (DEATTACK_DETECTED);
|
||||
else
|
||||
break;
|
||||
if (len > (SSH_MAXBLOCKS * SSH_BLOCKSIZE) ||
|
||||
len % SSH_BLOCKSIZE != 0) {
|
||||
fatal("detect_attack: bad length %d", len);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (DEATTACK_OK);
|
||||
}
|
||||
memset(h, HASH_UNUSEDCHAR, n * HASH_ENTRYSIZE);
|
||||
for (l = n; l < HASH_FACTOR(len / SSH_BLOCKSIZE); l = l << 2)
|
||||
;
|
||||
|
||||
if (IV)
|
||||
h[HASH(IV) & (n - 1)] = HASH_IV;
|
||||
|
||||
|
||||
for (c = buf, j = 0; c < (buf + len); c += SSH_BLOCKSIZE, j++)
|
||||
{
|
||||
for (i = HASH(c) & (n - 1); h[i] != HASH_UNUSED;
|
||||
i = (i + 1) & (n - 1))
|
||||
{
|
||||
if (h[i] == HASH_IV)
|
||||
{
|
||||
if (!CMP(c, IV))
|
||||
{
|
||||
if (check_crc(c, buf, len, IV))
|
||||
return (DEATTACK_DETECTED);
|
||||
else
|
||||
break;
|
||||
if (h == NULL) {
|
||||
debug("Installing crc compensation attack detector.");
|
||||
n = l;
|
||||
h = (u_int16_t *) xmalloc(n * HASH_ENTRYSIZE);
|
||||
} else {
|
||||
if (l > n) {
|
||||
n = l;
|
||||
h = (u_int16_t *) xrealloc(h, n * HASH_ENTRYSIZE);
|
||||
}
|
||||
}
|
||||
} else if (!CMP(c, buf + h[i] * SSH_BLOCKSIZE))
|
||||
{
|
||||
if (check_crc(c, buf, len, IV))
|
||||
return (DEATTACK_DETECTED);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
h[i] = j;
|
||||
}
|
||||
|
||||
return (DEATTACK_OK);
|
||||
if (len <= HASH_MINBLOCKS) {
|
||||
for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) {
|
||||
if (IV && (!CMP(c, IV))) {
|
||||
if ((check_crc(c, buf, len, IV)))
|
||||
return (DEATTACK_DETECTED);
|
||||
else
|
||||
break;
|
||||
}
|
||||
for (d = buf; d < c; d += SSH_BLOCKSIZE) {
|
||||
if (!CMP(c, d)) {
|
||||
if ((check_crc(c, buf, len, IV)))
|
||||
return (DEATTACK_DETECTED);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (DEATTACK_OK);
|
||||
}
|
||||
memset(h, HASH_UNUSEDCHAR, n * HASH_ENTRYSIZE);
|
||||
|
||||
if (IV)
|
||||
h[HASH(IV) & (n - 1)] = HASH_IV;
|
||||
|
||||
for (c = buf, j = 0; c < (buf + len); c += SSH_BLOCKSIZE, j++) {
|
||||
for (i = HASH(c) & (n - 1); h[i] != HASH_UNUSED;
|
||||
i = (i + 1) & (n - 1)) {
|
||||
if (h[i] == HASH_IV) {
|
||||
if (!CMP(c, IV)) {
|
||||
if (check_crc(c, buf, len, IV))
|
||||
return (DEATTACK_DETECTED);
|
||||
else
|
||||
break;
|
||||
}
|
||||
} else if (!CMP(c, buf + h[i] * SSH_BLOCKSIZE)) {
|
||||
if (check_crc(c, buf, len, IV))
|
||||
return (DEATTACK_DETECTED);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
h[i] = j;
|
||||
}
|
||||
return (DEATTACK_OK);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $Id: deattack.h,v 1.1 1999/10/27 03:42:44 damien Exp $
|
||||
/*
|
||||
* Cryptographic attack detector for ssh - Header file
|
||||
*
|
||||
* Copyright (c) 1998 CORE SDI S.A., Buenos Aires, Argentina.
|
||||
|
@ -14,7 +14,8 @@
|
|||
* SOFTWARE.
|
||||
*
|
||||
* Ariel Futoransky <futo@core-sdi.com>
|
||||
* <http://www.core-sdi.com> */
|
||||
* <http://www.core-sdi.com>
|
||||
*/
|
||||
|
||||
#ifndef _DEATTACK_H
|
||||
#define _DEATTACK_H
|
||||
|
@ -23,5 +24,5 @@
|
|||
#define DEATTACK_OK 0
|
||||
#define DEATTACK_DETECTED 1
|
||||
|
||||
int detect_attack(unsigned char *buf, u_int32_t len, unsigned char IV[8]);
|
||||
int detect_attack(unsigned char *buf, u_int32_t len, unsigned char IV[8]);
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include "includes.h"
|
||||
RCSID("$Id: fingerprint.c,v 1.1 1999/11/17 06:29:08 damien Exp $");
|
||||
RCSID("$Id: fingerprint.c,v 1.3 1999/11/24 00:26:01 deraadt Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "xmalloc.h"
|
||||
|
@ -13,17 +13,18 @@ RCSID("$Id: fingerprint.c,v 1.1 1999/11/17 06:29:08 damien Exp $");
|
|||
|
||||
#define FPRINT "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
|
||||
|
||||
/* Generate key fingerprint in ascii format.
|
||||
Based on ideas and code from Bjoern Groenvall <bg@sics.se> */
|
||||
|
||||
/*
|
||||
* Generate key fingerprint in ascii format.
|
||||
* Based on ideas and code from Bjoern Groenvall <bg@sics.se>
|
||||
*/
|
||||
char *
|
||||
fingerprint(BIGNUM *e, BIGNUM *n)
|
||||
{
|
||||
static char retval[80];
|
||||
MD5_CTX md;
|
||||
unsigned char d[16];
|
||||
char *buf;
|
||||
int nlen, elen;
|
||||
static char retval[80];
|
||||
MD5_CTX md;
|
||||
unsigned char d[16];
|
||||
char *buf;
|
||||
int nlen, elen;
|
||||
|
||||
nlen = BN_num_bytes(n);
|
||||
elen = BN_num_bytes(e);
|
||||
|
@ -37,8 +38,8 @@ fingerprint(BIGNUM *e, BIGNUM *n)
|
|||
MD5_Update(&md, buf, nlen + elen);
|
||||
MD5_Final(d, &md);
|
||||
snprintf(retval, sizeof(retval), FPRINT,
|
||||
d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7],
|
||||
d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
|
||||
d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7],
|
||||
d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
|
||||
memset(buf, 0, nlen + elen);
|
||||
xfree(buf);
|
||||
return retval;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* RCSID("$Id: fingerprint.h,v 1.1 1999/11/16 22:49:28 markus Exp $"); */
|
||||
/* RCSID("$Id: fingerprint.h,v 1.2 1999/11/24 00:26:02 deraadt Exp $"); */
|
||||
|
||||
#ifndef FINGERPRINT_H
|
||||
#define FINGERPRINT_H
|
||||
char * fingerprint(BIGNUM *e, BIGNUM *n);
|
||||
char *fingerprint(BIGNUM * e, BIGNUM * n);
|
||||
#endif
|
||||
|
|
31
getput.h
31
getput.h
|
@ -1,19 +1,19 @@
|
|||
/*
|
||||
*
|
||||
* getput.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Wed Jun 28 22:36:30 1995 ylo
|
||||
*
|
||||
* Macros for storing and retrieving data in msb first and lsb first order.
|
||||
*
|
||||
*/
|
||||
|
||||
getput.h
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Wed Jun 28 22:36:30 1995 ylo
|
||||
|
||||
Macros for storing and retrieving data in msb first and lsb first order.
|
||||
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: getput.h,v 1.1 1999/10/27 03:42:44 damien Exp $"); */
|
||||
/* RCSID("$Id: getput.h,v 1.2 1999/11/24 13:26:22 damien Exp $"); */
|
||||
|
||||
#ifndef GETPUT_H
|
||||
#define GETPUT_H
|
||||
|
@ -60,5 +60,4 @@ Macros for storing and retrieving data in msb first and lsb first order.
|
|||
(cp)[0] = (value); \
|
||||
(cp)[1] = (value) >> 8; } while (0)
|
||||
|
||||
#endif /* GETPUT_H */
|
||||
|
||||
#endif /* GETPUT_H */
|
||||
|
|
417
hostfile.c
417
hostfile.c
|
@ -1,20 +1,20 @@
|
|||
/*
|
||||
|
||||
hostfile.c
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Thu Jun 29 07:10:56 1995 ylo
|
||||
|
||||
Functions for manipulating the known hosts files.
|
||||
|
||||
*/
|
||||
*
|
||||
* hostfile.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Thu Jun 29 07:10:56 1995 ylo
|
||||
*
|
||||
* Functions for manipulating the known hosts files.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: hostfile.c,v 1.4 1999/11/17 06:29:08 damien Exp $");
|
||||
RCSID("$Id: hostfile.c,v 1.5 1999/11/24 13:26:22 damien Exp $");
|
||||
|
||||
#include "packet.h"
|
||||
#include "ssh.h"
|
||||
|
@ -26,140 +26,136 @@ RCSID("$Id: hostfile.c,v 1.4 1999/11/17 06:29:08 damien Exp $");
|
|||
modify the buffer containing the number. */
|
||||
|
||||
int
|
||||
auth_rsa_read_bignum(char **cpp, BIGNUM *value)
|
||||
auth_rsa_read_bignum(char **cpp, BIGNUM * value)
|
||||
{
|
||||
char *cp = *cpp;
|
||||
int len, old;
|
||||
char *cp = *cpp;
|
||||
int len, old;
|
||||
|
||||
/* Skip any leading whitespace. */
|
||||
for (; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
/* Skip any leading whitespace. */
|
||||
for (; *cp == ' ' || *cp == '\t'; cp++);
|
||||
|
||||
/* Check that it begins with a hex digit. */
|
||||
if (*cp < '0' || *cp > '9')
|
||||
return 0;
|
||||
/* Check that it begins with a hex digit. */
|
||||
if (*cp < '0' || *cp > '9')
|
||||
return 0;
|
||||
|
||||
/* Save starting position. */
|
||||
*cpp = cp;
|
||||
/* Save starting position. */
|
||||
*cpp = cp;
|
||||
|
||||
/* Move forward until all hex digits skipped. */
|
||||
for (; *cp >= '0' && *cp <= '9'; cp++)
|
||||
;
|
||||
/* Move forward until all hex digits skipped. */
|
||||
for (; *cp >= '0' && *cp <= '9'; cp++);
|
||||
|
||||
/* Compute the length of the hex number. */
|
||||
len = cp - *cpp;
|
||||
/* Compute the length of the hex number. */
|
||||
len = cp - *cpp;
|
||||
|
||||
/* Save the old terminating character, and replace it by \0. */
|
||||
old = *cp;
|
||||
*cp = 0;
|
||||
/* Save the old terminating character, and replace it by \0. */
|
||||
old = *cp;
|
||||
*cp = 0;
|
||||
|
||||
|
||||
/* Parse the number. */
|
||||
if (BN_dec2bn(&value, *cpp) == 0)
|
||||
return 0;
|
||||
|
||||
/* Restore old terminating character. */
|
||||
*cp = old;
|
||||
/* Parse the number. */
|
||||
if (BN_dec2bn(&value, *cpp) == 0)
|
||||
return 0;
|
||||
|
||||
/* Move beyond the number and return success. */
|
||||
*cpp = cp;
|
||||
return 1;
|
||||
/* Restore old terminating character. */
|
||||
*cp = old;
|
||||
|
||||
/* Move beyond the number and return success. */
|
||||
*cpp = cp;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 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, unsigned int *bitsp, BIGNUM *e, BIGNUM *n)
|
||||
auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n)
|
||||
{
|
||||
unsigned int bits;
|
||||
char *cp;
|
||||
unsigned int bits;
|
||||
char *cp;
|
||||
|
||||
/* Skip leading whitespace. */
|
||||
for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
/* Skip leading whitespace. */
|
||||
for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++);
|
||||
|
||||
/* Get number of bits. */
|
||||
if (*cp < '0' || *cp > '9')
|
||||
return 0; /* Bad bit count... */
|
||||
for (bits = 0; *cp >= '0' && *cp <= '9'; cp++)
|
||||
bits = 10 * bits + *cp - '0';
|
||||
/* Get number of bits. */
|
||||
if (*cp < '0' || *cp > '9')
|
||||
return 0; /* Bad bit count... */
|
||||
for (bits = 0; *cp >= '0' && *cp <= '9'; cp++)
|
||||
bits = 10 * bits + *cp - '0';
|
||||
|
||||
/* Get public exponent. */
|
||||
if (!auth_rsa_read_bignum(&cp, e))
|
||||
return 0;
|
||||
/* Get public exponent. */
|
||||
if (!auth_rsa_read_bignum(&cp, e))
|
||||
return 0;
|
||||
|
||||
/* Get public modulus. */
|
||||
if (!auth_rsa_read_bignum(&cp, n))
|
||||
return 0;
|
||||
/* Get public modulus. */
|
||||
if (!auth_rsa_read_bignum(&cp, n))
|
||||
return 0;
|
||||
|
||||
/* Skip trailing whitespace. */
|
||||
for (; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
|
||||
/* Return results. */
|
||||
*cpp = cp;
|
||||
*bitsp = bits;
|
||||
return 1;
|
||||
/* Skip trailing whitespace. */
|
||||
for (; *cp == ' ' || *cp == '\t'; cp++);
|
||||
|
||||
/* Return results. */
|
||||
*cpp = cp;
|
||||
*bitsp = bits;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Tries to match the host name (which must be in all lowercase) against the
|
||||
comma-separated sequence of subpatterns (each possibly preceded by ! to
|
||||
comma-separated sequence of subpatterns (each possibly preceded by ! to
|
||||
indicate negation). Returns true if there is a positive match; zero
|
||||
otherwise. */
|
||||
|
||||
int
|
||||
match_hostname(const char *host, const char *pattern, unsigned int len)
|
||||
{
|
||||
char sub[1024];
|
||||
int negated;
|
||||
int got_positive;
|
||||
unsigned int i, subi;
|
||||
char sub[1024];
|
||||
int negated;
|
||||
int got_positive;
|
||||
unsigned int i, subi;
|
||||
|
||||
got_positive = 0;
|
||||
for (i = 0; i < len;)
|
||||
{
|
||||
/* Check if the subpattern is negated. */
|
||||
if (pattern[i] == '!')
|
||||
{
|
||||
negated = 1;
|
||||
i++;
|
||||
got_positive = 0;
|
||||
for (i = 0; i < len;) {
|
||||
/* Check if the subpattern is negated. */
|
||||
if (pattern[i] == '!') {
|
||||
negated = 1;
|
||||
i++;
|
||||
} else
|
||||
negated = 0;
|
||||
|
||||
/* Extract the subpattern up to a comma or end. Convert
|
||||
the subpattern to lowercase. */
|
||||
for (subi = 0;
|
||||
i < len && subi < sizeof(sub) - 1 && pattern[i] != ',';
|
||||
subi++, i++)
|
||||
sub[subi] = isupper(pattern[i]) ? tolower(pattern[i]) : pattern[i];
|
||||
/* If subpattern too long, return failure (no match). */
|
||||
if (subi >= sizeof(sub) - 1)
|
||||
return 0;
|
||||
|
||||
/* If the subpattern was terminated by a comma, skip the
|
||||
comma. */
|
||||
if (i < len && pattern[i] == ',')
|
||||
i++;
|
||||
|
||||
/* Null-terminate the subpattern. */
|
||||
sub[subi] = '\0';
|
||||
|
||||
/* Try to match the subpattern against the host name. */
|
||||
if (match_pattern(host, sub)) {
|
||||
if (negated)
|
||||
return 0; /* Fail if host matches
|
||||
any negated subpattern. */
|
||||
else
|
||||
got_positive = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
negated = 0;
|
||||
|
||||
/* Extract the subpattern up to a comma or end. Convert the subpattern
|
||||
to lowercase. */
|
||||
for (subi = 0;
|
||||
i < len && subi < sizeof(sub) - 1 && pattern[i] != ',';
|
||||
subi++, i++)
|
||||
sub[subi] = isupper(pattern[i]) ? tolower(pattern[i]) : pattern[i];
|
||||
/* If subpattern too long, return failure (no match). */
|
||||
if (subi >= sizeof(sub) - 1)
|
||||
return 0;
|
||||
|
||||
/* If the subpattern was terminated by a comma, skip the comma. */
|
||||
if (i < len && pattern[i] == ',')
|
||||
i++;
|
||||
|
||||
/* Null-terminate the subpattern. */
|
||||
sub[subi] = '\0';
|
||||
|
||||
/* Try to match the subpattern against the host name. */
|
||||
if (match_pattern(host, sub)) {
|
||||
if (negated)
|
||||
return 0; /* Fail if host matches any negated subpattern. */
|
||||
else
|
||||
got_positive = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return success if got a positive match. If there was a negative match,
|
||||
we have already returned zero and never get here. */
|
||||
return got_positive;
|
||||
/* Return success if got a positive match. If there was a
|
||||
negative match, we have already returned zero and never get
|
||||
here. */
|
||||
return got_positive;
|
||||
}
|
||||
|
||||
/* Checks whether the given host (which must be in all lowercase) is
|
||||
/* Checks whether the given host (which must be in all lowercase) is
|
||||
already in the list of our known hosts.
|
||||
Returns HOST_OK if the host is known and has the specified key,
|
||||
HOST_NEW if the host is not known, and HOST_CHANGED if the host is known
|
||||
|
@ -167,87 +163,82 @@ match_hostname(const char *host, const char *pattern, unsigned int len)
|
|||
|
||||
HostStatus
|
||||
check_host_in_hostfile(const char *filename, const char *host,
|
||||
BIGNUM *e, BIGNUM *n, BIGNUM *ke, BIGNUM *kn)
|
||||
BIGNUM * e, BIGNUM * n, BIGNUM * ke, BIGNUM * kn)
|
||||
{
|
||||
FILE *f;
|
||||
char line[8192];
|
||||
int linenum = 0;
|
||||
unsigned int bits, kbits, hostlen;
|
||||
char *cp, *cp2;
|
||||
HostStatus end_return;
|
||||
FILE *f;
|
||||
char line[8192];
|
||||
int linenum = 0;
|
||||
unsigned int bits, kbits, hostlen;
|
||||
char *cp, *cp2;
|
||||
HostStatus end_return;
|
||||
|
||||
/* Open the file containing the list of known hosts. */
|
||||
f = fopen(filename, "r");
|
||||
if (!f)
|
||||
return HOST_NEW;
|
||||
/* Open the file containing the list of known hosts. */
|
||||
f = fopen(filename, "r");
|
||||
if (!f)
|
||||
return HOST_NEW;
|
||||
|
||||
/* Cache the length of the host name. */
|
||||
hostlen = strlen(host);
|
||||
|
||||
/* Return value when the loop terminates. This is set to HOST_CHANGED if
|
||||
we have seen a different key for the host and have not found the proper
|
||||
one. */
|
||||
end_return = HOST_NEW;
|
||||
/* Cache the length of the host name. */
|
||||
hostlen = strlen(host);
|
||||
|
||||
/* size of modulus 'n' */
|
||||
bits = BN_num_bits(n);
|
||||
/* Return value when the loop terminates. This is set to
|
||||
HOST_CHANGED if we have seen a different key for the host and
|
||||
have not found the proper one. */
|
||||
end_return = HOST_NEW;
|
||||
|
||||
/* Go trough the file. */
|
||||
while (fgets(line, sizeof(line), f))
|
||||
{
|
||||
cp = line;
|
||||
linenum++;
|
||||
/* size of modulus 'n' */
|
||||
bits = BN_num_bits(n);
|
||||
|
||||
/* Skip any leading whitespace. */
|
||||
for (; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
/* Go trough the file. */
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
cp = line;
|
||||
linenum++;
|
||||
|
||||
/* Ignore comment lines and empty lines. */
|
||||
if (!*cp || *cp == '#' || *cp == '\n')
|
||||
continue;
|
||||
|
||||
/* Find the end of the host name portion. */
|
||||
for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++)
|
||||
;
|
||||
/* Skip any leading whitespace. */
|
||||
for (; *cp == ' ' || *cp == '\t'; cp++);
|
||||
|
||||
/* Check if the host name matches. */
|
||||
if (!match_hostname(host, cp, (unsigned int)(cp2 - cp)))
|
||||
continue;
|
||||
|
||||
/* Got a match. Skip host name. */
|
||||
cp = cp2;
|
||||
|
||||
/* Extract the key from the line. This will skip any leading
|
||||
whitespace. Ignore badly formatted lines. */
|
||||
if (!auth_rsa_read_key(&cp, &kbits, ke, kn))
|
||||
continue;
|
||||
/* Ignore comment lines and empty lines. */
|
||||
if (!*cp || *cp == '#' || *cp == '\n')
|
||||
continue;
|
||||
|
||||
if (kbits != BN_num_bits(kn)) {
|
||||
error("Warning: error in %s, line %d: keysize mismatch for host %s: "
|
||||
"actual size %d vs. announced %d.",
|
||||
filename, linenum, host, BN_num_bits(kn), kbits);
|
||||
error("Warning: replace %d with %d in %s, line %d.",
|
||||
kbits, BN_num_bits(kn), filename, linenum);
|
||||
}
|
||||
/* Find the end of the host name portion. */
|
||||
for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++);
|
||||
|
||||
/* Check if the current key is the same as the given key. */
|
||||
if (BN_cmp(ke, e) == 0 && BN_cmp(kn, n) == 0)
|
||||
{
|
||||
/* Ok, they match. */
|
||||
fclose(f);
|
||||
return HOST_OK;
|
||||
/* Check if the host name matches. */
|
||||
if (!match_hostname(host, cp, (unsigned int) (cp2 - cp)))
|
||||
continue;
|
||||
|
||||
/* Got a match. Skip host name. */
|
||||
cp = cp2;
|
||||
|
||||
/* Extract the key from the line. This will skip any
|
||||
leading whitespace. Ignore badly formatted lines. */
|
||||
if (!auth_rsa_read_key(&cp, &kbits, ke, kn))
|
||||
continue;
|
||||
|
||||
if (kbits != BN_num_bits(kn)) {
|
||||
error("Warning: error in %s, line %d: keysize mismatch for host %s: "
|
||||
"actual size %d vs. announced %d.",
|
||||
filename, linenum, host, BN_num_bits(kn), kbits);
|
||||
error("Warning: replace %d with %d in %s, line %d.",
|
||||
kbits, BN_num_bits(kn), filename, linenum);
|
||||
}
|
||||
/* Check if the current key is the same as the given key. */
|
||||
if (BN_cmp(ke, e) == 0 && BN_cmp(kn, n) == 0) {
|
||||
/* Ok, they match. */
|
||||
fclose(f);
|
||||
return HOST_OK;
|
||||
}
|
||||
/* They do not match. We will continue to go through the
|
||||
file; however, we note that we will not return that it
|
||||
is new. */
|
||||
end_return = HOST_CHANGED;
|
||||
}
|
||||
|
||||
/* They do not match. We will continue to go through the file; however,
|
||||
we note that we will not return that it is new. */
|
||||
end_return = HOST_CHANGED;
|
||||
}
|
||||
/* Clear variables and close the file. */
|
||||
fclose(f);
|
||||
/* Clear variables and close the file. */
|
||||
fclose(f);
|
||||
|
||||
/* Return either HOST_NEW or HOST_CHANGED, depending on whether we saw a
|
||||
different key for the host. */
|
||||
return end_return;
|
||||
/* Return either HOST_NEW or HOST_CHANGED, depending on whether we
|
||||
saw a different key for the host. */
|
||||
return end_return;
|
||||
}
|
||||
|
||||
/* Appends an entry to the host file. Returns false if the entry
|
||||
|
@ -255,40 +246,40 @@ check_host_in_hostfile(const char *filename, const char *host,
|
|||
|
||||
int
|
||||
add_host_to_hostfile(const char *filename, const char *host,
|
||||
BIGNUM *e, BIGNUM *n)
|
||||
BIGNUM * e, BIGNUM * n)
|
||||
{
|
||||
FILE *f;
|
||||
char *buf;
|
||||
unsigned int bits;
|
||||
|
||||
/* Open the file for appending. */
|
||||
f = fopen(filename, "a");
|
||||
if (!f)
|
||||
return 0;
|
||||
FILE *f;
|
||||
char *buf;
|
||||
unsigned int bits;
|
||||
|
||||
/* size of modulus 'n' */
|
||||
bits = BN_num_bits(n);
|
||||
/* Open the file for appending. */
|
||||
f = fopen(filename, "a");
|
||||
if (!f)
|
||||
return 0;
|
||||
|
||||
/* Print the host name and key to the file. */
|
||||
fprintf(f, "%s %u ", host, bits);
|
||||
buf = BN_bn2dec(e);
|
||||
if (buf == NULL) {
|
||||
error("add_host_to_hostfile: BN_bn2dec(e) failed");
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
fprintf(f, "%s ", buf);
|
||||
free (buf);
|
||||
buf = BN_bn2dec(n);
|
||||
if (buf == NULL) {
|
||||
error("add_host_to_hostfile: BN_bn2dec(n) failed");
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
fprintf(f, "%s\n", buf);
|
||||
free (buf);
|
||||
/* size of modulus 'n' */
|
||||
bits = BN_num_bits(n);
|
||||
|
||||
/* Close the file. */
|
||||
fclose(f);
|
||||
return 1;
|
||||
/* Print the host name and key to the file. */
|
||||
fprintf(f, "%s %u ", host, bits);
|
||||
buf = BN_bn2dec(e);
|
||||
if (buf == NULL) {
|
||||
error("add_host_to_hostfile: BN_bn2dec(e) failed");
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
fprintf(f, "%s ", buf);
|
||||
free(buf);
|
||||
buf = BN_bn2dec(n);
|
||||
if (buf == NULL) {
|
||||
error("add_host_to_hostfile: BN_bn2dec(n) failed");
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
fprintf(f, "%s\n", buf);
|
||||
free(buf);
|
||||
|
||||
/* Close the file. */
|
||||
fclose(f);
|
||||
return 1;
|
||||
}
|
||||
|
|
28
includes.h
28
includes.h
|
@ -1,17 +1,17 @@
|
|||
/*
|
||||
|
||||
includes.h
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Thu Mar 23 16:29:37 1995 ylo
|
||||
|
||||
This file includes most of the needed system headers.
|
||||
|
||||
*/
|
||||
*
|
||||
* includes.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Thu Mar 23 16:29:37 1995 ylo
|
||||
*
|
||||
* This file includes most of the needed system headers.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef INCLUDES_H
|
||||
#define INCLUDES_H
|
||||
|
@ -91,4 +91,4 @@ static /**/const char *const rcsid[] = { (char *)rcsid, "\100(#)" msg }
|
|||
client program. Socketpairs do not seem to work on all systems. */
|
||||
#define USE_PIPES 1
|
||||
|
||||
#endif /* INCLUDES_H */
|
||||
#endif /* INCLUDES_H */
|
||||
|
|
79
log-client.c
79
log-client.c
|
@ -1,21 +1,21 @@
|
|||
/*
|
||||
|
||||
log-client.c
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Mon Mar 20 21:13:40 1995 ylo
|
||||
|
||||
Client-side versions of debug(), log(), etc. These print to stderr.
|
||||
This is a stripped down version of log-server.c.
|
||||
|
||||
*/
|
||||
*
|
||||
* log-client.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Mon Mar 20 21:13:40 1995 ylo
|
||||
*
|
||||
* Client-side versions of debug(), log(), etc. These print to stderr.
|
||||
* This is a stripped down version of log-server.c.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: log-client.c,v 1.2 1999/11/11 06:57:39 damien Exp $");
|
||||
RCSID("$Id: log-client.c,v 1.3 1999/11/24 13:26:22 damien Exp $");
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
|
@ -23,27 +23,26 @@ RCSID("$Id: log-client.c,v 1.2 1999/11/11 06:57:39 damien Exp $");
|
|||
static LogLevel log_level = SYSLOG_LEVEL_INFO;
|
||||
|
||||
/* Initialize the log.
|
||||
av0 program name (should be argv[0])
|
||||
level logging level
|
||||
*/
|
||||
* av0 program name (should be argv[0])
|
||||
* level logging level
|
||||
*/
|
||||
|
||||
void
|
||||
log_init(char *av0, LogLevel level, SyslogFacility ignored1, int ignored2)
|
||||
{
|
||||
switch (level)
|
||||
{
|
||||
case SYSLOG_LEVEL_QUIET:
|
||||
case SYSLOG_LEVEL_ERROR:
|
||||
case SYSLOG_LEVEL_FATAL:
|
||||
case SYSLOG_LEVEL_INFO:
|
||||
case SYSLOG_LEVEL_CHAT:
|
||||
case SYSLOG_LEVEL_DEBUG:
|
||||
log_level = level;
|
||||
break;
|
||||
default:
|
||||
/* unchanged */
|
||||
break;
|
||||
}
|
||||
switch (level) {
|
||||
case SYSLOG_LEVEL_QUIET:
|
||||
case SYSLOG_LEVEL_ERROR:
|
||||
case SYSLOG_LEVEL_FATAL:
|
||||
case SYSLOG_LEVEL_INFO:
|
||||
case SYSLOG_LEVEL_VERBOSE:
|
||||
case SYSLOG_LEVEL_DEBUG:
|
||||
log_level = level;
|
||||
break;
|
||||
default:
|
||||
/* unchanged */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#define MSGBUFSIZE 1024
|
||||
|
@ -51,13 +50,13 @@ log_init(char *av0, LogLevel level, SyslogFacility ignored1, int ignored2)
|
|||
void
|
||||
do_log(LogLevel level, const char *fmt, va_list args)
|
||||
{
|
||||
char msgbuf[MSGBUFSIZE];
|
||||
char msgbuf[MSGBUFSIZE];
|
||||
|
||||
if (level > log_level)
|
||||
return;
|
||||
if (level == SYSLOG_LEVEL_DEBUG)
|
||||
fprintf(stderr, "debug: ");
|
||||
vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
|
||||
fprintf(stderr, "%s", msgbuf);
|
||||
fprintf(stderr, "\r\n");
|
||||
if (level > log_level)
|
||||
return;
|
||||
if (level == SYSLOG_LEVEL_DEBUG)
|
||||
fprintf(stderr, "debug: ");
|
||||
vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
|
||||
fprintf(stderr, "%s", msgbuf);
|
||||
fprintf(stderr, "\r\n");
|
||||
}
|
||||
|
|
236
log-server.c
236
log-server.c
|
@ -1,21 +1,21 @@
|
|||
/*
|
||||
|
||||
log-server.c
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Mon Mar 20 21:19:30 1995 ylo
|
||||
|
||||
Server-side versions of debug(), log(), etc. These normally send the output
|
||||
to the system log.
|
||||
|
||||
*/
|
||||
*
|
||||
* log-server.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Mon Mar 20 21:19:30 1995 ylo
|
||||
*
|
||||
* Server-side versions of debug(), log(), etc. These normally send the output
|
||||
* to the system log.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: log-server.c,v 1.4 1999/11/15 06:10:57 damien Exp $");
|
||||
RCSID("$Id: log-server.c,v 1.5 1999/11/24 13:26:22 damien Exp $");
|
||||
|
||||
#include <syslog.h>
|
||||
#include "packet.h"
|
||||
|
@ -33,72 +33,68 @@ static int log_on_stderr = 0;
|
|||
static int log_facility = LOG_AUTH;
|
||||
|
||||
/* Initialize the log.
|
||||
av0 program name (should be argv[0])
|
||||
on_stderr print also on stderr
|
||||
level logging level
|
||||
*/
|
||||
* av0 program name (should be argv[0])
|
||||
* on_stderr print also on stderr
|
||||
* level logging level
|
||||
*/
|
||||
|
||||
void log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr)
|
||||
void
|
||||
log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr)
|
||||
{
|
||||
|
||||
switch (level)
|
||||
{
|
||||
case SYSLOG_LEVEL_QUIET:
|
||||
case SYSLOG_LEVEL_ERROR:
|
||||
case SYSLOG_LEVEL_FATAL:
|
||||
case SYSLOG_LEVEL_INFO:
|
||||
case SYSLOG_LEVEL_CHAT:
|
||||
case SYSLOG_LEVEL_DEBUG:
|
||||
log_level = level;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unrecognized internal syslog level code %d\n",
|
||||
(int)level);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
switch (facility)
|
||||
{
|
||||
case SYSLOG_FACILITY_DAEMON:
|
||||
log_facility = LOG_DAEMON;
|
||||
break;
|
||||
case SYSLOG_FACILITY_USER:
|
||||
log_facility = LOG_USER;
|
||||
break;
|
||||
case SYSLOG_FACILITY_AUTH:
|
||||
log_facility = LOG_AUTH;
|
||||
break;
|
||||
case SYSLOG_FACILITY_LOCAL0:
|
||||
log_facility = LOG_LOCAL0;
|
||||
break;
|
||||
case SYSLOG_FACILITY_LOCAL1:
|
||||
log_facility = LOG_LOCAL1;
|
||||
break;
|
||||
case SYSLOG_FACILITY_LOCAL2:
|
||||
log_facility = LOG_LOCAL2;
|
||||
break;
|
||||
case SYSLOG_FACILITY_LOCAL3:
|
||||
log_facility = LOG_LOCAL3;
|
||||
break;
|
||||
case SYSLOG_FACILITY_LOCAL4:
|
||||
log_facility = LOG_LOCAL4;
|
||||
break;
|
||||
case SYSLOG_FACILITY_LOCAL5:
|
||||
log_facility = LOG_LOCAL5;
|
||||
break;
|
||||
case SYSLOG_FACILITY_LOCAL6:
|
||||
log_facility = LOG_LOCAL6;
|
||||
break;
|
||||
case SYSLOG_FACILITY_LOCAL7:
|
||||
log_facility = LOG_LOCAL7;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unrecognized internal syslog facility code %d\n",
|
||||
(int)facility);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
log_on_stderr = on_stderr;
|
||||
switch (level) {
|
||||
case SYSLOG_LEVEL_QUIET:
|
||||
case SYSLOG_LEVEL_ERROR:
|
||||
case SYSLOG_LEVEL_FATAL:
|
||||
case SYSLOG_LEVEL_INFO:
|
||||
case SYSLOG_LEVEL_VERBOSE:
|
||||
case SYSLOG_LEVEL_DEBUG:
|
||||
log_level = level;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unrecognized internal syslog level code %d\n",
|
||||
(int) level);
|
||||
exit(1);
|
||||
}
|
||||
switch (facility) {
|
||||
case SYSLOG_FACILITY_DAEMON:
|
||||
log_facility = LOG_DAEMON;
|
||||
break;
|
||||
case SYSLOG_FACILITY_USER:
|
||||
log_facility = LOG_USER;
|
||||
break;
|
||||
case SYSLOG_FACILITY_AUTH:
|
||||
log_facility = LOG_AUTH;
|
||||
break;
|
||||
case SYSLOG_FACILITY_LOCAL0:
|
||||
log_facility = LOG_LOCAL0;
|
||||
break;
|
||||
case SYSLOG_FACILITY_LOCAL1:
|
||||
log_facility = LOG_LOCAL1;
|
||||
break;
|
||||
case SYSLOG_FACILITY_LOCAL2:
|
||||
log_facility = LOG_LOCAL2;
|
||||
break;
|
||||
case SYSLOG_FACILITY_LOCAL3:
|
||||
log_facility = LOG_LOCAL3;
|
||||
break;
|
||||
case SYSLOG_FACILITY_LOCAL4:
|
||||
log_facility = LOG_LOCAL4;
|
||||
break;
|
||||
case SYSLOG_FACILITY_LOCAL5:
|
||||
log_facility = LOG_LOCAL5;
|
||||
break;
|
||||
case SYSLOG_FACILITY_LOCAL6:
|
||||
log_facility = LOG_LOCAL6;
|
||||
break;
|
||||
case SYSLOG_FACILITY_LOCAL7:
|
||||
log_facility = LOG_LOCAL7;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unrecognized internal syslog facility code %d\n",
|
||||
(int) facility);
|
||||
exit(1);
|
||||
}
|
||||
log_on_stderr = on_stderr;
|
||||
}
|
||||
|
||||
#define MSGBUFSIZE 1024
|
||||
|
@ -106,48 +102,44 @@ void log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr)
|
|||
void
|
||||
do_log(LogLevel level, const char *fmt, va_list args)
|
||||
{
|
||||
char msgbuf[MSGBUFSIZE];
|
||||
char fmtbuf[MSGBUFSIZE];
|
||||
char *txt = NULL;
|
||||
int pri = LOG_INFO;
|
||||
char msgbuf[MSGBUFSIZE];
|
||||
char fmtbuf[MSGBUFSIZE];
|
||||
char *txt = NULL;
|
||||
int pri = LOG_INFO;
|
||||
|
||||
if (level > log_level)
|
||||
return;
|
||||
switch (level)
|
||||
{
|
||||
case SYSLOG_LEVEL_ERROR:
|
||||
txt = "error";
|
||||
pri = LOG_ERR;
|
||||
break;
|
||||
case SYSLOG_LEVEL_FATAL:
|
||||
txt = "fatal";
|
||||
pri = LOG_ERR;
|
||||
break;
|
||||
case SYSLOG_LEVEL_INFO:
|
||||
pri = LOG_INFO;
|
||||
break;
|
||||
case SYSLOG_LEVEL_CHAT:
|
||||
pri = LOG_INFO;
|
||||
break;
|
||||
case SYSLOG_LEVEL_DEBUG:
|
||||
txt = "debug";
|
||||
pri = LOG_DEBUG;
|
||||
break;
|
||||
default:
|
||||
txt = "internal error";
|
||||
pri = LOG_ERR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (txt != NULL) {
|
||||
snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt);
|
||||
vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args);
|
||||
}else{
|
||||
vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
|
||||
}
|
||||
if (log_on_stderr)
|
||||
fprintf(stderr, "%s\n", msgbuf);
|
||||
openlog(__progname, LOG_PID, log_facility);
|
||||
syslog(pri, "%.500s", msgbuf);
|
||||
closelog();
|
||||
if (level > log_level)
|
||||
return;
|
||||
switch (level) {
|
||||
case SYSLOG_LEVEL_ERROR:
|
||||
txt = "error";
|
||||
pri = LOG_ERR;
|
||||
break;
|
||||
case SYSLOG_LEVEL_FATAL:
|
||||
txt = "fatal";
|
||||
pri = LOG_ERR;
|
||||
break;
|
||||
case SYSLOG_LEVEL_INFO:
|
||||
case SYSLOG_LEVEL_VERBOSE:
|
||||
pri = LOG_INFO;
|
||||
break;
|
||||
case SYSLOG_LEVEL_DEBUG:
|
||||
txt = "debug";
|
||||
pri = LOG_DEBUG;
|
||||
break;
|
||||
default:
|
||||
txt = "internal error";
|
||||
pri = LOG_ERR;
|
||||
break;
|
||||
}
|
||||
if (txt != NULL) {
|
||||
snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt);
|
||||
vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args);
|
||||
} else {
|
||||
vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
|
||||
}
|
||||
if (log_on_stderr)
|
||||
fprintf(stderr, "%s\n", msgbuf);
|
||||
openlog(__progname, LOG_PID, log_facility);
|
||||
syslog(pri, "%.500s", msgbuf);
|
||||
closelog();
|
||||
}
|
||||
|
|
217
log.c
217
log.c
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
|
||||
Shared versions of debug(), log(), etc.
|
||||
|
||||
*
|
||||
* Shared versions of debug(), log(), etc.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: log.c,v 1.2 1999/11/19 16:04:17 markus Exp $");
|
||||
RCSID("$OpenBSD: log.c,v 1.5 1999/11/24 00:26:02 deraadt Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "xmalloc.h"
|
||||
|
@ -13,66 +13,65 @@ RCSID("$OpenBSD: log.c,v 1.2 1999/11/19 16:04:17 markus Exp $");
|
|||
/* Fatal messages. This function never returns. */
|
||||
|
||||
void
|
||||
fatal(const char *fmt, ...)
|
||||
fatal(const char *fmt,...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
do_log(SYSLOG_LEVEL_FATAL, fmt, args);
|
||||
va_end(args);
|
||||
fatal_cleanup();
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
do_log(SYSLOG_LEVEL_FATAL, fmt, args);
|
||||
va_end(args);
|
||||
fatal_cleanup();
|
||||
}
|
||||
|
||||
/* Error messages that should be logged. */
|
||||
|
||||
void
|
||||
error(const char *fmt, ...)
|
||||
error(const char *fmt,...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
do_log(SYSLOG_LEVEL_ERROR, fmt, args);
|
||||
va_end(args);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
do_log(SYSLOG_LEVEL_ERROR, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* Log this message (information that usually should go to the log). */
|
||||
|
||||
void
|
||||
log(const char *fmt, ...)
|
||||
log(const char *fmt,...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
do_log(SYSLOG_LEVEL_INFO, fmt, args);
|
||||
va_end(args);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
do_log(SYSLOG_LEVEL_INFO, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* More detailed messages (information that does not need to go to the log). */
|
||||
|
||||
void
|
||||
chat(const char *fmt, ...)
|
||||
verbose(const char *fmt,...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
do_log(SYSLOG_LEVEL_CHAT, fmt, args);
|
||||
va_end(args);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
do_log(SYSLOG_LEVEL_VERBOSE, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* Debugging messages that should not be logged during normal operation. */
|
||||
|
||||
void
|
||||
debug(const char *fmt, ...)
|
||||
debug(const char *fmt,...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
do_log(SYSLOG_LEVEL_DEBUG, fmt, args);
|
||||
va_end(args);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
do_log(SYSLOG_LEVEL_DEBUG, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* Fatal cleanup */
|
||||
|
||||
struct fatal_cleanup
|
||||
{
|
||||
struct fatal_cleanup *next;
|
||||
void (*proc)(void *);
|
||||
void *context;
|
||||
struct fatal_cleanup {
|
||||
struct fatal_cleanup *next;
|
||||
void (*proc) (void *);
|
||||
void *context;
|
||||
};
|
||||
|
||||
static struct fatal_cleanup *fatal_cleanups = NULL;
|
||||
|
@ -80,116 +79,108 @@ static struct fatal_cleanup *fatal_cleanups = NULL;
|
|||
/* Registers a cleanup function to be called by fatal() before exiting. */
|
||||
|
||||
void
|
||||
fatal_add_cleanup(void (*proc)(void *), void *context)
|
||||
fatal_add_cleanup(void (*proc) (void *), void *context)
|
||||
{
|
||||
struct fatal_cleanup *cu;
|
||||
struct fatal_cleanup *cu;
|
||||
|
||||
cu = xmalloc(sizeof(*cu));
|
||||
cu->proc = proc;
|
||||
cu->context = context;
|
||||
cu->next = fatal_cleanups;
|
||||
fatal_cleanups = cu;
|
||||
cu = xmalloc(sizeof(*cu));
|
||||
cu->proc = proc;
|
||||
cu->context = context;
|
||||
cu->next = fatal_cleanups;
|
||||
fatal_cleanups = cu;
|
||||
}
|
||||
|
||||
/* Removes a cleanup frunction to be called at fatal(). */
|
||||
|
||||
void
|
||||
fatal_remove_cleanup(void (*proc)(void *context), void *context)
|
||||
fatal_remove_cleanup(void (*proc) (void *context), void *context)
|
||||
{
|
||||
struct fatal_cleanup **cup, *cu;
|
||||
|
||||
for (cup = &fatal_cleanups; *cup; cup = &cu->next)
|
||||
{
|
||||
cu = *cup;
|
||||
if (cu->proc == proc && cu->context == context)
|
||||
{
|
||||
*cup = cu->next;
|
||||
xfree(cu);
|
||||
return;
|
||||
struct fatal_cleanup **cup, *cu;
|
||||
|
||||
for (cup = &fatal_cleanups; *cup; cup = &cu->next) {
|
||||
cu = *cup;
|
||||
if (cu->proc == proc && cu->context == context) {
|
||||
*cup = cu->next;
|
||||
xfree(cu);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
fatal("fatal_remove_cleanup: no such cleanup function: 0x%lx 0x%lx\n",
|
||||
(unsigned long)proc, (unsigned long)context);
|
||||
fatal("fatal_remove_cleanup: no such cleanup function: 0x%lx 0x%lx\n",
|
||||
(unsigned long) proc, (unsigned long) context);
|
||||
}
|
||||
|
||||
/* Cleanup and exit */
|
||||
void
|
||||
fatal_cleanup(void)
|
||||
{
|
||||
struct fatal_cleanup *cu, *next_cu;
|
||||
static int called = 0;
|
||||
if (called)
|
||||
exit(255);
|
||||
called = 1;
|
||||
struct fatal_cleanup *cu, *next_cu;
|
||||
static int called = 0;
|
||||
|
||||
/* Call cleanup functions. */
|
||||
for (cu = fatal_cleanups; cu; cu = next_cu)
|
||||
{
|
||||
next_cu = cu->next;
|
||||
debug("Calling cleanup 0x%lx(0x%lx)",
|
||||
(unsigned long)cu->proc, (unsigned long)cu->context);
|
||||
(*cu->proc)(cu->context);
|
||||
}
|
||||
|
||||
exit(255);
|
||||
if (called)
|
||||
exit(255);
|
||||
called = 1;
|
||||
/* Call cleanup functions. */
|
||||
for (cu = fatal_cleanups; cu; cu = next_cu) {
|
||||
next_cu = cu->next;
|
||||
debug("Calling cleanup 0x%lx(0x%lx)",
|
||||
(unsigned long) cu->proc, (unsigned long) cu->context);
|
||||
(*cu->proc) (cu->context);
|
||||
}
|
||||
exit(255);
|
||||
}
|
||||
|
||||
/* textual representation of log-facilities/levels */
|
||||
|
||||
|
||||
static struct
|
||||
{
|
||||
const char *name;
|
||||
SyslogFacility val;
|
||||
} log_facilities[] =
|
||||
{
|
||||
{ "DAEMON", SYSLOG_FACILITY_DAEMON },
|
||||
{ "USER", SYSLOG_FACILITY_USER },
|
||||
{ "AUTH", SYSLOG_FACILITY_AUTH },
|
||||
{ "LOCAL0", SYSLOG_FACILITY_LOCAL0 },
|
||||
{ "LOCAL1", SYSLOG_FACILITY_LOCAL1 },
|
||||
{ "LOCAL2", SYSLOG_FACILITY_LOCAL2 },
|
||||
{ "LOCAL3", SYSLOG_FACILITY_LOCAL3 },
|
||||
{ "LOCAL4", SYSLOG_FACILITY_LOCAL4 },
|
||||
{ "LOCAL5", SYSLOG_FACILITY_LOCAL5 },
|
||||
{ "LOCAL6", SYSLOG_FACILITY_LOCAL6 },
|
||||
{ "LOCAL7", SYSLOG_FACILITY_LOCAL7 },
|
||||
{ NULL, 0 }
|
||||
static struct {
|
||||
const char *name;
|
||||
SyslogFacility val;
|
||||
} log_facilities[] = {
|
||||
{ "DAEMON", SYSLOG_FACILITY_DAEMON },
|
||||
{ "USER", SYSLOG_FACILITY_USER },
|
||||
{ "AUTH", SYSLOG_FACILITY_AUTH },
|
||||
{ "LOCAL0", SYSLOG_FACILITY_LOCAL0 },
|
||||
{ "LOCAL1", SYSLOG_FACILITY_LOCAL1 },
|
||||
{ "LOCAL2", SYSLOG_FACILITY_LOCAL2 },
|
||||
{ "LOCAL3", SYSLOG_FACILITY_LOCAL3 },
|
||||
{ "LOCAL4", SYSLOG_FACILITY_LOCAL4 },
|
||||
{ "LOCAL5", SYSLOG_FACILITY_LOCAL5 },
|
||||
{ "LOCAL6", SYSLOG_FACILITY_LOCAL6 },
|
||||
{ "LOCAL7", SYSLOG_FACILITY_LOCAL7 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
static struct
|
||||
{
|
||||
const char *name;
|
||||
LogLevel val;
|
||||
static struct {
|
||||
const char *name;
|
||||
LogLevel val;
|
||||
} log_levels[] =
|
||||
{
|
||||
{ "QUIET", SYSLOG_LEVEL_QUIET },
|
||||
{ "FATAL", SYSLOG_LEVEL_FATAL },
|
||||
{ "ERROR", SYSLOG_LEVEL_ERROR },
|
||||
{ "INFO", SYSLOG_LEVEL_INFO },
|
||||
{ "CHAT", SYSLOG_LEVEL_CHAT },
|
||||
{ "DEBUG", SYSLOG_LEVEL_DEBUG },
|
||||
{ NULL, 0 }
|
||||
{ "QUIET", SYSLOG_LEVEL_QUIET },
|
||||
{ "FATAL", SYSLOG_LEVEL_FATAL },
|
||||
{ "ERROR", SYSLOG_LEVEL_ERROR },
|
||||
{ "INFO", SYSLOG_LEVEL_INFO },
|
||||
{ "VERBOSE", SYSLOG_LEVEL_VERBOSE },
|
||||
{ "DEBUG", SYSLOG_LEVEL_DEBUG },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
SyslogFacility
|
||||
log_facility_number(char *name)
|
||||
{
|
||||
int i;
|
||||
if (name != NULL)
|
||||
for (i = 0; log_facilities[i].name; i++)
|
||||
if (strcasecmp(log_facilities[i].name, name) == 0)
|
||||
return log_facilities[i].val;
|
||||
return (SyslogFacility)-1;
|
||||
int i;
|
||||
if (name != NULL)
|
||||
for (i = 0; log_facilities[i].name; i++)
|
||||
if (strcasecmp(log_facilities[i].name, name) == 0)
|
||||
return log_facilities[i].val;
|
||||
return (SyslogFacility) - 1;
|
||||
}
|
||||
|
||||
LogLevel
|
||||
log_level_number(char *name)
|
||||
{
|
||||
int i;
|
||||
if (name != NULL)
|
||||
for (i = 0; log_levels[i].name; i++)
|
||||
if (strcasecmp(log_levels[i].name, name) == 0)
|
||||
return log_levels[i].val;
|
||||
return (LogLevel)-1;
|
||||
int i;
|
||||
if (name != NULL)
|
||||
for (i = 0; log_levels[i].name; i++)
|
||||
if (strcasecmp(log_levels[i].name, name) == 0)
|
||||
return log_levels[i].val;
|
||||
return (LogLevel) - 1;
|
||||
}
|
||||
|
|
181
login.c
181
login.c
|
@ -1,128 +1,129 @@
|
|||
/*
|
||||
|
||||
login.c
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Fri Mar 24 14:51:08 1995 ylo
|
||||
|
||||
This file performs some of the things login(1) normally does. We cannot
|
||||
easily use something like login -p -h host -f user, because there are
|
||||
several different logins around, and it is hard to determined what kind of
|
||||
login the current system has. Also, we want to be able to execute commands
|
||||
on a tty.
|
||||
|
||||
*/
|
||||
*
|
||||
* login.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Fri Mar 24 14:51:08 1995 ylo
|
||||
*
|
||||
* This file performs some of the things login(1) normally does. We cannot
|
||||
* easily use something like login -p -h host -f user, because there are
|
||||
* several different logins around, and it is hard to determined what kind of
|
||||
* login the current system has. Also, we want to be able to execute commands
|
||||
* on a tty.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: login.c,v 1.2 1999/11/10 23:40:23 damien Exp $");
|
||||
RCSID("$Id: login.c,v 1.3 1999/11/24 13:26:22 damien Exp $");
|
||||
|
||||
#include <utmp.h>
|
||||
#include "ssh.h"
|
||||
|
||||
#ifdef HAVE_UTIL_H
|
||||
# include <util.h>
|
||||
#endif
|
||||
#ifdef HAVE_LASTLOG_H
|
||||
# include <lastlog.h>
|
||||
#endif
|
||||
|
||||
#include "ssh.h"
|
||||
|
||||
/* Returns the time when the user last logged in. Returns 0 if the
|
||||
information is not available. This must be called before record_login.
|
||||
/* Returns the time when the user last logged in. Returns 0 if the
|
||||
information is not available. This must be called before record_login.
|
||||
The host the user logged in from will be returned in buf. */
|
||||
|
||||
/* Returns the time when the user last logged in (or 0 if no previous login
|
||||
is found). The name of the host used last time is returned in buf. */
|
||||
|
||||
unsigned long get_last_login_time(uid_t uid, const char *logname,
|
||||
char *buf, unsigned int bufsize)
|
||||
unsigned long
|
||||
get_last_login_time(uid_t uid, const char *logname,
|
||||
char *buf, unsigned int bufsize)
|
||||
{
|
||||
struct lastlog ll;
|
||||
char *lastlog;
|
||||
int fd;
|
||||
struct lastlog ll;
|
||||
char *lastlog;
|
||||
int fd;
|
||||
|
||||
lastlog = _PATH_LASTLOG;
|
||||
lastlog = _PATH_LASTLOG;
|
||||
buf[0] = '\0';
|
||||
|
||||
buf[0] = '\0';
|
||||
|
||||
fd = open(lastlog, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return 0;
|
||||
lseek(fd, (off_t)((long)uid * sizeof(ll)), SEEK_SET);
|
||||
if (read(fd, &ll, sizeof(ll)) != sizeof(ll))
|
||||
{
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
close(fd);
|
||||
if (bufsize > sizeof(ll.ll_host) + 1)
|
||||
bufsize = sizeof(ll.ll_host) + 1;
|
||||
strncpy(buf, ll.ll_host, bufsize - 1);
|
||||
buf[bufsize - 1] = 0;
|
||||
return ll.ll_time;
|
||||
fd = open(lastlog, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return 0;
|
||||
lseek(fd, (off_t) ((long) uid * sizeof(ll)), SEEK_SET);
|
||||
if (read(fd, &ll, sizeof(ll)) != sizeof(ll)) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
close(fd);
|
||||
if (bufsize > sizeof(ll.ll_host) + 1)
|
||||
bufsize = sizeof(ll.ll_host) + 1;
|
||||
strncpy(buf, ll.ll_host, bufsize - 1);
|
||||
buf[bufsize - 1] = 0;
|
||||
return ll.ll_time;
|
||||
}
|
||||
|
||||
/* Records that the user has logged in. I these parts of operating systems
|
||||
were more standardized. */
|
||||
|
||||
void record_login(int pid, const char *ttyname, const char *user, uid_t uid,
|
||||
const char *host, struct sockaddr_in *addr)
|
||||
void
|
||||
record_login(int pid, const char *ttyname, const char *user, uid_t uid,
|
||||
const char *host, struct sockaddr_in * addr)
|
||||
{
|
||||
int fd;
|
||||
struct lastlog ll;
|
||||
char *lastlog;
|
||||
int fd;
|
||||
struct lastlog ll;
|
||||
char *lastlog;
|
||||
struct utmp u;
|
||||
const char *utmp, *wtmp;
|
||||
|
||||
struct utmp u;
|
||||
const char *utmp, *wtmp;
|
||||
|
||||
/* Construct an utmp/wtmp entry. */
|
||||
memset(&u, 0, sizeof(u));
|
||||
strncpy(u.ut_line, ttyname + 5, sizeof(u.ut_line));
|
||||
u.ut_time = time(NULL);
|
||||
strncpy(u.ut_name, user, sizeof(u.ut_name));
|
||||
/* Construct an utmp/wtmp entry. */
|
||||
memset(&u, 0, sizeof(u));
|
||||
strncpy(u.ut_line, ttyname + 5, sizeof(u.ut_line));
|
||||
u.ut_time = time(NULL);
|
||||
strncpy(u.ut_name, user, sizeof(u.ut_name));
|
||||
#ifdef HAVE_HOST_IN_UTMP
|
||||
strncpy(u.ut_host, host, sizeof(u.ut_host));
|
||||
strncpy(u.ut_host, host, sizeof(u.ut_host));
|
||||
#endif
|
||||
|
||||
/* Figure out the file names. */
|
||||
utmp = _PATH_UTMP;
|
||||
wtmp = _PATH_WTMP;
|
||||
|
||||
login(&u);
|
||||
/* Figure out the file names. */
|
||||
utmp = _PATH_UTMP;
|
||||
wtmp = _PATH_WTMP;
|
||||
|
||||
lastlog = _PATH_LASTLOG;
|
||||
login(&u);
|
||||
lastlog = _PATH_LASTLOG;
|
||||
|
||||
/* Update lastlog unless actually recording a logout. */
|
||||
if (strcmp(user, "") != 0)
|
||||
{
|
||||
/* It is safer to bzero the lastlog structure first because some
|
||||
systems might have some extra fields in it (e.g. SGI) */
|
||||
memset(&ll, 0, sizeof(ll));
|
||||
/* Update lastlog unless actually recording a logout. */
|
||||
if (strcmp(user, "") != 0) {
|
||||
/* It is safer to bzero the lastlog structure first
|
||||
because some systems might have some extra fields in it
|
||||
(e.g. SGI) */
|
||||
memset(&ll, 0, sizeof(ll));
|
||||
|
||||
/* Update lastlog. */
|
||||
ll.ll_time = time(NULL);
|
||||
strncpy(ll.ll_line, ttyname + 5, sizeof(ll.ll_line));
|
||||
strncpy(ll.ll_host, host, sizeof(ll.ll_host));
|
||||
fd = open(lastlog, O_RDWR);
|
||||
if (fd >= 0)
|
||||
{
|
||||
lseek(fd, (off_t)((long)uid * sizeof(ll)), SEEK_SET);
|
||||
if (write(fd, &ll, sizeof(ll)) != sizeof(ll))
|
||||
log("Could not write %.100s: %.100s", lastlog, strerror(errno));
|
||||
close(fd);
|
||||
/* Update lastlog. */
|
||||
ll.ll_time = time(NULL);
|
||||
strncpy(ll.ll_line, ttyname + 5, sizeof(ll.ll_line));
|
||||
strncpy(ll.ll_host, host, sizeof(ll.ll_host));
|
||||
fd = open(lastlog, O_RDWR);
|
||||
if (fd >= 0) {
|
||||
lseek(fd, (off_t) ((long) uid * sizeof(ll)), SEEK_SET);
|
||||
if (write(fd, &ll, sizeof(ll)) != sizeof(ll))
|
||||
log("Could not write %.100s: %.100s", lastlog, strerror(errno));
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void record_logout(int pid, const char *ttyname)
|
||||
|
||||
/* Records that the user has logged out. */
|
||||
|
||||
void
|
||||
record_logout(int pid, const char *ttyname)
|
||||
{
|
||||
#ifdef HAVE_LIBUTIL_LOGIN
|
||||
const char *line = ttyname + 5; /* /dev/ttyq8 -> ttyq8 */
|
||||
if (logout(line))
|
||||
logwtmp(line, "", "");
|
||||
const char *line = ttyname + 5; /* /dev/ttyq8 -> ttyq8 */
|
||||
if (logout(line))
|
||||
logwtmp(line, "", "");
|
||||
#else /* HAVE_LIBUTIL_LOGIN */
|
||||
record_login(pid, ttyname, "", -1, "", NULL);
|
||||
record_login(pid, ttyname, "", -1, "", NULL);
|
||||
#endif /* HAVE_LIBUTIL_LOGIN */
|
||||
}
|
||||
|
||||
|
|
125
match.c
125
match.c
|
@ -1,78 +1,77 @@
|
|||
/*
|
||||
|
||||
match.c
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Thu Jun 22 01:17:50 1995 ylo
|
||||
|
||||
Simple pattern matching, with '*' and '?' as wildcards.
|
||||
|
||||
*/
|
||||
*
|
||||
* match.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Thu Jun 22 01:17:50 1995 ylo
|
||||
*
|
||||
* Simple pattern matching, with '*' and '?' as wildcards.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: match.c,v 1.1 1999/10/27 03:42:44 damien Exp $");
|
||||
RCSID("$Id: match.c,v 1.2 1999/11/24 13:26:22 damien Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
|
||||
/* Returns true if the given string matches the pattern (which may contain
|
||||
? and * as wildcards), and zero if it does not match. */
|
||||
|
||||
int match_pattern(const char *s, const char *pattern)
|
||||
|
||||
int
|
||||
match_pattern(const char *s, const char *pattern)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
/* If at end of pattern, accept if also at end of string. */
|
||||
if (!*pattern)
|
||||
return !*s;
|
||||
for (;;) {
|
||||
/* If at end of pattern, accept if also at end of string. */
|
||||
if (!*pattern)
|
||||
return !*s;
|
||||
|
||||
/* Process '*'. */
|
||||
if (*pattern == '*')
|
||||
{
|
||||
/* Skip the asterisk. */
|
||||
pattern++;
|
||||
/* Process '*'. */
|
||||
if (*pattern == '*') {
|
||||
/* Skip the asterisk. */
|
||||
pattern++;
|
||||
|
||||
/* If at end of pattern, accept immediately. */
|
||||
if (!*pattern)
|
||||
return 1;
|
||||
/* If at end of pattern, accept immediately. */
|
||||
if (!*pattern)
|
||||
return 1;
|
||||
|
||||
/* If next character in pattern is known, optimize. */
|
||||
if (*pattern != '?' && *pattern != '*')
|
||||
{
|
||||
/* Look instances of the next character in pattern, and try
|
||||
to match starting from those. */
|
||||
for (; *s; s++)
|
||||
if (*s == *pattern &&
|
||||
match_pattern(s + 1, pattern + 1))
|
||||
return 1;
|
||||
/* Failed. */
|
||||
return 0;
|
||||
}
|
||||
/* If next character in pattern is known, optimize. */
|
||||
if (*pattern != '?' && *pattern != '*') {
|
||||
/* Look instances of the next character in
|
||||
pattern, and try to match starting from
|
||||
those. */
|
||||
for (; *s; s++)
|
||||
if (*s == *pattern &&
|
||||
match_pattern(s + 1, pattern + 1))
|
||||
return 1;
|
||||
/* Failed. */
|
||||
return 0;
|
||||
}
|
||||
/* Move ahead one character at a time and try to
|
||||
match at each position. */
|
||||
for (; *s; s++)
|
||||
if (match_pattern(s, pattern))
|
||||
return 1;
|
||||
/* Failed. */
|
||||
return 0;
|
||||
}
|
||||
/* There must be at least one more character in the
|
||||
string. If we are at the end, fail. */
|
||||
if (!*s)
|
||||
return 0;
|
||||
|
||||
/* Move ahead one character at a time and try to match at each
|
||||
position. */
|
||||
for (; *s; s++)
|
||||
if (match_pattern(s, pattern))
|
||||
return 1;
|
||||
/* Failed. */
|
||||
return 0;
|
||||
}
|
||||
/* Check if the next character of the string is
|
||||
acceptable. */
|
||||
if (*pattern != '?' && *pattern != *s)
|
||||
return 0;
|
||||
|
||||
/* There must be at least one more character in the string. If we are
|
||||
at the end, fail. */
|
||||
if (!*s)
|
||||
return 0;
|
||||
|
||||
/* Check if the next character of the string is acceptable. */
|
||||
if (*pattern != '?' && *pattern != *s)
|
||||
return 0;
|
||||
|
||||
/* Move to the next character, both in string and in pattern. */
|
||||
s++;
|
||||
pattern++;
|
||||
}
|
||||
/*NOTREACHED*/
|
||||
/* Move to the next character, both in string and in
|
||||
pattern. */
|
||||
s++;
|
||||
pattern++;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
|
66
mpaux.c
66
mpaux.c
|
@ -1,21 +1,24 @@
|
|||
/*
|
||||
|
||||
mpaux.c
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Sun Jul 16 04:29:30 1995 ylo
|
||||
|
||||
This file contains various auxiliary functions related to multiple
|
||||
precision integers.
|
||||
|
||||
*
|
||||
* mpaux.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Sun Jul 16 04:29:30 1995 ylo
|
||||
*
|
||||
* This file contains various auxiliary functions related to multiple
|
||||
* precision integers.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: mpaux.c,v 1.6 1999/11/16 02:37:16 damien Exp $");
|
||||
RCSID("$Id: mpaux.c,v 1.7 1999/11/24 13:26:22 damien Exp $");
|
||||
|
||||
#include "getput.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
#include <openssl/bn.h>
|
||||
|
@ -26,29 +29,24 @@ RCSID("$Id: mpaux.c,v 1.6 1999/11/16 02:37:16 damien Exp $");
|
|||
#include <ssl/md5.h>
|
||||
#endif
|
||||
|
||||
#include "getput.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
|
||||
void
|
||||
compute_session_id(unsigned char session_id[16],
|
||||
unsigned char cookie[8],
|
||||
BIGNUM *host_key_n,
|
||||
BIGNUM *session_key_n)
|
||||
BIGNUM* host_key_n,
|
||||
BIGNUM* session_key_n)
|
||||
{
|
||||
unsigned int host_key_bits = BN_num_bits(host_key_n);
|
||||
unsigned int session_key_bits = BN_num_bits(session_key_n);
|
||||
unsigned int bytes = (host_key_bits + 7) / 8 + (session_key_bits + 7) / 8 + 8;
|
||||
unsigned char *buf = xmalloc(bytes);
|
||||
MD5_CTX md;
|
||||
unsigned int host_key_bits = BN_num_bits(host_key_n);
|
||||
unsigned int session_key_bits = BN_num_bits(session_key_n);
|
||||
unsigned int bytes = (host_key_bits + 7) / 8 + (session_key_bits + 7) / 8 + 8;
|
||||
unsigned char *buf = xmalloc(bytes);
|
||||
MD5_CTX md;
|
||||
|
||||
BN_bn2bin(host_key_n, buf);
|
||||
BN_bn2bin(session_key_n, buf + (host_key_bits + 7 ) / 8);
|
||||
memcpy(buf + (host_key_bits + 7) / 8 + (session_key_bits + 7) / 8,
|
||||
cookie, 8);
|
||||
MD5_Init(&md);
|
||||
MD5_Update(&md, buf, bytes);
|
||||
MD5_Final(session_id, &md);
|
||||
memset(buf, 0, bytes);
|
||||
xfree(buf);
|
||||
BN_bn2bin(host_key_n, buf);
|
||||
BN_bn2bin(session_key_n, buf + (host_key_bits + 7) / 8);
|
||||
memcpy(buf + (host_key_bits + 7) / 8 + (session_key_bits + 7) / 8, cookie, 8);
|
||||
MD5_Init(&md);
|
||||
MD5_Update(&md, buf, bytes);
|
||||
MD5_Final(session_id, &md);
|
||||
memset(buf, 0, bytes);
|
||||
xfree(buf);
|
||||
}
|
||||
|
|
40
mpaux.h
40
mpaux.h
|
@ -1,20 +1,19 @@
|
|||
/*
|
||||
*
|
||||
* mpaux.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Sun Jul 16 04:29:30 1995 ylo
|
||||
*
|
||||
* This file contains various auxiliary functions related to multiple
|
||||
* precision integers.
|
||||
*/
|
||||
|
||||
mpaux.h
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Sun Jul 16 04:29:30 1995 ylo
|
||||
|
||||
This file contains various auxiliary functions related to multiple
|
||||
precision integers.
|
||||
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: mpaux.h,v 1.2 1999/11/16 02:37:16 damien Exp $"); */
|
||||
/* RCSID("$Id: mpaux.h,v 1.3 1999/11/24 13:26:22 damien Exp $"); */
|
||||
|
||||
#ifndef MPAUX_H
|
||||
#define MPAUX_H
|
||||
|
@ -22,9 +21,10 @@ precision integers.
|
|||
/* Computes a 16-byte session id in the global variable session_id.
|
||||
The session id is computed by concatenating the linearized, msb
|
||||
first representations of host_key_n, session_key_n, and the cookie. */
|
||||
void compute_session_id(unsigned char session_id[16],
|
||||
unsigned char cookie[8],
|
||||
BIGNUM *host_key_n,
|
||||
BIGNUM *session_key_n);
|
||||
void
|
||||
compute_session_id(unsigned char session_id[16],
|
||||
unsigned char cookie[8],
|
||||
BIGNUM * host_key_n,
|
||||
BIGNUM * session_key_n);
|
||||
|
||||
#endif /* MPAUX_H */
|
||||
#endif /* MPAUX_H */
|
||||
|
|
119
nchan.c
119
nchan.c
|
@ -1,5 +1,5 @@
|
|||
#include "includes.h"
|
||||
RCSID("$Id: nchan.c,v 1.1 1999/10/27 03:42:44 damien Exp $");
|
||||
RCSID("$Id: nchan.c,v 1.2 1999/11/24 13:26:22 damien Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
|
||||
|
@ -15,122 +15,131 @@ static void chan_shutdown_read(Channel *c);
|
|||
static void chan_delele_if_full_closed(Channel *c);
|
||||
|
||||
/*
|
||||
* EVENTS: update channel input/output states
|
||||
* execute ACTIONS
|
||||
* EVENTS update channel input/output states execute ACTIONS
|
||||
*/
|
||||
|
||||
/* events concerning the INPUT from socket for channel (istate) */
|
||||
void
|
||||
chan_rcvd_oclose(Channel *c){
|
||||
switch(c->istate){
|
||||
chan_rcvd_oclose(Channel *c)
|
||||
{
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_WAIT_OCLOSE:
|
||||
debug("channel %d: INPUT_WAIT_OCLOSE -> INPUT_CLOSED [rcvd OCLOSE]", c->self);
|
||||
c->istate=CHAN_INPUT_CLOSED;
|
||||
c->istate = CHAN_INPUT_CLOSED;
|
||||
chan_delele_if_full_closed(c);
|
||||
break;
|
||||
case CHAN_INPUT_OPEN:
|
||||
debug("channel %d: INPUT_OPEN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self);
|
||||
chan_shutdown_read(c);
|
||||
chan_send_ieof(c);
|
||||
c->istate=CHAN_INPUT_CLOSED;
|
||||
c->istate = CHAN_INPUT_CLOSED;
|
||||
chan_delele_if_full_closed(c);
|
||||
break;
|
||||
default:
|
||||
debug("protocol error: chan_rcvd_oclose %d for istate %d",c->self,c->istate);
|
||||
debug("protocol error: chan_rcvd_oclose %d for istate %d", c->self, c->istate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
void
|
||||
chan_read_failed(Channel *c){
|
||||
switch(c->istate){
|
||||
chan_read_failed(Channel *c)
|
||||
{
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_OPEN:
|
||||
debug("channel %d: INPUT_OPEN -> INPUT_WAIT_DRAIN [read failed]", c->self);
|
||||
chan_shutdown_read(c);
|
||||
c->istate=CHAN_INPUT_WAIT_DRAIN;
|
||||
c->istate = CHAN_INPUT_WAIT_DRAIN;
|
||||
break;
|
||||
default:
|
||||
debug("internal error: we do not read, but chan_read_failed %d for istate %d",
|
||||
c->self,c->istate);
|
||||
c->self, c->istate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
void
|
||||
chan_ibuf_empty(Channel *c){
|
||||
if(buffer_len(&c->input)){
|
||||
debug("internal error: chan_ibuf_empty %d for non empty buffer",c->self);
|
||||
chan_ibuf_empty(Channel *c)
|
||||
{
|
||||
if (buffer_len(&c->input)) {
|
||||
debug("internal error: chan_ibuf_empty %d for non empty buffer", c->self);
|
||||
return;
|
||||
}
|
||||
switch(c->istate){
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_WAIT_DRAIN:
|
||||
debug("channel %d: INPUT_WAIT_DRAIN -> INPUT_WAIT_OCLOSE [inbuf empty, send IEOF]", c->self);
|
||||
chan_send_ieof(c);
|
||||
c->istate=CHAN_INPUT_WAIT_OCLOSE;
|
||||
c->istate = CHAN_INPUT_WAIT_OCLOSE;
|
||||
break;
|
||||
default:
|
||||
debug("internal error: chan_ibuf_empty %d for istate %d",c->self,c->istate);
|
||||
debug("internal error: chan_ibuf_empty %d for istate %d", c->self, c->istate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* events concerning the OUTPUT from channel for socket (ostate) */
|
||||
void
|
||||
chan_rcvd_ieof(Channel *c){
|
||||
switch(c->ostate){
|
||||
chan_rcvd_ieof(Channel *c)
|
||||
{
|
||||
switch (c->ostate) {
|
||||
case CHAN_OUTPUT_OPEN:
|
||||
debug("channel %d: OUTPUT_OPEN -> OUTPUT_WAIT_DRAIN [rvcd IEOF]", c->self);
|
||||
c->ostate=CHAN_OUTPUT_WAIT_DRAIN;
|
||||
c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
|
||||
break;
|
||||
case CHAN_OUTPUT_WAIT_IEOF:
|
||||
debug("channel %d: OUTPUT_WAIT_IEOF -> OUTPUT_CLOSED [rvcd IEOF]", c->self);
|
||||
c->ostate=CHAN_OUTPUT_CLOSED;
|
||||
c->ostate = CHAN_OUTPUT_CLOSED;
|
||||
chan_delele_if_full_closed(c);
|
||||
break;
|
||||
default:
|
||||
debug("protocol error: chan_rcvd_ieof %d for ostate %d", c->self,c->ostate);
|
||||
debug("protocol error: chan_rcvd_ieof %d for ostate %d", c->self, c->ostate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
void
|
||||
chan_write_failed(Channel *c){
|
||||
switch(c->ostate){
|
||||
chan_write_failed(Channel *c)
|
||||
{
|
||||
switch (c->ostate) {
|
||||
case CHAN_OUTPUT_OPEN:
|
||||
debug("channel %d: OUTPUT_OPEN -> OUTPUT_WAIT_IEOF [write failed]", c->self);
|
||||
chan_send_oclose(c);
|
||||
c->ostate=CHAN_OUTPUT_WAIT_IEOF;
|
||||
c->ostate = CHAN_OUTPUT_WAIT_IEOF;
|
||||
break;
|
||||
case CHAN_OUTPUT_WAIT_DRAIN:
|
||||
debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [write failed]", c->self);
|
||||
chan_send_oclose(c);
|
||||
c->ostate=CHAN_OUTPUT_CLOSED;
|
||||
c->ostate = CHAN_OUTPUT_CLOSED;
|
||||
chan_delele_if_full_closed(c);
|
||||
break;
|
||||
default:
|
||||
debug("internal error: chan_write_failed %d for ostate %d",c->self,c->ostate);
|
||||
debug("internal error: chan_write_failed %d for ostate %d", c->self, c->ostate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
void
|
||||
chan_obuf_empty(Channel *c){
|
||||
if(buffer_len(&c->output)){
|
||||
debug("internal error: chan_obuf_empty %d for non empty buffer",c->self);
|
||||
chan_obuf_empty(Channel *c)
|
||||
{
|
||||
if (buffer_len(&c->output)) {
|
||||
debug("internal error: chan_obuf_empty %d for non empty buffer", c->self);
|
||||
return;
|
||||
}
|
||||
switch(c->ostate){
|
||||
switch (c->ostate) {
|
||||
case CHAN_OUTPUT_WAIT_DRAIN:
|
||||
debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [obuf empty, send OCLOSE]", c->self);
|
||||
chan_send_oclose(c);
|
||||
c->ostate=CHAN_OUTPUT_CLOSED;
|
||||
c->ostate = CHAN_OUTPUT_CLOSED;
|
||||
chan_delele_if_full_closed(c);
|
||||
break;
|
||||
default:
|
||||
debug("internal error: chan_obuf_empty %d for ostate %d",c->self,c->ostate);
|
||||
debug("internal error: chan_obuf_empty %d for ostate %d", c->self, c->ostate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ACTIONS: should never update c->istate or c->ostate
|
||||
* ACTIONS: should never update the channel states: c->istate or c->ostate
|
||||
*/
|
||||
static void
|
||||
chan_send_ieof(Channel *c){
|
||||
switch(c->istate){
|
||||
chan_send_ieof(Channel *c)
|
||||
{
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_OPEN:
|
||||
case CHAN_INPUT_WAIT_DRAIN:
|
||||
packet_start(SSH_MSG_CHANNEL_INPUT_EOF);
|
||||
|
@ -138,13 +147,14 @@ chan_send_ieof(Channel *c){
|
|||
packet_send();
|
||||
break;
|
||||
default:
|
||||
debug("internal error: channel %d: cannot send IEOF for istate %d",c->self,c->istate);
|
||||
debug("internal error: channel %d: cannot send IEOF for istate %d", c->self, c->istate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_send_oclose(Channel *c){
|
||||
switch(c->ostate){
|
||||
chan_send_oclose(Channel *c)
|
||||
{
|
||||
switch (c->ostate) {
|
||||
case CHAN_OUTPUT_OPEN:
|
||||
case CHAN_OUTPUT_WAIT_DRAIN:
|
||||
chan_shutdown_write(c);
|
||||
|
@ -154,34 +164,39 @@ chan_send_oclose(Channel *c){
|
|||
packet_send();
|
||||
break;
|
||||
default:
|
||||
debug("internal error: channel %d: cannot send OCLOSE for ostate %d",c->self,c->istate);
|
||||
debug("internal error: channel %d: cannot send OCLOSE for ostate %d", c->self, c->istate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* helper */
|
||||
static void
|
||||
chan_shutdown_write(Channel *c){
|
||||
chan_shutdown_write(Channel *c)
|
||||
{
|
||||
debug("channel %d: shutdown_write", c->self);
|
||||
if(shutdown(c->sock, SHUT_WR)<0)
|
||||
if (shutdown(c->sock, SHUT_WR) < 0)
|
||||
error("chan_shutdown_write failed for #%d/fd%d: %.100s",
|
||||
c->self, c->sock, strerror(errno));
|
||||
c->self, c->sock, strerror(errno));
|
||||
}
|
||||
static void
|
||||
chan_shutdown_read(Channel *c){
|
||||
chan_shutdown_read(Channel *c)
|
||||
{
|
||||
debug("channel %d: shutdown_read", c->self);
|
||||
if(shutdown(c->sock, SHUT_RD)<0)
|
||||
if (shutdown(c->sock, SHUT_RD) < 0)
|
||||
error("chan_shutdown_read failed for #%d/fd%d: %.100s",
|
||||
c->self, c->sock, strerror(errno));
|
||||
c->self, c->sock, strerror(errno));
|
||||
}
|
||||
static void
|
||||
chan_delele_if_full_closed(Channel *c){
|
||||
if(c->istate==CHAN_INPUT_CLOSED && c->ostate==CHAN_OUTPUT_CLOSED){
|
||||
chan_delele_if_full_closed(Channel *c)
|
||||
{
|
||||
if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) {
|
||||
debug("channel %d: closing", c->self);
|
||||
channel_free(c->self);
|
||||
}
|
||||
}
|
||||
void
|
||||
chan_init_iostates(Channel *c){
|
||||
c->ostate=CHAN_OUTPUT_OPEN;
|
||||
c->istate=CHAN_INPUT_OPEN;
|
||||
chan_init_iostates(Channel *c)
|
||||
{
|
||||
c->ostate = CHAN_OUTPUT_OPEN;
|
||||
c->istate = CHAN_INPUT_OPEN;
|
||||
}
|
||||
|
|
26
nchan.h
26
nchan.h
|
@ -1,4 +1,4 @@
|
|||
/* RCSID("$Id: nchan.h,v 1.1 1999/10/27 03:42:44 damien Exp $"); */
|
||||
/* RCSID("$Id: nchan.h,v 1.2 1999/11/24 13:26:22 damien Exp $"); */
|
||||
|
||||
#ifndef NCHAN_H
|
||||
#define NCHAN_H
|
||||
|
@ -7,24 +7,24 @@
|
|||
* SSH Protocol 1.5 aka New Channel Protocol
|
||||
* Thanks to Martina, Axel and everyone who left Erlangen, leaving me bored.
|
||||
* Written by Markus Friedl in October 1999
|
||||
*
|
||||
*
|
||||
* Protocol versions 1.3 and 1.5 differ in the handshake protocol used for the
|
||||
* tear down of channels:
|
||||
*
|
||||
*
|
||||
* 1.3: strict request-ack-protocol:
|
||||
* CLOSE ->
|
||||
* <- CLOSE_CONFIRM
|
||||
*
|
||||
*
|
||||
* 1.5: uses variations of:
|
||||
* IEOF ->
|
||||
* <- OCLOSE
|
||||
* <- IEOF
|
||||
* OCLOSE ->
|
||||
* i.e. both sides have to close the channel
|
||||
*
|
||||
*
|
||||
* See the debugging output from 'ssh -v' and 'sshd -d' of
|
||||
* ssh-1.2.27 as an example.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* ssh-proto-1.5 overloads prot-1.3-message-types */
|
||||
|
@ -44,14 +44,14 @@
|
|||
#define CHAN_OUTPUT_CLOSED 0x80
|
||||
|
||||
/* EVENTS for the input state */
|
||||
void chan_rcvd_oclose(Channel *c);
|
||||
void chan_read_failed(Channel *c);
|
||||
void chan_ibuf_empty(Channel *c);
|
||||
void chan_rcvd_oclose(Channel * c);
|
||||
void chan_read_failed(Channel * c);
|
||||
void chan_ibuf_empty(Channel * c);
|
||||
|
||||
/* EVENTS for the output state */
|
||||
void chan_rcvd_ieof(Channel *c);
|
||||
void chan_write_failed(Channel *c);
|
||||
void chan_obuf_empty(Channel *c);
|
||||
void chan_rcvd_ieof(Channel * c);
|
||||
void chan_write_failed(Channel * c);
|
||||
void chan_obuf_empty(Channel * c);
|
||||
|
||||
void chan_init_iostates(Channel *c);
|
||||
void chan_init_iostates(Channel * c);
|
||||
#endif
|
||||
|
|
803
packet.c
803
packet.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
101
packet.h
101
packet.h
|
@ -1,19 +1,19 @@
|
|||
/*
|
||||
*
|
||||
* packet.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Sat Mar 18 02:02:14 1995 ylo
|
||||
*
|
||||
* Interface for the packet protocol functions.
|
||||
*
|
||||
*/
|
||||
|
||||
packet.h
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Sat Mar 18 02:02:14 1995 ylo
|
||||
|
||||
Interface for the packet protocol functions.
|
||||
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: packet.h,v 1.5 1999/11/21 02:23:53 damien Exp $"); */
|
||||
/* RCSID("$Id: packet.h,v 1.6 1999/11/24 13:26:22 damien Exp $"); */
|
||||
|
||||
#ifndef PACKET_H
|
||||
#define PACKET_H
|
||||
|
@ -31,83 +31,84 @@ Interface for the packet protocol functions.
|
|||
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 fd_in, int fd_out);
|
||||
|
||||
/* Puts the connection file descriptors into non-blocking mode. */
|
||||
void packet_set_nonblocking(void);
|
||||
void packet_set_nonblocking(void);
|
||||
|
||||
/* Returns the file descriptor used for input. */
|
||||
int packet_get_connection_in(void);
|
||||
int packet_get_connection_in(void);
|
||||
|
||||
/* Returns the file descriptor used for output. */
|
||||
int packet_get_connection_out(void);
|
||||
int packet_get_connection_out(void);
|
||||
|
||||
/* Closes the connection (both descriptors) and clears and frees
|
||||
internal data structures. */
|
||||
void packet_close(void);
|
||||
internal data structures. */
|
||||
void packet_close(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 unsigned char *key, unsigned int keylen,
|
||||
int cipher_type);
|
||||
void
|
||||
packet_set_encryption_key(const unsigned char *key, unsigned int keylen,
|
||||
int cipher_type);
|
||||
|
||||
/* Sets remote side protocol flags for the current connection. This can
|
||||
be called at any time. */
|
||||
void packet_set_protocol_flags(unsigned int flags);
|
||||
void packet_set_protocol_flags(unsigned int flags);
|
||||
|
||||
/* Returns the remote protocol flags set earlier by the above function. */
|
||||
unsigned int packet_get_protocol_flags(void);
|
||||
|
||||
/* Enables compression in both directions starting from the next packet. */
|
||||
void packet_start_compression(int level);
|
||||
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, int keepalives);
|
||||
void packet_set_interactive(int interactive, int keepalives);
|
||||
|
||||
/* Returns true if the current connection is interactive. */
|
||||
int packet_is_interactive(void);
|
||||
int packet_is_interactive(void);
|
||||
|
||||
/* Starts constructing a packet to send. */
|
||||
void packet_start(int type);
|
||||
void packet_start(int type);
|
||||
|
||||
/* Appends a character to the packet data. */
|
||||
void packet_put_char(int ch);
|
||||
void packet_put_char(int ch);
|
||||
|
||||
/* Appends an integer to the packet data. */
|
||||
void packet_put_int(unsigned int value);
|
||||
void packet_put_int(unsigned int value);
|
||||
|
||||
/* Appends an arbitrary precision integer to packet data. */
|
||||
void packet_put_bignum(BIGNUM *value);
|
||||
void packet_put_bignum(BIGNUM * value);
|
||||
|
||||
/* Appends a string to packet data. */
|
||||
void packet_put_string(const char *buf, unsigned int len);
|
||||
void packet_put_string(const char *buf, unsigned int len);
|
||||
|
||||
/* Finalizes and sends the packet. If the encryption key has been set,
|
||||
encrypts the packet before sending. */
|
||||
void packet_send(void);
|
||||
void packet_send(void);
|
||||
|
||||
/* Waits until a packet has been received, and returns its type. */
|
||||
int packet_read(int *payload_len_ptr);
|
||||
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);
|
||||
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_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);
|
||||
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, unsigned int len);
|
||||
void packet_process_incoming(const char *buf, unsigned int len);
|
||||
|
||||
/* Returns a character (0-255) from the packet data. */
|
||||
unsigned int packet_get_char(void);
|
||||
|
@ -117,19 +118,19 @@ unsigned 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_bignum(BIGNUM * value, 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(unsigned int *length_ptr);
|
||||
char *packet_get_string(unsigned 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, ...);
|
||||
void packet_disconnect(const char *fmt,...);
|
||||
|
||||
/* Sends a diagnostic message to the other side. This message
|
||||
can be sent at any time (but not while constructing another message).
|
||||
|
@ -139,31 +140,31 @@ void packet_disconnect(const char *fmt, ...);
|
|||
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, ...);
|
||||
void packet_send_debug(const char *fmt,...);
|
||||
|
||||
/* Checks if there is any buffered output, and tries to write some of the
|
||||
output. */
|
||||
void packet_write_poll(void);
|
||||
void packet_write_poll(void);
|
||||
|
||||
/* Waits until all pending output data has been written. */
|
||||
void packet_write_wait(void);
|
||||
void packet_write_wait(void);
|
||||
|
||||
/* Returns true if there is buffered data to write to the connection. */
|
||||
int packet_have_data_to_write(void);
|
||||
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);
|
||||
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);
|
||||
int packet_set_maxsize(int s);
|
||||
#define packet_get_maxsize() max_packet_size
|
||||
|
||||
/* Stores tty modes from the fd into current packet. */
|
||||
void tty_make_modes(int fd);
|
||||
void tty_make_modes(int fd);
|
||||
|
||||
/* Parses tty modes for the fd from the current packet. */
|
||||
void tty_parse_modes(int fd, int *n_bytes_ptr);
|
||||
void tty_parse_modes(int fd, int *n_bytes_ptr);
|
||||
|
||||
#define packet_integrity_check(payload_len, expected_len, type) \
|
||||
do { \
|
||||
|
@ -175,4 +176,4 @@ do { \
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
#endif /* PACKET_H */
|
||||
#endif /* PACKET_H */
|
||||
|
|
390
pty.c
390
pty.c
|
@ -1,28 +1,28 @@
|
|||
/*
|
||||
|
||||
pty.c
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Fri Mar 17 04:37:25 1995 ylo
|
||||
|
||||
Allocating a pseudo-terminal, and making it the controlling tty.
|
||||
|
||||
*/
|
||||
*
|
||||
* pty.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Fri Mar 17 04:37:25 1995 ylo
|
||||
*
|
||||
* Allocating a pseudo-terminal, and making it the controlling tty.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: pty.c,v 1.3 1999/11/15 04:40:55 damien Exp $");
|
||||
RCSID("$Id: pty.c,v 1.4 1999/11/24 13:26:22 damien Exp $");
|
||||
|
||||
#include "pty.h"
|
||||
#include "ssh.h"
|
||||
|
||||
#ifdef HAVE_PTY_H
|
||||
#include <pty.h>
|
||||
#endif /* HAVE_PTY_H */
|
||||
|
||||
#include "pty.h"
|
||||
#include "ssh.h"
|
||||
|
||||
/* Pty allocated with _getpty gets broken if we do I_PUSH:es to it. */
|
||||
#if defined(HAVE__GETPTY) || defined(HAVE_OPENPTY)
|
||||
#undef HAVE_DEV_PTMX
|
||||
|
@ -34,235 +34,211 @@ RCSID("$Id: pty.c,v 1.3 1999/11/15 04:40:55 damien Exp $");
|
|||
|
||||
/* Allocates and opens a pty. Returns 0 if no pty could be allocated,
|
||||
or nonzero if a pty was successfully allocated. On success, open file
|
||||
descriptors for the pty and tty sides and the name of the tty side are
|
||||
descriptors for the pty and tty sides and the name of the tty side are
|
||||
returned (the buffer must be able to hold at least 64 characters). */
|
||||
|
||||
int pty_allocate(int *ptyfd, int *ttyfd, char *namebuf)
|
||||
int
|
||||
pty_allocate(int *ptyfd, int *ttyfd, char *namebuf)
|
||||
{
|
||||
#ifdef HAVE_OPENPTY
|
||||
/* openpty(3) exists in OSF/1 and some other os'es */
|
||||
int i;
|
||||
|
||||
/* openpty(3) exists in OSF/1 and some other os'es */
|
||||
|
||||
int i;
|
||||
|
||||
i = openpty(ptyfd, ttyfd, namebuf, NULL, NULL);
|
||||
|
||||
if (i < 0)
|
||||
{
|
||||
error("openpty: %.100s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
i = openpty(ptyfd, ttyfd, namebuf, NULL, NULL);
|
||||
if (i < 0) {
|
||||
error("openpty: %.100s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
#else /* HAVE_OPENPTY */
|
||||
#ifdef HAVE__GETPTY
|
||||
/* _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates
|
||||
more pty's automagically when needed */
|
||||
char *slave;
|
||||
|
||||
/* _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates more
|
||||
pty's automagically when needed */
|
||||
|
||||
char *slave;
|
||||
|
||||
slave = _getpty(ptyfd, O_RDWR, 0622, 0);
|
||||
if (slave == NULL)
|
||||
{
|
||||
error("_getpty: %.100s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
strcpy(namebuf, slave);
|
||||
/* Open the slave side. */
|
||||
*ttyfd = open(namebuf, O_RDWR|O_NOCTTY);
|
||||
if (*ttyfd < 0)
|
||||
{
|
||||
error("%.200s: %.100s", namebuf, strerror(errno));
|
||||
close(*ptyfd);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
||||
slave = _getpty(ptyfd, O_RDWR, 0622, 0);
|
||||
if (slave == NULL) {
|
||||
error("_getpty: %.100s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
strcpy(namebuf, slave);
|
||||
/* Open the slave side. */
|
||||
*ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
|
||||
if (*ttyfd < 0) {
|
||||
error("%.200s: %.100s", namebuf, strerror(errno));
|
||||
close(*ptyfd);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
#else /* HAVE__GETPTY */
|
||||
#ifdef HAVE_DEV_PTMX
|
||||
/* This code is used e.g. on Solaris 2.x. (Note that Solaris 2.3 also has
|
||||
bsd-style ptys, but they simply do not work.) */
|
||||
/* This code is used e.g. on Solaris 2.x. (Note that Solaris 2.3
|
||||
also has bsd-style ptys, but they simply do not work.) */
|
||||
int ptm;
|
||||
char *pts;
|
||||
|
||||
int ptm;
|
||||
char *pts;
|
||||
|
||||
ptm = open("/dev/ptmx", O_RDWR|O_NOCTTY);
|
||||
if (ptm < 0)
|
||||
{
|
||||
error("/dev/ptmx: %.100s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
if (grantpt(ptm) < 0)
|
||||
{
|
||||
error("grantpt: %.100s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
if (unlockpt(ptm) < 0)
|
||||
{
|
||||
error("unlockpt: %.100s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
pts = ptsname(ptm);
|
||||
if (pts == NULL)
|
||||
error("Slave pty side name could not be obtained.");
|
||||
strcpy(namebuf, pts);
|
||||
*ptyfd = ptm;
|
||||
|
||||
/* Open the slave side. */
|
||||
*ttyfd = open(namebuf, O_RDWR|O_NOCTTY);
|
||||
if (*ttyfd < 0)
|
||||
{
|
||||
error("%.100s: %.100s", namebuf, strerror(errno));
|
||||
close(*ptyfd);
|
||||
return 0;
|
||||
}
|
||||
/* Push the appropriate streams modules, as described in Solaris pts(7). */
|
||||
if (ioctl(*ttyfd, I_PUSH, "ptem") < 0)
|
||||
error("ioctl I_PUSH ptem: %.100s", strerror(errno));
|
||||
if (ioctl(*ttyfd, I_PUSH, "ldterm") < 0)
|
||||
error("ioctl I_PUSH ldterm: %.100s", strerror(errno));
|
||||
if (ioctl(*ttyfd, I_PUSH, "ttcompat") < 0)
|
||||
error("ioctl I_PUSH ttcompat: %.100s", strerror(errno));
|
||||
return 1;
|
||||
ptm = open("/dev/ptmx", O_RDWR | O_NOCTTY);
|
||||
if (ptm < 0) {
|
||||
error("/dev/ptmx: %.100s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
if (grantpt(ptm) < 0) {
|
||||
error("grantpt: %.100s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
if (unlockpt(ptm) < 0) {
|
||||
error("unlockpt: %.100s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
pts = ptsname(ptm);
|
||||
if (pts == NULL)
|
||||
error("Slave pty side name could not be obtained.");
|
||||
strcpy(namebuf, pts);
|
||||
*ptyfd = ptm;
|
||||
|
||||
/* Open the slave side. */
|
||||
*ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
|
||||
if (*ttyfd < 0) {
|
||||
error("%.100s: %.100s", namebuf, strerror(errno));
|
||||
close(*ptyfd);
|
||||
return 0;
|
||||
}
|
||||
/* Push the appropriate streams modules, as described in Solaris
|
||||
pts(7). */
|
||||
if (ioctl(*ttyfd, I_PUSH, "ptem") < 0)
|
||||
error("ioctl I_PUSH ptem: %.100s", strerror(errno));
|
||||
if (ioctl(*ttyfd, I_PUSH, "ldterm") < 0)
|
||||
error("ioctl I_PUSH ldterm: %.100s", strerror(errno));
|
||||
if (ioctl(*ttyfd, I_PUSH, "ttcompat") < 0)
|
||||
error("ioctl I_PUSH ttcompat: %.100s", strerror(errno));
|
||||
return 1;
|
||||
#else /* HAVE_DEV_PTMX */
|
||||
#ifdef HAVE_DEV_PTS_AND_PTC
|
||||
/* AIX-style pty code. */
|
||||
const char *name;
|
||||
|
||||
/* AIX-style pty code. */
|
||||
|
||||
const char *name;
|
||||
|
||||
*ptyfd = open("/dev/ptc", O_RDWR|O_NOCTTY);
|
||||
if (*ptyfd < 0)
|
||||
{
|
||||
error("Could not open /dev/ptc: %.100s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
name = ttyname(*ptyfd);
|
||||
if (!name)
|
||||
fatal("Open of /dev/ptc returns device for which ttyname fails.");
|
||||
strcpy(namebuf, name);
|
||||
*ttyfd = open(name, O_RDWR|O_NOCTTY);
|
||||
if (*ttyfd < 0)
|
||||
{
|
||||
error("Could not open pty slave side %.100s: %.100s",
|
||||
name, strerror(errno));
|
||||
close(*ptyfd);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
||||
#else /* HAVE_DEV_PTS_AND_PTC */
|
||||
/* BSD-style pty code. */
|
||||
|
||||
char buf[64];
|
||||
int i;
|
||||
const char *ptymajors =
|
||||
"pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
const char *ptyminors = "0123456789abcdef";
|
||||
int num_minors = strlen(ptyminors);
|
||||
int num_ptys = strlen(ptymajors) * num_minors;
|
||||
|
||||
for (i = 0; i < num_ptys; i++)
|
||||
{
|
||||
snprintf(buf, sizeof buf, "/dev/pty%c%c", ptymajors[i / num_minors],
|
||||
ptyminors[i % num_minors]);
|
||||
*ptyfd = open(buf, O_RDWR|O_NOCTTY);
|
||||
if (*ptyfd < 0)
|
||||
continue;
|
||||
snprintf(namebuf, sizeof buf, "/dev/tty%c%c", ptymajors[i / num_minors],
|
||||
ptyminors[i % num_minors]);
|
||||
|
||||
/* Open the slave side. */
|
||||
*ttyfd = open(namebuf, O_RDWR|O_NOCTTY);
|
||||
if (*ttyfd < 0)
|
||||
{
|
||||
error("%.100s: %.100s", namebuf, strerror(errno));
|
||||
close(*ptyfd);
|
||||
return 0;
|
||||
*ptyfd = open("/dev/ptc", O_RDWR | O_NOCTTY);
|
||||
if (*ptyfd < 0) {
|
||||
error("Could not open /dev/ptc: %.100s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
name = ttyname(*ptyfd);
|
||||
if (!name)
|
||||
fatal("Open of /dev/ptc returns device for which ttyname fails.");
|
||||
strcpy(namebuf, name);
|
||||
*ttyfd = open(name, O_RDWR | O_NOCTTY);
|
||||
if (*ttyfd < 0) {
|
||||
error("Could not open pty slave side %.100s: %.100s",
|
||||
name, strerror(errno));
|
||||
close(*ptyfd);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
#else /* HAVE_DEV_PTS_AND_PTC */
|
||||
/* BSD-style pty code. */
|
||||
char buf[64];
|
||||
int i;
|
||||
const char *ptymajors =
|
||||
"pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
const char *ptyminors = "0123456789abcdef";
|
||||
int num_minors = strlen(ptyminors);
|
||||
int num_ptys = strlen(ptymajors) * num_minors;
|
||||
|
||||
for (i = 0; i < num_ptys; i++) {
|
||||
snprintf(buf, sizeof buf, "/dev/pty%c%c", ptymajors[i / num_minors],
|
||||
ptyminors[i % num_minors]);
|
||||
*ptyfd = open(buf, O_RDWR | O_NOCTTY);
|
||||
if (*ptyfd < 0)
|
||||
continue;
|
||||
snprintf(namebuf, sizeof buf, "/dev/tty%c%c", ptymajors[i / num_minors],
|
||||
ptyminors[i % num_minors]);
|
||||
|
||||
/* Open the slave side. */
|
||||
*ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
|
||||
if (*ttyfd < 0) {
|
||||
error("%.100s: %.100s", namebuf, strerror(errno));
|
||||
close(*ptyfd);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
#endif /* HAVE_DEV_PTS_AND_PTC */
|
||||
#endif /* HAVE_DEV_PTMX */
|
||||
#endif /* HAVE__GETPTY */
|
||||
#endif /* HAVE_OPENPTY */
|
||||
}
|
||||
|
||||
/* Releases the tty. Its ownership is returned to root, and permissions to
|
||||
0666. */
|
||||
/* Releases the tty. Its ownership is returned to root, and permissions to 0666. */
|
||||
|
||||
void pty_release(const char *ttyname)
|
||||
void
|
||||
pty_release(const char *ttyname)
|
||||
{
|
||||
if (chown(ttyname, (uid_t)0, (gid_t)0) < 0)
|
||||
debug("chown %.100s 0 0 failed: %.100s", ttyname, strerror(errno));
|
||||
if (chmod(ttyname, (mode_t)0666) < 0)
|
||||
debug("chmod %.100s 0666 failed: %.100s", ttyname, strerror(errno));
|
||||
if (chown(ttyname, (uid_t) 0, (gid_t) 0) < 0)
|
||||
debug("chown %.100s 0 0 failed: %.100s", ttyname, strerror(errno));
|
||||
if (chmod(ttyname, (mode_t) 0666) < 0)
|
||||
debug("chmod %.100s 0666 failed: %.100s", ttyname, strerror(errno));
|
||||
}
|
||||
|
||||
/* Makes the tty the processes controlling tty and sets it to sane modes. */
|
||||
|
||||
void pty_make_controlling_tty(int *ttyfd, const char *ttyname)
|
||||
void
|
||||
pty_make_controlling_tty(int *ttyfd, const char *ttyname)
|
||||
{
|
||||
int fd;
|
||||
int fd;
|
||||
|
||||
/* First disconnect from the old controlling tty. */
|
||||
/* First disconnect from the old controlling tty. */
|
||||
#ifdef TIOCNOTTY
|
||||
fd = open("/dev/tty", O_RDWR|O_NOCTTY);
|
||||
if (fd >= 0)
|
||||
{
|
||||
(void)ioctl(fd, TIOCNOTTY, NULL);
|
||||
close(fd);
|
||||
}
|
||||
fd = open("/dev/tty", O_RDWR | O_NOCTTY);
|
||||
if (fd >= 0) {
|
||||
(void) ioctl(fd, TIOCNOTTY, NULL);
|
||||
close(fd);
|
||||
}
|
||||
#endif /* TIOCNOTTY */
|
||||
if (setsid() < 0)
|
||||
error("setsid: %.100s", strerror(errno));
|
||||
|
||||
/* Verify that we are successfully disconnected from the controlling tty. */
|
||||
fd = open("/dev/tty", O_RDWR|O_NOCTTY);
|
||||
if (fd >= 0)
|
||||
{
|
||||
error("Failed to disconnect from controlling tty.");
|
||||
close(fd);
|
||||
}
|
||||
if (setsid() < 0)
|
||||
error("setsid: %.100s", strerror(errno));
|
||||
|
||||
/* Make it our controlling tty. */
|
||||
/* Verify that we are successfully disconnected from the
|
||||
controlling tty. */
|
||||
fd = open("/dev/tty", O_RDWR | O_NOCTTY);
|
||||
if (fd >= 0) {
|
||||
error("Failed to disconnect from controlling tty.");
|
||||
close(fd);
|
||||
}
|
||||
/* Make it our controlling tty. */
|
||||
#ifdef TIOCSCTTY
|
||||
debug("Setting controlling tty using TIOCSCTTY.");
|
||||
/* We ignore errors from this, because HPSUX defines TIOCSCTTY, but returns
|
||||
EINVAL with these arguments, and there is absolutely no documentation. */
|
||||
ioctl(*ttyfd, TIOCSCTTY, NULL);
|
||||
debug("Setting controlling tty using TIOCSCTTY.");
|
||||
/* We ignore errors from this, because HPSUX defines TIOCSCTTY,
|
||||
but returns EINVAL with these arguments, and there is
|
||||
absolutely no documentation. */
|
||||
ioctl(*ttyfd, TIOCSCTTY, NULL);
|
||||
#endif /* TIOCSCTTY */
|
||||
fd = open(ttyname, O_RDWR);
|
||||
if (fd < 0)
|
||||
error("%.100s: %.100s", ttyname, strerror(errno));
|
||||
else
|
||||
close(fd);
|
||||
fd = open(ttyname, O_RDWR);
|
||||
if (fd < 0)
|
||||
error("%.100s: %.100s", ttyname, strerror(errno));
|
||||
else
|
||||
close(fd);
|
||||
|
||||
/* Verify that we now have a controlling tty. */
|
||||
fd = open("/dev/tty", O_WRONLY);
|
||||
if (fd < 0)
|
||||
error("open /dev/tty failed - could not set controlling tty: %.100s",
|
||||
strerror(errno));
|
||||
else
|
||||
{
|
||||
close(fd);
|
||||
}
|
||||
/* Verify that we now have a controlling tty. */
|
||||
fd = open("/dev/tty", O_WRONLY);
|
||||
if (fd < 0)
|
||||
error("open /dev/tty failed - could not set controlling tty: %.100s",
|
||||
strerror(errno));
|
||||
else {
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
/* Changes the window size associated with the pty. */
|
||||
|
||||
void pty_change_window_size(int ptyfd, int row, int col,
|
||||
int xpixel, int ypixel)
|
||||
void
|
||||
pty_change_window_size(int ptyfd, int row, int col,
|
||||
int xpixel, int ypixel)
|
||||
{
|
||||
struct winsize w;
|
||||
w.ws_row = row;
|
||||
w.ws_col = col;
|
||||
w.ws_xpixel = xpixel;
|
||||
w.ws_ypixel = ypixel;
|
||||
(void)ioctl(ptyfd, TIOCSWINSZ, &w);
|
||||
struct winsize w;
|
||||
w.ws_row = row;
|
||||
w.ws_col = col;
|
||||
w.ws_xpixel = xpixel;
|
||||
w.ws_ypixel = ypixel;
|
||||
(void) ioctl(ptyfd, TIOCSWINSZ, &w);
|
||||
}
|
||||
|
||||
|
|
46
pty.h
46
pty.h
|
@ -1,40 +1,40 @@
|
|||
/*
|
||||
*
|
||||
* pty.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Fri Mar 17 05:03:28 1995 ylo
|
||||
*
|
||||
* Functions for allocating a pseudo-terminal and making it the controlling
|
||||
* tty.
|
||||
*/
|
||||
|
||||
pty.h
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Fri Mar 17 05:03:28 1995 ylo
|
||||
|
||||
Functions for allocating a pseudo-terminal and making it the controlling
|
||||
tty.
|
||||
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: pty.h,v 1.1 1999/10/27 03:42:44 damien Exp $"); */
|
||||
/* RCSID("$Id: pty.h,v 1.2 1999/11/24 13:26:22 damien Exp $"); */
|
||||
|
||||
#ifndef PTY_H
|
||||
#define PTY_H
|
||||
|
||||
/* Allocates and opens a pty. Returns 0 if no pty could be allocated,
|
||||
or nonzero if a pty was successfully allocated. On success, open file
|
||||
descriptors for the pty and tty sides and the name of the tty side are
|
||||
descriptors for the pty and tty sides and the name of the tty side are
|
||||
returned (the buffer must be able to hold at least 64 characters). */
|
||||
int pty_allocate(int *ptyfd, int *ttyfd, char *ttyname);
|
||||
int pty_allocate(int *ptyfd, int *ttyfd, char *ttyname);
|
||||
|
||||
/* Releases the tty. Its ownership is returned to root, and permissions to
|
||||
0666. */
|
||||
void pty_release(const char *ttyname);
|
||||
void pty_release(const char *ttyname);
|
||||
|
||||
/* Makes the tty the processes controlling tty and sets it to sane modes.
|
||||
/* Makes the tty the processes controlling tty and sets it to sane modes.
|
||||
This may need to reopen the tty to get rid of possible eavesdroppers. */
|
||||
void pty_make_controlling_tty(int *ttyfd, const char *ttyname);
|
||||
void pty_make_controlling_tty(int *ttyfd, const char *ttyname);
|
||||
|
||||
/* Changes the window size associated with the pty. */
|
||||
void pty_change_window_size(int ptyfd, int row, int col,
|
||||
int xpixel, int ypixel);
|
||||
void
|
||||
pty_change_window_size(int ptyfd, int row, int col,
|
||||
int xpixel, int ypixel);
|
||||
|
||||
#endif /* PTY_H */
|
||||
#endif /* PTY_H */
|
||||
|
|
353
radix.c
353
radix.c
|
@ -1,101 +1,105 @@
|
|||
/*
|
||||
radix.c
|
||||
* radix.c
|
||||
*
|
||||
* base-64 encoding pinched from lynx2-7-2, who pinched it from rpem.
|
||||
* Originally written by Mark Riordan 12 August 1990 and 17 Feb 1991
|
||||
* and placed in the public domain.
|
||||
*
|
||||
* Dug Song <dugsong@UMICH.EDU>
|
||||
*/
|
||||
|
||||
base-64 encoding pinched from lynx2-7-2, who pinched it from rpem.
|
||||
Originally written by Mark Riordan 12 August 1990 and 17 Feb 1991
|
||||
and placed in the public domain.
|
||||
|
||||
Dug Song <dugsong@UMICH.EDU>
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#ifdef AFS
|
||||
#include <krb.h>
|
||||
|
||||
char six2pr[64] = {
|
||||
'A','B','C','D','E','F','G','H','I','J','K','L','M',
|
||||
'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
|
||||
'a','b','c','d','e','f','g','h','i','j','k','l','m',
|
||||
'n','o','p','q','r','s','t','u','v','w','x','y','z',
|
||||
'0','1','2','3','4','5','6','7','8','9','+','/'
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
||||
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
|
||||
};
|
||||
|
||||
unsigned char pr2six[256];
|
||||
|
||||
int uuencode(unsigned char *bufin, unsigned int nbytes, char *bufcoded)
|
||||
int
|
||||
uuencode(unsigned char *bufin, unsigned int nbytes, char *bufcoded)
|
||||
{
|
||||
/* ENC is the basic 1 character encoding function to make a char printing */
|
||||
/* ENC is the basic 1 character encoding function to make a char printing */
|
||||
#define ENC(c) six2pr[c]
|
||||
|
||||
register char *outptr = bufcoded;
|
||||
unsigned int i;
|
||||
|
||||
for (i=0; i<nbytes; i += 3) {
|
||||
*(outptr++) = ENC(*bufin >> 2); /* c1 */
|
||||
*(outptr++) = ENC(((*bufin << 4) & 060) | ((bufin[1] >> 4) & 017)); /*c2*/
|
||||
*(outptr++) = ENC(((bufin[1] << 2) & 074) | ((bufin[2] >> 6) & 03));/*c3*/
|
||||
*(outptr++) = ENC(bufin[2] & 077); /* c4 */
|
||||
bufin += 3;
|
||||
}
|
||||
if (i == nbytes+1) {
|
||||
outptr[-1] = '=';
|
||||
} else if (i == nbytes+2) {
|
||||
outptr[-1] = '=';
|
||||
outptr[-2] = '=';
|
||||
}
|
||||
*outptr = '\0';
|
||||
return(outptr - bufcoded);
|
||||
|
||||
register char *outptr = bufcoded;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < nbytes; i += 3) {
|
||||
*(outptr++) = ENC(*bufin >> 2); /* c1 */
|
||||
*(outptr++) = ENC(((*bufin << 4) & 060) | ((bufin[1] >> 4) & 017)); /* c2 */
|
||||
*(outptr++) = ENC(((bufin[1] << 2) & 074) | ((bufin[2] >> 6) & 03)); /* c3 */
|
||||
*(outptr++) = ENC(bufin[2] & 077); /* c4 */
|
||||
bufin += 3;
|
||||
}
|
||||
if (i == nbytes + 1) {
|
||||
outptr[-1] = '=';
|
||||
} else if (i == nbytes + 2) {
|
||||
outptr[-1] = '=';
|
||||
outptr[-2] = '=';
|
||||
}
|
||||
*outptr = '\0';
|
||||
return (outptr - bufcoded);
|
||||
}
|
||||
|
||||
int uudecode(const char *bufcoded, unsigned char *bufplain, int outbufsize)
|
||||
int
|
||||
uudecode(const char *bufcoded, unsigned char *bufplain, int outbufsize)
|
||||
{
|
||||
/* single character decode */
|
||||
/* single character decode */
|
||||
#define DEC(c) pr2six[(unsigned char)c]
|
||||
#define MAXVAL 63
|
||||
|
||||
static int first = 1;
|
||||
int nbytesdecoded, j;
|
||||
const char *bufin = bufcoded;
|
||||
register unsigned char *bufout = bufplain;
|
||||
register int nprbytes;
|
||||
|
||||
/* If this is the first call, initialize the mapping table. */
|
||||
if (first) {
|
||||
first = 0;
|
||||
for(j=0; j<256; j++) pr2six[j] = MAXVAL+1;
|
||||
for(j=0; j<64; j++) pr2six[(unsigned char)six2pr[j]] = (unsigned char)j;
|
||||
}
|
||||
|
||||
/* Strip leading whitespace. */
|
||||
while (*bufcoded==' ' || *bufcoded == '\t') bufcoded++;
|
||||
|
||||
/* Figure out how many characters are in the input buffer.
|
||||
If this would decode into more bytes than would fit into
|
||||
the output buffer, adjust the number of input bytes downwards. */
|
||||
bufin = bufcoded;
|
||||
while (DEC(*(bufin++)) <= MAXVAL);
|
||||
nprbytes = bufin - bufcoded - 1;
|
||||
nbytesdecoded = ((nprbytes+3)/4) * 3;
|
||||
if (nbytesdecoded > outbufsize)
|
||||
nprbytes = (outbufsize*4)/3;
|
||||
|
||||
bufin = bufcoded;
|
||||
|
||||
while (nprbytes > 0) {
|
||||
*(bufout++) = (unsigned char) (DEC(*bufin) << 2 | DEC(bufin[1]) >> 4);
|
||||
*(bufout++) = (unsigned char) (DEC(bufin[1]) << 4 | DEC(bufin[2]) >> 2);
|
||||
*(bufout++) = (unsigned char) (DEC(bufin[2]) << 6 | DEC(bufin[3]));
|
||||
bufin += 4;
|
||||
nprbytes -= 4;
|
||||
}
|
||||
if (nprbytes & 03) {
|
||||
if (DEC(bufin[-2]) > MAXVAL)
|
||||
nbytesdecoded -= 2;
|
||||
else
|
||||
nbytesdecoded -= 1;
|
||||
}
|
||||
return(nbytesdecoded);
|
||||
|
||||
static int first = 1;
|
||||
int nbytesdecoded, j;
|
||||
const char *bufin = bufcoded;
|
||||
register unsigned char *bufout = bufplain;
|
||||
register int nprbytes;
|
||||
|
||||
/* If this is the first call, initialize the mapping table. */
|
||||
if (first) {
|
||||
first = 0;
|
||||
for (j = 0; j < 256; j++)
|
||||
pr2six[j] = MAXVAL + 1;
|
||||
for (j = 0; j < 64; j++)
|
||||
pr2six[(unsigned char) six2pr[j]] = (unsigned char) j;
|
||||
}
|
||||
/* Strip leading whitespace. */
|
||||
while (*bufcoded == ' ' || *bufcoded == '\t')
|
||||
bufcoded++;
|
||||
|
||||
/* Figure out how many characters are in the input buffer. If this
|
||||
would decode into more bytes than would fit into the output
|
||||
buffer, adjust the number of input bytes downwards. */
|
||||
bufin = bufcoded;
|
||||
while (DEC(*(bufin++)) <= MAXVAL);
|
||||
nprbytes = bufin - bufcoded - 1;
|
||||
nbytesdecoded = ((nprbytes + 3) / 4) * 3;
|
||||
if (nbytesdecoded > outbufsize)
|
||||
nprbytes = (outbufsize * 4) / 3;
|
||||
|
||||
bufin = bufcoded;
|
||||
|
||||
while (nprbytes > 0) {
|
||||
*(bufout++) = (unsigned char) (DEC(*bufin) << 2 | DEC(bufin[1]) >> 4);
|
||||
*(bufout++) = (unsigned char) (DEC(bufin[1]) << 4 | DEC(bufin[2]) >> 2);
|
||||
*(bufout++) = (unsigned char) (DEC(bufin[2]) << 6 | DEC(bufin[3]));
|
||||
bufin += 4;
|
||||
nprbytes -= 4;
|
||||
}
|
||||
if (nprbytes & 03) {
|
||||
if (DEC(bufin[-2]) > MAXVAL)
|
||||
nbytesdecoded -= 2;
|
||||
else
|
||||
nbytesdecoded -= 1;
|
||||
}
|
||||
return (nbytesdecoded);
|
||||
}
|
||||
|
||||
typedef unsigned char my_u_char;
|
||||
|
@ -156,103 +160,124 @@ typedef unsigned short my_u_short;
|
|||
}
|
||||
|
||||
|
||||
int creds_to_radix(CREDENTIALS *creds, unsigned char *buf)
|
||||
int
|
||||
creds_to_radix(CREDENTIALS *creds, unsigned char *buf)
|
||||
{
|
||||
char *p, *s;
|
||||
int len;
|
||||
char temp[2048];
|
||||
|
||||
p = temp;
|
||||
*p++ = 1; /* version */
|
||||
s = creds->service; while (*s) *p++ = *s++; *p++ = *s;
|
||||
s = creds->instance; while (*s) *p++ = *s++; *p++ = *s;
|
||||
s = creds->realm; while (*s) *p++ = *s++; *p++ = *s;
|
||||
char *p, *s;
|
||||
int len;
|
||||
char temp[2048];
|
||||
|
||||
s = creds->pname; while (*s) *p++ = *s++; *p++ = *s;
|
||||
s = creds->pinst; while (*s) *p++ = *s++; *p++ = *s;
|
||||
/* Null string to repeat the realm. */
|
||||
*p++ = '\0';
|
||||
p = temp;
|
||||
*p++ = 1; /* version */
|
||||
s = creds->service;
|
||||
while (*s)
|
||||
*p++ = *s++;
|
||||
*p++ = *s;
|
||||
s = creds->instance;
|
||||
while (*s)
|
||||
*p++ = *s++;
|
||||
*p++ = *s;
|
||||
s = creds->realm;
|
||||
while (*s)
|
||||
*p++ = *s++;
|
||||
*p++ = *s;
|
||||
|
||||
PUTLONG(creds->issue_date,p);
|
||||
{
|
||||
unsigned int endTime ;
|
||||
endTime = (unsigned int)krb_life_to_time(creds->issue_date,
|
||||
creds->lifetime);
|
||||
PUTLONG(endTime,p);
|
||||
}
|
||||
s = creds->pname;
|
||||
while (*s)
|
||||
*p++ = *s++;
|
||||
*p++ = *s;
|
||||
s = creds->pinst;
|
||||
while (*s)
|
||||
*p++ = *s++;
|
||||
*p++ = *s;
|
||||
/* Null string to repeat the realm. */
|
||||
*p++ = '\0';
|
||||
|
||||
memcpy(p,&creds->session, sizeof(creds->session));
|
||||
p += sizeof(creds->session);
|
||||
|
||||
PUTSHORT(creds->kvno,p);
|
||||
PUTLONG(creds->ticket_st.length,p);
|
||||
|
||||
memcpy(p,creds->ticket_st.dat, creds->ticket_st.length);
|
||||
p += creds->ticket_st.length;
|
||||
len = p - temp;
|
||||
PUTLONG(creds->issue_date, p);
|
||||
{
|
||||
unsigned int endTime;
|
||||
endTime = (unsigned int) krb_life_to_time(creds->issue_date,
|
||||
creds->lifetime);
|
||||
PUTLONG(endTime, p);
|
||||
}
|
||||
|
||||
return(uuencode(temp, len, buf));
|
||||
memcpy(p, &creds->session, sizeof(creds->session));
|
||||
p += sizeof(creds->session);
|
||||
|
||||
PUTSHORT(creds->kvno, p);
|
||||
PUTLONG(creds->ticket_st.length, p);
|
||||
|
||||
memcpy(p, creds->ticket_st.dat, creds->ticket_st.length);
|
||||
p += creds->ticket_st.length;
|
||||
len = p - temp;
|
||||
|
||||
return (uuencode(temp, len, buf));
|
||||
}
|
||||
|
||||
int radix_to_creds(const char *buf, CREDENTIALS *creds)
|
||||
int
|
||||
radix_to_creds(const char *buf, CREDENTIALS *creds)
|
||||
{
|
||||
|
||||
char *p;
|
||||
int len, tl;
|
||||
char version;
|
||||
char temp[2048];
|
||||
|
||||
if (!(len = uudecode(buf, temp, sizeof(temp))))
|
||||
return 0;
|
||||
|
||||
p = temp;
|
||||
char *p;
|
||||
int len, tl;
|
||||
char version;
|
||||
char temp[2048];
|
||||
|
||||
/* check version and length! */
|
||||
if (len < 1) return 0;
|
||||
version = *p; p++; len--;
|
||||
if (!(len = uudecode(buf, temp, sizeof(temp))))
|
||||
return 0;
|
||||
|
||||
GETSTRING(creds->service, p, len);
|
||||
GETSTRING(creds->instance, p, len);
|
||||
GETSTRING(creds->realm, p, len);
|
||||
|
||||
GETSTRING(creds->pname, p, len);
|
||||
GETSTRING(creds->pinst, p, len);
|
||||
/* Ignore possibly different realm. */
|
||||
while (*p && len) p++, len--;
|
||||
if (len == 0) return 0;
|
||||
p++, len--;
|
||||
|
||||
/* Enough space for remaining fixed-length parts? */
|
||||
if (len < (4 + 4 + sizeof(creds->session) + 2 + 4))
|
||||
return 0;
|
||||
|
||||
GETLONG(creds->issue_date,p);
|
||||
len -= 4;
|
||||
{
|
||||
unsigned int endTime;
|
||||
GETLONG(endTime,p);
|
||||
len -= 4;
|
||||
creds->lifetime = krb_time_to_life(creds->issue_date, endTime);
|
||||
}
|
||||
p = temp;
|
||||
|
||||
memcpy(&creds->session, p, sizeof(creds->session));
|
||||
p += sizeof(creds->session);
|
||||
len -= sizeof(creds->session);
|
||||
|
||||
GETSHORT(creds->kvno,p);
|
||||
len -= 2;
|
||||
GETLONG(creds->ticket_st.length,p);
|
||||
len -= 4;
|
||||
/* check version and length! */
|
||||
if (len < 1)
|
||||
return 0;
|
||||
version = *p;
|
||||
p++;
|
||||
len--;
|
||||
|
||||
tl = creds->ticket_st.length;
|
||||
if (tl < 0 || tl > len || tl > sizeof(creds->ticket_st.dat))
|
||||
return 0;
|
||||
|
||||
memcpy(creds->ticket_st.dat, p, tl);
|
||||
p += tl;
|
||||
len -= tl;
|
||||
|
||||
return 1;
|
||||
GETSTRING(creds->service, p, len);
|
||||
GETSTRING(creds->instance, p, len);
|
||||
GETSTRING(creds->realm, p, len);
|
||||
|
||||
GETSTRING(creds->pname, p, len);
|
||||
GETSTRING(creds->pinst, p, len);
|
||||
/* Ignore possibly different realm. */
|
||||
while (*p && len)
|
||||
p++, len--;
|
||||
if (len == 0)
|
||||
return 0;
|
||||
p++, len--;
|
||||
|
||||
/* Enough space for remaining fixed-length parts? */
|
||||
if (len < (4 + 4 + sizeof(creds->session) + 2 + 4))
|
||||
return 0;
|
||||
|
||||
GETLONG(creds->issue_date, p);
|
||||
len -= 4;
|
||||
{
|
||||
unsigned int endTime;
|
||||
GETLONG(endTime, p);
|
||||
len -= 4;
|
||||
creds->lifetime = krb_time_to_life(creds->issue_date, endTime);
|
||||
}
|
||||
|
||||
memcpy(&creds->session, p, sizeof(creds->session));
|
||||
p += sizeof(creds->session);
|
||||
len -= sizeof(creds->session);
|
||||
|
||||
GETSHORT(creds->kvno, p);
|
||||
len -= 2;
|
||||
GETLONG(creds->ticket_st.length, p);
|
||||
len -= 4;
|
||||
|
||||
tl = creds->ticket_st.length;
|
||||
if (tl < 0 || tl > len || tl > sizeof(creds->ticket_st.dat))
|
||||
return 0;
|
||||
|
||||
memcpy(creds->ticket_st.dat, p, tl);
|
||||
p += tl;
|
||||
len -= tl;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* AFS */
|
||||
|
|
1059
readconf.c
1059
readconf.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
158
readconf.h
158
readconf.h
|
@ -1,118 +1,126 @@
|
|||
/*
|
||||
*
|
||||
* readconf.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Sat Apr 22 00:25:29 1995 ylo
|
||||
*
|
||||
* Functions for reading the configuration file.
|
||||
*
|
||||
*/
|
||||
|
||||
readconf.h
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Sat Apr 22 00:25:29 1995 ylo
|
||||
|
||||
Functions for reading the configuration file.
|
||||
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: readconf.h,v 1.3 1999/11/15 04:25:10 damien Exp $"); */
|
||||
/* RCSID("$Id: readconf.h,v 1.4 1999/11/24 13:26:22 damien Exp $"); */
|
||||
|
||||
#ifndef READCONF_H
|
||||
#define READCONF_H
|
||||
|
||||
/* Data structure for representing a forwarding request. */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int port; /* Port to forward. */
|
||||
char *host; /* Host to connect. */
|
||||
int host_port; /* Port to connect on host. */
|
||||
} Forward;
|
||||
|
||||
typedef struct {
|
||||
int port; /* Port to forward. */
|
||||
char *host; /* Host to connect. */
|
||||
int host_port; /* Port to connect on host. */
|
||||
} Forward;
|
||||
/* Data structure for representing option data. */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int forward_agent; /* Forward authentication agent. */
|
||||
int forward_x11; /* Forward X11 display. */
|
||||
int gateway_ports; /* Allow remote connects to forwarded ports. */
|
||||
int use_privileged_port; /* Don't use privileged port if false. */
|
||||
int rhosts_authentication; /* Try rhosts authentication. */
|
||||
int rhosts_rsa_authentication;/* Try rhosts with RSA authentication. */
|
||||
int rsa_authentication; /* Try RSA authentication. */
|
||||
typedef struct {
|
||||
int forward_agent; /* Forward authentication agent. */
|
||||
int forward_x11; /* Forward X11 display. */
|
||||
int gateway_ports; /* Allow remote connects to forwarded ports. */
|
||||
int use_privileged_port; /* Don't use privileged port if false. */
|
||||
int rhosts_authentication; /* Try rhosts authentication. */
|
||||
int rhosts_rsa_authentication; /* Try rhosts with RSA
|
||||
* authentication. */
|
||||
int rsa_authentication; /* Try RSA authentication. */
|
||||
int skey_authentication; /* Try S/Key or TIS authentication. */
|
||||
#ifdef KRB4
|
||||
int kerberos_authentication; /* Try Kerberos authentication. */
|
||||
int kerberos_authentication; /* Try Kerberos
|
||||
* authentication. */
|
||||
#endif
|
||||
#ifdef AFS
|
||||
int kerberos_tgt_passing; /* Try Kerberos tgt passing. */
|
||||
int afs_token_passing; /* Try AFS token passing. */
|
||||
int kerberos_tgt_passing; /* Try Kerberos tgt passing. */
|
||||
int afs_token_passing; /* Try AFS token passing. */
|
||||
#endif
|
||||
int password_authentication; /* Try password authentication. */
|
||||
int fallback_to_rsh; /* Use rsh if cannot connect with ssh. */
|
||||
int use_rsh; /* Always use rsh (don\'t try ssh). */
|
||||
int batch_mode; /* Batch mode: do not ask for passwords. */
|
||||
int check_host_ip; /* Also keep track of keys for IP address */
|
||||
int strict_host_key_checking; /* Strict host key checking. */
|
||||
int compression; /* Compress packets in both directions. */
|
||||
int compression_level; /* Compression level 1 (fast) to 9 (best). */
|
||||
int keepalives; /* Set SO_KEEPALIVE. */
|
||||
LogLevel log_level; /* Level for logging. */
|
||||
int password_authentication; /* Try password
|
||||
* authentication. */
|
||||
int fallback_to_rsh;/* Use rsh if cannot connect with ssh. */
|
||||
int use_rsh; /* Always use rsh (don\'t try ssh). */
|
||||
int batch_mode; /* Batch mode: do not ask for passwords. */
|
||||
int check_host_ip; /* Also keep track of keys for IP address */
|
||||
int strict_host_key_checking; /* Strict host key checking. */
|
||||
int compression; /* Compress packets in both directions. */
|
||||
int compression_level; /* Compression level 1 (fast) to 9
|
||||
* (best). */
|
||||
int keepalives; /* Set SO_KEEPALIVE. */
|
||||
LogLevel log_level; /* Level for logging. */
|
||||
|
||||
int port; /* Port to connect. */
|
||||
int connection_attempts; /* Max attempts (seconds) before giving up */
|
||||
int number_of_password_prompts; /* Max number of password prompts. */
|
||||
int cipher; /* Cipher to use. */
|
||||
char *hostname; /* Real host to connect. */
|
||||
char *proxy_command; /* Proxy command for connecting the host. */
|
||||
char *user; /* User to log in as. */
|
||||
int escape_char; /* Escape character; -2 = none */
|
||||
int port; /* Port to connect. */
|
||||
int connection_attempts; /* Max attempts (seconds) before
|
||||
* giving up */
|
||||
int number_of_password_prompts; /* Max number of password
|
||||
* prompts. */
|
||||
int cipher; /* Cipher to use. */
|
||||
char *hostname; /* Real host to connect. */
|
||||
char *proxy_command; /* Proxy command for connecting the host. */
|
||||
char *user; /* User to log in as. */
|
||||
int escape_char; /* Escape character; -2 = none */
|
||||
|
||||
char *system_hostfile; /* Path for /etc/ssh_known_hosts. */
|
||||
char *user_hostfile; /* Path for $HOME/.ssh/known_hosts. */
|
||||
char *system_hostfile;/* Path for /etc/ssh_known_hosts. */
|
||||
char *user_hostfile; /* Path for $HOME/.ssh/known_hosts. */
|
||||
|
||||
int num_identity_files; /* Number of files for RSA identities. */
|
||||
char *identity_files[SSH_MAX_IDENTITY_FILES];
|
||||
int num_identity_files; /* Number of files for RSA identities. */
|
||||
char *identity_files[SSH_MAX_IDENTITY_FILES];
|
||||
|
||||
/* Local TCP/IP forward requests. */
|
||||
int num_local_forwards;
|
||||
Forward local_forwards[SSH_MAX_FORWARDS_PER_DIRECTION];
|
||||
/* Local TCP/IP forward requests. */
|
||||
int num_local_forwards;
|
||||
Forward local_forwards[SSH_MAX_FORWARDS_PER_DIRECTION];
|
||||
|
||||
/* Remote TCP/IP forward requests. */
|
||||
int num_remote_forwards;
|
||||
Forward remote_forwards[SSH_MAX_FORWARDS_PER_DIRECTION];
|
||||
} Options;
|
||||
/* Remote TCP/IP forward requests. */
|
||||
int num_remote_forwards;
|
||||
Forward remote_forwards[SSH_MAX_FORWARDS_PER_DIRECTION];
|
||||
} 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 * 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);
|
||||
void fill_default_options(Options * options);
|
||||
|
||||
/* Processes a single option line as used in the configuration files.
|
||||
/* 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);
|
||||
int
|
||||
process_config_line(Options * options, const char *host,
|
||||
char *line, const char *filename, int linenum,
|
||||
int *activep);
|
||||
|
||||
/* 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);
|
||||
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, int port, const char *host,
|
||||
int host_port);
|
||||
void
|
||||
add_local_forward(Options * options, int port, const char *host,
|
||||
int host_port);
|
||||
|
||||
/* Adds a remote TCP/IP port forward to options. Never returns if there
|
||||
is an error. */
|
||||
void add_remote_forward(Options *options, int port, const char *host,
|
||||
int host_port);
|
||||
void
|
||||
add_remote_forward(Options * options, int port, const char *host,
|
||||
int host_port);
|
||||
|
||||
|
||||
#endif /* READCONF_H */
|
||||
#endif /* READCONF_H */
|
||||
|
|
173
readpass.c
173
readpass.c
|
@ -1,20 +1,20 @@
|
|||
/*
|
||||
|
||||
readpass.c
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Mon Jul 10 22:08:59 1995 ylo
|
||||
|
||||
Functions for reading passphrases and passwords.
|
||||
|
||||
*/
|
||||
*
|
||||
* readpass.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Mon Jul 10 22:08:59 1995 ylo
|
||||
*
|
||||
* Functions for reading passphrases and passwords.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: readpass.c,v 1.1 1999/10/27 03:42:44 damien Exp $");
|
||||
RCSID("$Id: readpass.c,v 1.2 1999/11/24 13:26:22 damien Exp $");
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
|
@ -23,92 +23,91 @@ RCSID("$Id: readpass.c,v 1.1 1999/10/27 03:42:44 damien Exp $");
|
|||
static struct termios saved_tio;
|
||||
|
||||
/* Old interrupt signal handler for read_passphrase. */
|
||||
static void (*old_handler)(int sig) = NULL;
|
||||
static void (*old_handler) (int sig) = NULL;
|
||||
|
||||
/* Interrupt signal handler for read_passphrase. */
|
||||
|
||||
void intr_handler(int sig)
|
||||
void
|
||||
intr_handler(int sig)
|
||||
{
|
||||
/* Restore terminal modes. */
|
||||
tcsetattr(fileno(stdin), TCSANOW, &saved_tio);
|
||||
/* Restore the old signal handler. */
|
||||
signal(sig, old_handler);
|
||||
/* Resend the signal, with the old handler. */
|
||||
kill(getpid(), sig);
|
||||
/* Restore terminal modes. */
|
||||
tcsetattr(fileno(stdin), TCSANOW, &saved_tio);
|
||||
/* Restore the old signal handler. */
|
||||
signal(sig, old_handler);
|
||||
/* Resend the signal, with the old handler. */
|
||||
kill(getpid(), sig);
|
||||
}
|
||||
|
||||
/* Reads a passphrase from /dev/tty with echo turned off. Returns the
|
||||
passphrase (allocated with xmalloc). Exits if EOF is encountered.
|
||||
/* Reads a passphrase from /dev/tty with echo turned off. Returns the
|
||||
passphrase (allocated with xmalloc). Exits if EOF is encountered.
|
||||
The passphrase if read from stdin if from_stdin is true (as is the
|
||||
case with ssh-keygen). */
|
||||
|
||||
char *read_passphrase(const char *prompt, int from_stdin)
|
||||
char *
|
||||
read_passphrase(const char *prompt, int from_stdin)
|
||||
{
|
||||
char buf[1024], *cp;
|
||||
struct termios tio;
|
||||
FILE *f;
|
||||
|
||||
if (from_stdin)
|
||||
f = stdin;
|
||||
else
|
||||
{
|
||||
/* Read the passphrase from /dev/tty to make it possible to ask it even
|
||||
when stdin has been redirected. */
|
||||
f = fopen("/dev/tty", "r");
|
||||
if (!f)
|
||||
{
|
||||
/* No controlling terminal and no DISPLAY. Nowhere to read. */
|
||||
fprintf(stderr, "You have no controlling tty and no DISPLAY. Cannot read passphrase.\n");
|
||||
exit(1);
|
||||
char buf[1024], *cp;
|
||||
struct termios tio;
|
||||
FILE *f;
|
||||
|
||||
if (from_stdin)
|
||||
f = stdin;
|
||||
else {
|
||||
/* Read the passphrase from /dev/tty to make it possible
|
||||
to ask it even when stdin has been redirected. */
|
||||
f = fopen("/dev/tty", "r");
|
||||
if (!f) {
|
||||
/* No controlling terminal and no DISPLAY. Nowhere to read. */
|
||||
fprintf(stderr, "You have no controlling tty and no DISPLAY. Cannot read passphrase.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Display the prompt (on stderr because stdout might be redirected). */
|
||||
fflush(stdout);
|
||||
fprintf(stderr, "%s", prompt);
|
||||
fflush(stderr);
|
||||
/* Display the prompt (on stderr because stdout might be redirected). */
|
||||
fflush(stdout);
|
||||
fprintf(stderr, "%s", prompt);
|
||||
fflush(stderr);
|
||||
|
||||
/* Get terminal modes. */
|
||||
tcgetattr(fileno(f), &tio);
|
||||
saved_tio = tio;
|
||||
/* Save signal handler and set the new handler. */
|
||||
old_handler = signal(SIGINT, intr_handler);
|
||||
/* Get terminal modes. */
|
||||
tcgetattr(fileno(f), &tio);
|
||||
saved_tio = tio;
|
||||
/* Save signal handler and set the new handler. */
|
||||
old_handler = signal(SIGINT, intr_handler);
|
||||
|
||||
/* Set new terminal modes disabling all echo. */
|
||||
tio.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
|
||||
tcsetattr(fileno(f), TCSANOW, &tio);
|
||||
/* Set new terminal modes disabling all echo. */
|
||||
tio.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
|
||||
tcsetattr(fileno(f), TCSANOW, &tio);
|
||||
|
||||
/* Read the passphrase from the terminal. */
|
||||
if (fgets(buf, sizeof(buf), f) == NULL)
|
||||
{
|
||||
/* Got EOF. Just exit. */
|
||||
/* Restore terminal modes. */
|
||||
tcsetattr(fileno(f), TCSANOW, &saved_tio);
|
||||
/* Restore the signal handler. */
|
||||
signal(SIGINT, old_handler);
|
||||
/* Print a newline (the prompt probably didn\'t have one). */
|
||||
fprintf(stderr, "\n");
|
||||
/* Close the file. */
|
||||
if (f != stdin)
|
||||
fclose(f);
|
||||
exit(1);
|
||||
}
|
||||
/* Restore terminal modes. */
|
||||
tcsetattr(fileno(f), TCSANOW, &saved_tio);
|
||||
/* Restore the signal handler. */
|
||||
(void)signal(SIGINT, old_handler);
|
||||
/* Remove newline from the passphrase. */
|
||||
if (strchr(buf, '\n'))
|
||||
*strchr(buf, '\n') = 0;
|
||||
/* Allocate a copy of the passphrase. */
|
||||
cp = xstrdup(buf);
|
||||
/* Clear the buffer so we don\'t leave copies of the passphrase laying
|
||||
around. */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
/* Print a newline since the prompt probably didn\'t have one. */
|
||||
fprintf(stderr, "\n");
|
||||
/* Close the file. */
|
||||
if (f != stdin)
|
||||
fclose(f);
|
||||
return cp;
|
||||
/* Read the passphrase from the terminal. */
|
||||
if (fgets(buf, sizeof(buf), f) == NULL) {
|
||||
/* Got EOF. Just exit. */
|
||||
/* Restore terminal modes. */
|
||||
tcsetattr(fileno(f), TCSANOW, &saved_tio);
|
||||
/* Restore the signal handler. */
|
||||
signal(SIGINT, old_handler);
|
||||
/* Print a newline (the prompt probably didn\'t have one). */
|
||||
fprintf(stderr, "\n");
|
||||
/* Close the file. */
|
||||
if (f != stdin)
|
||||
fclose(f);
|
||||
exit(1);
|
||||
}
|
||||
/* Restore terminal modes. */
|
||||
tcsetattr(fileno(f), TCSANOW, &saved_tio);
|
||||
/* Restore the signal handler. */
|
||||
(void) signal(SIGINT, old_handler);
|
||||
/* Remove newline from the passphrase. */
|
||||
if (strchr(buf, '\n'))
|
||||
*strchr(buf, '\n') = 0;
|
||||
/* Allocate a copy of the passphrase. */
|
||||
cp = xstrdup(buf);
|
||||
/* Clear the buffer so we don\'t leave copies of the passphrase
|
||||
laying around. */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
/* Print a newline since the prompt probably didn\'t have one. */
|
||||
fprintf(stderr, "\n");
|
||||
/* Close the file. */
|
||||
if (f != stdin)
|
||||
fclose(f);
|
||||
return cp;
|
||||
}
|
||||
|
|
215
rsa.c
215
rsa.c
|
@ -1,41 +1,41 @@
|
|||
/*
|
||||
|
||||
rsa.c
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Fri Mar 3 22:07:06 1995 ylo
|
||||
|
||||
Description of the RSA algorithm can be found e.g. from the following sources:
|
||||
|
||||
Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1994.
|
||||
|
||||
Jennifer Seberry and Josed Pieprzyk: Cryptography: An Introduction to
|
||||
Computer Security. Prentice-Hall, 1989.
|
||||
|
||||
Man Young Rhee: Cryptography and Secure Data Communications. McGraw-Hill,
|
||||
1994.
|
||||
|
||||
R. Rivest, A. Shamir, and L. M. Adleman: Cryptographic Communications
|
||||
System and Method. US Patent 4,405,829, 1983.
|
||||
|
||||
Hans Riesel: Prime Numbers and Computer Methods for Factorization.
|
||||
Birkhauser, 1994.
|
||||
|
||||
The RSA Frequently Asked Questions document by RSA Data Security, Inc., 1995.
|
||||
|
||||
RSA in 3 lines of perl by Adam Back <aba@atlax.ex.ac.uk>, 1995, as included
|
||||
below:
|
||||
|
||||
gone - had to be deleted - what a pity
|
||||
|
||||
*
|
||||
* rsa.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Fri Mar 3 22:07:06 1995 ylo
|
||||
*
|
||||
* Description of the RSA algorithm can be found e.g. from the following sources:
|
||||
*
|
||||
* Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1994.
|
||||
*
|
||||
* Jennifer Seberry and Josed Pieprzyk: Cryptography: An Introduction to
|
||||
* Computer Security. Prentice-Hall, 1989.
|
||||
*
|
||||
* Man Young Rhee: Cryptography and Secure Data Communications. McGraw-Hill,
|
||||
* 1994.
|
||||
*
|
||||
* R. Rivest, A. Shamir, and L. M. Adleman: Cryptographic Communications
|
||||
* System and Method. US Patent 4,405,829, 1983.
|
||||
*
|
||||
* Hans Riesel: Prime Numbers and Computer Methods for Factorization.
|
||||
* Birkhauser, 1994.
|
||||
*
|
||||
* The RSA Frequently Asked Questions document by RSA Data Security, Inc., 1995.
|
||||
*
|
||||
* RSA in 3 lines of perl by Adam Back <aba@atlax.ex.ac.uk>, 1995, as included
|
||||
* below:
|
||||
*
|
||||
* [gone - had to be deleted - what a pity]
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: rsa.c,v 1.3 1999/11/08 23:35:52 damien Exp $");
|
||||
RCSID("$Id: rsa.c,v 1.4 1999/11/24 13:26:22 damien Exp $");
|
||||
|
||||
#include "rsa.h"
|
||||
#include "ssh.h"
|
||||
|
@ -46,13 +46,13 @@ int rsa_verbose = 1;
|
|||
int
|
||||
rsa_alive()
|
||||
{
|
||||
RSA *key;
|
||||
RSA *key;
|
||||
|
||||
key = RSA_generate_key(32, 3, NULL, NULL);
|
||||
if (key == NULL)
|
||||
return (0);
|
||||
RSA_free(key);
|
||||
return (1);
|
||||
key = RSA_generate_key(32, 3, NULL, NULL);
|
||||
if (key == NULL)
|
||||
return (0);
|
||||
RSA_free(key);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Generates RSA public and private keys. This initializes the data
|
||||
|
@ -62,101 +62,100 @@ rsa_alive()
|
|||
void
|
||||
rsa_generate_key(RSA *prv, RSA *pub, unsigned int bits)
|
||||
{
|
||||
RSA *key;
|
||||
RSA *key;
|
||||
|
||||
if (rsa_verbose) {
|
||||
printf("Generating RSA keys: ");
|
||||
fflush(stdout);
|
||||
}
|
||||
if (rsa_verbose) {
|
||||
printf("Generating RSA keys: ");
|
||||
fflush(stdout);
|
||||
}
|
||||
key = RSA_generate_key(bits, 35, NULL, NULL);
|
||||
if (key == NULL)
|
||||
fatal("rsa_generate_key: key generation failed.");
|
||||
|
||||
key = RSA_generate_key(bits, 35, NULL, NULL);
|
||||
if (key == NULL)
|
||||
fatal("rsa_generate_key: key generation failed.");
|
||||
/* Copy public key parameters */
|
||||
pub->n = BN_new();
|
||||
BN_copy(pub->n, key->n);
|
||||
pub->e = BN_new();
|
||||
BN_copy(pub->e, key->e);
|
||||
|
||||
/* Copy public key parameters */
|
||||
pub->n = BN_new();
|
||||
BN_copy(pub->n, key->n);
|
||||
pub->e = BN_new();
|
||||
BN_copy(pub->e, key->e);
|
||||
/* Copy private key parameters */
|
||||
prv->n = BN_new();
|
||||
BN_copy(prv->n, key->n);
|
||||
prv->e = BN_new();
|
||||
BN_copy(prv->e, key->e);
|
||||
prv->d = BN_new();
|
||||
BN_copy(prv->d, key->d);
|
||||
prv->p = BN_new();
|
||||
BN_copy(prv->p, key->p);
|
||||
prv->q = BN_new();
|
||||
BN_copy(prv->q, key->q);
|
||||
|
||||
/* Copy private key parameters */
|
||||
prv->n = BN_new();
|
||||
BN_copy(prv->n, key->n);
|
||||
prv->e = BN_new();
|
||||
BN_copy(prv->e, key->e);
|
||||
prv->d = BN_new();
|
||||
BN_copy(prv->d, key->d);
|
||||
prv->p = BN_new();
|
||||
BN_copy(prv->p, key->p);
|
||||
prv->q = BN_new();
|
||||
BN_copy(prv->q, key->q);
|
||||
prv->dmp1 = BN_new();
|
||||
BN_copy(prv->dmp1, key->dmp1);
|
||||
|
||||
prv->dmp1 = BN_new();
|
||||
BN_copy(prv->dmp1, key->dmp1);
|
||||
prv->dmq1 = BN_new();
|
||||
BN_copy(prv->dmq1, key->dmq1);
|
||||
|
||||
prv->dmq1 = BN_new();
|
||||
BN_copy(prv->dmq1, key->dmq1);
|
||||
prv->iqmp = BN_new();
|
||||
BN_copy(prv->iqmp, key->iqmp);
|
||||
|
||||
prv->iqmp = BN_new();
|
||||
BN_copy(prv->iqmp, key->iqmp);
|
||||
RSA_free(key);
|
||||
|
||||
RSA_free(key);
|
||||
|
||||
if (rsa_verbose)
|
||||
printf("Key generation complete.\n");
|
||||
if (rsa_verbose)
|
||||
printf("Key generation complete.\n");
|
||||
}
|
||||
|
||||
void
|
||||
rsa_public_encrypt(BIGNUM *out, BIGNUM *in, RSA* key)
|
||||
rsa_public_encrypt(BIGNUM *out, BIGNUM *in, RSA *key)
|
||||
{
|
||||
char *inbuf, *outbuf;
|
||||
int len, ilen, olen;
|
||||
char *inbuf, *outbuf;
|
||||
int len, ilen, olen;
|
||||
|
||||
if (BN_num_bits(key->e) < 2 || !BN_is_odd(key->e))
|
||||
fatal("rsa_public_encrypt() exponent too small or not odd");
|
||||
if (BN_num_bits(key->e) < 2 || !BN_is_odd(key->e))
|
||||
fatal("rsa_public_encrypt() exponent too small or not odd");
|
||||
|
||||
olen = BN_num_bytes(key->n);
|
||||
outbuf = xmalloc(olen);
|
||||
olen = BN_num_bytes(key->n);
|
||||
outbuf = xmalloc(olen);
|
||||
|
||||
ilen = BN_num_bytes(in);
|
||||
inbuf = xmalloc(ilen);
|
||||
BN_bn2bin(in, inbuf);
|
||||
ilen = BN_num_bytes(in);
|
||||
inbuf = xmalloc(ilen);
|
||||
BN_bn2bin(in, inbuf);
|
||||
|
||||
if ((len = RSA_public_encrypt(ilen, inbuf, outbuf, key,
|
||||
RSA_PKCS1_PADDING)) <= 0)
|
||||
fatal("rsa_public_encrypt() failed");
|
||||
if ((len = RSA_public_encrypt(ilen, inbuf, outbuf, key,
|
||||
RSA_PKCS1_PADDING)) <= 0)
|
||||
fatal("rsa_public_encrypt() failed");
|
||||
|
||||
BN_bin2bn(outbuf, len, out);
|
||||
BN_bin2bn(outbuf, len, out);
|
||||
|
||||
memset(outbuf, 0, olen);
|
||||
memset(inbuf, 0, ilen);
|
||||
xfree(outbuf);
|
||||
xfree(inbuf);
|
||||
memset(outbuf, 0, olen);
|
||||
memset(inbuf, 0, ilen);
|
||||
xfree(outbuf);
|
||||
xfree(inbuf);
|
||||
}
|
||||
|
||||
void
|
||||
rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *key)
|
||||
{
|
||||
char *inbuf, *outbuf;
|
||||
int len, ilen, olen;
|
||||
char *inbuf, *outbuf;
|
||||
int len, ilen, olen;
|
||||
|
||||
olen = BN_num_bytes(key->n);
|
||||
outbuf = xmalloc(olen);
|
||||
olen = BN_num_bytes(key->n);
|
||||
outbuf = xmalloc(olen);
|
||||
|
||||
ilen = BN_num_bytes(in);
|
||||
inbuf = xmalloc(ilen);
|
||||
BN_bn2bin(in, inbuf);
|
||||
ilen = BN_num_bytes(in);
|
||||
inbuf = xmalloc(ilen);
|
||||
BN_bn2bin(in, inbuf);
|
||||
|
||||
if ((len = RSA_private_decrypt(ilen, inbuf, outbuf, key,
|
||||
RSA_SSLV23_PADDING)) <= 0)
|
||||
fatal("rsa_private_decrypt() failed");
|
||||
if ((len = RSA_private_decrypt(ilen, inbuf, outbuf, key,
|
||||
RSA_SSLV23_PADDING)) <= 0)
|
||||
fatal("rsa_private_decrypt() failed");
|
||||
|
||||
BN_bin2bn(outbuf, len, out);
|
||||
BN_bin2bn(outbuf, len, out);
|
||||
|
||||
memset(outbuf, 0, olen);
|
||||
memset(inbuf, 0, ilen);
|
||||
xfree(outbuf);
|
||||
xfree(inbuf);
|
||||
memset(outbuf, 0, olen);
|
||||
memset(inbuf, 0, ilen);
|
||||
xfree(outbuf);
|
||||
xfree(inbuf);
|
||||
}
|
||||
|
||||
/* Set whether to output verbose messages during key generation. */
|
||||
|
@ -164,5 +163,5 @@ rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *key)
|
|||
void
|
||||
rsa_set_verbose(int verbose)
|
||||
{
|
||||
rsa_verbose = verbose;
|
||||
rsa_verbose = verbose;
|
||||
}
|
||||
|
|
41
rsa.h
41
rsa.h
|
@ -1,24 +1,25 @@
|
|||
/*
|
||||
|
||||
rsa.h
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Fri Mar 3 22:01:06 1995 ylo
|
||||
|
||||
RSA key generation, encryption and decryption.
|
||||
|
||||
*
|
||||
* rsa.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Fri Mar 3 22:01:06 1995 ylo
|
||||
*
|
||||
* RSA key generation, encryption and decryption.
|
||||
*
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: rsa.h,v 1.3 1999/11/10 23:40:23 damien Exp $"); */
|
||||
#include "config.h"
|
||||
/* RCSID("$Id: rsa.h,v 1.4 1999/11/24 13:26:22 damien Exp $"); */
|
||||
|
||||
#ifndef RSA_H
|
||||
#define RSA_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/rsa.h>
|
||||
|
@ -30,15 +31,15 @@ RSA key generation, encryption and decryption.
|
|||
#endif
|
||||
|
||||
/* Calls SSL RSA_generate_key, only copies to prv and pub */
|
||||
void rsa_generate_key(RSA *prv, RSA *pub, unsigned int bits);
|
||||
void rsa_generate_key(RSA * prv, RSA * pub, unsigned int bits);
|
||||
|
||||
/* Indicates whether the rsa module is permitted to show messages on
|
||||
the terminal. */
|
||||
void rsa_set_verbose(int verbose);
|
||||
void rsa_set_verbose __P((int verbose));
|
||||
|
||||
int rsa_alive(void);
|
||||
int rsa_alive __P((void));
|
||||
|
||||
void rsa_public_encrypt(BIGNUM *out, BIGNUM *in, RSA *prv);
|
||||
void rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *prv);
|
||||
void rsa_public_encrypt __P((BIGNUM * out, BIGNUM * in, RSA * prv));
|
||||
void rsa_private_decrypt __P((BIGNUM * out, BIGNUM * in, RSA * prv));
|
||||
|
||||
#endif /* RSA_H */
|
||||
#endif /* RSA_H */
|
||||
|
|
619
scp.c
619
scp.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
909
servconf.c
909
servconf.c
|
@ -1,18 +1,18 @@
|
|||
/*
|
||||
|
||||
servconf.c
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Mon Aug 21 15:48:58 1995 ylo
|
||||
|
||||
*/
|
||||
*
|
||||
* servconf.c
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Mon Aug 21 15:48:58 1995 ylo
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: servconf.c,v 1.5 1999/11/21 02:23:53 damien Exp $");
|
||||
RCSID("$Id: servconf.c,v 1.6 1999/11/24 13:26:22 damien Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "servconf.h"
|
||||
|
@ -20,535 +20,514 @@ RCSID("$Id: servconf.c,v 1.5 1999/11/21 02:23:53 damien Exp $");
|
|||
|
||||
/* Initializes the server options to their default values. */
|
||||
|
||||
void initialize_server_options(ServerOptions *options)
|
||||
void
|
||||
initialize_server_options(ServerOptions *options)
|
||||
{
|
||||
memset(options, 0, sizeof(*options));
|
||||
options->port = -1;
|
||||
options->listen_addr.s_addr = htonl(INADDR_ANY);
|
||||
options->host_key_file = NULL;
|
||||
options->server_key_bits = -1;
|
||||
options->login_grace_time = -1;
|
||||
options->key_regeneration_time = -1;
|
||||
options->permit_root_login = -1;
|
||||
options->ignore_rhosts = -1;
|
||||
options->ignore_user_known_hosts = -1;
|
||||
options->print_motd = -1;
|
||||
options->check_mail = -1;
|
||||
options->x11_forwarding = -1;
|
||||
options->x11_display_offset = -1;
|
||||
options->strict_modes = -1;
|
||||
options->keepalives = -1;
|
||||
options->log_facility = (SyslogFacility)-1;
|
||||
options->log_level = (LogLevel)-1;
|
||||
options->rhosts_authentication = -1;
|
||||
options->rhosts_rsa_authentication = -1;
|
||||
options->rsa_authentication = -1;
|
||||
memset(options, 0, sizeof(*options));
|
||||
options->port = -1;
|
||||
options->listen_addr.s_addr = htonl(INADDR_ANY);
|
||||
options->host_key_file = NULL;
|
||||
options->server_key_bits = -1;
|
||||
options->login_grace_time = -1;
|
||||
options->key_regeneration_time = -1;
|
||||
options->permit_root_login = -1;
|
||||
options->ignore_rhosts = -1;
|
||||
options->ignore_user_known_hosts = -1;
|
||||
options->print_motd = -1;
|
||||
options->check_mail = -1;
|
||||
options->x11_forwarding = -1;
|
||||
options->x11_display_offset = -1;
|
||||
options->strict_modes = -1;
|
||||
options->keepalives = -1;
|
||||
options->log_facility = (SyslogFacility) - 1;
|
||||
options->log_level = (LogLevel) - 1;
|
||||
options->rhosts_authentication = -1;
|
||||
options->rhosts_rsa_authentication = -1;
|
||||
options->rsa_authentication = -1;
|
||||
#ifdef KRB4
|
||||
options->kerberos_authentication = -1;
|
||||
options->kerberos_or_local_passwd = -1;
|
||||
options->kerberos_ticket_cleanup = -1;
|
||||
options->kerberos_authentication = -1;
|
||||
options->kerberos_or_local_passwd = -1;
|
||||
options->kerberos_ticket_cleanup = -1;
|
||||
#endif
|
||||
#ifdef AFS
|
||||
options->kerberos_tgt_passing = -1;
|
||||
options->afs_token_passing = -1;
|
||||
options->kerberos_tgt_passing = -1;
|
||||
options->afs_token_passing = -1;
|
||||
#endif
|
||||
options->password_authentication = -1;
|
||||
options->password_authentication = -1;
|
||||
#ifdef SKEY
|
||||
options->skey_authentication = -1;
|
||||
options->skey_authentication = -1;
|
||||
#endif
|
||||
options->permit_empty_passwd = -1;
|
||||
options->use_login = -1;
|
||||
options->num_allow_users = 0;
|
||||
options->num_deny_users = 0;
|
||||
options->num_allow_groups = 0;
|
||||
options->num_deny_groups = 0;
|
||||
options->permit_empty_passwd = -1;
|
||||
options->use_login = -1;
|
||||
options->num_allow_users = 0;
|
||||
options->num_deny_users = 0;
|
||||
options->num_allow_groups = 0;
|
||||
options->num_deny_groups = 0;
|
||||
}
|
||||
|
||||
void fill_default_server_options(ServerOptions *options)
|
||||
void
|
||||
fill_default_server_options(ServerOptions *options)
|
||||
{
|
||||
if (options->port == -1)
|
||||
{
|
||||
struct servent *sp;
|
||||
if (options->port == -1) {
|
||||
struct servent *sp;
|
||||
|
||||
sp = getservbyname(SSH_SERVICE_NAME, "tcp");
|
||||
if (sp)
|
||||
options->port = ntohs(sp->s_port);
|
||||
else
|
||||
options->port = SSH_DEFAULT_PORT;
|
||||
endservent();
|
||||
}
|
||||
if (options->host_key_file == NULL)
|
||||
options->host_key_file = HOST_KEY_FILE;
|
||||
if (options->server_key_bits == -1)
|
||||
options->server_key_bits = 768;
|
||||
if (options->login_grace_time == -1)
|
||||
options->login_grace_time = 600;
|
||||
if (options->key_regeneration_time == -1)
|
||||
options->key_regeneration_time = 3600;
|
||||
if (options->permit_root_login == -1)
|
||||
options->permit_root_login = 1; /* yes */
|
||||
if (options->ignore_rhosts == -1)
|
||||
options->ignore_rhosts = 0;
|
||||
if (options->ignore_user_known_hosts == -1)
|
||||
options->ignore_user_known_hosts = 0;
|
||||
if (options->check_mail == -1)
|
||||
options->check_mail = 0;
|
||||
if (options->print_motd == -1)
|
||||
options->print_motd = 1;
|
||||
if (options->x11_forwarding == -1)
|
||||
options->x11_forwarding = 1;
|
||||
if (options->x11_display_offset == -1)
|
||||
options->x11_display_offset = 1;
|
||||
if (options->strict_modes == -1)
|
||||
options->strict_modes = 1;
|
||||
if (options->keepalives == -1)
|
||||
options->keepalives = 1;
|
||||
if (options->log_facility == (SyslogFacility)(-1))
|
||||
options->log_facility = SYSLOG_FACILITY_AUTH;
|
||||
if (options->log_level == (LogLevel)(-1))
|
||||
options->log_level = SYSLOG_LEVEL_INFO;
|
||||
if (options->rhosts_authentication == -1)
|
||||
options->rhosts_authentication = 0;
|
||||
if (options->rhosts_rsa_authentication == -1)
|
||||
options->rhosts_rsa_authentication = 1;
|
||||
if (options->rsa_authentication == -1)
|
||||
options->rsa_authentication = 1;
|
||||
sp = getservbyname(SSH_SERVICE_NAME, "tcp");
|
||||
if (sp)
|
||||
options->port = ntohs(sp->s_port);
|
||||
else
|
||||
options->port = SSH_DEFAULT_PORT;
|
||||
endservent();
|
||||
}
|
||||
if (options->host_key_file == NULL)
|
||||
options->host_key_file = HOST_KEY_FILE;
|
||||
if (options->server_key_bits == -1)
|
||||
options->server_key_bits = 768;
|
||||
if (options->login_grace_time == -1)
|
||||
options->login_grace_time = 600;
|
||||
if (options->key_regeneration_time == -1)
|
||||
options->key_regeneration_time = 3600;
|
||||
if (options->permit_root_login == -1)
|
||||
options->permit_root_login = 1; /* yes */
|
||||
if (options->ignore_rhosts == -1)
|
||||
options->ignore_rhosts = 0;
|
||||
if (options->ignore_user_known_hosts == -1)
|
||||
options->ignore_user_known_hosts = 0;
|
||||
if (options->check_mail == -1)
|
||||
options->check_mail = 0;
|
||||
if (options->print_motd == -1)
|
||||
options->print_motd = 1;
|
||||
if (options->x11_forwarding == -1)
|
||||
options->x11_forwarding = 1;
|
||||
if (options->x11_display_offset == -1)
|
||||
options->x11_display_offset = 1;
|
||||
if (options->strict_modes == -1)
|
||||
options->strict_modes = 1;
|
||||
if (options->keepalives == -1)
|
||||
options->keepalives = 1;
|
||||
if (options->log_facility == (SyslogFacility) (-1))
|
||||
options->log_facility = SYSLOG_FACILITY_AUTH;
|
||||
if (options->log_level == (LogLevel) (-1))
|
||||
options->log_level = SYSLOG_LEVEL_INFO;
|
||||
if (options->rhosts_authentication == -1)
|
||||
options->rhosts_authentication = 0;
|
||||
if (options->rhosts_rsa_authentication == -1)
|
||||
options->rhosts_rsa_authentication = 1;
|
||||
if (options->rsa_authentication == -1)
|
||||
options->rsa_authentication = 1;
|
||||
#ifdef KRB4
|
||||
if (options->kerberos_authentication == -1)
|
||||
options->kerberos_authentication = (access(KEYFILE, R_OK) == 0);
|
||||
if (options->kerberos_or_local_passwd == -1)
|
||||
options->kerberos_or_local_passwd = 1;
|
||||
if (options->kerberos_ticket_cleanup == -1)
|
||||
options->kerberos_ticket_cleanup = 1;
|
||||
if (options->kerberos_authentication == -1)
|
||||
options->kerberos_authentication = (access(KEYFILE, R_OK) == 0);
|
||||
if (options->kerberos_or_local_passwd == -1)
|
||||
options->kerberos_or_local_passwd = 1;
|
||||
if (options->kerberos_ticket_cleanup == -1)
|
||||
options->kerberos_ticket_cleanup = 1;
|
||||
#endif /* KRB4 */
|
||||
#ifdef AFS
|
||||
if (options->kerberos_tgt_passing == -1)
|
||||
options->kerberos_tgt_passing = 0;
|
||||
if (options->afs_token_passing == -1)
|
||||
options->afs_token_passing = k_hasafs();
|
||||
if (options->kerberos_tgt_passing == -1)
|
||||
options->kerberos_tgt_passing = 0;
|
||||
if (options->afs_token_passing == -1)
|
||||
options->afs_token_passing = k_hasafs();
|
||||
#endif /* AFS */
|
||||
if (options->password_authentication == -1)
|
||||
options->password_authentication = 1;
|
||||
if (options->password_authentication == -1)
|
||||
options->password_authentication = 1;
|
||||
#ifdef SKEY
|
||||
if (options->skey_authentication == -1)
|
||||
options->skey_authentication = 1;
|
||||
if (options->skey_authentication == -1)
|
||||
options->skey_authentication = 1;
|
||||
#endif
|
||||
if (options->permit_empty_passwd == -1)
|
||||
options->permit_empty_passwd = 1;
|
||||
if (options->use_login == -1)
|
||||
options->use_login = 0;
|
||||
if (options->permit_empty_passwd == -1)
|
||||
options->permit_empty_passwd = 1;
|
||||
if (options->use_login == -1)
|
||||
options->use_login = 0;
|
||||
}
|
||||
|
||||
#define WHITESPACE " \t\r\n"
|
||||
|
||||
/* Keyword tokens. */
|
||||
typedef enum
|
||||
{
|
||||
sBadOption, /* == unknown option */
|
||||
sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime,
|
||||
sPermitRootLogin, sLogFacility, sLogLevel,
|
||||
sRhostsAuthentication, sRhostsRSAAuthentication, sRSAAuthentication,
|
||||
typedef enum {
|
||||
sBadOption, /* == unknown option */
|
||||
sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime,
|
||||
sPermitRootLogin, sLogFacility, sLogLevel,
|
||||
sRhostsAuthentication, sRhostsRSAAuthentication, sRSAAuthentication,
|
||||
#ifdef KRB4
|
||||
sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
|
||||
sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
|
||||
#endif
|
||||
#ifdef AFS
|
||||
sKerberosTgtPassing, sAFSTokenPassing,
|
||||
sKerberosTgtPassing, sAFSTokenPassing,
|
||||
#endif
|
||||
#ifdef SKEY
|
||||
sSkeyAuthentication,
|
||||
sSkeyAuthentication,
|
||||
#endif
|
||||
sPasswordAuthentication, sListenAddress,
|
||||
sPrintMotd, sIgnoreRhosts, sX11Forwarding, sX11DisplayOffset,
|
||||
sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail,
|
||||
sUseLogin, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
|
||||
sIgnoreUserKnownHosts
|
||||
sPasswordAuthentication, sListenAddress,
|
||||
sPrintMotd, sIgnoreRhosts, sX11Forwarding, sX11DisplayOffset,
|
||||
sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail,
|
||||
sUseLogin, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
|
||||
sIgnoreUserKnownHosts
|
||||
} ServerOpCodes;
|
||||
|
||||
/* Textual representation of the tokens. */
|
||||
static struct
|
||||
{
|
||||
const char *name;
|
||||
ServerOpCodes opcode;
|
||||
} keywords[] =
|
||||
{
|
||||
{ "port", sPort },
|
||||
{ "hostkey", sHostKeyFile },
|
||||
{ "serverkeybits", sServerKeyBits },
|
||||
{ "logingracetime", sLoginGraceTime },
|
||||
{ "keyregenerationinterval", sKeyRegenerationTime },
|
||||
{ "permitrootlogin", sPermitRootLogin },
|
||||
{ "syslogfacility", sLogFacility },
|
||||
{ "loglevel", sLogLevel },
|
||||
{ "rhostsauthentication", sRhostsAuthentication },
|
||||
{ "rhostsrsaauthentication", sRhostsRSAAuthentication },
|
||||
{ "rsaauthentication", sRSAAuthentication },
|
||||
static struct {
|
||||
const char *name;
|
||||
ServerOpCodes opcode;
|
||||
} keywords[] = {
|
||||
{ "port", sPort },
|
||||
{ "hostkey", sHostKeyFile },
|
||||
{ "serverkeybits", sServerKeyBits },
|
||||
{ "logingracetime", sLoginGraceTime },
|
||||
{ "keyregenerationinterval", sKeyRegenerationTime },
|
||||
{ "permitrootlogin", sPermitRootLogin },
|
||||
{ "syslogfacility", sLogFacility },
|
||||
{ "loglevel", sLogLevel },
|
||||
{ "rhostsauthentication", sRhostsAuthentication },
|
||||
{ "rhostsrsaauthentication", sRhostsRSAAuthentication },
|
||||
{ "rsaauthentication", sRSAAuthentication },
|
||||
#ifdef KRB4
|
||||
{ "kerberosauthentication", sKerberosAuthentication },
|
||||
{ "kerberosorlocalpasswd", sKerberosOrLocalPasswd },
|
||||
{ "kerberosticketcleanup", sKerberosTicketCleanup },
|
||||
{ "kerberosauthentication", sKerberosAuthentication },
|
||||
{ "kerberosorlocalpasswd", sKerberosOrLocalPasswd },
|
||||
{ "kerberosticketcleanup", sKerberosTicketCleanup },
|
||||
#endif
|
||||
#ifdef AFS
|
||||
{ "kerberostgtpassing", sKerberosTgtPassing },
|
||||
{ "afstokenpassing", sAFSTokenPassing },
|
||||
{ "kerberostgtpassing", sKerberosTgtPassing },
|
||||
{ "afstokenpassing", sAFSTokenPassing },
|
||||
#endif
|
||||
{ "passwordauthentication", sPasswordAuthentication },
|
||||
{ "passwordauthentication", sPasswordAuthentication },
|
||||
#ifdef SKEY
|
||||
{ "skeyauthentication", sSkeyAuthentication },
|
||||
{ "skeyauthentication", sSkeyAuthentication },
|
||||
#endif
|
||||
{ "checkmail", sCheckMail },
|
||||
{ "listenaddress", sListenAddress },
|
||||
{ "printmotd", sPrintMotd },
|
||||
{ "ignorerhosts", sIgnoreRhosts },
|
||||
{ "ignoreuserknownhosts", sIgnoreUserKnownHosts },
|
||||
{ "x11forwarding", sX11Forwarding },
|
||||
{ "x11displayoffset", sX11DisplayOffset },
|
||||
{ "strictmodes", sStrictModes },
|
||||
{ "permitemptypasswords", sEmptyPasswd },
|
||||
{ "uselogin", sUseLogin },
|
||||
{ "randomseed", sRandomSeedFile },
|
||||
{ "keepalive", sKeepAlives },
|
||||
{ "allowusers", sAllowUsers },
|
||||
{ "denyusers", sDenyUsers },
|
||||
{ "allowgroups", sAllowGroups },
|
||||
{ "denygroups", sDenyGroups },
|
||||
{ NULL, 0 }
|
||||
{ "checkmail", sCheckMail },
|
||||
{ "listenaddress", sListenAddress },
|
||||
{ "printmotd", sPrintMotd },
|
||||
{ "ignorerhosts", sIgnoreRhosts },
|
||||
{ "ignoreuserknownhosts", sIgnoreUserKnownHosts },
|
||||
{ "x11forwarding", sX11Forwarding },
|
||||
{ "x11displayoffset", sX11DisplayOffset },
|
||||
{ "strictmodes", sStrictModes },
|
||||
{ "permitemptypasswords", sEmptyPasswd },
|
||||
{ "uselogin", sUseLogin },
|
||||
{ "randomseed", sRandomSeedFile },
|
||||
{ "keepalive", sKeepAlives },
|
||||
{ "allowusers", sAllowUsers },
|
||||
{ "denyusers", sDenyUsers },
|
||||
{ "allowgroups", sAllowGroups },
|
||||
{ "denygroups", sDenyGroups },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
/* Returns the number of the token pointed to by cp of length len.
|
||||
Never returns if the token is not known. */
|
||||
|
||||
static ServerOpCodes parse_token(const char *cp, const char *filename,
|
||||
int linenum)
|
||||
static ServerOpCodes
|
||||
parse_token(const char *cp, const char *filename,
|
||||
int linenum)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; keywords[i].name; i++)
|
||||
if (strcmp(cp, keywords[i].name) == 0)
|
||||
return keywords[i].opcode;
|
||||
for (i = 0; keywords[i].name; i++)
|
||||
if (strcmp(cp, keywords[i].name) == 0)
|
||||
return keywords[i].opcode;
|
||||
|
||||
fprintf(stderr, "%s: line %d: Bad configuration option: %s\n",
|
||||
filename, linenum, cp);
|
||||
return sBadOption;
|
||||
fprintf(stderr, "%s: line %d: Bad configuration option: %s\n",
|
||||
filename, linenum, cp);
|
||||
return sBadOption;
|
||||
}
|
||||
|
||||
/* Reads the server configuration file. */
|
||||
|
||||
void read_server_config(ServerOptions *options, const char *filename)
|
||||
void
|
||||
read_server_config(ServerOptions *options, const char *filename)
|
||||
{
|
||||
FILE *f;
|
||||
char line[1024];
|
||||
char *cp, **charptr;
|
||||
int linenum, *intptr, value;
|
||||
int bad_options = 0;
|
||||
ServerOpCodes opcode;
|
||||
FILE *f;
|
||||
char line[1024];
|
||||
char *cp, **charptr;
|
||||
int linenum, *intptr, value;
|
||||
int bad_options = 0;
|
||||
ServerOpCodes opcode;
|
||||
|
||||
f = fopen(filename, "r");
|
||||
if (!f)
|
||||
{
|
||||
perror(filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
linenum = 0;
|
||||
while (fgets(line, sizeof(line), f))
|
||||
{
|
||||
linenum++;
|
||||
cp = line + strspn(line, WHITESPACE);
|
||||
if (!*cp || *cp == '#')
|
||||
continue;
|
||||
cp = strtok(cp, WHITESPACE);
|
||||
{
|
||||
char *t = cp;
|
||||
for (; *t != 0; t++)
|
||||
if ('A' <= *t && *t <= 'Z')
|
||||
*t = *t - 'A' + 'a'; /* tolower */
|
||||
|
||||
}
|
||||
opcode = parse_token(cp, filename, linenum);
|
||||
switch (opcode)
|
||||
{
|
||||
case sBadOption:
|
||||
bad_options++;
|
||||
continue;
|
||||
case sPort:
|
||||
intptr = &options->port;
|
||||
parse_int:
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!cp)
|
||||
{
|
||||
fprintf(stderr, "%s line %d: missing integer value.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
value = atoi(cp);
|
||||
if (*intptr == -1)
|
||||
*intptr = value;
|
||||
break;
|
||||
|
||||
case sServerKeyBits:
|
||||
intptr = &options->server_key_bits;
|
||||
goto parse_int;
|
||||
|
||||
case sLoginGraceTime:
|
||||
intptr = &options->login_grace_time;
|
||||
goto parse_int;
|
||||
|
||||
case sKeyRegenerationTime:
|
||||
intptr = &options->key_regeneration_time;
|
||||
goto parse_int;
|
||||
|
||||
case sListenAddress:
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!cp)
|
||||
{
|
||||
fprintf(stderr, "%s line %d: missing inet addr.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
options->listen_addr.s_addr = inet_addr(cp);
|
||||
break;
|
||||
|
||||
case sHostKeyFile:
|
||||
charptr = &options->host_key_file;
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!cp)
|
||||
{
|
||||
fprintf(stderr, "%s line %d: missing file name.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
if (*charptr == NULL)
|
||||
*charptr = tilde_expand_filename(cp, getuid());
|
||||
break;
|
||||
|
||||
case sRandomSeedFile:
|
||||
fprintf(stderr, "%s line %d: \"randomseed\" option is obsolete.\n",
|
||||
filename, linenum);
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
break;
|
||||
|
||||
case sPermitRootLogin:
|
||||
intptr = &options->permit_root_login;
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!cp)
|
||||
{
|
||||
fprintf(stderr, "%s line %d: missing yes/without-password/no argument.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
if (strcmp(cp, "without-password") == 0)
|
||||
value = 2;
|
||||
else if (strcmp(cp, "yes") == 0)
|
||||
value = 1;
|
||||
else if (strcmp(cp, "no") == 0)
|
||||
value = 0;
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "%s line %d: Bad yes/without-password/no argument: %s\n",
|
||||
filename, linenum, cp);
|
||||
exit(1);
|
||||
}
|
||||
if (*intptr == -1)
|
||||
*intptr = value;
|
||||
break;
|
||||
|
||||
case sIgnoreRhosts:
|
||||
intptr = &options->ignore_rhosts;
|
||||
parse_flag:
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!cp)
|
||||
{
|
||||
fprintf(stderr, "%s line %d: missing yes/no argument.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
if (strcmp(cp, "yes") == 0)
|
||||
value = 1;
|
||||
else
|
||||
if (strcmp(cp, "no") == 0)
|
||||
value = 0;
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "%s line %d: Bad yes/no argument: %s\n",
|
||||
filename, linenum, cp);
|
||||
f = fopen(filename, "r");
|
||||
if (!f) {
|
||||
perror(filename);
|
||||
exit(1);
|
||||
}
|
||||
if (*intptr == -1)
|
||||
*intptr = value;
|
||||
break;
|
||||
}
|
||||
linenum = 0;
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
linenum++;
|
||||
cp = line + strspn(line, WHITESPACE);
|
||||
if (!*cp || *cp == '#')
|
||||
continue;
|
||||
cp = strtok(cp, WHITESPACE);
|
||||
{
|
||||
char *t = cp;
|
||||
for (; *t != 0; t++)
|
||||
if ('A' <= *t && *t <= 'Z')
|
||||
*t = *t - 'A' + 'a'; /* tolower */
|
||||
|
||||
case sIgnoreUserKnownHosts:
|
||||
intptr = &options->ignore_user_known_hosts;
|
||||
goto parse_int;
|
||||
}
|
||||
opcode = parse_token(cp, filename, linenum);
|
||||
switch (opcode) {
|
||||
case sBadOption:
|
||||
bad_options++;
|
||||
continue;
|
||||
case sPort:
|
||||
intptr = &options->port;
|
||||
parse_int:
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!cp) {
|
||||
fprintf(stderr, "%s line %d: missing integer value.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
value = atoi(cp);
|
||||
if (*intptr == -1)
|
||||
*intptr = value;
|
||||
break;
|
||||
|
||||
case sRhostsAuthentication:
|
||||
intptr = &options->rhosts_authentication;
|
||||
goto parse_flag;
|
||||
case sServerKeyBits:
|
||||
intptr = &options->server_key_bits;
|
||||
goto parse_int;
|
||||
|
||||
case sLoginGraceTime:
|
||||
intptr = &options->login_grace_time;
|
||||
goto parse_int;
|
||||
|
||||
case sKeyRegenerationTime:
|
||||
intptr = &options->key_regeneration_time;
|
||||
goto parse_int;
|
||||
|
||||
case sListenAddress:
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!cp) {
|
||||
fprintf(stderr, "%s line %d: missing inet addr.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
options->listen_addr.s_addr = inet_addr(cp);
|
||||
break;
|
||||
|
||||
case sHostKeyFile:
|
||||
charptr = &options->host_key_file;
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!cp) {
|
||||
fprintf(stderr, "%s line %d: missing file name.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
if (*charptr == NULL)
|
||||
*charptr = tilde_expand_filename(cp, getuid());
|
||||
break;
|
||||
|
||||
case sRandomSeedFile:
|
||||
fprintf(stderr, "%s line %d: \"randomseed\" option is obsolete.\n",
|
||||
filename, linenum);
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
break;
|
||||
|
||||
case sPermitRootLogin:
|
||||
intptr = &options->permit_root_login;
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!cp) {
|
||||
fprintf(stderr, "%s line %d: missing yes/without-password/no argument.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
if (strcmp(cp, "without-password") == 0)
|
||||
value = 2;
|
||||
else if (strcmp(cp, "yes") == 0)
|
||||
value = 1;
|
||||
else if (strcmp(cp, "no") == 0)
|
||||
value = 0;
|
||||
else {
|
||||
fprintf(stderr, "%s line %d: Bad yes/without-password/no argument: %s\n",
|
||||
filename, linenum, cp);
|
||||
exit(1);
|
||||
}
|
||||
if (*intptr == -1)
|
||||
*intptr = value;
|
||||
break;
|
||||
|
||||
case sIgnoreRhosts:
|
||||
intptr = &options->ignore_rhosts;
|
||||
parse_flag:
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!cp) {
|
||||
fprintf(stderr, "%s line %d: missing yes/no argument.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
if (strcmp(cp, "yes") == 0)
|
||||
value = 1;
|
||||
else if (strcmp(cp, "no") == 0)
|
||||
value = 0;
|
||||
else {
|
||||
fprintf(stderr, "%s line %d: Bad yes/no argument: %s\n",
|
||||
filename, linenum, cp);
|
||||
exit(1);
|
||||
}
|
||||
if (*intptr == -1)
|
||||
*intptr = value;
|
||||
break;
|
||||
|
||||
case sIgnoreUserKnownHosts:
|
||||
intptr = &options->ignore_user_known_hosts;
|
||||
goto parse_int;
|
||||
|
||||
case sRhostsAuthentication:
|
||||
intptr = &options->rhosts_authentication;
|
||||
goto parse_flag;
|
||||
|
||||
case sRhostsRSAAuthentication:
|
||||
intptr = &options->rhosts_rsa_authentication;
|
||||
goto parse_flag;
|
||||
|
||||
case sRSAAuthentication:
|
||||
intptr = &options->rsa_authentication;
|
||||
goto parse_flag;
|
||||
|
||||
case sRhostsRSAAuthentication:
|
||||
intptr = &options->rhosts_rsa_authentication;
|
||||
goto parse_flag;
|
||||
|
||||
case sRSAAuthentication:
|
||||
intptr = &options->rsa_authentication;
|
||||
goto parse_flag;
|
||||
|
||||
#ifdef KRB4
|
||||
case sKerberosAuthentication:
|
||||
intptr = &options->kerberos_authentication;
|
||||
goto parse_flag;
|
||||
|
||||
case sKerberosOrLocalPasswd:
|
||||
intptr = &options->kerberos_or_local_passwd;
|
||||
goto parse_flag;
|
||||
case sKerberosAuthentication:
|
||||
intptr = &options->kerberos_authentication;
|
||||
goto parse_flag;
|
||||
|
||||
case sKerberosTicketCleanup:
|
||||
intptr = &options->kerberos_ticket_cleanup;
|
||||
goto parse_flag;
|
||||
case sKerberosOrLocalPasswd:
|
||||
intptr = &options->kerberos_or_local_passwd;
|
||||
goto parse_flag;
|
||||
|
||||
case sKerberosTicketCleanup:
|
||||
intptr = &options->kerberos_ticket_cleanup;
|
||||
goto parse_flag;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef AFS
|
||||
case sKerberosTgtPassing:
|
||||
intptr = &options->kerberos_tgt_passing;
|
||||
goto parse_flag;
|
||||
case sKerberosTgtPassing:
|
||||
intptr = &options->kerberos_tgt_passing;
|
||||
goto parse_flag;
|
||||
|
||||
case sAFSTokenPassing:
|
||||
intptr = &options->afs_token_passing;
|
||||
goto parse_flag;
|
||||
case sAFSTokenPassing:
|
||||
intptr = &options->afs_token_passing;
|
||||
goto parse_flag;
|
||||
#endif
|
||||
|
||||
case sPasswordAuthentication:
|
||||
intptr = &options->password_authentication;
|
||||
goto parse_flag;
|
||||
case sPasswordAuthentication:
|
||||
intptr = &options->password_authentication;
|
||||
goto parse_flag;
|
||||
|
||||
case sCheckMail:
|
||||
intptr = &options->check_mail;
|
||||
goto parse_flag;
|
||||
case sCheckMail:
|
||||
intptr = &options->check_mail;
|
||||
goto parse_flag;
|
||||
|
||||
#ifdef SKEY
|
||||
case sSkeyAuthentication:
|
||||
intptr = &options->skey_authentication;
|
||||
goto parse_flag;
|
||||
case sSkeyAuthentication:
|
||||
intptr = &options->skey_authentication;
|
||||
goto parse_flag;
|
||||
#endif
|
||||
|
||||
case sPrintMotd:
|
||||
intptr = &options->print_motd;
|
||||
goto parse_flag;
|
||||
case sPrintMotd:
|
||||
intptr = &options->print_motd;
|
||||
goto parse_flag;
|
||||
|
||||
case sX11Forwarding:
|
||||
intptr = &options->x11_forwarding;
|
||||
goto parse_flag;
|
||||
case sX11Forwarding:
|
||||
intptr = &options->x11_forwarding;
|
||||
goto parse_flag;
|
||||
|
||||
case sX11DisplayOffset:
|
||||
intptr = &options->x11_display_offset;
|
||||
goto parse_int;
|
||||
case sX11DisplayOffset:
|
||||
intptr = &options->x11_display_offset;
|
||||
goto parse_int;
|
||||
|
||||
case sStrictModes:
|
||||
intptr = &options->strict_modes;
|
||||
goto parse_flag;
|
||||
case sStrictModes:
|
||||
intptr = &options->strict_modes;
|
||||
goto parse_flag;
|
||||
|
||||
case sKeepAlives:
|
||||
intptr = &options->keepalives;
|
||||
goto parse_flag;
|
||||
|
||||
case sEmptyPasswd:
|
||||
intptr = &options->permit_empty_passwd;
|
||||
goto parse_flag;
|
||||
case sKeepAlives:
|
||||
intptr = &options->keepalives;
|
||||
goto parse_flag;
|
||||
|
||||
case sUseLogin:
|
||||
intptr = &options->use_login;
|
||||
goto parse_flag;
|
||||
case sEmptyPasswd:
|
||||
intptr = &options->permit_empty_passwd;
|
||||
goto parse_flag;
|
||||
|
||||
case sLogFacility:
|
||||
intptr = (int *)&options->log_facility;
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
value = log_facility_number(cp);
|
||||
if (value == (SyslogFacility)-1)
|
||||
fatal("%.200s line %d: unsupported log facility '%s'\n",
|
||||
filename, linenum, cp ? cp : "<NONE>");
|
||||
if (*intptr == -1)
|
||||
*intptr = (SyslogFacility)value;
|
||||
break;
|
||||
case sUseLogin:
|
||||
intptr = &options->use_login;
|
||||
goto parse_flag;
|
||||
|
||||
case sLogLevel:
|
||||
intptr = (int *)&options->log_level;
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
value = log_level_number(cp);
|
||||
if (value == (LogLevel)-1)
|
||||
fatal("%.200s line %d: unsupported log level '%s'\n",
|
||||
filename, linenum, cp ? cp : "<NONE>");
|
||||
if (*intptr == -1)
|
||||
*intptr = (LogLevel)value;
|
||||
break;
|
||||
|
||||
case sAllowUsers:
|
||||
while ((cp = strtok(NULL, WHITESPACE)))
|
||||
{
|
||||
if (options->num_allow_users >= MAX_ALLOW_USERS)
|
||||
{
|
||||
fprintf(stderr, "%s line %d: too many allow users.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
case sLogFacility:
|
||||
intptr = (int *) &options->log_facility;
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
value = log_facility_number(cp);
|
||||
if (value == (SyslogFacility) - 1)
|
||||
fatal("%.200s line %d: unsupported log facility '%s'\n",
|
||||
filename, linenum, cp ? cp : "<NONE>");
|
||||
if (*intptr == -1)
|
||||
*intptr = (SyslogFacility) value;
|
||||
break;
|
||||
|
||||
case sLogLevel:
|
||||
intptr = (int *) &options->log_level;
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
value = log_level_number(cp);
|
||||
if (value == (LogLevel) - 1)
|
||||
fatal("%.200s line %d: unsupported log level '%s'\n",
|
||||
filename, linenum, cp ? cp : "<NONE>");
|
||||
if (*intptr == -1)
|
||||
*intptr = (LogLevel) value;
|
||||
break;
|
||||
|
||||
case sAllowUsers:
|
||||
while ((cp = strtok(NULL, WHITESPACE))) {
|
||||
if (options->num_allow_users >= MAX_ALLOW_USERS) {
|
||||
fprintf(stderr, "%s line %d: too many allow users.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
options->allow_users[options->num_allow_users++] = xstrdup(cp);
|
||||
}
|
||||
break;
|
||||
|
||||
case sDenyUsers:
|
||||
while ((cp = strtok(NULL, WHITESPACE))) {
|
||||
if (options->num_deny_users >= MAX_DENY_USERS) {
|
||||
fprintf(stderr, "%s line %d: too many deny users.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
options->deny_users[options->num_deny_users++] = xstrdup(cp);
|
||||
}
|
||||
break;
|
||||
|
||||
case sAllowGroups:
|
||||
while ((cp = strtok(NULL, WHITESPACE))) {
|
||||
if (options->num_allow_groups >= MAX_ALLOW_GROUPS) {
|
||||
fprintf(stderr, "%s line %d: too many allow groups.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
options->allow_groups[options->num_allow_groups++] = xstrdup(cp);
|
||||
}
|
||||
break;
|
||||
|
||||
case sDenyGroups:
|
||||
while ((cp = strtok(NULL, WHITESPACE))) {
|
||||
if (options->num_deny_groups >= MAX_DENY_GROUPS) {
|
||||
fprintf(stderr, "%s line %d: too many deny groups.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
options->deny_groups[options->num_deny_groups++] = xstrdup(cp);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "%s line %d: Missing handler for opcode %s (%d)\n",
|
||||
filename, linenum, cp, opcode);
|
||||
exit(1);
|
||||
}
|
||||
options->allow_users[options->num_allow_users++] = xstrdup(cp);
|
||||
}
|
||||
break;
|
||||
|
||||
case sDenyUsers:
|
||||
while ((cp = strtok(NULL, WHITESPACE)))
|
||||
{
|
||||
if (options->num_deny_users >= MAX_DENY_USERS)
|
||||
{
|
||||
fprintf(stderr, "%s line %d: too many deny users.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
if (strtok(NULL, WHITESPACE) != NULL) {
|
||||
fprintf(stderr, "%s line %d: garbage at end of line.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
options->deny_users[options->num_deny_users++] = xstrdup(cp);
|
||||
}
|
||||
break;
|
||||
|
||||
case sAllowGroups:
|
||||
while ((cp = strtok(NULL, WHITESPACE)))
|
||||
{
|
||||
if (options->num_allow_groups >= MAX_ALLOW_GROUPS)
|
||||
{
|
||||
fprintf(stderr, "%s line %d: too many allow groups.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
options->allow_groups[options->num_allow_groups++] = xstrdup(cp);
|
||||
}
|
||||
break;
|
||||
|
||||
case sDenyGroups:
|
||||
while ((cp = strtok(NULL, WHITESPACE)))
|
||||
{
|
||||
if (options->num_deny_groups >= MAX_DENY_GROUPS)
|
||||
{
|
||||
fprintf(stderr, "%s line %d: too many deny groups.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
options->deny_groups[options->num_deny_groups++] = xstrdup(cp);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "%s line %d: Missing handler for opcode %s (%d)\n",
|
||||
filename, linenum, cp, opcode);
|
||||
exit(1);
|
||||
}
|
||||
if (strtok(NULL, WHITESPACE) != NULL)
|
||||
{
|
||||
fprintf(stderr, "%s line %d: garbage at end of line.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
fclose(f);
|
||||
if (bad_options > 0) {
|
||||
fprintf(stderr, "%s: terminating, %d bad configuration options\n",
|
||||
filename, bad_options);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
if (bad_options > 0) {
|
||||
fprintf(stderr, "%s: terminating, %d bad configuration options\n",
|
||||
filename, bad_options);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
|
142
servconf.h
142
servconf.h
|
@ -1,86 +1,98 @@
|
|||
/*
|
||||
*
|
||||
* servconf.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Mon Aug 21 15:35:03 1995 ylo
|
||||
*
|
||||
* Definitions for server configuration data and for the functions reading it.
|
||||
*
|
||||
*/
|
||||
|
||||
servconf.h
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Mon Aug 21 15:35:03 1995 ylo
|
||||
|
||||
Definitions for server configuration data and for the functions reading it.
|
||||
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: servconf.h,v 1.3 1999/11/12 00:33:04 damien Exp $"); */
|
||||
/* RCSID("$Id: servconf.h,v 1.4 1999/11/24 13:26:22 damien Exp $"); */
|
||||
|
||||
#ifndef SERVCONF_H
|
||||
#define SERVCONF_H
|
||||
|
||||
#define MAX_ALLOW_USERS 256 /* Max # users on allow list. */
|
||||
#define MAX_DENY_USERS 256 /* Max # users on deny list. */
|
||||
#define MAX_ALLOW_GROUPS 256 /* Max # groups on allow list. */
|
||||
#define MAX_DENY_GROUPS 256 /* Max # groups on deny list. */
|
||||
#define MAX_ALLOW_USERS 256 /* Max # users on allow list. */
|
||||
#define MAX_DENY_USERS 256 /* Max # users on deny list. */
|
||||
#define MAX_ALLOW_GROUPS 256 /* Max # groups on allow list. */
|
||||
#define MAX_DENY_GROUPS 256 /* Max # groups on deny list. */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int port; /* Port number to listen on. */
|
||||
struct in_addr listen_addr; /* Address on which the server listens. */
|
||||
char *host_key_file; /* File containing host key. */
|
||||
int server_key_bits; /* Size of the server key. */
|
||||
int login_grace_time; /* Disconnect if no auth in this time (sec). */
|
||||
int key_regeneration_time; /* Server key lifetime (seconds). */
|
||||
int permit_root_login; /* If true, permit root login. */
|
||||
int ignore_rhosts; /* Ignore .rhosts and .shosts. */
|
||||
int ignore_user_known_hosts; /* Ignore ~/.ssh/known_hosts for RhostsRsaAuth */
|
||||
int print_motd; /* If true, print /etc/motd. */
|
||||
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 strict_modes; /* If true, require string home dir modes. */
|
||||
int keepalives; /* If true, set SO_KEEPALIVE. */
|
||||
SyslogFacility log_facility; /* Facility for system logging. */
|
||||
LogLevel log_level; /* Level for system logging. */
|
||||
int rhosts_authentication; /* If true, permit rhosts authentication. */
|
||||
int rhosts_rsa_authentication;/* If true, permit rhosts RSA authentication.*/
|
||||
int rsa_authentication; /* If true, permit RSA authentication. */
|
||||
typedef struct {
|
||||
int port; /* Port number to listen on. */
|
||||
struct in_addr listen_addr; /* Address on which the server
|
||||
* listens. */
|
||||
char *host_key_file; /* File containing host key. */
|
||||
int server_key_bits;/* Size of the server key. */
|
||||
int login_grace_time; /* Disconnect if no auth in this time
|
||||
* (sec). */
|
||||
int key_regeneration_time; /* Server key lifetime (seconds). */
|
||||
int permit_root_login; /* If true, permit root login. */
|
||||
int ignore_rhosts; /* Ignore .rhosts and .shosts. */
|
||||
int ignore_user_known_hosts; /* Ignore ~/.ssh/known_hosts
|
||||
* for RhostsRsaAuth */
|
||||
int print_motd; /* If true, print /etc/motd. */
|
||||
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 strict_modes; /* If true, require string home dir modes. */
|
||||
int keepalives; /* If true, set SO_KEEPALIVE. */
|
||||
SyslogFacility log_facility; /* Facility for system logging. */
|
||||
LogLevel log_level; /* Level for system logging. */
|
||||
int rhosts_authentication; /* If true, permit rhosts
|
||||
* authentication. */
|
||||
int rhosts_rsa_authentication; /* If true, permit rhosts RSA
|
||||
* authentication. */
|
||||
int rsa_authentication; /* If true, permit RSA authentication. */
|
||||
#ifdef KRB4
|
||||
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 kerberos_ticket_cleanup; /* If true, destroy ticket file on logout. */
|
||||
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 kerberos_ticket_cleanup; /* If true, destroy ticket
|
||||
* file on logout. */
|
||||
#endif
|
||||
#ifdef AFS
|
||||
int kerberos_tgt_passing; /* If true, permit Kerberos tgt passing. */
|
||||
int afs_token_passing; /* If true, permit AFS token passing. */
|
||||
int kerberos_tgt_passing; /* If true, permit Kerberos tgt
|
||||
* passing. */
|
||||
int afs_token_passing; /* If true, permit AFS token passing. */
|
||||
#endif
|
||||
int password_authentication; /* If true, permit password authentication. */
|
||||
int password_authentication; /* If true, permit password
|
||||
* authentication. */
|
||||
#ifdef SKEY
|
||||
int skey_authentication; /* If true, permit s/key authentication. */
|
||||
int skey_authentication; /* If true, permit s/key
|
||||
* authentication. */
|
||||
#endif
|
||||
int permit_empty_passwd; /* If false, do not permit empty passwords. */
|
||||
int use_login; /* If true, login(1) is used */
|
||||
unsigned int num_allow_users;
|
||||
char *allow_users[MAX_ALLOW_USERS];
|
||||
unsigned int num_deny_users;
|
||||
char *deny_users[MAX_DENY_USERS];
|
||||
unsigned int num_allow_groups;
|
||||
char *allow_groups[MAX_ALLOW_GROUPS];
|
||||
unsigned int num_deny_groups;
|
||||
char *deny_groups[MAX_DENY_GROUPS];
|
||||
} ServerOptions;
|
||||
|
||||
int permit_empty_passwd; /* If false, do not permit empty
|
||||
* passwords. */
|
||||
int use_login; /* If true, login(1) is used */
|
||||
unsigned int num_allow_users;
|
||||
char *allow_users[MAX_ALLOW_USERS];
|
||||
unsigned int num_deny_users;
|
||||
char *deny_users[MAX_DENY_USERS];
|
||||
unsigned int num_allow_groups;
|
||||
char *allow_groups[MAX_ALLOW_GROUPS];
|
||||
unsigned int num_deny_groups;
|
||||
char *deny_groups[MAX_DENY_GROUPS];
|
||||
} ServerOptions;
|
||||
/* Initializes the server options to special values that indicate that they
|
||||
have not yet been set. */
|
||||
void initialize_server_options(ServerOptions *options);
|
||||
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 read_server_config(ServerOptions * options, const char *filename);
|
||||
|
||||
/* Sets values for those values that have not yet been set. */
|
||||
void fill_default_server_options(ServerOptions *options);
|
||||
void fill_default_server_options(ServerOptions * options);
|
||||
|
||||
#endif /* SERVCONF_H */
|
||||
#endif /* SERVCONF_H */
|
||||
|
|
1130
serverloop.c
1130
serverloop.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
471
ssh-add.c
471
ssh-add.c
|
@ -1,20 +1,13 @@
|
|||
/*
|
||||
|
||||
ssh-add.c
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Thu Apr 6 00:52:24 1995 ylo
|
||||
|
||||
Adds an identity to the authentication server, or removes an identity.
|
||||
|
||||
*/
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Created: Thu Apr 6 00:52:24 1995 ylo
|
||||
* Adds an identity to the authentication server, or removes an identity.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: ssh-add.c,v 1.12 1999/11/23 00:24:32 damien Exp $");
|
||||
RCSID("$Id: ssh-add.c,v 1.13 1999/11/24 13:26:22 damien Exp $");
|
||||
|
||||
#include "rsa.h"
|
||||
#include "ssh.h"
|
||||
|
@ -35,291 +28,279 @@ const char *__progname = "ssh-add";
|
|||
void
|
||||
delete_file(AuthenticationConnection *ac, const char *filename)
|
||||
{
|
||||
RSA *key;
|
||||
char *comment;
|
||||
RSA *key;
|
||||
char *comment;
|
||||
|
||||
key = RSA_new();
|
||||
if (!load_public_key(filename, key, &comment))
|
||||
{
|
||||
printf("Bad key file %s: %s\n", filename, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ssh_remove_identity(ac, key))
|
||||
fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment);
|
||||
else
|
||||
fprintf(stderr, "Could not remove identity: %s\n", filename);
|
||||
RSA_free(key);
|
||||
xfree(comment);
|
||||
key = RSA_new();
|
||||
if (!load_public_key(filename, key, &comment)) {
|
||||
printf("Bad key file %s: %s\n", filename, strerror(errno));
|
||||
return;
|
||||
}
|
||||
if (ssh_remove_identity(ac, key))
|
||||
fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment);
|
||||
else
|
||||
fprintf(stderr, "Could not remove identity: %s\n", filename);
|
||||
RSA_free(key);
|
||||
xfree(comment);
|
||||
}
|
||||
|
||||
void
|
||||
delete_all(AuthenticationConnection *ac)
|
||||
{
|
||||
/* Send a request to remove all identities. */
|
||||
if (ssh_remove_all_identities(ac))
|
||||
fprintf(stderr, "All identities removed.\n");
|
||||
else
|
||||
fprintf(stderr, "Failed to remove all identitities.\n");
|
||||
/* Send a request to remove all identities. */
|
||||
if (ssh_remove_all_identities(ac))
|
||||
fprintf(stderr, "All identities removed.\n");
|
||||
else
|
||||
fprintf(stderr, "Failed to remove all identitities.\n");
|
||||
}
|
||||
|
||||
void
|
||||
add_file(AuthenticationConnection *ac, const char *filename)
|
||||
{
|
||||
RSA *key;
|
||||
RSA *public_key;
|
||||
char *saved_comment, *comment;
|
||||
int success;
|
||||
|
||||
key = RSA_new();
|
||||
public_key = RSA_new();
|
||||
if (!load_public_key(filename, public_key, &saved_comment))
|
||||
{
|
||||
printf("Bad key file %s: %s\n", filename, strerror(errno));
|
||||
return;
|
||||
}
|
||||
RSA_free(public_key);
|
||||
RSA *key;
|
||||
RSA *public_key;
|
||||
char *saved_comment, *comment;
|
||||
int success;
|
||||
|
||||
/* At first, try empty passphrase */
|
||||
success = load_private_key(filename, "", key, &comment);
|
||||
if (!success) {
|
||||
printf("Need passphrase for %s (%s).\n", filename, saved_comment);
|
||||
if (!isatty(STDIN_FILENO)) {
|
||||
key = RSA_new();
|
||||
public_key = RSA_new();
|
||||
if (!load_public_key(filename, public_key, &saved_comment)) {
|
||||
printf("Bad key file %s: %s\n", filename, strerror(errno));
|
||||
return;
|
||||
}
|
||||
RSA_free(public_key);
|
||||
|
||||
/* At first, try empty passphrase */
|
||||
success = load_private_key(filename, "", key, &comment);
|
||||
if (!success) {
|
||||
printf("Need passphrase for %s (%s).\n", filename, saved_comment);
|
||||
if (!isatty(STDIN_FILENO)) {
|
||||
#ifdef USE_EXTERNAL_ASKPASS
|
||||
int prompts = 3;
|
||||
|
||||
while (prompts && !success)
|
||||
{
|
||||
success = askpass(filename, key, saved_comment, &comment);
|
||||
prompts--;
|
||||
}
|
||||
if (!success)
|
||||
{
|
||||
xfree(saved_comment);
|
||||
return;
|
||||
}
|
||||
int prompts = 3;
|
||||
while (prompts && !success) {
|
||||
success = askpass(filename, key, saved_comment, &comment);
|
||||
prompts--;
|
||||
}
|
||||
if (!success) {
|
||||
xfree(saved_comment);
|
||||
return;
|
||||
}
|
||||
#else /* !USE_EXTERNAL_ASKPASS */
|
||||
xfree(saved_comment);
|
||||
return;
|
||||
xfree(saved_comment);
|
||||
return;
|
||||
#endif /* USE_EXTERNAL_ASKPASS */
|
||||
}
|
||||
}
|
||||
|
||||
while (!success) {
|
||||
char *pass = read_passphrase("Enter passphrase: ", 1);
|
||||
if (strcmp(pass, "") == 0){
|
||||
xfree(pass);
|
||||
xfree(saved_comment);
|
||||
return;
|
||||
}
|
||||
success = load_private_key(filename, pass, key, &comment);
|
||||
memset(pass, 0, strlen(pass));
|
||||
xfree(pass);
|
||||
if (success)
|
||||
break;
|
||||
printf("Bad passphrase.\n");
|
||||
}
|
||||
}
|
||||
xfree(saved_comment);
|
||||
while (!success) {
|
||||
char *pass = read_passphrase("Enter passphrase: ", 1);
|
||||
if (strcmp(pass, "") == 0) {
|
||||
xfree(pass);
|
||||
xfree(saved_comment);
|
||||
return;
|
||||
}
|
||||
success = load_private_key(filename, pass, key, &comment);
|
||||
memset(pass, 0, strlen(pass));
|
||||
xfree(pass);
|
||||
if (success)
|
||||
break;
|
||||
printf("Bad passphrase.\n");
|
||||
}
|
||||
}
|
||||
xfree(saved_comment);
|
||||
|
||||
if (ssh_add_identity(ac, key, comment))
|
||||
fprintf(stderr, "Identity added: %s (%s)\n", filename, comment);
|
||||
else
|
||||
fprintf(stderr, "Could not add identity: %s\n", filename);
|
||||
RSA_free(key);
|
||||
xfree(comment);
|
||||
if (ssh_add_identity(ac, key, comment))
|
||||
fprintf(stderr, "Identity added: %s (%s)\n", filename, comment);
|
||||
else
|
||||
fprintf(stderr, "Could not add identity: %s\n", filename);
|
||||
RSA_free(key);
|
||||
xfree(comment);
|
||||
}
|
||||
|
||||
void
|
||||
list_identities(AuthenticationConnection *ac, int fp)
|
||||
{
|
||||
BIGNUM *e, *n;
|
||||
int status;
|
||||
char *comment;
|
||||
int had_identities;
|
||||
BIGNUM *e, *n;
|
||||
int status;
|
||||
char *comment;
|
||||
int had_identities;
|
||||
|
||||
e = BN_new();
|
||||
n = BN_new();
|
||||
had_identities = 0;
|
||||
for (status = ssh_get_first_identity(ac, e, n, &comment);
|
||||
status;
|
||||
status = ssh_get_next_identity(ac, e, n, &comment))
|
||||
{
|
||||
unsigned int bits = BN_num_bits(n);
|
||||
had_identities = 1;
|
||||
if (fp) {
|
||||
printf("%d %s %s\n", bits, fingerprint(e, n), comment);
|
||||
} else {
|
||||
char *ebuf, *nbuf;
|
||||
ebuf = BN_bn2dec(e);
|
||||
if (ebuf == NULL) {
|
||||
error("list_identities: BN_bn2dec(e) failed.");
|
||||
}else{
|
||||
nbuf = BN_bn2dec(n);
|
||||
if (nbuf == NULL) {
|
||||
error("list_identities: BN_bn2dec(n) failed.");
|
||||
}else{
|
||||
printf("%d %s %s %s\n", bits, ebuf, nbuf, comment);
|
||||
free(nbuf);
|
||||
}
|
||||
free(ebuf);
|
||||
e = BN_new();
|
||||
n = BN_new();
|
||||
had_identities = 0;
|
||||
for (status = ssh_get_first_identity(ac, e, n, &comment);
|
||||
status;
|
||||
status = ssh_get_next_identity(ac, e, n, &comment)) {
|
||||
unsigned int bits = BN_num_bits(n);
|
||||
had_identities = 1;
|
||||
if (fp) {
|
||||
printf("%d %s %s\n", bits, fingerprint(e, n), comment);
|
||||
} else {
|
||||
char *ebuf, *nbuf;
|
||||
ebuf = BN_bn2dec(e);
|
||||
if (ebuf == NULL) {
|
||||
error("list_identities: BN_bn2dec(e) failed.");
|
||||
} else {
|
||||
nbuf = BN_bn2dec(n);
|
||||
if (nbuf == NULL) {
|
||||
error("list_identities: BN_bn2dec(n) failed.");
|
||||
} else {
|
||||
printf("%d %s %s %s\n", bits, ebuf, nbuf, comment);
|
||||
free(nbuf);
|
||||
}
|
||||
free(ebuf);
|
||||
}
|
||||
}
|
||||
xfree(comment);
|
||||
}
|
||||
}
|
||||
xfree(comment);
|
||||
}
|
||||
BN_clear_free(e);
|
||||
BN_clear_free(n);
|
||||
if (!had_identities)
|
||||
printf("The agent has no identities.\n");
|
||||
BN_clear_free(e);
|
||||
BN_clear_free(n);
|
||||
if (!had_identities)
|
||||
printf("The agent has no identities.\n");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
AuthenticationConnection *ac = NULL;
|
||||
struct passwd *pw;
|
||||
char buf[1024];
|
||||
int no_files = 1;
|
||||
int i;
|
||||
int deleting = 0;
|
||||
AuthenticationConnection *ac = NULL;
|
||||
struct passwd *pw;
|
||||
char buf[1024];
|
||||
int no_files = 1;
|
||||
int i;
|
||||
int deleting = 0;
|
||||
|
||||
/* check if RSA support exists */
|
||||
if (rsa_alive() == 0) {
|
||||
fprintf(stderr,
|
||||
"%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
|
||||
__progname);
|
||||
exit(1);
|
||||
}
|
||||
/* check if RSA support exists */
|
||||
if (rsa_alive() == 0) {
|
||||
extern char *__progname;
|
||||
|
||||
/* At first, get a connection to the authentication agent. */
|
||||
ac = ssh_get_authentication_connection();
|
||||
if (ac == NULL) {
|
||||
fprintf(stderr, "Could not open a connection to your authentication agent.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
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);
|
||||
no_files = 0; /* Don't default-add/delete if -l. */
|
||||
continue;
|
||||
fprintf(stderr,
|
||||
"%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
|
||||
__progname);
|
||||
exit(1);
|
||||
}
|
||||
if (strcmp(argv[i], "-d") == 0)
|
||||
{
|
||||
deleting = 1;
|
||||
continue;
|
||||
/* At first, get a connection to the authentication agent. */
|
||||
ac = ssh_get_authentication_connection();
|
||||
if (ac == NULL) {
|
||||
fprintf(stderr, "Could not open a connection to your authentication agent.\n");
|
||||
exit(1);
|
||||
}
|
||||
if (strcmp(argv[i], "-D") == 0)
|
||||
{
|
||||
delete_all(ac);
|
||||
no_files = 0;
|
||||
continue;
|
||||
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) {
|
||||
deleting = 1;
|
||||
continue;
|
||||
}
|
||||
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]);
|
||||
}
|
||||
no_files = 0;
|
||||
if (deleting)
|
||||
delete_file(ac, argv[i]);
|
||||
else
|
||||
add_file(ac, argv[i]);
|
||||
}
|
||||
if (no_files)
|
||||
{
|
||||
pw = getpwuid(getuid());
|
||||
if (!pw)
|
||||
{
|
||||
fprintf(stderr, "No user found with uid %d\n", (int)getuid());
|
||||
ssh_close_authentication_connection(ac);
|
||||
exit(1);
|
||||
if (no_files) {
|
||||
pw = getpwuid(getuid());
|
||||
if (!pw) {
|
||||
fprintf(stderr, "No user found with uid %d\n", (int) getuid());
|
||||
ssh_close_authentication_connection(ac);
|
||||
exit(1);
|
||||
}
|
||||
snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, SSH_CLIENT_IDENTITY);
|
||||
if (deleting)
|
||||
delete_file(ac, buf);
|
||||
else
|
||||
add_file(ac, buf);
|
||||
}
|
||||
snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, SSH_CLIENT_IDENTITY);
|
||||
if (deleting)
|
||||
delete_file(ac, buf);
|
||||
else
|
||||
add_file(ac, buf);
|
||||
}
|
||||
ssh_close_authentication_connection(ac);
|
||||
exit(0);
|
||||
ssh_close_authentication_connection(ac);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#ifdef USE_EXTERNAL_ASKPASS
|
||||
int askpass(const char *filename, RSA *key, const char *saved_comment, char **comment)
|
||||
{
|
||||
int pipes[2];
|
||||
char buf[1024];
|
||||
int tmp;
|
||||
pid_t child;
|
||||
FILE *pipef;
|
||||
int pipes[2];
|
||||
char buf[1024];
|
||||
int tmp;
|
||||
pid_t child;
|
||||
FILE *pipef;
|
||||
|
||||
/* Check that we are X11-capable */
|
||||
if (getenv("DISPLAY") == NULL)
|
||||
exit(1);
|
||||
/* Check that we are X11-capable */
|
||||
if (getenv("DISPLAY") == NULL)
|
||||
exit(1);
|
||||
|
||||
if (pipe(pipes) == -1) {
|
||||
fprintf(stderr, "Creating pipes failed: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
if (pipe(pipes) == -1) {
|
||||
fprintf(stderr, "Creating pipes failed: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (fflush(NULL) == EOF) {
|
||||
fprintf(stderr, "Cannot flush buffers: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
if (fflush(NULL) == EOF) {
|
||||
fprintf(stderr, "Cannot flush buffers: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
child = fork();
|
||||
if (child == -1) {
|
||||
fprintf(stderr, "Cannot fork: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (child == 0) {
|
||||
/* In child */
|
||||
child = fork();
|
||||
if (child == -1) {
|
||||
fprintf(stderr, "Cannot fork: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
close(pipes[0]);
|
||||
if (dup2(pipes[1], 1) ==-1) {
|
||||
fprintf(stderr, "dup2 failed: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
if (child == 0) {
|
||||
/* In child */
|
||||
|
||||
tmp = snprintf(buf, sizeof(buf), "Need passphrase for %s", saved_comment);
|
||||
/* skip the prompt if it won't fit */
|
||||
if ((tmp < 0) || (tmp >= sizeof(buf)))
|
||||
tmp = execlp(ASKPASS_PROGRAM, "ssh-askpass", 0);
|
||||
else
|
||||
tmp = execlp(ASKPASS_PROGRAM, "ssh-askpass", buf, 0);
|
||||
close(pipes[0]);
|
||||
if (dup2(pipes[1], 1) ==-1) {
|
||||
fprintf(stderr, "dup2 failed: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Shouldn't get this far */
|
||||
fprintf(stderr, "Executing ssh-askpass failed: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
tmp = snprintf(buf, sizeof(buf), "Need passphrase for %s", saved_comment);
|
||||
/* skip the prompt if it won't fit */
|
||||
if ((tmp < 0) || (tmp >= sizeof(buf)))
|
||||
tmp = execlp(ASKPASS_PROGRAM, "ssh-askpass", 0);
|
||||
else
|
||||
tmp = execlp(ASKPASS_PROGRAM, "ssh-askpass", buf, 0);
|
||||
|
||||
/* In parent */
|
||||
close(pipes[1]);
|
||||
/* Shouldn't get this far */
|
||||
fprintf(stderr, "Executing ssh-askpass failed: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((pipef = fdopen(pipes[0], "r")) == NULL) {
|
||||
fprintf(stderr, "fdopen failed: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Read passphrase back from child, abort if none presented */
|
||||
if(fgets(buf, sizeof(buf), pipef) == NULL)
|
||||
exit(1);
|
||||
/* In parent */
|
||||
close(pipes[1]);
|
||||
|
||||
fclose(pipef);
|
||||
if ((pipef = fdopen(pipes[0], "r")) == NULL) {
|
||||
fprintf(stderr, "fdopen failed: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (strchr(buf, '\n'))
|
||||
*strchr(buf, '\n') = 0;
|
||||
/* Read passphrase back from child, abort if none presented */
|
||||
if(fgets(buf, sizeof(buf), pipef) == NULL)
|
||||
exit(1);
|
||||
|
||||
if (waitpid(child, NULL, 0) == -1) {
|
||||
fprintf(stderr, "Waiting for child failed: %s\n",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
fclose(pipef);
|
||||
|
||||
/* Try password as it was presented */
|
||||
tmp = load_private_key(filename, buf, key, comment);
|
||||
if (strchr(buf, '\n'))
|
||||
*strchr(buf, '\n') = 0;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
if (waitpid(child, NULL, 0) == -1) {
|
||||
fprintf(stderr, "Waiting for child failed: %s\n",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return(tmp);
|
||||
/* Try password as it was presented */
|
||||
tmp = load_private_key(filename, buf, key, comment);
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
return(tmp);
|
||||
}
|
||||
#endif /* USE_EXTERNAL_ASKPASS */
|
||||
|
|
1088
ssh-agent.c
1088
ssh-agent.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
943
ssh-keygen.c
943
ssh-keygen.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
12
ssh.1
12
ssh.1
|
@ -9,7 +9,7 @@
|
|||
.\"
|
||||
.\" Created: Sat Apr 22 21:55:14 1995 ylo
|
||||
.\"
|
||||
.\" $Id: ssh.1,v 1.8 1999/11/18 00:35:13 damien Exp $
|
||||
.\" $Id: ssh.1,v 1.9 1999/11/24 13:26:23 damien Exp $
|
||||
.\"
|
||||
.Dd September 25, 1999
|
||||
.Dt SSH 1
|
||||
|
@ -662,6 +662,16 @@ or
|
|||
RSA authentication will only be
|
||||
attempted if the identity file exists, or an authentication agent is
|
||||
running.
|
||||
.It Cm SkeyAuthentication
|
||||
Specifies whether to use
|
||||
.Xr skey 1
|
||||
authentication. The argument to
|
||||
this keyword must be
|
||||
.Dq yes
|
||||
or
|
||||
.Dq no .
|
||||
The default is
|
||||
.Dq no .
|
||||
.It Cm CheckHostIP
|
||||
If this flag is set to
|
||||
.Dq yes ,
|
||||
|
|
1307
ssh.c
1307
ssh.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
347
ssh.h
347
ssh.h
|
@ -1,19 +1,19 @@
|
|||
/*
|
||||
*
|
||||
* ssh.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Fri Mar 17 17:09:37 1995 ylo
|
||||
*
|
||||
* Generic header file for ssh.
|
||||
*
|
||||
*/
|
||||
|
||||
ssh.h
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Fri Mar 17 17:09:37 1995 ylo
|
||||
|
||||
Generic header file for ssh.
|
||||
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: ssh.h,v 1.14 1999/11/21 02:23:53 damien Exp $"); */
|
||||
/* RCSID("$Id: ssh.h,v 1.15 1999/11/24 13:26:23 damien Exp $"); */
|
||||
|
||||
#ifndef SSH_H
|
||||
#define SSH_H
|
||||
|
@ -25,7 +25,7 @@ Generic header file for ssh.
|
|||
#include "rsa.h"
|
||||
#include "cipher.h"
|
||||
|
||||
/* The default cipher used if IDEA is not supported by the remote host.
|
||||
/* The default cipher used if IDEA is not supported by the remote host.
|
||||
It is recommended that this be one of the mandatory ciphers (DES, 3DES),
|
||||
though that is not required. */
|
||||
#define SSH_FALLBACK_CIPHER SSH_CIPHER_3DES
|
||||
|
@ -59,7 +59,9 @@ Generic header file for ssh.
|
|||
#define ETCDIR "/etc"
|
||||
#endif /* ETCDIR */
|
||||
|
||||
#ifndef PIDDIR
|
||||
#define PIDDIR "/var/run"
|
||||
#endif /* PIDDIR */
|
||||
|
||||
/* System-wide file containing host keys of known hosts. This file should be
|
||||
world-readable. */
|
||||
|
@ -76,15 +78,15 @@ only by root, whereas ssh_config should be world-readable. */
|
|||
#define HOST_CONFIG_FILE ETCDIR "/ssh_config"
|
||||
|
||||
#ifndef SSH_PROGRAM
|
||||
#define SSH_PROGRAM "/usr/bin/ssh"
|
||||
#define SSH_PROGRAM "/usr/bin/ssh"
|
||||
#endif /* SSH_PROGRAM */
|
||||
|
||||
#ifndef LOGIN_PROGRAM
|
||||
#define LOGIN_PROGRAM "/usr/bin/login"
|
||||
#define LOGIN_PROGRAM "/usr/bin/login"
|
||||
#endif /* LOGIN_PROGRAM */
|
||||
|
||||
#ifndef ASKPASS_PROGRAM
|
||||
#define ASKPASS_PROGRAM "/usr/lib/ssh/ssh-askpass"
|
||||
#define ASKPASS_PROGRAM "/usr/lib/ssh/ssh-askpass"
|
||||
#endif /* ASKPASS_PROGRAM */
|
||||
|
||||
/* The process id of the daemon listening for connections is saved
|
||||
|
@ -100,7 +102,7 @@ only by root, whereas ssh_config should be world-readable. */
|
|||
not contain anything particularly secret. */
|
||||
#define SSH_USER_HOSTFILE "~/.ssh/known_hosts"
|
||||
|
||||
/* Name of the default file containing client-side authentication key.
|
||||
/* Name of the default file containing client-side authentication key.
|
||||
This file should only be readable by the user him/herself. */
|
||||
#define SSH_CLIENT_IDENTITY ".ssh/identity"
|
||||
|
||||
|
@ -116,7 +118,7 @@ only by root, whereas ssh_config should be world-readable. */
|
|||
readable by anyone but the user him/herself, but does not contain
|
||||
anything particularly secret. If the user\'s home directory resides
|
||||
on an NFS volume where root is mapped to nobody, this may need to be
|
||||
world-readable. (This file is read by the daemon which is running as
|
||||
world-readable. (This file is read by the daemon which is running as
|
||||
root.) */
|
||||
#define SSH_USER_PERMITTED_KEYS ".ssh/authorized_keys"
|
||||
|
||||
|
@ -130,7 +132,7 @@ only by root, whereas ssh_config should be world-readable. */
|
|||
/* Ssh-only version of /etc/hosts.equiv. */
|
||||
#define SSH_HOSTS_EQUIV ETCDIR "/shosts.equiv"
|
||||
|
||||
/* Additionally, the daemon may use ~/.rhosts and /etc/hosts.equiv if
|
||||
/* Additionally, the daemon may use ~/.rhosts and /etc/hosts.equiv if
|
||||
rhosts authentication is enabled. */
|
||||
|
||||
/* Name of the environment variable containing the pathname of the
|
||||
|
@ -145,7 +147,7 @@ only by root, whereas ssh_config should be world-readable. */
|
|||
many bits. This is to make double encryption with rsaref work. */
|
||||
#define SSH_KEY_BITS_RESERVED 128
|
||||
|
||||
/* Length of the session key in bytes. (Specified as 256 bits in the
|
||||
/* Length of the session key in bytes. (Specified as 256 bits in the
|
||||
protocol.) */
|
||||
#define SSH_SESSION_KEY_LENGTH 32
|
||||
|
||||
|
@ -158,21 +160,23 @@ only by root, whereas ssh_config should be world-readable. */
|
|||
#define SSH_AUTH_RSA 2
|
||||
#define SSH_AUTH_PASSWORD 3
|
||||
#define SSH_AUTH_RHOSTS_RSA 4
|
||||
/* 5 is TIS */
|
||||
#define SSH_AUTH_TIS 5
|
||||
#define SSH_AUTH_KERBEROS 6
|
||||
#define SSH_PASS_KERBEROS_TGT 7
|
||||
/* 8 to 15 are reserved */
|
||||
/* 8 to 15 are reserved */
|
||||
#define SSH_PASS_AFS_TOKEN 21
|
||||
|
||||
/* Protocol flags. These are bit masks. */
|
||||
#define SSH_PROTOFLAG_SCREEN_NUMBER 1 /* X11 forwarding includes screen */
|
||||
#define SSH_PROTOFLAG_HOST_IN_FWD_OPEN 2 /* forwarding opens contain host */
|
||||
#define SSH_PROTOFLAG_SCREEN_NUMBER 1 /* X11 forwarding includes
|
||||
* screen */
|
||||
#define SSH_PROTOFLAG_HOST_IN_FWD_OPEN 2 /* forwarding opens contain
|
||||
* host */
|
||||
|
||||
/* Definition of message types. New values can be added, but old values
|
||||
should not be removed or without careful consideration of the consequences
|
||||
for compatibility. The maximum value is 254; value 255 is reserved
|
||||
for future extension. */
|
||||
/* Message name */ /* msg code */ /* arguments */
|
||||
/* Message name *//* msg code *//* arguments */
|
||||
#define SSH_MSG_NONE 0 /* no message */
|
||||
#define SSH_MSG_DISCONNECT 1 /* cause (string) */
|
||||
#define SSH_SMSG_PUBLIC_KEY 2 /* ck,msk,srvk,hostk */
|
||||
|
@ -212,10 +216,9 @@ only by root, whereas ssh_config should be world-readable. */
|
|||
#define SSH_MSG_DEBUG 36 /* string */
|
||||
#define SSH_CMSG_REQUEST_COMPRESSION 37 /* level 1-9 (int) */
|
||||
#define SSH_CMSG_MAX_PACKET_SIZE 38 /* size 4k-1024k (int) */
|
||||
#define SSH_CMSG_AUTH_TIS 39 /* this is proto-1.5, but we ignore TIS */
|
||||
#define SSH_SMSG_AUTH_TIS_CHALLENGE 40
|
||||
#define SSH_CMSG_AUTH_TIS_RESPONSE 41
|
||||
|
||||
#define SSH_CMSG_AUTH_TIS 39 /* we use this for s/key */
|
||||
#define SSH_SMSG_AUTH_TIS_CHALLENGE 40 /* challenge (string) */
|
||||
#define SSH_CMSG_AUTH_TIS_RESPONSE 41 /* response (string) */
|
||||
#define SSH_CMSG_AUTH_KERBEROS 42 /* (KTEXT) */
|
||||
#define SSH_SMSG_AUTH_KERBEROS_RESPONSE 43 /* (KTEXT) */
|
||||
#define SSH_CMSG_HAVE_KERBEROS_TGT 44 /* credentials (s) */
|
||||
|
@ -223,74 +226,79 @@ only by root, whereas ssh_config should be world-readable. */
|
|||
|
||||
/*------------ definitions for login.c -------------*/
|
||||
|
||||
/* Returns the time when the user last logged in. Returns 0 if the
|
||||
information is not available. This must be called before record_login.
|
||||
/* Returns the time when the user last logged in. Returns 0 if the
|
||||
information is not available. This must be called before record_login.
|
||||
The host from which the user logged in is stored in buf. */
|
||||
unsigned long get_last_login_time(uid_t uid, const char *logname,
|
||||
char *buf, unsigned int bufsize);
|
||||
unsigned long
|
||||
get_last_login_time(uid_t uid, const char *logname,
|
||||
char *buf, unsigned int bufsize);
|
||||
|
||||
/* Records that the user has logged in. This does many things normally
|
||||
done by login(1). */
|
||||
void record_login(int pid, const char *ttyname, const char *user, uid_t uid,
|
||||
const char *host, struct sockaddr_in *addr);
|
||||
void
|
||||
record_login(int pid, const char *ttyname, const char *user, uid_t uid,
|
||||
const char *host, struct sockaddr_in * addr);
|
||||
|
||||
/* Records that the user has logged out. This does many thigs normally
|
||||
done by login(1) or init. */
|
||||
void record_logout(int pid, const char *ttyname);
|
||||
void record_logout(int pid, const char *ttyname);
|
||||
|
||||
/*------------ definitions for sshconnect.c ----------*/
|
||||
|
||||
/* Opens a TCP/IP connection to the remote server on the given host. If
|
||||
port is 0, the default port will be used. If anonymous is zero,
|
||||
a privileged port will be allocated to make the connection.
|
||||
This requires super-user privileges if anonymous is false.
|
||||
a privileged port will be allocated to make the connection.
|
||||
This requires super-user privileges if anonymous is false.
|
||||
Connection_attempts specifies the maximum number of tries, one per
|
||||
second. This returns true on success, and zero on failure. If the
|
||||
connection is successful, this calls packet_set_connection for the
|
||||
connection. */
|
||||
int ssh_connect(const char *host, struct sockaddr_in *hostaddr,
|
||||
int port, int connection_attempts,
|
||||
int anonymous, uid_t original_real_uid,
|
||||
const char *proxy_command);
|
||||
int
|
||||
ssh_connect(const char *host, struct sockaddr_in * hostaddr,
|
||||
int port, int connection_attempts,
|
||||
int anonymous, uid_t original_real_uid,
|
||||
const char *proxy_command);
|
||||
|
||||
/* Starts a dialog with the server, and authenticates the current user on the
|
||||
server. This does not need any extra privileges. The basic connection
|
||||
to the server must already have been established before this is called.
|
||||
If login fails, this function prints an error and never returns.
|
||||
to the server must already have been established before this is called.
|
||||
If login fails, this function prints an error and never returns.
|
||||
This initializes the random state, and leaves it initialized (it will also
|
||||
have references from the packet module). */
|
||||
|
||||
void ssh_login(int host_key_valid, RSA *host_key, const char *host,
|
||||
struct sockaddr_in *hostaddr, uid_t original_real_uid);
|
||||
void
|
||||
ssh_login(int host_key_valid, RSA * host_key, const char *host,
|
||||
struct sockaddr_in * hostaddr, uid_t original_real_uid);
|
||||
|
||||
/*------------ Definitions for various authentication methods. -------*/
|
||||
|
||||
/* 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). */
|
||||
int auth_rhosts(struct passwd *pw, const char *client_user);
|
||||
int auth_rhosts(struct passwd * pw, const char *client_user);
|
||||
|
||||
/* 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,
|
||||
BIGNUM *client_host_key_e, BIGNUM *client_host_key_n);
|
||||
int
|
||||
auth_rhosts_rsa(struct passwd * pw, const char *client_user,
|
||||
BIGNUM * client_host_key_e, BIGNUM * client_host_key_n);
|
||||
|
||||
/* Tries to authenticate the user using password. Returns true if
|
||||
authentication succeeds. */
|
||||
int auth_password(struct passwd *pw, const char *password);
|
||||
int auth_password(struct passwd * pw, 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);
|
||||
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, unsigned int *bitsp, BIGNUM *e, BIGNUM *n);
|
||||
int auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n);
|
||||
|
||||
/* Returns the name of the machine at the other end of the socket. The
|
||||
returned string should be freed by the caller. */
|
||||
char *get_remote_hostname(int socket);
|
||||
char *get_remote_hostname(int socket);
|
||||
|
||||
/* Return the canonical name of the host in the other side of the current
|
||||
connection (as returned by packet_get_connection). The host name is
|
||||
|
@ -302,296 +310,301 @@ const char *get_canonical_hostname(void);
|
|||
const char *get_remote_ipaddr(void);
|
||||
|
||||
/* Returns the port number of the peer of the socket. */
|
||||
int get_peer_port(int sock);
|
||||
int get_peer_port(int sock);
|
||||
|
||||
/* Returns the port number of the remote host. */
|
||||
int get_remote_port(void);
|
||||
int get_remote_port(void);
|
||||
|
||||
/* Tries to match the host name (which must be in all lowercase) against the
|
||||
comma-separated sequence of subpatterns (each possibly preceded by ! to
|
||||
comma-separated sequence of subpatterns (each possibly preceded by ! to
|
||||
indicate negation). Returns true if there is a positive match; zero
|
||||
otherwise. */
|
||||
int match_hostname(const char *host, const char *pattern, unsigned int len);
|
||||
int match_hostname(const char *host, const char *pattern, unsigned int len);
|
||||
|
||||
/* Checks whether the given host is already in the list of our known hosts.
|
||||
Returns HOST_OK if the host is known and has the specified key,
|
||||
HOST_NEW if the host is not known, and HOST_CHANGED if the host is known
|
||||
but used to have a different host key. The host must be in all lowercase. */
|
||||
typedef enum { HOST_OK, HOST_NEW, HOST_CHANGED } HostStatus;
|
||||
HostStatus check_host_in_hostfile(const char *filename, const char *host,
|
||||
BIGNUM *e, BIGNUM *n, BIGNUM *ke, BIGNUM *kn);
|
||||
typedef enum {
|
||||
HOST_OK, HOST_NEW, HOST_CHANGED
|
||||
} HostStatus;
|
||||
HostStatus
|
||||
check_host_in_hostfile(const char *filename, const char *host,
|
||||
BIGNUM * e, BIGNUM * n, BIGNUM * ke, BIGNUM * kn);
|
||||
|
||||
/* Appends an entry to the host file. Returns false if the entry
|
||||
could not be appended. */
|
||||
int add_host_to_hostfile(const char *filename, const char *host,
|
||||
BIGNUM *e, BIGNUM *n);
|
||||
int
|
||||
add_host_to_hostfile(const char *filename, const char *host,
|
||||
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(BIGNUM *e, BIGNUM *n);
|
||||
int auth_rsa_challenge_dialog(BIGNUM * e, BIGNUM * n);
|
||||
|
||||
/* Reads a passphrase from /dev/tty with echo turned off. Returns the
|
||||
passphrase (allocated with xmalloc). Exits if EOF is encountered.
|
||||
/* Reads a passphrase from /dev/tty with echo turned off. Returns the
|
||||
passphrase (allocated with xmalloc). Exits if EOF is encountered.
|
||||
If from_stdin is true, the passphrase will be read from stdin instead. */
|
||||
char *read_passphrase(const char *prompt, int from_stdin);
|
||||
char *read_passphrase(const char *prompt, int from_stdin);
|
||||
|
||||
/* Saves the authentication (private) key in a file, encrypting it with
|
||||
passphrase. The identification of the file (lowest 64 bits of n)
|
||||
will precede the key to provide identification of the key without
|
||||
needing a passphrase. */
|
||||
int save_private_key(const char *filename, const char *passphrase,
|
||||
RSA *private_key, const char *comment);
|
||||
int
|
||||
save_private_key(const char *filename, const char *passphrase,
|
||||
RSA * private_key, const char *comment);
|
||||
|
||||
/* Loads the public part of the key file (public key and comment).
|
||||
/* Loads the public part of the key file (public key and comment).
|
||||
Returns 0 if an error occurred; zero if the public key was successfully
|
||||
read. The comment of the key is returned in comment_return if it is
|
||||
non-NULL; the caller must free the value with xfree. */
|
||||
int load_public_key(const char *filename, RSA *pub,
|
||||
char **comment_return);
|
||||
int
|
||||
load_public_key(const char *filename, RSA * pub,
|
||||
char **comment_return);
|
||||
|
||||
/* Loads the private key from the file. Returns 0 if an error is encountered
|
||||
(file does not exist or is not readable, or passphrase is bad).
|
||||
This initializes the private key. The comment of the key is returned
|
||||
in comment_return if it is non-NULL; the caller must free the value
|
||||
This initializes the private key. The comment of the key is returned
|
||||
in comment_return if it is non-NULL; the caller must free the value
|
||||
with xfree. */
|
||||
int load_private_key(const char *filename, const char *passphrase,
|
||||
RSA *private_key, char **comment_return);
|
||||
int
|
||||
load_private_key(const char *filename, const char *passphrase,
|
||||
RSA * private_key, char **comment_return);
|
||||
|
||||
/*------------ Definitions for logging. -----------------------*/
|
||||
|
||||
/* Supported syslog facilities and levels. */
|
||||
typedef enum
|
||||
{
|
||||
SYSLOG_FACILITY_DAEMON,
|
||||
SYSLOG_FACILITY_USER,
|
||||
SYSLOG_FACILITY_AUTH,
|
||||
SYSLOG_FACILITY_LOCAL0,
|
||||
SYSLOG_FACILITY_LOCAL1,
|
||||
SYSLOG_FACILITY_LOCAL2,
|
||||
SYSLOG_FACILITY_LOCAL3,
|
||||
SYSLOG_FACILITY_LOCAL4,
|
||||
SYSLOG_FACILITY_LOCAL5,
|
||||
SYSLOG_FACILITY_LOCAL6,
|
||||
SYSLOG_FACILITY_LOCAL7
|
||||
} SyslogFacility;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SYSLOG_LEVEL_QUIET,
|
||||
SYSLOG_LEVEL_FATAL,
|
||||
SYSLOG_LEVEL_ERROR,
|
||||
SYSLOG_LEVEL_INFO,
|
||||
SYSLOG_LEVEL_CHAT,
|
||||
SYSLOG_LEVEL_DEBUG
|
||||
} LogLevel;
|
||||
typedef enum {
|
||||
SYSLOG_FACILITY_DAEMON,
|
||||
SYSLOG_FACILITY_USER,
|
||||
SYSLOG_FACILITY_AUTH,
|
||||
SYSLOG_FACILITY_LOCAL0,
|
||||
SYSLOG_FACILITY_LOCAL1,
|
||||
SYSLOG_FACILITY_LOCAL2,
|
||||
SYSLOG_FACILITY_LOCAL3,
|
||||
SYSLOG_FACILITY_LOCAL4,
|
||||
SYSLOG_FACILITY_LOCAL5,
|
||||
SYSLOG_FACILITY_LOCAL6,
|
||||
SYSLOG_FACILITY_LOCAL7
|
||||
} SyslogFacility;
|
||||
|
||||
typedef enum {
|
||||
SYSLOG_LEVEL_QUIET,
|
||||
SYSLOG_LEVEL_FATAL,
|
||||
SYSLOG_LEVEL_ERROR,
|
||||
SYSLOG_LEVEL_INFO,
|
||||
SYSLOG_LEVEL_VERBOSE,
|
||||
SYSLOG_LEVEL_DEBUG
|
||||
} LogLevel;
|
||||
/* Initializes logging. */
|
||||
void log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr);
|
||||
void log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr);
|
||||
|
||||
/* Logging implementation, depending on server or client */
|
||||
void do_log(LogLevel level, const char *fmt, va_list args);
|
||||
void do_log(LogLevel level, const char *fmt, va_list args);
|
||||
|
||||
/* name to facility/level */
|
||||
SyslogFacility log_facility_number(char *name);
|
||||
LogLevel log_level_number(char *name);
|
||||
|
||||
/* Output a message to syslog or stderr */
|
||||
void fatal(const char *fmt, ...);
|
||||
void error(const char *fmt, ...);
|
||||
void log(const char *fmt, ...);
|
||||
void chat(const char *fmt, ...);
|
||||
void debug(const char *fmt, ...);
|
||||
void fatal(const char *fmt,...) __attribute__((format(printf, 1, 2)));
|
||||
void error(const char *fmt,...) __attribute__((format(printf, 1, 2)));
|
||||
void log(const char *fmt,...) __attribute__((format(printf, 1, 2)));
|
||||
void verbose(const char *fmt,...) __attribute__((format(printf, 1, 2)));
|
||||
void debug(const char *fmt,...) __attribute__((format(printf, 1, 2)));
|
||||
|
||||
/* same as fatal() but w/o logging */
|
||||
void fatal_cleanup(void);
|
||||
void fatal_cleanup(void);
|
||||
|
||||
/* Registers a cleanup function to be called by fatal()/fatal_cleanup() before exiting.
|
||||
/* Registers a cleanup function to be called by fatal()/fatal_cleanup() before exiting.
|
||||
It is permissible to call fatal_remove_cleanup for the function itself
|
||||
from the function. */
|
||||
void fatal_add_cleanup(void (*proc)(void *context), void *context);
|
||||
void fatal_add_cleanup(void (*proc) (void *context), void *context);
|
||||
|
||||
/* Removes a cleanup function to be called at fatal(). */
|
||||
void fatal_remove_cleanup(void (*proc)(void *context), void *context);
|
||||
void fatal_remove_cleanup(void (*proc) (void *context), void *context);
|
||||
|
||||
/*---------------- definitions for channels ------------------*/
|
||||
|
||||
/* Sets specific protocol options. */
|
||||
void channel_set_options(int hostname_in_open);
|
||||
void channel_set_options(int hostname_in_open);
|
||||
|
||||
/* 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);
|
||||
int channel_allocate(int type, int sock, char *remote_name);
|
||||
|
||||
/* Free the channel and close its socket. */
|
||||
void channel_free(int channel);
|
||||
void channel_free(int channel);
|
||||
|
||||
/* Add any bits relevant to channels in select bitmasks. */
|
||||
void channel_prepare_select(fd_set *readset, fd_set *writeset);
|
||||
void channel_prepare_select(fd_set * readset, fd_set * writeset);
|
||||
|
||||
/* After select, perform any appropriate operations for channels which
|
||||
have events pending. */
|
||||
void channel_after_select(fd_set *readset, fd_set *writeset);
|
||||
void channel_after_select(fd_set * readset, fd_set * writeset);
|
||||
|
||||
/* If there is data to send to the connection, send some of it now. */
|
||||
void channel_output_poll(void);
|
||||
void channel_output_poll(void);
|
||||
|
||||
/* This is called when a packet of type CHANNEL_DATA has just been received.
|
||||
The message type has already been consumed, but channel number and data
|
||||
is still there. */
|
||||
void channel_input_data(int payload_len);
|
||||
void channel_input_data(int payload_len);
|
||||
|
||||
/* Returns true if no channel has too much buffered data. */
|
||||
int channel_not_very_much_buffered_data(void);
|
||||
int channel_not_very_much_buffered_data(void);
|
||||
|
||||
/* This is called after receiving CHANNEL_CLOSE. */
|
||||
void channel_input_close(void);
|
||||
void channel_input_close(void);
|
||||
|
||||
/* This is called after receiving CHANNEL_CLOSE_CONFIRMATION. */
|
||||
void channel_input_close_confirmation(void);
|
||||
void channel_input_close_confirmation(void);
|
||||
|
||||
/* This is called after receiving CHANNEL_OPEN_CONFIRMATION. */
|
||||
void channel_input_open_confirmation(void);
|
||||
void channel_input_open_confirmation(void);
|
||||
|
||||
/* This is called after receiving CHANNEL_OPEN_FAILURE from the other side. */
|
||||
void channel_input_open_failure(void);
|
||||
void channel_input_open_failure(void);
|
||||
|
||||
/* This closes any sockets that are listening for connections; this removes
|
||||
any unix domain sockets. */
|
||||
void channel_stop_listening(void);
|
||||
void channel_stop_listening(void);
|
||||
|
||||
/* Closes the sockets of all channels. This is used to close extra file
|
||||
descriptors after a fork. */
|
||||
void channel_close_all(void);
|
||||
void channel_close_all(void);
|
||||
|
||||
/* Returns the maximum file descriptor number used by the channels. */
|
||||
int channel_max_fd(void);
|
||||
int channel_max_fd(void);
|
||||
|
||||
/* Returns true if there is still an open channel over the connection. */
|
||||
int channel_still_open(void);
|
||||
int channel_still_open(void);
|
||||
|
||||
/* 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);
|
||||
char *channel_open_message(void);
|
||||
|
||||
/* Initiate forwarding of connections to local port "port" through the secure
|
||||
channel to host:port from remote side. This never returns if there
|
||||
was an error. */
|
||||
void channel_request_local_forwarding(int port, const char *host,
|
||||
int remote_port);
|
||||
void
|
||||
channel_request_local_forwarding(int port, const char *host,
|
||||
int remote_port);
|
||||
|
||||
/* 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(int port, const char *host,
|
||||
int remote_port);
|
||||
void
|
||||
channel_request_remote_forwarding(int port, const char *host,
|
||||
int remote_port);
|
||||
|
||||
/* Permits opening to any host/port in SSH_MSG_PORT_OPEN. 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);
|
||||
void channel_permit_all_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
|
||||
message if there was an error). This never returns if there was an
|
||||
error. */
|
||||
void channel_input_port_forward_request(int is_root);
|
||||
void channel_input_port_forward_request(int is_root);
|
||||
|
||||
/* This is called after receiving PORT_OPEN message. This attempts to connect
|
||||
to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION or
|
||||
CHANNEL_OPEN_FAILURE. */
|
||||
void channel_input_port_open(int payload_len);
|
||||
void channel_input_port_open(int payload_len);
|
||||
|
||||
/* 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);
|
||||
char *x11_create_display(int screen);
|
||||
|
||||
/* Creates an internet domain socket for listening for X11 connections.
|
||||
/* 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);
|
||||
char *x11_create_display_inet(int screen);
|
||||
|
||||
/* 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 payload_len);
|
||||
void x11_input_open(int payload_len);
|
||||
|
||||
/* Requests forwarding of X11 connections. This should be called on the
|
||||
/* Requests forwarding of X11 connections. This should be called on the
|
||||
client only. */
|
||||
void x11_request_forwarding(void);
|
||||
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(const char *proto, const char *data);
|
||||
void x11_request_forwarding_with_spoofing(const char *proto, const char *data);
|
||||
|
||||
/* Sends a message to the server to request authentication fd forwarding. */
|
||||
void auth_request_forwarding(void);
|
||||
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);
|
||||
char *auth_get_socket_name(void);
|
||||
|
||||
/* This if called to process SSH_CMSG_AGENT_REQUEST_FORWARDING on the server.
|
||||
This starts forwarding authentication requests. */
|
||||
void auth_input_request_forwarding(struct passwd *pw);
|
||||
void auth_input_request_forwarding(struct passwd * pw);
|
||||
|
||||
/* This is called to process an SSH_SMSG_AGENT_OPEN message. */
|
||||
void auth_input_open_request(void);
|
||||
void auth_input_open_request(void);
|
||||
|
||||
/* Returns true if the given string matches the pattern (which may contain
|
||||
? and * as wildcards), and zero if it does not match. */
|
||||
int match_pattern(const char *s, const char *pattern);
|
||||
int match_pattern(const char *s, const char *pattern);
|
||||
|
||||
/* Expands tildes in the file name. Returns data allocated by xmalloc.
|
||||
Warning: this calls getpw*. */
|
||||
char *tilde_expand_filename(const char *filename, uid_t my_uid);
|
||||
char *tilde_expand_filename(const char *filename, uid_t my_uid);
|
||||
|
||||
/* Performs the interactive session. This handles data transmission between
|
||||
the client and the program. Note that the notion of stdin, stdout, and
|
||||
stderr in this function is sort of reversed: this function writes to
|
||||
stdin (of the child program), and reads from stdout and stderr (of the
|
||||
child program). */
|
||||
void server_loop(int pid, int fdin, int fdout, int fderr);
|
||||
void server_loop(int pid, int fdin, int fdout, int fderr);
|
||||
|
||||
/* Client side main loop for the interactive session. */
|
||||
int client_loop(int have_pty, int escape_char);
|
||||
int client_loop(int have_pty, int escape_char);
|
||||
|
||||
/* Linked list of custom environment strings (see auth-rsa.c). */
|
||||
struct envstring {
|
||||
struct envstring *next;
|
||||
char *s;
|
||||
struct envstring *next;
|
||||
char *s;
|
||||
};
|
||||
|
||||
#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(const char *server_user, KTEXT auth, char **client);
|
||||
int krb4_init(uid_t uid);
|
||||
void krb4_cleanup_proc(void *ignore);
|
||||
|
||||
#ifdef AFS
|
||||
#include <kafs.h>
|
||||
|
||||
/* 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);
|
||||
int auth_kerberos_tgt(struct passwd * pw, const char *string);
|
||||
int auth_afs_token(struct passwd * pw, const char *token_string);
|
||||
|
||||
int creds_to_radix(CREDENTIALS *creds, unsigned char *buf);
|
||||
int radix_to_creds(const char *buf, CREDENTIALS *creds);
|
||||
#endif /* AFS */
|
||||
int creds_to_radix(CREDENTIALS * creds, unsigned char *buf);
|
||||
int radix_to_creds(const char *buf, CREDENTIALS * creds);
|
||||
#endif /* AFS */
|
||||
|
||||
#endif /* KRB4 */
|
||||
#endif /* KRB4 */
|
||||
|
||||
#ifdef SKEY
|
||||
#include <skey.h>
|
||||
char *skey_fake_keyinfo(char *username);
|
||||
#endif /* SKEY */
|
||||
char *skey_fake_keyinfo(char *username);
|
||||
#endif /* SKEY */
|
||||
|
||||
#endif /* SSH_H */
|
||||
#endif /* SSH_H */
|
||||
|
|
2719
sshconnect.c
2719
sshconnect.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
12
sshd.8
12
sshd.8
|
@ -9,7 +9,7 @@
|
|||
.\"
|
||||
.\" Created: Sat Apr 22 21:55:14 1995 ylo
|
||||
.\"
|
||||
.\" $Id: sshd.8,v 1.8 1999/11/21 02:23:53 damien Exp $
|
||||
.\" $Id: sshd.8,v 1.9 1999/11/24 13:26:23 damien Exp $
|
||||
.\"
|
||||
.Dd September 25, 1999
|
||||
.Dt SSHD 8
|
||||
|
@ -26,6 +26,7 @@
|
|||
.Op Fl h Ar host_key_file
|
||||
.Op Fl k Ar key_gen_time
|
||||
.Op Fl p Ar port
|
||||
.Op Fl V Ar client_protocol_id
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
(Secure Shell Daemon) is the daemon program for
|
||||
|
@ -165,6 +166,13 @@ Quiet mode. Nothing is sent to the system log. Normally the beginning,
|
|||
authentication, and termination of each connection is logged.
|
||||
.It Fl Q
|
||||
Do not print an error message if RSA support is missing.
|
||||
.It Fl V Ar client_protocol_id
|
||||
SSH2 compatibility mode.
|
||||
When this options is specified
|
||||
.Nm
|
||||
assumes the client has sent the given version string
|
||||
and skips the
|
||||
Protocol Version Identification Exchange.
|
||||
.El
|
||||
.Sh CONFIGURATION FILE
|
||||
.Nm
|
||||
|
@ -320,7 +328,7 @@ The default is 600 (seconds).
|
|||
Gives the verbosity level that is used when logging messages from
|
||||
.Nm sshd .
|
||||
The possible values are:
|
||||
QUIET, FATAL, ERROR, INFO, CHAT and DEBUG.
|
||||
QUIET, FATAL, ERROR, INFO, VERBOSE and DEBUG.
|
||||
The default is INFO.
|
||||
Logging with level DEBUG violates the privacy of users
|
||||
and is not recommended.
|
||||
|
|
4329
sshd.c
4329
sshd.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
106
tildexpand.c
106
tildexpand.c
|
@ -1,70 +1,62 @@
|
|||
/*
|
||||
|
||||
tildexpand.c
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Wed Jul 12 01:07:36 1995 ylo
|
||||
|
||||
*/
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Created: Wed Jul 12 01:07:36 1995 ylo
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: tildexpand.c,v 1.1 1999/10/27 03:42:46 damien Exp $");
|
||||
RCSID("$Id: tildexpand.c,v 1.2 1999/11/24 13:26:23 damien Exp $");
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
|
||||
/* Expands tildes in the file name. Returns data allocated by xmalloc.
|
||||
Warning: this calls getpw*. */
|
||||
|
||||
char *tilde_expand_filename(const char *filename, uid_t my_uid)
|
||||
/*
|
||||
* Expands tildes in the file name. Returns data allocated by xmalloc.
|
||||
* Warning: this calls getpw*.
|
||||
*/
|
||||
char *
|
||||
tilde_expand_filename(const char *filename, uid_t my_uid)
|
||||
{
|
||||
const char *cp;
|
||||
unsigned int userlen;
|
||||
char *expanded;
|
||||
struct passwd *pw;
|
||||
char user[100];
|
||||
const char *cp;
|
||||
unsigned int userlen;
|
||||
char *expanded;
|
||||
struct passwd *pw;
|
||||
char user[100];
|
||||
|
||||
/* Return immediately if no tilde. */
|
||||
if (filename[0] != '~')
|
||||
return xstrdup(filename);
|
||||
/* Return immediately if no tilde. */
|
||||
if (filename[0] != '~')
|
||||
return xstrdup(filename);
|
||||
|
||||
/* Skip the tilde. */
|
||||
filename++;
|
||||
/* Skip the tilde. */
|
||||
filename++;
|
||||
|
||||
/* Find where the username ends. */
|
||||
cp = strchr(filename, '/');
|
||||
if (cp)
|
||||
userlen = cp - filename; /* Have something after username. */
|
||||
else
|
||||
userlen = strlen(filename); /* Nothign after username. */
|
||||
if (userlen == 0)
|
||||
pw = getpwuid(my_uid); /* Own home directory. */
|
||||
else
|
||||
{
|
||||
/* Tilde refers to someone elses home directory. */
|
||||
if (userlen > sizeof(user) - 1)
|
||||
fatal("User name after tilde too long.");
|
||||
memcpy(user, filename, userlen);
|
||||
user[userlen] = 0;
|
||||
pw = getpwnam(user);
|
||||
}
|
||||
/* Find where the username ends. */
|
||||
cp = strchr(filename, '/');
|
||||
if (cp)
|
||||
userlen = cp - filename; /* Something after username. */
|
||||
else
|
||||
userlen = strlen(filename); /* Nothing after username. */
|
||||
if (userlen == 0)
|
||||
pw = getpwuid(my_uid); /* Own home directory. */
|
||||
else {
|
||||
/* Tilde refers to someone elses home directory. */
|
||||
if (userlen > sizeof(user) - 1)
|
||||
fatal("User name after tilde too long.");
|
||||
memcpy(user, filename, userlen);
|
||||
user[userlen] = 0;
|
||||
pw = getpwnam(user);
|
||||
}
|
||||
/* Check that we found the user. */
|
||||
if (!pw)
|
||||
fatal("Unknown user %100s.", user);
|
||||
|
||||
/* Check that we found the user. */
|
||||
if (!pw)
|
||||
fatal("Unknown user %100s.", user);
|
||||
|
||||
/* If referring to someones home directory, return it now. */
|
||||
if (!cp)
|
||||
{ /* Only home directory specified */
|
||||
return xstrdup(pw->pw_dir);
|
||||
}
|
||||
|
||||
/* Build a path combining the specified directory and path. */
|
||||
expanded = xmalloc(strlen(pw->pw_dir) + strlen(cp + 1) + 2);
|
||||
sprintf(expanded, "%s/%s", pw->pw_dir, cp + 1);
|
||||
return expanded;
|
||||
/* If referring to someones home directory, return it now. */
|
||||
if (!cp) { /* Only home directory specified */
|
||||
return xstrdup(pw->pw_dir);
|
||||
}
|
||||
/* Build a path combining the specified directory and path. */
|
||||
expanded = xmalloc(strlen(pw->pw_dir) + strlen(cp + 1) + 2);
|
||||
sprintf(expanded, "%s/%s", pw->pw_dir, cp + 1);
|
||||
return expanded;
|
||||
}
|
||||
|
|
467
ttymodes.c
467
ttymodes.c
|
@ -1,233 +1,229 @@
|
|||
/*
|
||||
|
||||
ttymodes.c
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Tue Mar 21 15:59:15 1995 ylo
|
||||
|
||||
Encoding and decoding of terminal modes in a portable way.
|
||||
Much of the format is defined in ttymodes.h; it is included multiple times
|
||||
into this file with the appropriate macro definitions to generate the
|
||||
suitable code.
|
||||
|
||||
*/
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Created: Tue Mar 21 15:59:15 1995 ylo
|
||||
* Encoding and decoding of terminal modes in a portable way.
|
||||
* Much of the format is defined in ttymodes.h; it is included multiple times
|
||||
* into this file with the appropriate macro definitions to generate the
|
||||
* suitable code.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: ttymodes.c,v 1.1 1999/10/27 03:42:46 damien Exp $");
|
||||
RCSID("$Id: ttymodes.c,v 1.2 1999/11/24 13:26:23 damien Exp $");
|
||||
|
||||
#include "packet.h"
|
||||
#include "ssh.h"
|
||||
|
||||
#define TTY_OP_END 0
|
||||
#define TTY_OP_ISPEED 192 /* int follows */
|
||||
#define TTY_OP_OSPEED 193 /* int follows */
|
||||
#define TTY_OP_ISPEED 192 /* int follows */
|
||||
#define TTY_OP_OSPEED 193 /* int follows */
|
||||
|
||||
/* Converts POSIX speed_t to a baud rate. The values of the constants
|
||||
for speed_t are not themselves portable. */
|
||||
|
||||
static int speed_to_baud(speed_t speed)
|
||||
/*
|
||||
* Converts POSIX speed_t to a baud rate. The values of the
|
||||
* constants for speed_t are not themselves portable.
|
||||
*/
|
||||
static int
|
||||
speed_to_baud(speed_t speed)
|
||||
{
|
||||
switch (speed)
|
||||
{
|
||||
case B0:
|
||||
return 0;
|
||||
case B50:
|
||||
return 50;
|
||||
case B75:
|
||||
return 75;
|
||||
case B110:
|
||||
return 110;
|
||||
case B134:
|
||||
return 134;
|
||||
case B150:
|
||||
return 150;
|
||||
case B200:
|
||||
return 200;
|
||||
case B300:
|
||||
return 300;
|
||||
case B600:
|
||||
return 600;
|
||||
case B1200:
|
||||
return 1200;
|
||||
case B1800:
|
||||
return 1800;
|
||||
case B2400:
|
||||
return 2400;
|
||||
case B4800:
|
||||
return 4800;
|
||||
case B9600:
|
||||
return 9600;
|
||||
switch (speed) {
|
||||
case B0:
|
||||
return 0;
|
||||
case B50:
|
||||
return 50;
|
||||
case B75:
|
||||
return 75;
|
||||
case B110:
|
||||
return 110;
|
||||
case B134:
|
||||
return 134;
|
||||
case B150:
|
||||
return 150;
|
||||
case B200:
|
||||
return 200;
|
||||
case B300:
|
||||
return 300;
|
||||
case B600:
|
||||
return 600;
|
||||
case B1200:
|
||||
return 1200;
|
||||
case B1800:
|
||||
return 1800;
|
||||
case B2400:
|
||||
return 2400;
|
||||
case B4800:
|
||||
return 4800;
|
||||
case B9600:
|
||||
return 9600;
|
||||
|
||||
#ifdef B19200
|
||||
case B19200:
|
||||
return 19200;
|
||||
case B19200:
|
||||
return 19200;
|
||||
#else /* B19200 */
|
||||
#ifdef EXTA
|
||||
case EXTA:
|
||||
return 19200;
|
||||
case EXTA:
|
||||
return 19200;
|
||||
#endif /* EXTA */
|
||||
#endif /* B19200 */
|
||||
|
||||
#ifdef B38400
|
||||
case B38400:
|
||||
return 38400;
|
||||
case B38400:
|
||||
return 38400;
|
||||
#else /* B38400 */
|
||||
#ifdef EXTB
|
||||
case EXTB:
|
||||
return 38400;
|
||||
case EXTB:
|
||||
return 38400;
|
||||
#endif /* EXTB */
|
||||
#endif /* B38400 */
|
||||
|
||||
#ifdef B7200
|
||||
case B7200:
|
||||
return 7200;
|
||||
case B7200:
|
||||
return 7200;
|
||||
#endif /* B7200 */
|
||||
#ifdef B14400
|
||||
case B14400:
|
||||
return 14400;
|
||||
case B14400:
|
||||
return 14400;
|
||||
#endif /* B14400 */
|
||||
#ifdef B28800
|
||||
case B28800:
|
||||
return 28800;
|
||||
case B28800:
|
||||
return 28800;
|
||||
#endif /* B28800 */
|
||||
#ifdef B57600
|
||||
case B57600:
|
||||
return 57600;
|
||||
case B57600:
|
||||
return 57600;
|
||||
#endif /* B57600 */
|
||||
#ifdef B76800
|
||||
case B76800:
|
||||
return 76800;
|
||||
case B76800:
|
||||
return 76800;
|
||||
#endif /* B76800 */
|
||||
#ifdef B115200
|
||||
case B115200:
|
||||
return 115200;
|
||||
case B115200:
|
||||
return 115200;
|
||||
#endif /* B115200 */
|
||||
#ifdef B230400
|
||||
case B230400:
|
||||
return 230400;
|
||||
case B230400:
|
||||
return 230400;
|
||||
#endif /* B230400 */
|
||||
default:
|
||||
return 9600;
|
||||
}
|
||||
default:
|
||||
return 9600;
|
||||
}
|
||||
}
|
||||
|
||||
/* Converts a numeric baud rate to a POSIX speed_t. */
|
||||
|
||||
static speed_t baud_to_speed(int baud)
|
||||
/*
|
||||
* Converts a numeric baud rate to a POSIX speed_t.
|
||||
*/
|
||||
static speed_t
|
||||
baud_to_speed(int baud)
|
||||
{
|
||||
switch (baud)
|
||||
{
|
||||
case 0:
|
||||
return B0;
|
||||
case 50:
|
||||
return B50;
|
||||
case 75:
|
||||
return B75;
|
||||
case 110:
|
||||
return B110;
|
||||
case 134:
|
||||
return B134;
|
||||
case 150:
|
||||
return B150;
|
||||
case 200:
|
||||
return B200;
|
||||
case 300:
|
||||
return B300;
|
||||
case 600:
|
||||
return B600;
|
||||
case 1200:
|
||||
return B1200;
|
||||
case 1800:
|
||||
return B1800;
|
||||
case 2400:
|
||||
return B2400;
|
||||
case 4800:
|
||||
return B4800;
|
||||
case 9600:
|
||||
return B9600;
|
||||
switch (baud) {
|
||||
case 0:
|
||||
return B0;
|
||||
case 50:
|
||||
return B50;
|
||||
case 75:
|
||||
return B75;
|
||||
case 110:
|
||||
return B110;
|
||||
case 134:
|
||||
return B134;
|
||||
case 150:
|
||||
return B150;
|
||||
case 200:
|
||||
return B200;
|
||||
case 300:
|
||||
return B300;
|
||||
case 600:
|
||||
return B600;
|
||||
case 1200:
|
||||
return B1200;
|
||||
case 1800:
|
||||
return B1800;
|
||||
case 2400:
|
||||
return B2400;
|
||||
case 4800:
|
||||
return B4800;
|
||||
case 9600:
|
||||
return B9600;
|
||||
|
||||
#ifdef B19200
|
||||
case 19200:
|
||||
return B19200;
|
||||
case 19200:
|
||||
return B19200;
|
||||
#else /* B19200 */
|
||||
#ifdef EXTA
|
||||
case 19200:
|
||||
return EXTA;
|
||||
case 19200:
|
||||
return EXTA;
|
||||
#endif /* EXTA */
|
||||
#endif /* B19200 */
|
||||
|
||||
#ifdef B38400
|
||||
case 38400:
|
||||
return B38400;
|
||||
case 38400:
|
||||
return B38400;
|
||||
#else /* B38400 */
|
||||
#ifdef EXTB
|
||||
case 38400:
|
||||
return EXTB;
|
||||
case 38400:
|
||||
return EXTB;
|
||||
#endif /* EXTB */
|
||||
#endif /* B38400 */
|
||||
|
||||
#ifdef B7200
|
||||
case 7200:
|
||||
return B7200;
|
||||
case 7200:
|
||||
return B7200;
|
||||
#endif /* B7200 */
|
||||
#ifdef B14400
|
||||
case 14400:
|
||||
return B14400;
|
||||
case 14400:
|
||||
return B14400;
|
||||
#endif /* B14400 */
|
||||
#ifdef B28800
|
||||
case 28800:
|
||||
return B28800;
|
||||
case 28800:
|
||||
return B28800;
|
||||
#endif /* B28800 */
|
||||
#ifdef B57600
|
||||
case 57600:
|
||||
return B57600;
|
||||
case 57600:
|
||||
return B57600;
|
||||
#endif /* B57600 */
|
||||
#ifdef B76800
|
||||
case 76800:
|
||||
return B76800;
|
||||
case 76800:
|
||||
return B76800;
|
||||
#endif /* B76800 */
|
||||
#ifdef B115200
|
||||
case 115200:
|
||||
return B115200;
|
||||
case 115200:
|
||||
return B115200;
|
||||
#endif /* B115200 */
|
||||
#ifdef B230400
|
||||
case 230400:
|
||||
return B230400;
|
||||
case 230400:
|
||||
return B230400;
|
||||
#endif /* B230400 */
|
||||
default:
|
||||
return B9600;
|
||||
}
|
||||
default:
|
||||
return B9600;
|
||||
}
|
||||
}
|
||||
|
||||
/* Encodes terminal modes for the terminal referenced by fd in a portable
|
||||
manner, and appends the modes to a packet being constructed. */
|
||||
|
||||
void tty_make_modes(int fd)
|
||||
/*
|
||||
* Encodes terminal modes for the terminal referenced by fd
|
||||
* in a portable manner, and appends the modes to a packet
|
||||
* being constructed.
|
||||
*/
|
||||
void
|
||||
tty_make_modes(int fd)
|
||||
{
|
||||
struct termios tio;
|
||||
int baud;
|
||||
struct termios tio;
|
||||
int baud;
|
||||
|
||||
/* Get the modes. */
|
||||
if (tcgetattr(fd, &tio) < 0)
|
||||
{
|
||||
packet_put_char(TTY_OP_END);
|
||||
log("tcgetattr: %.100s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
/* Get the modes. */
|
||||
if (tcgetattr(fd, &tio) < 0) {
|
||||
packet_put_char(TTY_OP_END);
|
||||
log("tcgetattr: %.100s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
/* Store input and output baud rates. */
|
||||
baud = speed_to_baud(cfgetospeed(&tio));
|
||||
packet_put_char(TTY_OP_OSPEED);
|
||||
packet_put_int(baud);
|
||||
baud = speed_to_baud(cfgetispeed(&tio));
|
||||
packet_put_char(TTY_OP_ISPEED);
|
||||
packet_put_int(baud);
|
||||
|
||||
/* Store input and output baud rates. */
|
||||
baud = speed_to_baud(cfgetospeed(&tio));
|
||||
packet_put_char(TTY_OP_OSPEED);
|
||||
packet_put_int(baud);
|
||||
baud = speed_to_baud(cfgetispeed(&tio));
|
||||
packet_put_char(TTY_OP_ISPEED);
|
||||
packet_put_int(baud);
|
||||
|
||||
/* Store values of mode flags. */
|
||||
/* Store values of mode flags. */
|
||||
#define TTYCHAR(NAME, OP) \
|
||||
packet_put_char(OP); packet_put_char(tio.c_cc[NAME]);
|
||||
#define TTYMODE(NAME, FIELD, OP) \
|
||||
|
@ -244,48 +240,50 @@ void tty_make_modes(int fd)
|
|||
#undef SGTTYMODE
|
||||
#undef SGTTYMODEN
|
||||
|
||||
/* Mark end of mode data. */
|
||||
packet_put_char(TTY_OP_END);
|
||||
/* Mark end of mode data. */
|
||||
packet_put_char(TTY_OP_END);
|
||||
}
|
||||
|
||||
/* Decodes terminal modes for the terminal referenced by fd in a portable
|
||||
manner from a packet being read. */
|
||||
|
||||
void tty_parse_modes(int fd, int *n_bytes_ptr)
|
||||
/*
|
||||
* Decodes terminal modes for the terminal referenced by fd in a portable
|
||||
* manner from a packet being read.
|
||||
*/
|
||||
void
|
||||
tty_parse_modes(int fd, int *n_bytes_ptr)
|
||||
{
|
||||
struct termios tio;
|
||||
int opcode, baud;
|
||||
int n_bytes = 0;
|
||||
int failure = 0;
|
||||
struct termios tio;
|
||||
int opcode, baud;
|
||||
int n_bytes = 0;
|
||||
int failure = 0;
|
||||
|
||||
/* Get old attributes for the terminal. We will modify these flags.
|
||||
I am hoping that if there are any machine-specific modes, they will
|
||||
initially have reasonable values. */
|
||||
if (tcgetattr(fd, &tio) < 0)
|
||||
failure = -1;
|
||||
/*
|
||||
* Get old attributes for the terminal. We will modify these
|
||||
* flags. I am hoping that if there are any machine-specific
|
||||
* modes, they will initially have reasonable values.
|
||||
*/
|
||||
if (tcgetattr(fd, &tio) < 0)
|
||||
failure = -1;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
n_bytes += 1;
|
||||
opcode = packet_get_char();
|
||||
switch (opcode)
|
||||
{
|
||||
case TTY_OP_END:
|
||||
goto set;
|
||||
for (;;) {
|
||||
n_bytes += 1;
|
||||
opcode = packet_get_char();
|
||||
switch (opcode) {
|
||||
case TTY_OP_END:
|
||||
goto set;
|
||||
|
||||
case TTY_OP_ISPEED:
|
||||
n_bytes += 4;
|
||||
baud = packet_get_int();
|
||||
if (failure != -1 && cfsetispeed(&tio, baud_to_speed(baud)) < 0)
|
||||
error("cfsetispeed failed for %d", baud);
|
||||
break;
|
||||
case TTY_OP_ISPEED:
|
||||
n_bytes += 4;
|
||||
baud = packet_get_int();
|
||||
if (failure != -1 && cfsetispeed(&tio, baud_to_speed(baud)) < 0)
|
||||
error("cfsetispeed failed for %d", baud);
|
||||
break;
|
||||
|
||||
case TTY_OP_OSPEED:
|
||||
n_bytes += 4;
|
||||
baud = packet_get_int();
|
||||
if (failure != -1 && cfsetospeed(&tio, baud_to_speed(baud)) < 0)
|
||||
error("cfsetospeed failed for %d", baud);
|
||||
break;
|
||||
case TTY_OP_OSPEED:
|
||||
n_bytes += 4;
|
||||
baud = packet_get_int();
|
||||
if (failure != -1 && cfsetospeed(&tio, baud_to_speed(baud)) < 0)
|
||||
error("cfsetospeed failed for %d", baud);
|
||||
break;
|
||||
|
||||
#define TTYCHAR(NAME, OP) \
|
||||
case OP: \
|
||||
|
@ -312,48 +310,51 @@ void tty_parse_modes(int fd, int *n_bytes_ptr)
|
|||
#undef SGTTYMODE
|
||||
#undef SGTTYMODEN
|
||||
|
||||
default:
|
||||
debug("Ignoring unsupported tty mode opcode %d (0x%x)",
|
||||
opcode, opcode);
|
||||
/* Opcodes 0 to 127 are defined to have a one-byte argument. */
|
||||
if (opcode >= 0 && opcode < 128)
|
||||
{
|
||||
n_bytes += 1;
|
||||
(void)packet_get_char();
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Opcodes 128 to 159 are defined to have an integer argument. */
|
||||
if (opcode >= 128 && opcode < 160)
|
||||
{
|
||||
n_bytes += 4;
|
||||
(void)packet_get_int();
|
||||
break;
|
||||
default:
|
||||
debug("Ignoring unsupported tty mode opcode %d (0x%x)",
|
||||
opcode, opcode);
|
||||
/*
|
||||
* Opcodes 0 to 127 are defined to have
|
||||
* a one-byte argument.
|
||||
*/
|
||||
if (opcode >= 0 && opcode < 128) {
|
||||
n_bytes += 1;
|
||||
(void) packet_get_char();
|
||||
break;
|
||||
} else {
|
||||
/*
|
||||
* Opcodes 128 to 159 are defined to have
|
||||
* an integer argument.
|
||||
*/
|
||||
if (opcode >= 128 && opcode < 160) {
|
||||
n_bytes += 4;
|
||||
(void) packet_get_int();
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* It is a truly undefined opcode (160 to 255).
|
||||
* We have no idea about its arguments. So we
|
||||
* must stop parsing. Note that some data may be
|
||||
* left in the packet; hopefully there is nothing
|
||||
* more coming after the mode data.
|
||||
*/
|
||||
log("parse_tty_modes: unknown opcode %d", opcode);
|
||||
packet_integrity_check(0, 1, SSH_CMSG_REQUEST_PTY);
|
||||
goto set;
|
||||
}
|
||||
}
|
||||
/* It is a truly undefined opcode (160 to 255). We have no idea
|
||||
about its arguments. So we must stop parsing. Note that some
|
||||
data may be left in the packet; hopefully there is nothing more
|
||||
coming after the mode data. */
|
||||
log("parse_tty_modes: unknown opcode %d", opcode);
|
||||
packet_integrity_check(0, 1, SSH_CMSG_REQUEST_PTY);
|
||||
goto set;
|
||||
}
|
||||
}
|
||||
|
||||
set:
|
||||
if (*n_bytes_ptr != n_bytes)
|
||||
{
|
||||
*n_bytes_ptr = n_bytes;
|
||||
return; /* Don't process bytes passed */
|
||||
}
|
||||
set:
|
||||
if (*n_bytes_ptr != n_bytes) {
|
||||
*n_bytes_ptr = n_bytes;
|
||||
return; /* Don't process bytes passed */
|
||||
}
|
||||
if (failure == -1)
|
||||
return; /* Packet parsed ok but tty stuff failed */
|
||||
|
||||
if (failure == -1)
|
||||
return; /* Packet parsed ok but tty stuff failed */
|
||||
|
||||
/* Set the new modes for the terminal. */
|
||||
if (tcsetattr(fd, TCSANOW, &tio) < 0)
|
||||
log("Setting tty modes failed: %.100s", strerror(errno));
|
||||
return;
|
||||
/* Set the new modes for the terminal. */
|
||||
if (tcsetattr(fd, TCSANOW, &tio) < 0)
|
||||
log("Setting tty modes failed: %.100s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
|
188
ttymodes.h
188
ttymodes.h
|
@ -1,138 +1,140 @@
|
|||
/*
|
||||
*
|
||||
* ttymodes.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* SGTTY stuff contributed by Janne Snabb <snabb@niksula.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Tue Mar 21 15:42:09 1995 ylo
|
||||
*
|
||||
*/
|
||||
|
||||
ttymodes.h
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
SGTTY stuff contributed by Janne Snabb <snabb@niksula.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Tue Mar 21 15:42:09 1995 ylo
|
||||
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: ttymodes.h,v 1.1 1999/10/27 03:42:46 damien Exp $"); */
|
||||
/* RCSID("$Id: ttymodes.h,v 1.2 1999/11/24 13:26:23 damien Exp $"); */
|
||||
|
||||
/* The tty mode description is a stream of bytes. The stream consists of
|
||||
opcode-arguments pairs. It is terminated by opcode TTY_OP_END (0).
|
||||
Opcodes 1-127 have one-byte arguments. Opcodes 128-159 have integer
|
||||
arguments. Opcodes 160-255 are not yet defined, and cause parsing to
|
||||
stop (they should only be used after any other data).
|
||||
* opcode-arguments pairs. It is terminated by opcode TTY_OP_END (0).
|
||||
* Opcodes 1-127 have one-byte arguments. Opcodes 128-159 have integer
|
||||
* arguments. Opcodes 160-255 are not yet defined, and cause parsing to
|
||||
* stop (they should only be used after any other data).
|
||||
*
|
||||
* The client puts in the stream any modes it knows about, and the
|
||||
* server ignores any modes it does not know about. This allows some degree
|
||||
* of machine-independence, at least between systems that use a posix-like
|
||||
* tty interface. The protocol can support other systems as well, but might
|
||||
* require reimplementing as mode names would likely be different.
|
||||
*/
|
||||
|
||||
The client puts in the stream any modes it knows about, and the
|
||||
server ignores any modes it does not know about. This allows some degree
|
||||
of machine-independence, at least between systems that use a posix-like
|
||||
tty interface. The protocol can support other systems as well, but might
|
||||
require reimplementing as mode names would likely be different. */
|
||||
|
||||
/* Some constants and prototypes are defined in packet.h; this file
|
||||
is only intended for including from ttymodes.h. */
|
||||
/*
|
||||
* Some constants and prototypes are defined in packet.h; this file
|
||||
* is only intended for including from ttymodes.h.
|
||||
*/
|
||||
|
||||
/* termios macro */ /* sgtty macro */
|
||||
/* termios macro *//* sgtty macro */
|
||||
/* name, op */
|
||||
TTYCHAR(VINTR, 1) SGTTYCHAR(tiotc.t_intrc, 1)
|
||||
TTYCHAR(VQUIT, 2) SGTTYCHAR(tiotc.t_quitc, 2)
|
||||
TTYCHAR(VERASE, 3) SGTTYCHAR(tio.sg_erase, 3)
|
||||
TTYCHAR(VINTR, 1) SGTTYCHAR(tiotc.t_intrc, 1)
|
||||
TTYCHAR(VQUIT, 2) SGTTYCHAR(tiotc.t_quitc, 2)
|
||||
TTYCHAR(VERASE, 3) SGTTYCHAR(tio.sg_erase, 3)
|
||||
#if defined(VKILL)
|
||||
TTYCHAR(VKILL, 4) SGTTYCHAR(tio.sg_kill, 4)
|
||||
#endif /* VKILL */
|
||||
TTYCHAR(VEOF, 5) SGTTYCHAR(tiotc.t_eofc, 5)
|
||||
TTYCHAR(VKILL, 4) SGTTYCHAR(tio.sg_kill, 4)
|
||||
#endif /* VKILL */
|
||||
TTYCHAR(VEOF, 5) SGTTYCHAR(tiotc.t_eofc, 5)
|
||||
#if defined(VEOL)
|
||||
TTYCHAR(VEOL, 6) SGTTYCHAR(tiotc.t_brkc, 6)
|
||||
#endif /* VEOL */
|
||||
TTYCHAR(VEOL, 6) SGTTYCHAR(tiotc.t_brkc, 6)
|
||||
#endif /* VEOL */
|
||||
#ifdef VEOL2 /* n/a */
|
||||
TTYCHAR(VEOL2, 7)
|
||||
#endif /* VEOL2 */
|
||||
TTYCHAR(VSTART, 8) SGTTYCHAR(tiotc.t_startc, 8)
|
||||
TTYCHAR(VSTOP, 9) SGTTYCHAR(tiotc.t_stopc, 9)
|
||||
#endif /* VEOL2 */
|
||||
TTYCHAR(VSTART, 8) SGTTYCHAR(tiotc.t_startc, 8)
|
||||
TTYCHAR(VSTOP, 9) SGTTYCHAR(tiotc.t_stopc, 9)
|
||||
#if defined(VSUSP)
|
||||
TTYCHAR(VSUSP, 10) SGTTYCHAR(tioltc.t_suspc, 10)
|
||||
#endif /* VSUSP */
|
||||
TTYCHAR(VSUSP, 10) SGTTYCHAR(tioltc.t_suspc, 10)
|
||||
#endif /* VSUSP */
|
||||
#if defined(VDSUSP)
|
||||
TTYCHAR(VDSUSP, 11) SGTTYCHAR(tioltc.t_dsuspc, 11)
|
||||
#endif /* VDSUSP */
|
||||
TTYCHAR(VDSUSP, 11) SGTTYCHAR(tioltc.t_dsuspc, 11)
|
||||
#endif /* VDSUSP */
|
||||
#if defined(VREPRINT)
|
||||
TTYCHAR(VREPRINT, 12) SGTTYCHAR(tioltc.t_rprntc, 12)
|
||||
#endif /* VREPRINT */
|
||||
TTYCHAR(VREPRINT, 12) SGTTYCHAR(tioltc.t_rprntc, 12)
|
||||
#endif /* VREPRINT */
|
||||
#if defined(VWERASE)
|
||||
TTYCHAR(VWERASE, 13) SGTTYCHAR(tioltc.t_werasc, 13)
|
||||
#endif /* VWERASE */
|
||||
TTYCHAR(VWERASE, 13) SGTTYCHAR(tioltc.t_werasc, 13)
|
||||
#endif /* VWERASE */
|
||||
#if defined(VLNEXT)
|
||||
TTYCHAR(VLNEXT, 14) SGTTYCHAR(tioltc.t_lnextc, 14)
|
||||
#endif /* VLNEXT */
|
||||
TTYCHAR(VLNEXT, 14) SGTTYCHAR(tioltc.t_lnextc, 14)
|
||||
#endif /* VLNEXT */
|
||||
#if defined(VFLUSH)
|
||||
TTYCHAR(VFLUSH, 15) SGTTYCHAR(tioltc.t_flushc, 15)
|
||||
#endif /* VFLUSH */
|
||||
TTYCHAR(VFLUSH, 15) SGTTYCHAR(tioltc.t_flushc, 15)
|
||||
#endif /* VFLUSH */
|
||||
#ifdef VSWTCH
|
||||
TTYCHAR(VSWTCH, 16) /* n/a */
|
||||
#endif /* VSWTCH */
|
||||
#endif /* VSWTCH */
|
||||
#if defined(VSTATUS)
|
||||
TTYCHAR(VSTATUS, 17) SGTTYCHAR(tiots.tc_statusc, 17)
|
||||
#endif /* VSTATUS */
|
||||
TTYCHAR(VSTATUS, 17) SGTTYCHAR(tiots.tc_statusc, 17)
|
||||
#endif /* VSTATUS */
|
||||
#ifdef VDISCARD
|
||||
TTYCHAR(VDISCARD, 18) /* n/a */
|
||||
#endif /* VDISCARD */
|
||||
#endif /* VDISCARD */
|
||||
|
||||
/* name, field, op */
|
||||
TTYMODE(IGNPAR, c_iflag, 30) /* n/a */
|
||||
TTYMODE(PARMRK, c_iflag, 31) /* n/a */
|
||||
TTYMODE(INPCK, c_iflag, 32) SGTTYMODEN(ANYP, tio.sg_flags, 32)
|
||||
TTYMODE(ISTRIP, c_iflag, 33) SGTTYMODEN(LPASS8, tiolm, 33)
|
||||
TTYMODE(INLCR, c_iflag, 34) /* n/a */
|
||||
TTYMODE(IGNCR, c_iflag, 35) /* n/a */
|
||||
TTYMODE(ICRNL, c_iflag, 36) SGTTYMODE(CRMOD, tio.sg_flags, 36)
|
||||
TTYMODE(IGNPAR, c_iflag, 30) /* n/a */
|
||||
TTYMODE(PARMRK, c_iflag, 31) /* n/a */
|
||||
TTYMODE(INPCK, c_iflag, 32) SGTTYMODEN(ANYP, tio.sg_flags, 32)
|
||||
TTYMODE(ISTRIP, c_iflag, 33) SGTTYMODEN(LPASS8, tiolm, 33)
|
||||
TTYMODE(INLCR, c_iflag, 34) /* n/a */
|
||||
TTYMODE(IGNCR, c_iflag, 35) /* n/a */
|
||||
TTYMODE(ICRNL, c_iflag, 36) SGTTYMODE(CRMOD, tio.sg_flags, 36)
|
||||
#if defined(IUCLC)
|
||||
TTYMODE(IUCLC, c_iflag, 37) SGTTYMODE(LCASE, tio.sg_flags, 37)
|
||||
TTYMODE(IUCLC, c_iflag, 37) SGTTYMODE(LCASE, tio.sg_flags, 37)
|
||||
#endif
|
||||
TTYMODE(IXON, c_iflag, 38) /* n/a */
|
||||
TTYMODE(IXANY, c_iflag, 39) SGTTYMODEN(LDECCTQ, tiolm, 39)
|
||||
TTYMODE(IXOFF, c_iflag, 40) SGTTYMODE(TANDEM, tio.sg_flags, 40)
|
||||
TTYMODE(IXON, c_iflag, 38) /* n/a */
|
||||
TTYMODE(IXANY, c_iflag, 39) SGTTYMODEN(LDECCTQ, tiolm, 39)
|
||||
TTYMODE(IXOFF, c_iflag, 40) SGTTYMODE(TANDEM, tio.sg_flags, 40)
|
||||
#ifdef IMAXBEL
|
||||
TTYMODE(IMAXBEL,c_iflag, 41) /* n/a */
|
||||
#endif /* IMAXBEL */
|
||||
TTYMODE(IMAXBEL, c_iflag, 41) /* n/a */
|
||||
#endif /* IMAXBEL */
|
||||
|
||||
TTYMODE(ISIG, c_lflag, 50) /* n/a */
|
||||
TTYMODE(ICANON, c_lflag, 51) SGTTYMODEN(CBREAK, tio.sg_flags, 51)
|
||||
TTYMODE(ISIG, c_lflag, 50) /* n/a */
|
||||
TTYMODE(ICANON, c_lflag, 51) SGTTYMODEN(CBREAK, tio.sg_flags, 51)
|
||||
#ifdef XCASE
|
||||
TTYMODE(XCASE, c_lflag, 52) /* n/a */
|
||||
TTYMODE(XCASE, c_lflag, 52) /* n/a */
|
||||
#endif
|
||||
TTYMODE(ECHO, c_lflag, 53) SGTTYMODE(ECHO, tio.sg_flags, 53)
|
||||
TTYMODE(ECHOE, c_lflag, 54) SGTTYMODE(LCRTERA, tiolm, 54)
|
||||
TTYMODE(ECHOK, c_lflag, 55) SGTTYMODE(LCRTKIL, tiolm, 55)
|
||||
TTYMODE(ECHONL, c_lflag, 56) /* n/a */
|
||||
TTYMODE(NOFLSH, c_lflag, 57) SGTTYMODE(LNOFLSH, tiolm, 57)
|
||||
TTYMODE(TOSTOP, c_lflag, 58) SGTTYMODE(LTOSTOP, tiolm, 58)
|
||||
TTYMODE(ECHO, c_lflag, 53) SGTTYMODE(ECHO, tio.sg_flags, 53)
|
||||
TTYMODE(ECHOE, c_lflag, 54) SGTTYMODE(LCRTERA, tiolm, 54)
|
||||
TTYMODE(ECHOK, c_lflag, 55) SGTTYMODE(LCRTKIL, tiolm, 55)
|
||||
TTYMODE(ECHONL, c_lflag, 56) /* n/a */
|
||||
TTYMODE(NOFLSH, c_lflag, 57) SGTTYMODE(LNOFLSH, tiolm, 57)
|
||||
TTYMODE(TOSTOP, c_lflag, 58) SGTTYMODE(LTOSTOP, tiolm, 58)
|
||||
#ifdef IEXTEN
|
||||
TTYMODE(IEXTEN, c_lflag, 59) /* n/a */
|
||||
#endif /* IEXTEN */
|
||||
#endif /* IEXTEN */
|
||||
#if defined(ECHOCTL)
|
||||
TTYMODE(ECHOCTL,c_lflag, 60) SGTTYMODE(LCTLECH, tiolm, 60)
|
||||
#endif /* ECHOCTL */
|
||||
TTYMODE(ECHOCTL, c_lflag, 60) SGTTYMODE(LCTLECH, tiolm, 60)
|
||||
#endif /* ECHOCTL */
|
||||
#ifdef ECHOKE
|
||||
TTYMODE(ECHOKE, c_lflag, 61) /* n/a */
|
||||
#endif /* ECHOKE */
|
||||
TTYMODE(ECHOKE, c_lflag, 61) /* n/a */
|
||||
#endif /* ECHOKE */
|
||||
#if defined(PENDIN)
|
||||
TTYMODE(PENDIN, c_lflag, 62) SGTTYMODE(LPENDIN, tiolm, 62)
|
||||
#endif /* PENDIN */
|
||||
TTYMODE(PENDIN, c_lflag, 62) SGTTYMODE(LPENDIN, tiolm, 62)
|
||||
#endif /* PENDIN */
|
||||
|
||||
TTYMODE(OPOST, c_oflag, 70) /* n/a */
|
||||
TTYMODE(OPOST, c_oflag, 70) /* n/a */
|
||||
#if defined(OLCUC)
|
||||
TTYMODE(OLCUC, c_oflag, 71) SGTTYMODE(LCASE, tio.sg_flags, 71)
|
||||
TTYMODE(OLCUC, c_oflag, 71) SGTTYMODE(LCASE, tio.sg_flags, 71)
|
||||
#endif
|
||||
TTYMODE(ONLCR, c_oflag, 72) SGTTYMODE(CRMOD, tio.sg_flags, 72)
|
||||
TTYMODE(ONLCR, c_oflag, 72) SGTTYMODE(CRMOD, tio.sg_flags, 72)
|
||||
#ifdef OCRNL
|
||||
TTYMODE(OCRNL, c_oflag, 73) /* n/a */
|
||||
TTYMODE(OCRNL, c_oflag, 73) /* n/a */
|
||||
#endif
|
||||
#ifdef ONOCR
|
||||
TTYMODE(ONOCR, c_oflag, 74) /* n/a */
|
||||
TTYMODE(ONOCR, c_oflag, 74) /* n/a */
|
||||
#endif
|
||||
#ifdef ONLRET
|
||||
TTYMODE(ONLRET, c_oflag, 75) /* n/a */
|
||||
TTYMODE(ONLRET, c_oflag, 75) /* n/a */
|
||||
#endif
|
||||
|
||||
TTYMODE(CS7, c_cflag, 90) /* n/a */
|
||||
TTYMODE(CS8, c_cflag, 91) SGTTYMODE(LPASS8, tiolm, 91)
|
||||
TTYMODE(PARENB, c_cflag, 92) /* n/a */
|
||||
TTYMODE(PARODD, c_cflag, 93) SGTTYMODE(ODDP, tio.sg_flags, 93)
|
||||
|
||||
TTYMODE(CS7, c_cflag, 90) /* n/a */
|
||||
TTYMODE(CS8, c_cflag, 91) SGTTYMODE(LPASS8, tiolm, 91)
|
||||
TTYMODE(PARENB, c_cflag, 92) /* n/a */
|
||||
TTYMODE(PARODD, c_cflag, 93) SGTTYMODE(ODDP, tio.sg_flags, 93)
|
||||
|
|
115
uidswap.c
115
uidswap.c
|
@ -1,32 +1,25 @@
|
|||
/*
|
||||
|
||||
uidswap.c
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Sat Sep 9 01:56:14 1995 ylo
|
||||
|
||||
Code for uid-swapping.
|
||||
|
||||
*/
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Created: Sat Sep 9 01:56:14 1995 ylo
|
||||
* Code for uid-swapping.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: uidswap.c,v 1.1 1999/10/27 03:42:46 damien Exp $");
|
||||
RCSID("$Id: uidswap.c,v 1.2 1999/11/24 13:26:23 damien Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "uidswap.h"
|
||||
|
||||
/* Note: all these functions must work in all of the following cases:
|
||||
|
||||
1. euid=0, ruid=0
|
||||
2. euid=0, ruid!=0
|
||||
3. euid!=0, ruid!=0
|
||||
|
||||
Additionally, they must work regardless of whether the system has
|
||||
POSIX saved uids or not. */
|
||||
/*
|
||||
* Note: all these functions must work in all of the following cases:
|
||||
* 1. euid=0, ruid=0
|
||||
* 2. euid=0, ruid!=0
|
||||
* 3. euid!=0, ruid!=0
|
||||
* Additionally, they must work regardless of whether the system has
|
||||
* POSIX saved uids or not.
|
||||
*/
|
||||
|
||||
#ifdef _POSIX_SAVED_IDS
|
||||
/* Lets assume that posix saved ids also work with seteuid, even though that
|
||||
|
@ -37,59 +30,57 @@ RCSID("$Id: uidswap.c,v 1.1 1999/10/27 03:42:46 damien Exp $");
|
|||
/* Saved effective uid. */
|
||||
static uid_t saved_euid = 0;
|
||||
|
||||
/* Temporarily changes to the given uid. If the effective user id is not
|
||||
root, this does nothing. This call cannot be nested. */
|
||||
|
||||
void temporarily_use_uid(uid_t uid)
|
||||
/*
|
||||
* Temporarily changes to the given uid. If the effective user
|
||||
* id is not root, this does nothing. This call cannot be nested.
|
||||
*/
|
||||
void
|
||||
temporarily_use_uid(uid_t uid)
|
||||
{
|
||||
#ifdef SAVED_IDS_WORK_WITH_SETEUID
|
||||
/* Save the current euid. */
|
||||
saved_euid = geteuid();
|
||||
|
||||
/* Save the current euid. */
|
||||
saved_euid = geteuid();
|
||||
|
||||
/* Set the effective uid to the given (unprivileged) uid. */
|
||||
if (seteuid(uid) == -1)
|
||||
debug("seteuid %d: %.100s", (int)uid, strerror(errno));
|
||||
|
||||
/* Set the effective uid to the given (unprivileged) uid. */
|
||||
if (seteuid(uid) == -1)
|
||||
debug("seteuid %d: %.100s", (int) uid, strerror(errno));
|
||||
#else /* SAVED_IDS_WORK_WITH_SETUID */
|
||||
/* Propagate the privileged uid to all of our uids. */
|
||||
if (setuid(geteuid()) < 0)
|
||||
debug("setuid %d: %.100s", (int) geteuid(), strerror(errno));
|
||||
|
||||
/* Propagate the privileged uid to all of our uids. */
|
||||
if (setuid(geteuid()) < 0)
|
||||
debug("setuid %d: %.100s", (int)geteuid(), strerror(errno));
|
||||
|
||||
/* Set the effective uid to the given (unprivileged) uid. */
|
||||
if (seteuid(uid) == -1)
|
||||
debug("seteuid %d: %.100s", (int)uid, strerror(errno));
|
||||
|
||||
/* Set the effective uid to the given (unprivileged) uid. */
|
||||
if (seteuid(uid) == -1)
|
||||
debug("seteuid %d: %.100s", (int) uid, strerror(errno));
|
||||
#endif /* SAVED_IDS_WORK_WITH_SETEUID */
|
||||
|
||||
}
|
||||
|
||||
/* Restores to the original uid. */
|
||||
|
||||
void restore_uid()
|
||||
/*
|
||||
* Restores to the original uid.
|
||||
*/
|
||||
void
|
||||
restore_uid()
|
||||
{
|
||||
#ifdef SAVED_IDS_WORK_WITH_SETEUID
|
||||
|
||||
/* Set the effective uid back to the saved uid. */
|
||||
if (seteuid(saved_euid) < 0)
|
||||
debug("seteuid %d: %.100s", (int)saved_euid, strerror(errno));
|
||||
|
||||
/* Set the effective uid back to the saved uid. */
|
||||
if (seteuid(saved_euid) < 0)
|
||||
debug("seteuid %d: %.100s", (int) saved_euid, strerror(errno));
|
||||
#else /* SAVED_IDS_WORK_WITH_SETEUID */
|
||||
|
||||
/* We are unable to restore the real uid to its unprivileged value. */
|
||||
/* Propagate the real uid (usually more privileged) to effective uid
|
||||
as well. */
|
||||
setuid(getuid());
|
||||
|
||||
/* We are unable to restore the real uid to its unprivileged
|
||||
value. */
|
||||
/* Propagate the real uid (usually more privileged) to effective
|
||||
uid as well. */
|
||||
setuid(getuid());
|
||||
#endif /* SAVED_IDS_WORK_WITH_SETEUID */
|
||||
}
|
||||
|
||||
/* Permanently sets all uids to the given uid. This cannot be called while
|
||||
temporarily_use_uid is effective. */
|
||||
|
||||
void permanently_set_uid(uid_t uid)
|
||||
/*
|
||||
* Permanently sets all uids to the given uid. This cannot be
|
||||
* called while temporarily_use_uid is effective.
|
||||
*/
|
||||
void
|
||||
permanently_set_uid(uid_t uid)
|
||||
{
|
||||
if (setuid(uid) < 0)
|
||||
debug("setuid %d: %.100s", (int)uid, strerror(errno));
|
||||
if (setuid(uid) < 0)
|
||||
debug("setuid %d: %.100s", (int) uid, strerror(errno));
|
||||
}
|
||||
|
|
50
uidswap.h
50
uidswap.h
|
@ -1,30 +1,36 @@
|
|||
/*
|
||||
|
||||
uidswap.h
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Sat Sep 9 01:43:15 1995 ylo
|
||||
Last modified: Sat Sep 9 02:34:04 1995 ylo
|
||||
|
||||
*/
|
||||
*
|
||||
* uidswap.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Sat Sep 9 01:43:15 1995 ylo
|
||||
* Last modified: Sat Sep 9 02:34:04 1995 ylo
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef UIDSWAP_H
|
||||
#define UIDSWAP_H
|
||||
|
||||
/* Temporarily changes to the given uid. If the effective user id is not
|
||||
root, this does nothing. This call cannot be nested. */
|
||||
void temporarily_use_uid(uid_t uid);
|
||||
/*
|
||||
* Temporarily changes to the given uid. If the effective user id is not
|
||||
* root, this does nothing. This call cannot be nested.
|
||||
*/
|
||||
void temporarily_use_uid(uid_t uid);
|
||||
|
||||
/* Restores the original effective user id after temporarily_use_uid().
|
||||
This should only be called while temporarily_use_uid is effective. */
|
||||
void restore_uid();
|
||||
/*
|
||||
* Restores the original effective user id after temporarily_use_uid().
|
||||
* This should only be called while temporarily_use_uid is effective.
|
||||
*/
|
||||
void restore_uid();
|
||||
|
||||
/* Permanently sets all uids to the given uid. This cannot be called while
|
||||
temporarily_use_uid is effective. This must also clear any saved uids. */
|
||||
void permanently_set_uid(uid_t uid);
|
||||
/*
|
||||
* Permanently sets all uids to the given uid. This cannot be called while
|
||||
* temporarily_use_uid is effective. This must also clear any saved uids.
|
||||
*/
|
||||
void permanently_set_uid(uid_t uid);
|
||||
|
||||
#endif /* UIDSWAP_H */
|
||||
#endif /* UIDSWAP_H */
|
||||
|
|
71
xmalloc.c
71
xmalloc.c
|
@ -1,56 +1,53 @@
|
|||
/*
|
||||
|
||||
xmalloc.c
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Mon Mar 20 21:23:10 1995 ylo
|
||||
|
||||
Versions of malloc and friends that check their results, and never return
|
||||
failure (they call fatal if they encounter an error).
|
||||
|
||||
*/
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Created: Mon Mar 20 21:23:10 1995 ylo
|
||||
* Versions of malloc and friends that check their results, and never return
|
||||
* failure (they call fatal if they encounter an error).
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: xmalloc.c,v 1.1 1999/10/27 03:42:46 damien Exp $");
|
||||
RCSID("$Id: xmalloc.c,v 1.2 1999/11/24 13:26:23 damien Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
|
||||
void *xmalloc(size_t size)
|
||||
void *
|
||||
xmalloc(size_t size)
|
||||
{
|
||||
void *ptr = malloc(size);
|
||||
if (ptr == NULL)
|
||||
fatal("xmalloc: out of memory (allocating %d bytes)", (int)size);
|
||||
return ptr;
|
||||
void *ptr = malloc(size);
|
||||
if (ptr == NULL)
|
||||
fatal("xmalloc: out of memory (allocating %d bytes)", (int) size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *xrealloc(void *ptr, size_t new_size)
|
||||
void *
|
||||
xrealloc(void *ptr, size_t new_size)
|
||||
{
|
||||
void *new_ptr;
|
||||
void *new_ptr;
|
||||
|
||||
if (ptr == NULL)
|
||||
fatal("xrealloc: NULL pointer given as argument");
|
||||
new_ptr = realloc(ptr, new_size);
|
||||
if (new_ptr == NULL)
|
||||
fatal("xrealloc: out of memory (new_size %d bytes)", (int)new_size);
|
||||
return new_ptr;
|
||||
if (ptr == NULL)
|
||||
fatal("xrealloc: NULL pointer given as argument");
|
||||
new_ptr = realloc(ptr, new_size);
|
||||
if (new_ptr == NULL)
|
||||
fatal("xrealloc: out of memory (new_size %d bytes)", (int) new_size);
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
void xfree(void *ptr)
|
||||
void
|
||||
xfree(void *ptr)
|
||||
{
|
||||
if (ptr == NULL)
|
||||
fatal("xfree: NULL pointer given as argument");
|
||||
free(ptr);
|
||||
if (ptr == NULL)
|
||||
fatal("xfree: NULL pointer given as argument");
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
char *xstrdup(const char *str)
|
||||
char *
|
||||
xstrdup(const char *str)
|
||||
{
|
||||
int len = strlen(str) + 1;
|
||||
int len = strlen(str) + 1;
|
||||
|
||||
char *cp = xmalloc(len);
|
||||
strlcpy(cp, str, len);
|
||||
return cp;
|
||||
char *cp = xmalloc(len);
|
||||
strlcpy(cp, str, len);
|
||||
return cp;
|
||||
}
|
||||
|
|
40
xmalloc.h
40
xmalloc.h
|
@ -1,34 +1,34 @@
|
|||
/*
|
||||
*
|
||||
* xmalloc.h
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Created: Mon Mar 20 22:09:17 1995 ylo
|
||||
*
|
||||
* Versions of malloc and friends that check their results, and never return
|
||||
* failure (they call fatal if they encounter an error).
|
||||
*
|
||||
*/
|
||||
|
||||
xmalloc.h
|
||||
|
||||
Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
|
||||
Created: Mon Mar 20 22:09:17 1995 ylo
|
||||
|
||||
Versions of malloc and friends that check their results, and never return
|
||||
failure (they call fatal if they encounter an error).
|
||||
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: xmalloc.h,v 1.1 1999/10/27 03:42:46 damien Exp $"); */
|
||||
/* RCSID("$Id: xmalloc.h,v 1.2 1999/11/24 13:26:23 damien Exp $"); */
|
||||
|
||||
#ifndef XMALLOC_H
|
||||
#define XMALLOC_H
|
||||
|
||||
/* Like malloc, but calls fatal() if out of memory. */
|
||||
void *xmalloc(size_t size);
|
||||
void *xmalloc(size_t size);
|
||||
|
||||
/* Like realloc, but calls fatal() if out of memory. */
|
||||
void *xrealloc(void *ptr, size_t new_size);
|
||||
void *xrealloc(void *ptr, size_t new_size);
|
||||
|
||||
/* Frees memory allocated using xmalloc or xrealloc. */
|
||||
void xfree(void *ptr);
|
||||
void xfree(void *ptr);
|
||||
|
||||
/* Allocates memory using xmalloc, and copies the string into that memory. */
|
||||
char *xstrdup(const char *str);
|
||||
char *xstrdup(const char *str);
|
||||
|
||||
#endif /* XMALLOC_H */
|
||||
#endif /* XMALLOC_H */
|
||||
|
|
Загрузка…
Ссылка в новой задаче