summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog23
-rw-r--r--auth-krb4.c408
-rw-r--r--auth-passwd.c344
-rw-r--r--auth-rh-rsa.c174
-rw-r--r--auth-rhosts.c476
-rw-r--r--auth-rsa.c805
-rw-r--r--auth-skey.c8
-rw-r--r--authfd.c921
-rw-r--r--authfd.h89
-rw-r--r--authfile.c597
-rw-r--r--bufaux.c228
-rw-r--r--bufaux.h44
-rw-r--r--buffer.c179
-rw-r--r--buffer.h68
-rw-r--r--canohost.c371
-rw-r--r--channels.c2427
-rw-r--r--channels.h62
-rw-r--r--cipher.c409
-rw-r--r--cipher.h97
-rw-r--r--clientloop.c1524
-rw-r--r--compat.c13
-rw-r--r--compat.h4
-rw-r--r--compress.c233
-rw-r--r--compress.h40
-rw-r--r--configure.in2
-rw-r--r--crc32.c139
-rw-r--r--crc32.h32
-rw-r--r--deattack.c238
-rw-r--r--deattack.h7
-rw-r--r--fingerprint.c23
-rw-r--r--fingerprint.h4
-rw-r--r--getput.h33
-rw-r--r--hostfile.c457
-rw-r--r--includes.h28
-rw-r--r--log-client.c81
-rw-r--r--log-server.c238
-rw-r--r--log.c219
-rw-r--r--login.c193
-rw-r--r--match.c125
-rw-r--r--mpaux.c68
-rw-r--r--mpaux.h42
-rw-r--r--nchan.c119
-rw-r--r--nchan.h26
-rw-r--r--packet.c859
-rw-r--r--packet.h103
-rw-r--r--pty.c398
-rw-r--r--pty.h48
-rw-r--r--radix.c369
-rw-r--r--readconf.c1097
-rw-r--r--readconf.h170
-rw-r--r--readpass.c179
-rw-r--r--rsa.c231
-rw-r--r--rsa.h41
-rw-r--r--scp.c637
-rw-r--r--servconf.c935
-rw-r--r--servconf.h142
-rw-r--r--serverloop.c1112
-rw-r--r--ssh-add.c515
-rw-r--r--ssh-agent.c1124
-rw-r--r--ssh-keygen.c975
-rw-r--r--ssh.112
-rw-r--r--ssh.c1387
-rw-r--r--ssh.h351
-rw-r--r--sshconnect.c2851
-rw-r--r--sshd.812
-rw-r--r--sshd.c4503
-rw-r--r--tildexpand.c114
-rw-r--r--ttymodes.c479
-rw-r--r--ttymodes.h188
-rw-r--r--uidswap.c115
-rw-r--r--uidswap.h50
-rw-r--r--xmalloc.c73
-rw-r--r--xmalloc.h42
73 files changed, 15163 insertions, 15567 deletions
diff --git a/ChangeLog b/ChangeLog
index 16072e6a7..7b68e3fc1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
119991124
2 - Merged very large OpenBSD source code reformat
3 - OpenBSD CVS updates
4 - [channels.c cipher.c compat.c log-client.c scp.c serverloop.c]
5 [ssh.h sshd.8 sshd.c]
6 syslog changes:
7 * Unified Logmessage for all auth-types, for success and for failed
8 * Standard connections get only ONE line in the LOG when level==LOG:
9 Auth-attempts are logged only, if authentication is:
10 a) successfull or
11 b) with passwd or
12 c) we had more than AUTH_FAIL_LOG failues
13 * many log() became verbose()
14 * old behaviour with level=VERBOSE
15 - [readconf.c readconf.h ssh.1 ssh.h sshconnect.c sshd.c]
16 tranfer s/key challenge/response data in SSH_SMSG_AUTH_TIS_CHALLENGE
17 messages. allows use of s/key in windows (ttssh, securecrt) and
18 ssh-1.2.27 clients without 'ssh -v', ok: niels@
19 - [sshd.8]
20 -V, for fallback to openssh in SSH2 compatibility mode
21 - [sshd.c]
22 fix sigchld race; cjc5@po.cwru.edu
23
119991123 2419991123
2 - Added SuSE package files from Chris Saia <csaia@wtower.com> 25 - Added SuSE package files from Chris Saia <csaia@wtower.com>
3 - Restructured package-related files under packages/* 26 - Restructured package-related files under packages/*
diff --git a/auth-krb4.c b/auth-krb4.c
index 72acd47db..9f99533b1 100644
--- a/auth-krb4.c
+++ b/auth-krb4.c
@@ -1,13 +1,7 @@
1/* 1/*
2 2 * Dug Song <dugsong@UMICH.EDU>
3 auth-kerberos.c 3 * Kerberos v4 authentication and ticket-passing routines.
4 4 */
5 Dug Song <dugsong@UMICH.EDU>
6
7 Kerberos v4 authentication and ticket-passing routines.
8
9 $Id: auth-krb4.c,v 1.4 1999/11/15 04:25:10 damien Exp $
10*/
11 5
12#include "includes.h" 6#include "includes.h"
13#include "packet.h" 7#include "packet.h"
@@ -20,216 +14,222 @@ char *ticket = NULL;
20void 14void
21krb4_cleanup_proc(void *ignore) 15krb4_cleanup_proc(void *ignore)
22{ 16{
23 debug("krb4_cleanup_proc called"); 17 debug("krb4_cleanup_proc called");
24 18 if (ticket) {
25 if (ticket) { 19 (void) dest_tkt();
26 (void) dest_tkt(); 20 xfree(ticket);
27 xfree(ticket); 21 ticket = NULL;
28 ticket = NULL; 22 }
29 }
30} 23}
31 24
32int krb4_init(uid_t uid) 25int
26krb4_init(uid_t uid)
33{ 27{
34 static int cleanup_registered = 0; 28 static int cleanup_registered = 0;
35 char *tkt_root = TKT_ROOT; 29 char *tkt_root = TKT_ROOT;
36 struct stat st; 30 struct stat st;
37 int fd; 31 int fd;
38 32
39 if (!ticket) { 33 if (!ticket) {
40 /* Set unique ticket string manually since we're still root. */ 34 /* Set unique ticket string manually since we're still root. */
41 ticket = xmalloc(MAXPATHLEN); 35 ticket = xmalloc(MAXPATHLEN);
42#ifdef AFS 36#ifdef AFS
43 if (lstat("/ticket", &st) != -1) 37 if (lstat("/ticket", &st) != -1)
44 tkt_root = "/ticket/"; 38 tkt_root = "/ticket/";
45#endif /* AFS */ 39#endif /* AFS */
46 snprintf(ticket, MAXPATHLEN, "%s%d_%d", tkt_root, uid, getpid()); 40 snprintf(ticket, MAXPATHLEN, "%s%d_%d", tkt_root, uid, getpid());
47 (void) krb_set_tkt_string(ticket); 41 (void) krb_set_tkt_string(ticket);
48 } 42 }
49 /* Register ticket cleanup in case of fatal error. */ 43 /* Register ticket cleanup in case of fatal error. */
50 if (!cleanup_registered) { 44 if (!cleanup_registered) {
51 fatal_add_cleanup(krb4_cleanup_proc, NULL); 45 fatal_add_cleanup(krb4_cleanup_proc, NULL);
52 cleanup_registered = 1; 46 cleanup_registered = 1;
53 } 47 }
54 /* Try to create our ticket file. */ 48 /* Try to create our ticket file. */
55 if ((fd = mkstemp(ticket)) != -1) { 49 if ((fd = mkstemp(ticket)) != -1) {
56 close(fd); 50 close(fd);
57 return 1; 51 return 1;
58 } 52 }
59 /* Ticket file exists - make sure user owns it (just passed ticket). */ 53 /* Ticket file exists - make sure user owns it (just passed ticket). */
60 if (lstat(ticket, &st) != -1) { 54 if (lstat(ticket, &st) != -1) {
61 if (st.st_mode == (S_IFREG|S_IRUSR|S_IWUSR) && st.st_uid == uid) 55 if (st.st_mode == (S_IFREG | S_IRUSR | S_IWUSR) &&
62 return 1; 56 st.st_uid == uid)
63 } 57 return 1;
64 /* Failure - cancel cleanup function, leaving bad ticket for inspection. */ 58 }
65 log("WARNING: bad ticket file %s", ticket); 59 /* Failure - cancel cleanup function, leaving bad ticket for inspection. */
66 fatal_remove_cleanup(krb4_cleanup_proc, NULL); 60 log("WARNING: bad ticket file %s", ticket);
67 cleanup_registered = 0; 61 fatal_remove_cleanup(krb4_cleanup_proc, NULL);
68 xfree(ticket); 62 cleanup_registered = 0;
69 ticket = NULL; 63 xfree(ticket);
70 64 ticket = NULL;
71 return 0; 65
66 return 0;
72} 67}
73 68
74int auth_krb4(const char *server_user, KTEXT auth, char **client) 69int
70auth_krb4(const char *server_user, KTEXT auth, char **client)
75{ 71{
76 AUTH_DAT adat = { 0 }; 72 AUTH_DAT adat = {0};
77 KTEXT_ST reply; 73 KTEXT_ST reply;
78 char instance[INST_SZ]; 74 char instance[INST_SZ];
79 int r, s; 75 int r, s;
80 u_int cksum; 76 u_int cksum;
81 Key_schedule schedule; 77 Key_schedule schedule;
82 struct sockaddr_in local, foreign; 78 struct sockaddr_in local, foreign;
83 79
84 s = packet_get_connection_in(); 80 s = packet_get_connection_in();
85 81
86 r = sizeof(local); 82 r = sizeof(local);
87 memset(&local, 0, sizeof(local)); 83 memset(&local, 0, sizeof(local));
88 if (getsockname(s, (struct sockaddr *) &local, &r) < 0) 84 if (getsockname(s, (struct sockaddr *) & local, &r) < 0)
89 debug("getsockname failed: %.100s", strerror(errno)); 85 debug("getsockname failed: %.100s", strerror(errno));
90 r = sizeof(foreign); 86 r = sizeof(foreign);
91 memset(&foreign, 0, sizeof(foreign)); 87 memset(&foreign, 0, sizeof(foreign));
92 if (getpeername(s, (struct sockaddr *)&foreign, &r) < 0) { 88 if (getpeername(s, (struct sockaddr *) & foreign, &r) < 0) {
93 debug("getpeername failed: %.100s", strerror(errno)); 89 debug("getpeername failed: %.100s", strerror(errno));
94 fatal_cleanup(); 90 fatal_cleanup();
95 } 91 }
96 92 instance[0] = '*';
97 instance[0] = '*'; instance[1] = 0; 93 instance[1] = 0;
98 94
99 /* Get the encrypted request, challenge, and session key. */ 95 /* Get the encrypted request, challenge, and session key. */
100 if ((r = krb_rd_req(auth, KRB4_SERVICE_NAME, instance, 0, &adat, ""))) { 96 if ((r = krb_rd_req(auth, KRB4_SERVICE_NAME, instance, 0, &adat, ""))) {
101 packet_send_debug("Kerberos V4 krb_rd_req: %.100s", krb_err_txt[r]); 97 packet_send_debug("Kerberos V4 krb_rd_req: %.100s", krb_err_txt[r]);
102 return 0; 98 return 0;
103 } 99 }
104 des_key_sched((des_cblock *)adat.session, schedule); 100 des_key_sched((des_cblock *) adat.session, schedule);
105 101
106 *client = xmalloc(MAX_K_NAME_SZ); 102 *client = xmalloc(MAX_K_NAME_SZ);
107 (void) snprintf(*client, MAX_K_NAME_SZ, "%s%s%s@%s", adat.pname, 103 (void) snprintf(*client, MAX_K_NAME_SZ, "%s%s%s@%s", adat.pname,
108 *adat.pinst ? "." : "", adat.pinst, adat.prealm); 104 *adat.pinst ? "." : "", adat.pinst, adat.prealm);
109 105
110 /* Check ~/.klogin authorization now. */ 106 /* Check ~/.klogin authorization now. */
111 if (kuserok(&adat, (char *)server_user) != KSUCCESS) { 107 if (kuserok(&adat, (char *) server_user) != KSUCCESS) {
112 packet_send_debug("Kerberos V4 .klogin authorization failed!"); 108 packet_send_debug("Kerberos V4 .klogin authorization failed!");
113 log("Kerberos V4 .klogin authorization failed for %s to account %s", 109 log("Kerberos V4 .klogin authorization failed for %s to account %s",
114 *client, server_user); 110 *client, server_user);
115 xfree(*client); 111 xfree(*client);
116 return 0; 112 return 0;
117 } 113 }
118 /* Increment the checksum, and return it encrypted with the session key. */ 114 /* Increment the checksum, and return it encrypted with the
119 cksum = adat.checksum + 1; 115 session key. */
120 cksum = htonl(cksum); 116 cksum = adat.checksum + 1;
121 117 cksum = htonl(cksum);
122 /* If we can't successfully encrypt the checksum, we send back an empty 118
123 message, admitting our failure. */ 119 /* If we can't successfully encrypt the checksum, we send back an
124 if ((r = krb_mk_priv((u_char *)&cksum, reply.dat, sizeof(cksum)+1, 120 empty message, admitting our failure. */
125 schedule, &adat.session, &local, &foreign)) < 0) { 121 if ((r = krb_mk_priv((u_char *) & cksum, reply.dat, sizeof(cksum) + 1,
126 packet_send_debug("Kerberos V4 mk_priv: (%d) %s", r, krb_err_txt[r]); 122 schedule, &adat.session, &local, &foreign)) < 0) {
127 reply.dat[0] = 0; 123 packet_send_debug("Kerberos V4 mk_priv: (%d) %s", r, krb_err_txt[r]);
128 reply.length = 0; 124 reply.dat[0] = 0;
129 } 125 reply.length = 0;
130 else reply.length = r; 126 } else
131 127 reply.length = r;
132 /* Clear session key. */ 128
133 memset(&adat.session, 0, sizeof(&adat.session)); 129 /* Clear session key. */
134 130 memset(&adat.session, 0, sizeof(&adat.session));
135 packet_start(SSH_SMSG_AUTH_KERBEROS_RESPONSE); 131
136 packet_put_string((char *) reply.dat, reply.length); 132 packet_start(SSH_SMSG_AUTH_KERBEROS_RESPONSE);
137 packet_send(); 133 packet_put_string((char *) reply.dat, reply.length);
138 packet_write_wait(); 134 packet_send();
139 return 1; 135 packet_write_wait();
136 return 1;
140} 137}
141#endif /* KRB4 */ 138#endif /* KRB4 */
142 139
143#ifdef AFS 140#ifdef AFS
144int auth_kerberos_tgt(struct passwd *pw, const char *string) 141int
142auth_kerberos_tgt(struct passwd *pw, const char *string)
145{ 143{
146 CREDENTIALS creds; 144 CREDENTIALS creds;
147 145
148 if (!radix_to_creds(string, &creds)) { 146 if (!radix_to_creds(string, &creds)) {
149 log("Protocol error decoding Kerberos V4 tgt"); 147 log("Protocol error decoding Kerberos V4 tgt");
150 packet_send_debug("Protocol error decoding Kerberos V4 tgt"); 148 packet_send_debug("Protocol error decoding Kerberos V4 tgt");
151 goto auth_kerberos_tgt_failure; 149 goto auth_kerberos_tgt_failure;
152 } 150 }
153 if (strncmp(creds.service, "", 1) == 0) /* backward compatibility */ 151 if (strncmp(creds.service, "", 1) == 0) /* backward compatibility */
154 strlcpy(creds.service, "krbtgt", sizeof creds.service); 152 strlcpy(creds.service, "krbtgt", sizeof creds.service);
155 153
156 if (strcmp(creds.service, "krbtgt")) { 154 if (strcmp(creds.service, "krbtgt")) {
157 log("Kerberos V4 tgt (%s%s%s@%s) rejected for %s", creds.pname, 155 log("Kerberos V4 tgt (%s%s%s@%s) rejected for %s", creds.pname,
158 creds.pinst[0] ? "." : "", creds.pinst, creds.realm, pw->pw_name); 156 creds.pinst[0] ? "." : "", creds.pinst, creds.realm,
159 packet_send_debug("Kerberos V4 tgt (%s%s%s@%s) rejected for %s", 157 pw->pw_name);
160 creds.pname, creds.pinst[0] ? "." : "", creds.pinst, 158 packet_send_debug("Kerberos V4 tgt (%s%s%s@%s) rejected for %s",
161 creds.realm, pw->pw_name); 159 creds.pname, creds.pinst[0] ? "." : "", creds.pinst,
162 goto auth_kerberos_tgt_failure; 160 creds.realm, pw->pw_name);
163 } 161 goto auth_kerberos_tgt_failure;
164 if (!krb4_init(pw->pw_uid)) 162 }
165 goto auth_kerberos_tgt_failure; 163 if (!krb4_init(pw->pw_uid))
166 164 goto auth_kerberos_tgt_failure;
167 if (in_tkt(creds.pname, creds.pinst) != KSUCCESS) 165
168 goto auth_kerberos_tgt_failure; 166 if (in_tkt(creds.pname, creds.pinst) != KSUCCESS)
169 167 goto auth_kerberos_tgt_failure;
170 if (save_credentials(creds.service, creds.instance, creds.realm, 168
171 creds.session, creds.lifetime, creds.kvno, 169 if (save_credentials(creds.service, creds.instance, creds.realm,
172 &creds.ticket_st, creds.issue_date) != KSUCCESS) { 170 creds.session, creds.lifetime, creds.kvno,
173 packet_send_debug("Kerberos V4 tgt refused: couldn't save credentials"); 171 &creds.ticket_st, creds.issue_date) != KSUCCESS) {
174 goto auth_kerberos_tgt_failure; 172 packet_send_debug("Kerberos V4 tgt refused: couldn't save credentials");
175 } 173 goto auth_kerberos_tgt_failure;
176 /* Successful authentication, passed all checks. */ 174 }
177 chown(tkt_string(), pw->pw_uid, pw->pw_gid); 175 /* Successful authentication, passed all checks. */
178 176 chown(tkt_string(), pw->pw_uid, pw->pw_gid);
179 packet_send_debug("Kerberos V4 tgt accepted (%s.%s@%s, %s%s%s@%s)", 177
180 creds.service, creds.instance, creds.realm, creds.pname, 178 packet_send_debug("Kerberos V4 tgt accepted (%s.%s@%s, %s%s%s@%s)",
181 creds.pinst[0] ? "." : "", creds.pinst, creds.realm); 179 creds.service, creds.instance, creds.realm, creds.pname,
182 memset(&creds, 0, sizeof(creds)); 180 creds.pinst[0] ? "." : "", creds.pinst, creds.realm);
183 packet_start(SSH_SMSG_SUCCESS); 181 memset(&creds, 0, sizeof(creds));
184 packet_send(); 182 packet_start(SSH_SMSG_SUCCESS);
185 packet_write_wait(); 183 packet_send();
186 return 1; 184 packet_write_wait();
187 185 return 1;
188 auth_kerberos_tgt_failure: 186
189 krb4_cleanup_proc(NULL); 187auth_kerberos_tgt_failure:
190 memset(&creds, 0, sizeof(creds)); 188 krb4_cleanup_proc(NULL);
191 packet_start(SSH_SMSG_FAILURE); 189 memset(&creds, 0, sizeof(creds));
192 packet_send(); 190 packet_start(SSH_SMSG_FAILURE);
193 packet_write_wait(); 191 packet_send();
194 return 0; 192 packet_write_wait();
193 return 0;
195} 194}
196 195
197int auth_afs_token(struct passwd *pw, const char *token_string) 196int
197auth_afs_token(struct passwd *pw, const char *token_string)
198{ 198{
199 CREDENTIALS creds; 199 CREDENTIALS creds;
200 uid_t uid = pw->pw_uid; 200 uid_t uid = pw->pw_uid;
201 201
202 if (!radix_to_creds(token_string, &creds)) { 202 if (!radix_to_creds(token_string, &creds)) {
203 log("Protocol error decoding AFS token"); 203 log("Protocol error decoding AFS token");
204 packet_send_debug("Protocol error decoding AFS token"); 204 packet_send_debug("Protocol error decoding AFS token");
205 packet_start(SSH_SMSG_FAILURE); 205 packet_start(SSH_SMSG_FAILURE);
206 packet_send(); 206 packet_send();
207 packet_write_wait(); 207 packet_write_wait();
208 return 0; 208 return 0;
209 } 209 }
210 if (strncmp(creds.service, "", 1) == 0) /* backward compatibility */ 210 if (strncmp(creds.service, "", 1) == 0) /* backward compatibility */
211 strlcpy(creds.service, "afs", sizeof creds.service); 211 strlcpy(creds.service, "afs", sizeof creds.service);
212 212
213 if (strncmp(creds.pname, "AFS ID ", 7) == 0) 213 if (strncmp(creds.pname, "AFS ID ", 7) == 0)
214 uid = atoi(creds.pname + 7); 214 uid = atoi(creds.pname + 7);
215 215
216 if (kafs_settoken(creds.realm, uid, &creds)) { 216 if (kafs_settoken(creds.realm, uid, &creds)) {
217 log("AFS token (%s@%s) rejected for %s", creds.pname, creds.realm, 217 log("AFS token (%s@%s) rejected for %s", creds.pname, creds.realm,
218 pw->pw_name); 218 pw->pw_name);
219 packet_send_debug("AFS token (%s@%s) rejected for %s", creds.pname, 219 packet_send_debug("AFS token (%s@%s) rejected for %s", creds.pname,
220 creds.realm, pw->pw_name); 220 creds.realm, pw->pw_name);
221 memset(&creds, 0, sizeof(creds)); 221 memset(&creds, 0, sizeof(creds));
222 packet_start(SSH_SMSG_FAILURE); 222 packet_start(SSH_SMSG_FAILURE);
223 packet_send(); 223 packet_send();
224 packet_write_wait(); 224 packet_write_wait();
225 return 0; 225 return 0;
226 } 226 }
227 packet_send_debug("AFS token accepted (%s@%s, %s@%s)", creds.service, 227 packet_send_debug("AFS token accepted (%s@%s, %s@%s)", creds.service,
228 creds.realm, creds.pname, creds.realm); 228 creds.realm, creds.pname, creds.realm);
229 memset(&creds, 0, sizeof(creds)); 229 memset(&creds, 0, sizeof(creds));
230 packet_start(SSH_SMSG_SUCCESS); 230 packet_start(SSH_SMSG_SUCCESS);
231 packet_send(); 231 packet_send();
232 packet_write_wait(); 232 packet_write_wait();
233 return 1; 233 return 1;
234} 234}
235#endif /* AFS */ 235#endif /* AFS */
diff --git a/auth-passwd.c b/auth-passwd.c
index a08bab3af..d3914fca3 100644
--- a/auth-passwd.c
+++ b/auth-passwd.c
@@ -1,30 +1,22 @@
1/* 1/*
2 2 * Author: Tatu Ylonen <ylo@cs.hut.fi>
3auth-passwd.c 3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 4 * All rights reserved
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Created: Sat Mar 18 05:11:38 1995 ylo
6 6 * Password authentication. This file contains the functions to check whether
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * the password is valid for the user.
8 All rights reserved 8 */
9
10Created: Sat Mar 18 05:11:38 1995 ylo
11
12Password authentication. This file contains the functions to check whether
13the password is valid for the user.
14
15*/
16 9
17#include "includes.h" 10#include "includes.h"
18 11
19#ifndef HAVE_PAM 12#ifndef HAVE_PAM
20 13
21RCSID("$Id: auth-passwd.c,v 1.5 1999/11/19 04:53:20 damien Exp $"); 14RCSID("$Id: auth-passwd.c,v 1.6 1999/11/24 13:26:21 damien Exp $");
22 15
23#include "packet.h" 16#include "packet.h"
24#include "ssh.h" 17#include "ssh.h"
25#include "servconf.h" 18#include "servconf.h"
26#include "xmalloc.h" 19#include "xmalloc.h"
27#include "config.h"
28 20
29#ifdef HAVE_SHADOW_H 21#ifdef HAVE_SHADOW_H
30#include <shadow.h> 22#include <shadow.h>
@@ -34,185 +26,189 @@ RCSID("$Id: auth-passwd.c,v 1.5 1999/11/19 04:53:20 damien Exp $");
34#include "md5crypt.h" 26#include "md5crypt.h"
35#endif 27#endif
36 28
37/* Don't need anything from here if we are using PAM */ 29/*
38 30 * Tries to authenticate the user using password. Returns true if
39/* Tries to authenticate the user using password. Returns true if 31 * authentication succeeds.
40 authentication succeeds. */ 32 */
41 33int
42int auth_password(struct passwd *pw, const char *password) 34auth_password(struct passwd * pw, const char *password)
43{ 35{
44 extern ServerOptions options; 36 extern ServerOptions options;
45 char *encrypted_password; 37 char *encrypted_password;
46#ifdef HAVE_SHADOW_H 38#ifdef HAVE_SHADOW_H
47 struct spwd *spw; 39 struct spwd *spw;
48#endif 40#endif
49 41
50 if (pw->pw_uid == 0 && options.permit_root_login == 2) 42 if (pw->pw_uid == 0 && options.permit_root_login == 2) {
51 { 43 /* Server does not permit root login with password */
52 /*packet_send_debug("Server does not permit root login with password.");*/ 44 return 0;
53 return 0; 45 }
54 } 46 if (*password == '\0' && options.permit_empty_passwd == 0) {
55 47 /* Server does not permit empty password login */
56 if (*password == '\0' && options.permit_empty_passwd == 0) 48 return 0;
57 { 49 }
58 /*packet_send_debug("Server does not permit empty password login.");*/ 50 /* deny if no user. */
59 return 0; 51 if (pw == NULL)
60 } 52 return 0;
61
62 /* deny if no user. */
63 if (pw == NULL)
64 return 0;
65 53
66#ifdef SKEY 54#ifdef SKEY
67 if (options.skey_authentication == 1) { 55 if (options.skey_authentication == 1) {
68 if (strncasecmp(password, "s/key", 5) == 0) { 56 if (strncasecmp(password, "s/key", 5) == 0) {
69 char *skeyinfo = skey_keyinfo(pw->pw_name); 57 char *skeyinfo = skey_keyinfo(pw->pw_name);
70 if(skeyinfo == NULL){ 58 if (skeyinfo == NULL) {
71 debug("generating fake skeyinfo for %.100s.", pw->pw_name); 59 debug("generating fake skeyinfo for %.100s.",
72 skeyinfo = skey_fake_keyinfo(pw->pw_name); 60 pw->pw_name);
73 } 61 skeyinfo = skey_fake_keyinfo(pw->pw_name);
74 if(skeyinfo != NULL) 62 }
75 packet_send_debug(skeyinfo); 63 if (skeyinfo != NULL)
76 /* Try again. */ 64 packet_send_debug(skeyinfo);
77 return 0; 65 /* Try again. */
78 } 66 return 0;
79 else if (skey_haskey(pw->pw_name) == 0 && 67 } else if (skey_haskey(pw->pw_name) == 0 &&
80 skey_passcheck(pw->pw_name, (char *)password) != -1) { 68 skey_passcheck(pw->pw_name, (char *) password) != -1) {
81 /* Authentication succeeded. */ 69 /* Authentication succeeded. */
82 return 1; 70 return 1;
83 } 71 }
84 /* Fall back to ordinary passwd authentication. */ 72 /* Fall back to ordinary passwd authentication. */
85 } 73 }
86#endif 74#endif
87 75
88#if defined(KRB4) 76#if defined(KRB4)
89 /* Support for Kerberos v4 authentication - Dug Song <dugsong@UMICH.EDU> */ 77 /* Support for Kerberos v4 authentication - Dug Song
90 if (options.kerberos_authentication) 78 <dugsong@UMICH.EDU> */
91 { 79 if (options.kerberos_authentication) {
92 AUTH_DAT adata; 80 AUTH_DAT adata;
93 KTEXT_ST tkt; 81 KTEXT_ST tkt;
94 struct hostent *hp; 82 struct hostent *hp;
95 unsigned long faddr; 83 unsigned long faddr;
96 char localhost[MAXHOSTNAMELEN]; 84 char localhost[MAXHOSTNAMELEN];
97 char phost[INST_SZ]; 85 char phost[INST_SZ];
98 char realm[REALM_SZ]; 86 char realm[REALM_SZ];
99 int r; 87 int r;
100 88
101 /* Try Kerberos password authentication only for non-root 89 /* Try Kerberos password authentication only for non-root
102 users and only if Kerberos is installed. */ 90 users and only if Kerberos is installed. */
103 if (pw->pw_uid != 0 && krb_get_lrealm(realm, 1) == KSUCCESS) { 91 if (pw->pw_uid != 0 && krb_get_lrealm(realm, 1) == KSUCCESS) {
104 92
105 /* Set up our ticket file. */ 93 /* Set up our ticket file. */
106 if (!krb4_init(pw->pw_uid)) { 94 if (!krb4_init(pw->pw_uid)) {
107 log("Couldn't initialize Kerberos ticket file for %s!", pw->pw_name); 95 log("Couldn't initialize Kerberos ticket file for %s!",
108 goto kerberos_auth_failure; 96 pw->pw_name);
109 } 97 goto kerberos_auth_failure;
110 /* Try to get TGT using our password. */ 98 }
111 r = krb_get_pw_in_tkt((char *)pw->pw_name, "", realm, "krbtgt", realm, 99 /* Try to get TGT using our password. */
112 DEFAULT_TKT_LIFE, (char *)password); 100 r = krb_get_pw_in_tkt((char *) pw->pw_name, "",
113 if (r != INTK_OK) { 101 realm, "krbtgt", realm,
114 packet_send_debug("Kerberos V4 password authentication for %s " 102 DEFAULT_TKT_LIFE, (char *) password);
115 "failed: %s", pw->pw_name, krb_err_txt[r]); 103 if (r != INTK_OK) {
116 goto kerberos_auth_failure; 104 packet_send_debug("Kerberos V4 password "
105 "authentication for %s failed: %s",
106 pw->pw_name, krb_err_txt[r]);
107 goto kerberos_auth_failure;
108 }
109 /* Successful authentication. */
110 chown(tkt_string(), pw->pw_uid, pw->pw_gid);
111
112 /*
113 * Now that we have a TGT, try to get a local
114 * "rcmd" ticket to ensure that we are not talking
115 * to a bogus Kerberos server.
116 */
117 (void) gethostname(localhost, sizeof(localhost));
118 (void) strlcpy(phost, (char *) krb_get_phost(localhost),
119 INST_SZ);
120 r = krb_mk_req(&tkt, KRB4_SERVICE_NAME, phost, realm, 33);
121
122 if (r == KSUCCESS) {
123 if (!(hp = gethostbyname(localhost))) {
124 log("Couldn't get local host address!");
125 goto kerberos_auth_failure;
126 }
127 memmove((void *) &faddr, (void *) hp->h_addr,
128 sizeof(faddr));
129
130 /* Verify our "rcmd" ticket. */
131 r = krb_rd_req(&tkt, KRB4_SERVICE_NAME, phost,
132 faddr, &adata, "");
133 if (r == RD_AP_UNDEC) {
134 /*
135 * Probably didn't have a srvtab on
136 * localhost. Allow login.
137 */
138 log("Kerberos V4 TGT for %s unverifiable, "
139 "no srvtab installed? krb_rd_req: %s",
140 pw->pw_name, krb_err_txt[r]);
141 } else if (r != KSUCCESS) {
142 log("Kerberos V4 %s ticket unverifiable: %s",
143 KRB4_SERVICE_NAME, krb_err_txt[r]);
144 goto kerberos_auth_failure;
145 }
146 } else if (r == KDC_PR_UNKNOWN) {
147 /* Allow login if no rcmd service exists,
148 but log the error. */
149 log("Kerberos V4 TGT for %s unverifiable: %s; %s.%s "
150 "not registered, or srvtab is wrong?", pw->pw_name,
151 krb_err_txt[r], KRB4_SERVICE_NAME, phost);
152 } else {
153 /* TGT is bad, forget it. Possibly
154 spoofed! */
155 packet_send_debug("WARNING: Kerberos V4 TGT "
156 "possibly spoofed for %s: %s",
157 pw->pw_name, krb_err_txt[r]);
158 goto kerberos_auth_failure;
159 }
160
161 /* Authentication succeeded. */
162 return 1;
163
164 kerberos_auth_failure:
165 krb4_cleanup_proc(NULL);
166
167 if (!options.kerberos_or_local_passwd)
168 return 0;
169 } else {
170 /* Logging in as root or no local Kerberos realm. */
171 packet_send_debug("Unable to authenticate to Kerberos.");
172 }
173 /* Fall back to ordinary passwd authentication. */
117 } 174 }
118 /* Successful authentication. */ 175#endif /* KRB4 */
119 chown(tkt_string(), pw->pw_uid, pw->pw_gid); 176
120 177 /* Check for users with no password. */
121 /* Now that we have a TGT, try to get a local "rcmd" ticket to 178 if (strcmp(password, "") == 0 && strcmp(pw->pw_passwd, "") == 0) {
122 ensure that we are not talking to a bogus Kerberos server. */ 179 packet_send_debug("Login permitted without a password "
123 (void) gethostname(localhost, sizeof(localhost)); 180 "because the account has no password.");
124 (void) strlcpy(phost, (char *)krb_get_phost(localhost), INST_SZ); 181 return 1;
125 r = krb_mk_req(&tkt, KRB4_SERVICE_NAME, phost, realm, 33);
126
127 if (r == KSUCCESS) {
128 if (!(hp = gethostbyname(localhost))) {
129 log("Couldn't get local host address!");
130 goto kerberos_auth_failure;
131 }
132 memmove((void *)&faddr, (void *)hp->h_addr, sizeof(faddr));
133
134 /* Verify our "rcmd" ticket. */
135 r = krb_rd_req(&tkt, KRB4_SERVICE_NAME, phost, faddr, &adata, "");
136 if (r == RD_AP_UNDEC) {
137 /* Probably didn't have a srvtab on localhost. Allow login. */
138 log("Kerberos V4 TGT for %s unverifiable, no srvtab installed? "
139 "krb_rd_req: %s", pw->pw_name, krb_err_txt[r]);
140 }
141 else if (r != KSUCCESS) {
142 log("Kerberos V4 %s ticket unverifiable: %s",
143 KRB4_SERVICE_NAME, krb_err_txt[r]);
144 goto kerberos_auth_failure;
145 }
146 }
147 else if (r == KDC_PR_UNKNOWN) {
148 /* Allow login if no rcmd service exists, but log the error. */
149 log("Kerberos V4 TGT for %s unverifiable: %s; %s.%s "
150 "not registered, or srvtab is wrong?", pw->pw_name,
151 krb_err_txt[r], KRB4_SERVICE_NAME, phost);
152 }
153 else {
154 /* TGT is bad, forget it. Possibly spoofed! */
155 packet_send_debug("WARNING: Kerberos V4 TGT possibly spoofed for"
156 "%s: %s", pw->pw_name, krb_err_txt[r]);
157 goto kerberos_auth_failure;
158 } 182 }
159
160 /* Authentication succeeded. */
161 return 1;
162
163 kerberos_auth_failure:
164 krb4_cleanup_proc(NULL);
165
166 if (!options.kerberos_or_local_passwd)
167 return 0;
168 }
169 else {
170 /* Logging in as root or no local Kerberos realm. */
171 packet_send_debug("Unable to authenticate to Kerberos.");
172 }
173 /* Fall back to ordinary passwd authentication. */
174 }
175#endif /* KRB4 */
176
177 /* Check for users with no password. */
178 if (strcmp(password, "") == 0 && strcmp(pw->pw_passwd, "") == 0)
179 {
180 packet_send_debug("Login permitted without a password because the account has no password.");
181 return 1; /* The user has no password and an empty password was tried. */
182 }
183 183
184#ifdef HAVE_SHADOW_H 184#ifdef HAVE_SHADOW_H
185 spw = getspnam(pw->pw_name); 185 spw = getspnam(pw->pw_name);
186 if (spw == NULL) 186 if (spw == NULL)
187 return(0); 187 return(0);
188 188
189 if ((spw->sp_namp == NULL) || (strcmp(pw->pw_name, spw->sp_namp) != 0)) 189 if ((spw->sp_namp == NULL) || (strcmp(pw->pw_name, spw->sp_namp) != 0))
190 fatal("Shadow lookup returned garbage."); 190 fatal("Shadow lookup returned garbage.");
191 191
192 if (strlen(spw->sp_pwdp) < 3) 192 if (strlen(spw->sp_pwdp) < 3)
193 return(0); 193 return(0);
194 194
195 /* Encrypt the candidate password using the proper salt. */ 195 /* Encrypt the candidate password using the proper salt. */
196#ifdef HAVE_MD5_PASSWORDS 196#ifdef HAVE_MD5_PASSWORDS
197 if (is_md5_salt(spw->sp_pwdp)) 197 if (is_md5_salt(spw->sp_pwdp))
198 encrypted_password = md5_crypt(password, spw->sp_pwdp); 198 encrypted_password = md5_crypt(password, spw->sp_pwdp);
199 else 199 else
200 encrypted_password = crypt(password, spw->sp_pwdp); 200 encrypted_password = crypt(password, spw->sp_pwdp);
201#else /* HAVE_MD5_PASSWORDS */ 201#else /* HAVE_MD5_PASSWORDS */
202 encrypted_password = crypt(password, spw->sp_pwdp); 202 encrypted_password = crypt(password, spw->sp_pwdp);
203#endif /* HAVE_MD5_PASSWORDS */ 203#endif /* HAVE_MD5_PASSWORDS */
204 204 /* Authentication is accepted if the encrypted passwords are identical. */
205 /* Authentication is accepted if the encrypted passwords are identical. */ 205 return (strcmp(encrypted_password, spw->sp_pwdp) == 0);
206 return (strcmp(encrypted_password, spw->sp_pwdp) == 0);
207#else /* !HAVE_SHADOW_H */ 206#else /* !HAVE_SHADOW_H */
207 encrypted_password = crypt(password,
208 (pw->pw_passwd[0] && pw->pw_passwd[1]) ? pw->pw_passwd : "xx");
208 209
209 /* Encrypt the candidate password using the proper salt. */ 210 /* Authentication is accepted if the encrypted passwords are identical. */
210 encrypted_password = crypt(password, 211 return (strcmp(encrypted_password, pw->pw_passwd) == 0);
211 (pw->pw_passwd[0] && pw->pw_passwd[1]) ?
212 pw->pw_passwd : "xx");
213 /* Authentication is accepted if the encrypted passwords are identical. */
214 return (strcmp(encrypted_password, pw->pw_passwd) == 0);
215#endif /* !HAVE_SHADOW_H */ 212#endif /* !HAVE_SHADOW_H */
216} 213}
217
218#endif /* !HAVE_PAM */ 214#endif /* !HAVE_PAM */
diff --git a/auth-rh-rsa.c b/auth-rh-rsa.c
index 68e0b829e..4e9a383a2 100644
--- a/auth-rh-rsa.c
+++ b/auth-rh-rsa.c
@@ -1,21 +1,21 @@
1/* 1/*
2 2 *
3auth-rh-rsa.c 3 * auth-rh-rsa.c
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Sun May 7 03:08:06 1995 ylo 10 * Created: Sun May 7 03:08:06 1995 ylo
11 11 *
12Rhosts or /etc/hosts.equiv authentication combined with RSA host 12 * Rhosts or /etc/hosts.equiv authentication combined with RSA host
13authentication. 13 * authentication.
14 14 *
15*/ 15 */
16 16
17#include "includes.h" 17#include "includes.h"
18RCSID("$Id: auth-rh-rsa.c,v 1.5 1999/11/16 02:37:16 damien Exp $"); 18RCSID("$Id: auth-rh-rsa.c,v 1.6 1999/11/24 13:26:21 damien Exp $");
19 19
20#include "packet.h" 20#include "packet.h"
21#include "ssh.h" 21#include "ssh.h"
@@ -26,78 +26,76 @@ RCSID("$Id: auth-rh-rsa.c,v 1.5 1999/11/16 02:37:16 damien Exp $");
26/* Tries to authenticate the user using the .rhosts file and the host using 26/* Tries to authenticate the user using the .rhosts file and the host using
27 its host key. Returns true if authentication succeeds. */ 27 its host key. Returns true if authentication succeeds. */
28 28
29int auth_rhosts_rsa(struct passwd *pw, const char *client_user, 29int
30 BIGNUM *client_host_key_e, BIGNUM *client_host_key_n) 30auth_rhosts_rsa(struct passwd *pw, const char *client_user,
31 BIGNUM *client_host_key_e, BIGNUM *client_host_key_n)
31{ 32{
32 extern ServerOptions options; 33 extern ServerOptions options;
33 const char *canonical_hostname; 34 const char *canonical_hostname;
34 HostStatus host_status; 35 HostStatus host_status;
35 BIGNUM *ke, *kn; 36 BIGNUM *ke, *kn;
36 37
37 debug("Trying rhosts with RSA host authentication for %.100s", client_user); 38 debug("Trying rhosts with RSA host authentication for %.100s", client_user);
38 39
39 /* Check if we would accept it using rhosts authentication. */ 40 /* Check if we would accept it using rhosts authentication. */
40 if (!auth_rhosts(pw, client_user)) 41 if (!auth_rhosts(pw, client_user))
41 return 0; 42 return 0;
42 43
43 canonical_hostname = get_canonical_hostname(); 44 canonical_hostname = get_canonical_hostname();
44 45
45 debug("Rhosts RSA authentication: canonical host %.900s", 46 debug("Rhosts RSA authentication: canonical host %.900s",
46 canonical_hostname); 47 canonical_hostname);
47 48
48 /* Check if we know the host and its host key. */ 49 /* Check if we know the host and its host key. */
49 /* Check system-wide host file. */ 50 ke = BN_new();
50 ke = BN_new(); 51 kn = BN_new();
51 kn = BN_new(); 52 host_status = check_host_in_hostfile(SSH_SYSTEM_HOSTFILE, canonical_hostname,
52 host_status = check_host_in_hostfile(SSH_SYSTEM_HOSTFILE, canonical_hostname, 53 client_host_key_e, client_host_key_n,
53 client_host_key_e, client_host_key_n, ke, kn); 54 ke, kn);
54 55
55 /* Check user host file unless ignored. */ 56 /* Check user host file unless ignored. */
56 if (host_status != HOST_OK && !options.ignore_user_known_hosts) { 57 if (host_status != HOST_OK && !options.ignore_user_known_hosts) {
57 struct stat st; 58 struct stat st;
58 char *user_hostfile = tilde_expand_filename(SSH_USER_HOSTFILE, pw->pw_uid); 59 char *user_hostfile = tilde_expand_filename(SSH_USER_HOSTFILE, pw->pw_uid);
59 /* Check file permissions of SSH_USER_HOSTFILE, 60 /* Check file permissions of SSH_USER_HOSTFILE, auth_rsa()
60 auth_rsa() did already check pw->pw_dir, but there is a race XXX */ 61 did already check pw->pw_dir, but there is a race XXX */
61 if (options.strict_modes && 62 if (options.strict_modes &&
62 (stat(user_hostfile, &st) == 0) && 63 (stat(user_hostfile, &st) == 0) &&
63 ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || 64 ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
64 (st.st_mode & 022) != 0)) { 65 (st.st_mode & 022) != 0)) {
65 log("Rhosts RSA authentication refused for %.100s: bad owner or modes for %.200s", 66 log("Rhosts RSA authentication refused for %.100s: bad owner or modes for %.200s",
66 pw->pw_name, user_hostfile); 67 pw->pw_name, user_hostfile);
67 } else { 68 } else {
68 /* XXX race between stat and the following open() */ 69 /* XXX race between stat and the following open() */
69 temporarily_use_uid(pw->pw_uid); 70 temporarily_use_uid(pw->pw_uid);
70 host_status = check_host_in_hostfile(user_hostfile, canonical_hostname, 71 host_status = check_host_in_hostfile(user_hostfile, canonical_hostname,
71 client_host_key_e, client_host_key_n, ke, kn); 72 client_host_key_e, client_host_key_n,
72 restore_uid(); 73 ke, kn);
73 } 74 restore_uid();
74 xfree(user_hostfile); 75 }
75 } 76 xfree(user_hostfile);
76 BN_free(ke); 77 }
77 BN_free(kn); 78 BN_free(ke);
78 79 BN_free(kn);
79 if (host_status != HOST_OK) { 80
80 /* The host key was not found. */ 81 if (host_status != HOST_OK) {
81 debug("Rhosts with RSA host authentication denied: unknown or invalid host key"); 82 debug("Rhosts with RSA host authentication denied: unknown or invalid host key");
82 packet_send_debug("Your host key cannot be verified: unknown or invalid host key."); 83 packet_send_debug("Your host key cannot be verified: unknown or invalid host key.");
83 return 0; 84 return 0;
84 } 85 }
85 86 /* A matching host key was found and is known. */
86 /* A matching host key was found and is known. */ 87
87 88 /* Perform the challenge-response dialog with the client for the host key. */
88 /* Perform the challenge-response dialog with the client for the host key. */ 89 if (!auth_rsa_challenge_dialog(client_host_key_e, client_host_key_n)) {
89 if (!auth_rsa_challenge_dialog(client_host_key_e, client_host_key_n)) 90 log("Client on %.800s failed to respond correctly to host authentication.",
90 { 91 canonical_hostname);
91 log("Client on %.800s failed to respond correctly to host authentication.", 92 return 0;
92 canonical_hostname); 93 }
93 return 0; 94 /* We have authenticated the user using .rhosts or /etc/hosts.equiv, and the host using RSA.
94 } 95 We accept the authentication. */
95 96
96 /* We have authenticated the user using .rhosts or /etc/hosts.equiv, and 97 verbose("Rhosts with RSA host authentication accepted for %.100s, %.100s on %.700s.",
97 the host using RSA. We accept the authentication. */ 98 pw->pw_name, client_user, canonical_hostname);
98 99 packet_send_debug("Rhosts with RSA host authentication accepted.");
99 log("Rhosts with RSA host authentication accepted for %.100s, %.100s on %.700s.", 100 return 1;
100 pw->pw_name, client_user, canonical_hostname);
101 packet_send_debug("Rhosts with RSA host authentication accepted.");
102 return 1;
103} 101}
diff --git a/auth-rhosts.c b/auth-rhosts.c
index dc82849be..500dcebb1 100644
--- a/auth-rhosts.c
+++ b/auth-rhosts.c
@@ -1,22 +1,22 @@
1/* 1/*
2 2 *
3auth-rhosts.c 3 * auth-rhosts.c
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Fri Mar 17 05:12:18 1995 ylo 10 * Created: Fri Mar 17 05:12:18 1995 ylo
11 11 *
12Rhosts authentication. This file contains code to check whether to admit 12 * Rhosts authentication. This file contains code to check whether to admit
13the login based on rhosts authentication. This file also processes 13 * the login based on rhosts authentication. This file also processes
14/etc/hosts.equiv. 14 * /etc/hosts.equiv.
15 15 *
16*/ 16 */
17 17
18#include "includes.h" 18#include "includes.h"
19RCSID("$Id: auth-rhosts.c,v 1.4 1999/11/18 21:25:48 damien Exp $"); 19RCSID("$Id: auth-rhosts.c,v 1.5 1999/11/24 13:26:21 damien Exp $");
20 20
21#include "packet.h" 21#include "packet.h"
22#include "ssh.h" 22#include "ssh.h"
@@ -28,256 +28,228 @@ RCSID("$Id: auth-rhosts.c,v 1.4 1999/11/18 21:25:48 damien Exp $");
28 /etc/hosts.equiv). This returns true if authentication can be granted 28 /etc/hosts.equiv). This returns true if authentication can be granted
29 based on the file, and returns zero otherwise. */ 29 based on the file, and returns zero otherwise. */
30 30
31int check_rhosts_file(const char *filename, const char *hostname, 31int
32 const char *ipaddr, const char *client_user, 32check_rhosts_file(const char *filename, const char *hostname,
33 const char *server_user) 33 const char *ipaddr, const char *client_user,
34 const char *server_user)
34{ 35{
35 FILE *f; 36 FILE *f;
36 char buf[1024]; /* Must not be larger than host, user, dummy below. */ 37 char buf[1024]; /* Must not be larger than host, user, dummy below. */
37 38
38 /* Open the .rhosts file. */ 39 /* Open the .rhosts file, deny if unreadable */
39 f = fopen(filename, "r"); 40 f = fopen(filename, "r");
40 if (!f) 41 if (!f)
41 return 0; /* Cannot read the .rhosts - deny access. */ 42 return 0;
42 43
43 /* Go through the file, checking every entry. */ 44 /* Go through the file, checking every entry. */
44 while (fgets(buf, sizeof(buf), f)) 45 while (fgets(buf, sizeof(buf), f)) {
45 { 46 /* All three must be at least as big as buf to avoid overflows. */
46 /* All three must be at least as big as buf to avoid overflows. */ 47 char hostbuf[1024], userbuf[1024], dummy[1024], *host, *user, *cp;
47 char hostbuf[1024], userbuf[1024], dummy[1024], *host, *user, *cp; 48 int negated;
48 int negated; 49
49 50 for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)
50 for (cp = buf; *cp == ' ' || *cp == '\t'; cp++) 51 ;
51 ; 52 if (*cp == '#' || *cp == '\n' || !*cp)
52 if (*cp == '#' || *cp == '\n' || !*cp) 53 continue;
53 continue; 54
54 55 /* NO_PLUS is supported at least on OSF/1. We skip it (we
55 /* NO_PLUS is supported at least on OSF/1. We skip it (we don't ever 56 don't ever support the plus syntax). */
56 support the plus syntax). */ 57 if (strncmp(cp, "NO_PLUS", 7) == 0)
57 if (strncmp(cp, "NO_PLUS", 7) == 0) 58 continue;
58 continue; 59
59 60 /* This should be safe because each buffer is as big as
60 /* This should be safe because each buffer is as big as the whole 61 the whole string, and thus cannot be overwritten. */
61 string, and thus cannot be overwritten. */ 62 switch (sscanf(buf, "%s %s %s", hostbuf, userbuf, dummy)) {
62 switch (sscanf(buf, "%s %s %s", hostbuf, userbuf, dummy)) 63 case 0:
63 { 64 packet_send_debug("Found empty line in %.100s.", filename);
64 case 0: 65 continue;
65 packet_send_debug("Found empty line in %.100s.", filename); 66 case 1:
66 continue; /* Empty line? */ 67 /* Host name only. */
67 case 1: 68 strlcpy(userbuf, server_user, sizeof(userbuf));
68 /* Host name only. */ 69 break;
69 strlcpy(userbuf, server_user, sizeof(userbuf)); 70 case 2:
70 break; 71 /* Got both host and user name. */
71 case 2: 72 break;
72 /* Got both host and user name. */ 73 case 3:
73 break; 74 packet_send_debug("Found garbage in %.100s.", filename);
74 case 3: 75 continue;
75 packet_send_debug("Found garbage in %.100s.", filename); 76 default:
76 continue; /* Extra garbage */ 77 /* Weird... */
77 default: 78 continue;
78 continue; /* Weird... */ 79 }
79 } 80
80 81 host = hostbuf;
81 host = hostbuf; 82 user = userbuf;
82 user = userbuf; 83 negated = 0;
83 negated = 0; 84
84 85 /* Process negated host names, or positive netgroups. */
85 /* Process negated host names, or positive netgroups. */ 86 if (host[0] == '-') {
86 if (host[0] == '-') 87 negated = 1;
87 { 88 host++;
88 negated = 1; 89 } else if (host[0] == '+')
89 host++; 90 host++;
90 } 91
91 else 92 if (user[0] == '-') {
92 if (host[0] == '+') 93 negated = 1;
93 host++; 94 user++;
94 95 } else if (user[0] == '+')
95 if (user[0] == '-') 96 user++;
96 { 97
97 negated = 1; 98 /* Check for empty host/user names (particularly '+'). */
98 user++; 99 if (!host[0] || !user[0]) {
99 } 100 /* We come here if either was '+' or '-'. */
100 else 101 packet_send_debug("Ignoring wild host/user names in %.100s.",
101 if (user[0] == '+') 102 filename);
102 user++; 103 continue;
103 104 }
104 /* Check for empty host/user names (particularly '+'). */ 105 /* Verify that host name matches. */
105 if (!host[0] || !user[0]) 106 if (host[0] == '@') {
106 { 107 if (!innetgr(host + 1, hostname, NULL, NULL) &&
107 /* We come here if either was '+' or '-'. */ 108 !innetgr(host + 1, ipaddr, NULL, NULL))
108 packet_send_debug("Ignoring wild host/user names in %.100s.", 109 continue;
109 filename); 110 } else if (strcasecmp(host, hostname) && strcmp(host, ipaddr) != 0)
110 continue; 111 continue; /* Different hostname. */
111 } 112
112 113 /* Verify that user name matches. */
113 /* Verify that host name matches. */ 114 if (user[0] == '@') {
114 if (host[0] == '@') 115 if (!innetgr(user + 1, NULL, client_user, NULL))
115 { 116 continue;
116 if (!innetgr(host + 1, hostname, NULL, NULL) && 117 } else if (strcmp(user, client_user) != 0)
117 !innetgr(host + 1, ipaddr, NULL, NULL)) 118 continue; /* Different username. */
118 continue; 119
119 } 120 /* Found the user and host. */
120 else 121 fclose(f);
121 if (strcasecmp(host, hostname) && strcmp(host, ipaddr) != 0) 122
122 continue; /* Different hostname. */ 123 /* If the entry was negated, deny access. */
123 124 if (negated) {
124 /* Verify that user name matches. */ 125 packet_send_debug("Matched negative entry in %.100s.",
125 if (user[0] == '@') 126 filename);
126 { 127 return 0;
127 if (!innetgr(user + 1, NULL, client_user, NULL)) 128 }
128 continue; 129 /* Accept authentication. */
130 return 1;
129 } 131 }
130 else
131 if (strcmp(user, client_user) != 0)
132 continue; /* Different username. */
133 132
134 /* Found the user and host. */ 133 /* Authentication using this file denied. */
135 fclose(f); 134 fclose(f);
136 135 return 0;
137 /* If the entry was negated, deny access. */
138 if (negated)
139 {
140 packet_send_debug("Matched negative entry in %.100s.",
141 filename);
142 return 0;
143 }
144
145 /* Accept authentication. */
146 return 1;
147 }
148
149 /* Authentication using this file denied. */
150 fclose(f);
151 return 0;
152} 136}
153 137
154/* Tries to authenticate the user using the .shosts or .rhosts file. 138/* Tries to authenticate the user using the .shosts or .rhosts file.
155 Returns true if authentication succeeds. If ignore_rhosts is 139 Returns true if authentication succeeds. If ignore_rhosts is
156 true, only /etc/hosts.equiv will be considered (.rhosts and .shosts 140 true, only /etc/hosts.equiv will be considered (.rhosts and .shosts
157 are ignored). */ 141 are ignored). */
158 142
159int auth_rhosts(struct passwd *pw, const char *client_user) 143int
144auth_rhosts(struct passwd *pw, const char *client_user)
160{ 145{
161 extern ServerOptions options; 146 extern ServerOptions options;
162 char buf[1024]; 147 char buf[1024];
163 const char *hostname, *ipaddr; 148 const char *hostname, *ipaddr;
164 struct stat st; 149 struct stat st;
165 static const char *rhosts_files[] = { ".shosts", ".rhosts", NULL }; 150 static const char *rhosts_files[] = {".shosts", ".rhosts", NULL};
166 unsigned int rhosts_file_index; 151 unsigned int rhosts_file_index;
167 152
168 /* Quick check: if the user has no .shosts or .rhosts files, return failure 153 /* Quick check: if the user has no .shosts or .rhosts files,
169 immediately without doing costly lookups from name servers. */ 154 return failure immediately without doing costly lookups from
170 /* Switch to the user's uid. */ 155 name servers. */
171 temporarily_use_uid(pw->pw_uid); 156 /* Switch to the user's uid. */
172 for (rhosts_file_index = 0; rhosts_files[rhosts_file_index]; 157 temporarily_use_uid(pw->pw_uid);
173 rhosts_file_index++) 158 for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];
174 { 159 rhosts_file_index++) {
175 /* Check users .rhosts or .shosts. */ 160 /* Check users .rhosts or .shosts. */
176 snprintf(buf, sizeof buf, "%.500s/%.100s", 161 snprintf(buf, sizeof buf, "%.500s/%.100s",
177 pw->pw_dir, rhosts_files[rhosts_file_index]); 162 pw->pw_dir, rhosts_files[rhosts_file_index]);
178 if (stat(buf, &st) >= 0) 163 if (stat(buf, &st) >= 0)
179 break; 164 break;
180 }
181 /* Switch back to privileged uid. */
182 restore_uid();
183
184 if (!rhosts_files[rhosts_file_index] && stat("/etc/hosts.equiv", &st) < 0 &&
185 stat(SSH_HOSTS_EQUIV, &st) < 0)
186 return 0; /* The user has no .shosts or .rhosts file and there are no
187 system-wide files. */
188
189 /* Get the name, address, and port of the remote host. */
190 hostname = get_canonical_hostname();
191 ipaddr = get_remote_ipaddr();
192
193 /* If not logging in as superuser, try /etc/hosts.equiv and shosts.equiv. */
194 if (pw->pw_uid != 0)
195 {
196 if (check_rhosts_file("/etc/hosts.equiv", hostname, ipaddr, client_user,
197 pw->pw_name))
198 {
199 packet_send_debug("Accepted for %.100s [%.100s] by /etc/hosts.equiv.",
200 hostname, ipaddr);
201 return 1;
202 } 165 }
203 if (check_rhosts_file(SSH_HOSTS_EQUIV, hostname, ipaddr, client_user, 166 /* Switch back to privileged uid. */
204 pw->pw_name)) 167 restore_uid();
205 { 168
206 packet_send_debug("Accepted for %.100s [%.100s] by %.100s.", 169 /* Deny if The user has no .shosts or .rhosts file and there are no system-wide files. */
207 hostname, ipaddr, SSH_HOSTS_EQUIV); 170 if (!rhosts_files[rhosts_file_index] &&
208 return 1; 171 stat("/etc/hosts.equiv", &st) < 0 &&
172 stat(SSH_HOSTS_EQUIV, &st) < 0)
173 return 0;
174
175 /* Get the name, address, and port of the remote host. */
176 hostname = get_canonical_hostname();
177 ipaddr = get_remote_ipaddr();
178
179 /* If not logging in as superuser, try /etc/hosts.equiv and shosts.equiv. */
180 if (pw->pw_uid != 0) {
181 if (check_rhosts_file("/etc/hosts.equiv", hostname, ipaddr, client_user,
182 pw->pw_name)) {
183 packet_send_debug("Accepted for %.100s [%.100s] by /etc/hosts.equiv.",
184 hostname, ipaddr);
185 return 1;
186 }
187 if (check_rhosts_file(SSH_HOSTS_EQUIV, hostname, ipaddr, client_user,
188 pw->pw_name)) {
189 packet_send_debug("Accepted for %.100s [%.100s] by %.100s.",
190 hostname, ipaddr, SSH_HOSTS_EQUIV);
191 return 1;
192 }
209 } 193 }
210 } 194 /* Check that the home directory is owned by root or the user, and
211 195 is not group or world writable. */
212 /* Check that the home directory is owned by root or the user, and is not 196 if (stat(pw->pw_dir, &st) < 0) {
213 group or world writable. */ 197 log("Rhosts authentication refused for %.100s: no home directory %.200s",
214 if (stat(pw->pw_dir, &st) < 0) 198 pw->pw_name, pw->pw_dir);
215 { 199 packet_send_debug("Rhosts authentication refused for %.100: no home directory %.200s",
216 log("Rhosts authentication refused for %.100s: no home directory %.200s", 200 pw->pw_name, pw->pw_dir);
217 pw->pw_name, pw->pw_dir); 201 return 0;
218 packet_send_debug("Rhosts authentication refused for %.100: no home directory %.200s",
219 pw->pw_name, pw->pw_dir);
220 return 0;
221 }
222 if (options.strict_modes &&
223 ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
224 (st.st_mode & 022) != 0))
225 {
226 log("Rhosts authentication refused for %.100s: bad ownership or modes for home directory.",
227 pw->pw_name);
228 packet_send_debug("Rhosts authentication refused for %.100s: bad ownership or modes for home directory.",
229 pw->pw_name);
230 return 0;
231 }
232
233 /* Check all .rhosts files (currently .shosts and .rhosts). */
234 /* Temporarily use the user's uid. */
235 temporarily_use_uid(pw->pw_uid);
236 for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];
237 rhosts_file_index++)
238 {
239 /* Check users .rhosts or .shosts. */
240 snprintf(buf, sizeof buf, "%.500s/%.100s",
241 pw->pw_dir, rhosts_files[rhosts_file_index]);
242 if (stat(buf, &st) < 0)
243 continue; /* No such file. */
244
245 /* Make sure that the file is either owned by the user or by root,
246 and make sure it is not writable by anyone but the owner. This is
247 to help avoid novices accidentally allowing access to their account
248 by anyone. */
249 if (options.strict_modes &&
250 ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
251 (st.st_mode & 022) != 0))
252 {
253 log("Rhosts authentication refused for %.100s: bad modes for %.200s",
254 pw->pw_name, buf);
255 packet_send_debug("Bad file modes for %.200s", buf);
256 continue;
257 } 202 }
258 203 if (options.strict_modes &&
259 /* Check if we have been configured to ignore .rhosts and .shosts 204 ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
260 files. */ 205 (st.st_mode & 022) != 0)) {
261 if (options.ignore_rhosts) 206 log("Rhosts authentication refused for %.100s: bad ownership or modes for home directory.",
262 { 207 pw->pw_name);
263 packet_send_debug("Server has been configured to ignore %.100s.", 208 packet_send_debug("Rhosts authentication refused for %.100s: bad ownership or modes for home directory.",
264 rhosts_files[rhosts_file_index]); 209 pw->pw_name);
265 continue; 210 return 0;
266 } 211 }
267 212 /* Temporarily use the user's uid. */
268 /* Check if authentication is permitted by the file. */ 213 temporarily_use_uid(pw->pw_uid);
269 if (check_rhosts_file(buf, hostname, ipaddr, client_user, pw->pw_name)) 214
270 { 215 /* Check all .rhosts files (currently .shosts and .rhosts). */
271 packet_send_debug("Accepted by %.100s.", 216 for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];
272 rhosts_files[rhosts_file_index]); 217 rhosts_file_index++) {
273 /* Restore the privileged uid. */ 218 /* Check users .rhosts or .shosts. */
274 restore_uid(); 219 snprintf(buf, sizeof buf, "%.500s/%.100s",
275 return 1; 220 pw->pw_dir, rhosts_files[rhosts_file_index]);
221 if (stat(buf, &st) < 0)
222 continue;
223
224 /* Make sure that the file is either owned by the user or
225 by root, and make sure it is not writable by anyone but
226 the owner. This is to help avoid novices accidentally
227 allowing access to their account by anyone. */
228 if (options.strict_modes &&
229 ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
230 (st.st_mode & 022) != 0)) {
231 log("Rhosts authentication refused for %.100s: bad modes for %.200s",
232 pw->pw_name, buf);
233 packet_send_debug("Bad file modes for %.200s", buf);
234 continue;
235 }
236 /* Check if we have been configured to ignore .rhosts and .shosts files. */
237 if (options.ignore_rhosts) {
238 packet_send_debug("Server has been configured to ignore %.100s.",
239 rhosts_files[rhosts_file_index]);
240 continue;
241 }
242 /* Check if authentication is permitted by the file. */
243 if (check_rhosts_file(buf, hostname, ipaddr, client_user, pw->pw_name)) {
244 packet_send_debug("Accepted by %.100s.",
245 rhosts_files[rhosts_file_index]);
246 /* Restore the privileged uid. */
247 restore_uid();
248 return 1;
249 }
276 } 250 }
277 }
278 251
279 /* Rhosts authentication denied. */ 252 /* Restore the privileged uid. */
280 /* Restore the privileged uid. */ 253 restore_uid();
281 restore_uid(); 254 return 0;
282 return 0;
283} 255}
diff --git a/auth-rsa.c b/auth-rsa.c
index f2295078b..88841482b 100644
--- a/auth-rsa.c
+++ b/auth-rsa.c
@@ -1,22 +1,22 @@
1/* 1/*
2 2 *
3auth-rsa.c 3 * auth-rsa.c
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Mon Mar 27 01:46:52 1995 ylo 10 * Created: Mon Mar 27 01:46:52 1995 ylo
11 11 *
12RSA-based authentication. This code determines whether to admit a login 12 * RSA-based authentication. This code determines whether to admit a login
13based on RSA authentication. This file also contains functions to check 13 * based on RSA authentication. This file also contains functions to check
14validity of the host key. 14 * validity of the host key.
15 15 *
16*/ 16 */
17 17
18#include "includes.h" 18#include "includes.h"
19RCSID("$Id: auth-rsa.c,v 1.8 1999/11/18 21:25:48 damien Exp $"); 19RCSID("$Id: auth-rsa.c,v 1.9 1999/11/24 13:26:21 damien Exp $");
20 20
21#include "rsa.h" 21#include "rsa.h"
22#include "packet.h" 22#include "packet.h"
@@ -50,7 +50,7 @@ extern unsigned char session_id[16];
50/* The .ssh/authorized_keys file contains public keys, one per line, in the 50/* The .ssh/authorized_keys file contains public keys, one per line, in the
51 following format: 51 following format:
52 options bits e n comment 52 options bits e n comment
53 where bits, e and n are decimal numbers, 53 where bits, e and n are decimal numbers,
54 and comment is any string of characters up to newline. The maximum 54 and comment is any string of characters up to newline. The maximum
55 length of a line is 8000 characters. See the documentation for a 55 length of a line is 8000 characters. See the documentation for a
56 description of the options. 56 description of the options.
@@ -63,71 +63,69 @@ extern unsigned char session_id[16];
63int 63int
64auth_rsa_challenge_dialog(BIGNUM *e, BIGNUM *n) 64auth_rsa_challenge_dialog(BIGNUM *e, BIGNUM *n)
65{ 65{
66 BIGNUM *challenge, *encrypted_challenge, *aux; 66 BIGNUM *challenge, *encrypted_challenge, *aux;
67 RSA *pk; 67 RSA *pk;
68 BN_CTX *ctx = BN_CTX_new(); 68 BN_CTX *ctx = BN_CTX_new();
69 unsigned char buf[32], mdbuf[16], response[16]; 69 unsigned char buf[32], mdbuf[16], response[16];
70 MD5_CTX md; 70 MD5_CTX md;
71 unsigned int i; 71 unsigned int i;
72 int plen, len; 72 int plen, len;
73 73
74 encrypted_challenge = BN_new(); 74 encrypted_challenge = BN_new();
75 challenge = BN_new(); 75 challenge = BN_new();
76 aux = BN_new(); 76 aux = BN_new();
77 77
78 /* Generate a random challenge. */ 78 /* Generate a random challenge. */
79 BN_rand(challenge, 256, 0, 0); 79 BN_rand(challenge, 256, 0, 0);
80 BN_mod(challenge, challenge, n, ctx); 80 BN_mod(challenge, challenge, n, ctx);
81 81
82 /* Create the public key data structure. */ 82 /* Create the public key data structure. */
83 pk = RSA_new(); 83 pk = RSA_new();
84 pk->e = BN_new(); 84 pk->e = BN_new();
85 BN_copy(pk->e, e); 85 BN_copy(pk->e, e);
86 pk->n = BN_new(); 86 pk->n = BN_new();
87 BN_copy(pk->n, n); 87 BN_copy(pk->n, n);
88 88
89 /* Encrypt the challenge with the public key. */ 89 /* Encrypt the challenge with the public key. */
90 rsa_public_encrypt(encrypted_challenge, challenge, pk); 90 rsa_public_encrypt(encrypted_challenge, challenge, pk);
91 RSA_free(pk); 91 RSA_free(pk);
92 92
93 /* Send the encrypted challenge to the client. */ 93 /* Send the encrypted challenge to the client. */
94 packet_start(SSH_SMSG_AUTH_RSA_CHALLENGE); 94 packet_start(SSH_SMSG_AUTH_RSA_CHALLENGE);
95 packet_put_bignum(encrypted_challenge); 95 packet_put_bignum(encrypted_challenge);
96 packet_send(); 96 packet_send();
97 packet_write_wait(); 97 packet_write_wait();
98 98
99 /* The response is MD5 of decrypted challenge plus session id. */ 99 /* The response is MD5 of decrypted challenge plus session id. */
100 len = BN_num_bytes(challenge); 100 len = BN_num_bytes(challenge);
101 if (len <= 0 || len > 32) 101 if (len <= 0 || len > 32)
102 fatal("auth_rsa_challenge_dialog: bad challenge length %d", len); 102 fatal("auth_rsa_challenge_dialog: bad challenge length %d", len);
103 memset(buf, 0, 32); 103 memset(buf, 0, 32);
104 BN_bn2bin(challenge, buf + 32 - len); 104 BN_bn2bin(challenge, buf + 32 - len);
105 MD5_Init(&md); 105 MD5_Init(&md);
106 MD5_Update(&md, buf, 32); 106 MD5_Update(&md, buf, 32);
107 MD5_Update(&md, session_id, 16); 107 MD5_Update(&md, session_id, 16);
108 MD5_Final(mdbuf, &md); 108 MD5_Final(mdbuf, &md);
109 109
110 /* We will no longer need these. */ 110 /* We will no longer need these. */
111 BN_clear_free(encrypted_challenge); 111 BN_clear_free(encrypted_challenge);
112 BN_clear_free(challenge); 112 BN_clear_free(challenge);
113 BN_clear_free(aux); 113 BN_clear_free(aux);
114 BN_CTX_free(ctx); 114 BN_CTX_free(ctx);
115 115
116 /* Wait for a response. */ 116 /* Wait for a response. */
117 packet_read_expect(&plen, SSH_CMSG_AUTH_RSA_RESPONSE); 117 packet_read_expect(&plen, SSH_CMSG_AUTH_RSA_RESPONSE);
118 packet_integrity_check(plen, 16, SSH_CMSG_AUTH_RSA_RESPONSE); 118 packet_integrity_check(plen, 16, SSH_CMSG_AUTH_RSA_RESPONSE);
119 for (i = 0; i < 16; i++) 119 for (i = 0; i < 16; i++)
120 response[i] = packet_get_char(); 120 response[i] = packet_get_char();
121 121
122 /* Verify that the response is the original challenge. */ 122 /* Verify that the response is the original challenge. */
123 if (memcmp(response, mdbuf, 16) != 0) 123 if (memcmp(response, mdbuf, 16) != 0) {
124 { 124 /* Wrong answer. */
125 /* Wrong answer. */ 125 return 0;
126 return 0; 126 }
127 } 127 /* Correct answer. */
128 128 return 1;
129 /* Correct answer. */
130 return 1;
131} 129}
132 130
133/* Performs the RSA authentication dialog with the client. This returns 131/* Performs the RSA authentication dialog with the client. This returns
@@ -137,357 +135,324 @@ auth_rsa_challenge_dialog(BIGNUM *e, BIGNUM *n)
137int 135int
138auth_rsa(struct passwd *pw, BIGNUM *client_n) 136auth_rsa(struct passwd *pw, BIGNUM *client_n)
139{ 137{
140 extern ServerOptions options; 138 extern ServerOptions options;
141 char line[8192], file[1024]; 139 char line[8192], file[1024];
142 int authenticated; 140 int authenticated;
143 unsigned int bits; 141 unsigned int bits;
144 FILE *f; 142 FILE *f;
145 unsigned long linenum = 0; 143 unsigned long linenum = 0;
146 struct stat st; 144 struct stat st;
147 BIGNUM *e, *n; 145 BIGNUM *e, *n;
148 146
149 /* Temporarily use the user's uid. */ 147 /* Temporarily use the user's uid. */
150 temporarily_use_uid(pw->pw_uid); 148 temporarily_use_uid(pw->pw_uid);
151 149
152 /* The authorized keys. */ 150 /* The authorized keys. */
153 snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir, 151 snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
154 SSH_USER_PERMITTED_KEYS); 152 SSH_USER_PERMITTED_KEYS);
155 153
156 /* Fail quietly if file does not exist */ 154 /* Fail quietly if file does not exist */
157 if (stat(file, &st) < 0) 155 if (stat(file, &st) < 0) {
158 { 156 /* Restore the privileged uid. */
159 /* Restore the privileged uid. */ 157 restore_uid();
160 restore_uid(); 158 return 0;
161 return 0;
162 }
163
164 /* Open the file containing the authorized keys. */
165 f = fopen(file, "r");
166 if (!f)
167 {
168 /* Restore the privileged uid. */
169 restore_uid();
170 packet_send_debug("Could not open %.900s for reading.", file);
171 packet_send_debug("If your home is on an NFS volume, it may need to be world-readable.");
172 return 0;
173 }
174
175 if (options.strict_modes) {
176 int fail=0;
177 char buf[1024];
178 /* Check open file in order to avoid open/stat races */
179 if (fstat(fileno(f), &st) < 0 ||
180 (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
181 (st.st_mode & 022) != 0) {
182 snprintf(buf, sizeof buf, "RSA authentication refused for %.100s: "
183 "bad ownership or modes for '%s'.", pw->pw_name, file);
184 fail=1;
185 }else{
186 /* Check path to SSH_USER_PERMITTED_KEYS */
187 int i;
188 static const char *check[] = {
189 "", SSH_USER_DIR, NULL
190 };
191 for (i=0; check[i]; i++) {
192 snprintf(line, sizeof line, "%.500s/%.100s", pw->pw_dir, check[i]);
193 if (stat(line, &st) < 0 ||
194 (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
195 (st.st_mode & 022) != 0) {
196 snprintf(buf, sizeof buf, "RSA authentication refused for %.100s: "
197 "bad ownership or modes for '%s'.", pw->pw_name, line);
198 fail=1;
199 break;
200 }
201 }
202 }
203 if (fail) {
204 log(buf);
205 packet_send_debug(buf);
206 restore_uid();
207 return 0;
208 }
209 }
210
211 /* Flag indicating whether authentication has succeeded. */
212 authenticated = 0;
213
214 /* Initialize mp-int variables. */
215 e = BN_new();
216 n = BN_new();
217
218 /* Go though the accepted keys, looking for the current key. If found,
219 perform a challenge-response dialog to verify that the user really has
220 the corresponding private key. */
221 while (fgets(line, sizeof(line), f))
222 {
223 char *cp;
224 char *options;
225
226 linenum++;
227
228 /* Skip leading whitespace. */
229 for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
230 ;
231
232 /* Skip empty and comment lines. */
233 if (!*cp || *cp == '\n' || *cp == '#')
234 continue;
235
236 /* Check if there are options for this key, and if so, save their
237 starting address and skip the option part for now. If there are no
238 options, set the starting address to NULL. */
239 if (*cp < '0' || *cp > '9')
240 {
241 int quoted = 0;
242 options = cp;
243 for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++)
244 {
245 if (*cp == '\\' && cp[1] == '"')
246 cp++; /* Skip both */
247 else
248 if (*cp == '"')
249 quoted = !quoted;
250 }
251 } 159 }
252 else 160 /* Open the file containing the authorized keys. */
253 options = NULL; 161 f = fopen(file, "r");
254 162 if (!f) {
255 /* Parse the key from the line. */ 163 /* Restore the privileged uid. */
256 if (!auth_rsa_read_key(&cp, &bits, e, n)) 164 restore_uid();
257 { 165 packet_send_debug("Could not open %.900s for reading.", file);
258 debug("%.100s, line %lu: bad key syntax", 166 packet_send_debug("If your home is on an NFS volume, it may need to be world-readable.");
259 SSH_USER_PERMITTED_KEYS, linenum); 167 return 0;
260 packet_send_debug("%.100s, line %lu: bad key syntax",
261 SSH_USER_PERMITTED_KEYS, linenum);
262 continue;
263 } 168 }
264 /* cp now points to the comment part. */ 169 if (options.strict_modes) {
265 170 int fail = 0;
266 /* check the real bits */ 171 char buf[1024];
267 if (bits != BN_num_bits(n)) 172 /* Check open file in order to avoid open/stat races */
268 error("Warning: error in %s, line %ld: keysize mismatch: " 173 if (fstat(fileno(f), &st) < 0 ||
269 "actual size %d vs. announced %d.", 174 (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
270 file, linenum, BN_num_bits(n), bits); 175 (st.st_mode & 022) != 0) {
271 176 snprintf(buf, sizeof buf, "RSA authentication refused for %.100s: "
272 /* Check if the we have found the desired key (identified by its 177 "bad ownership or modes for '%s'.", pw->pw_name, file);
273 modulus). */ 178 fail = 1;
274 if (BN_cmp(n, client_n) != 0) 179 } else {
275 continue; /* Wrong key. */ 180 /* Check path to SSH_USER_PERMITTED_KEYS */
276 181 int i;
277 /* We have found the desired key. */ 182 static const char *check[] = {
278 183 "", SSH_USER_DIR, NULL
279 /* Perform the challenge-response dialog for this key. */ 184 };
280 if (!auth_rsa_challenge_dialog(e, n)) 185 for (i = 0; check[i]; i++) {
281 { 186 snprintf(line, sizeof line, "%.500s/%.100s", pw->pw_dir, check[i]);
282 /* Wrong response. */ 187 if (stat(line, &st) < 0 ||
283 log("Wrong response to RSA authentication challenge."); 188 (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
284 packet_send_debug("Wrong response to RSA authentication challenge."); 189 (st.st_mode & 022) != 0) {
285 continue; 190 snprintf(buf, sizeof buf, "RSA authentication refused for %.100s: "
286 } 191 "bad ownership or modes for '%s'.", pw->pw_name, line);
287 192 fail = 1;
288 /* Correct response. The client has been successfully authenticated. 193 break;
289 Note that we have not yet processed the options; this will be reset 194 }
290 if the options cause the authentication to be rejected. */ 195 }
291 authenticated = 1;
292
293 /* RSA part of authentication was accepted. Now process the options. */
294 if (options)
295 {
296 while (*options && *options != ' ' && *options != '\t')
297 {
298 cp = "no-port-forwarding";
299 if (strncmp(options, cp, strlen(cp)) == 0)
300 {
301 packet_send_debug("Port forwarding disabled.");
302 no_port_forwarding_flag = 1;
303 options += strlen(cp);
304 goto next_option;
305 }
306 cp = "no-agent-forwarding";
307 if (strncmp(options, cp, strlen(cp)) == 0)
308 {
309 packet_send_debug("Agent forwarding disabled.");
310 no_agent_forwarding_flag = 1;
311 options += strlen(cp);
312 goto next_option;
313 }
314 cp = "no-X11-forwarding";
315 if (strncmp(options, cp, strlen(cp)) == 0)
316 {
317 packet_send_debug("X11 forwarding disabled.");
318 no_x11_forwarding_flag = 1;
319 options += strlen(cp);
320 goto next_option;
321 } 196 }
322 cp = "no-pty"; 197 if (fail) {
323 if (strncmp(options, cp, strlen(cp)) == 0) 198 log(buf);
324 { 199 packet_send_debug(buf);
325 packet_send_debug("Pty allocation disabled."); 200 restore_uid();
326 no_pty_flag = 1; 201 return 0;
327 options += strlen(cp);
328 goto next_option;
329 } 202 }
330 cp = "command=\""; 203 }
331 if (strncmp(options, cp, strlen(cp)) == 0) 204 /* Flag indicating whether authentication has succeeded. */
332 { 205 authenticated = 0;
333 int i; 206
334 options += strlen(cp); 207 /* Initialize mp-int variables. */
335 forced_command = xmalloc(strlen(options) + 1); 208 e = BN_new();
336 i = 0; 209 n = BN_new();
337 while (*options) 210
338 { 211 /* Go though the accepted keys, looking for the current key. If
339 if (*options == '"') 212 found, perform a challenge-response dialog to verify that the
340 break; 213 user really has the corresponding private key. */
341 if (*options == '\\' && options[1] == '"') 214 while (fgets(line, sizeof(line), f)) {
342 { 215 char *cp;
343 options += 2; 216 char *options;
344 forced_command[i++] = '"'; 217
345 continue; 218 linenum++;
219
220 /* Skip leading whitespace. */
221 for (cp = line; *cp == ' ' || *cp == '\t'; cp++);
222
223 /* Skip empty and comment lines. */
224 if (!*cp || *cp == '\n' || *cp == '#')
225 continue;
226
227 /* Check if there are options for this key, and if so,
228 save their starting address and skip the option part
229 for now. If there are no options, set the starting
230 address to NULL. */
231 if (*cp < '0' || *cp > '9') {
232 int quoted = 0;
233 options = cp;
234 for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
235 if (*cp == '\\' && cp[1] == '"')
236 cp++; /* Skip both */
237 else if (*cp == '"')
238 quoted = !quoted;
346 } 239 }
347 forced_command[i++] = *options++; 240 } else
348 } 241 options = NULL;
349 if (!*options) 242
350 { 243 /* Parse the key from the line. */
351 debug("%.100s, line %lu: missing end quote", 244 if (!auth_rsa_read_key(&cp, &bits, e, n)) {
352 SSH_USER_PERMITTED_KEYS, linenum); 245 debug("%.100s, line %lu: bad key syntax",
353 packet_send_debug("%.100s, line %lu: missing end quote", 246 SSH_USER_PERMITTED_KEYS, linenum);
354 SSH_USER_PERMITTED_KEYS, linenum); 247 packet_send_debug("%.100s, line %lu: bad key syntax",
355 continue; 248 SSH_USER_PERMITTED_KEYS, linenum);
356 } 249 continue;
357 forced_command[i] = 0;
358 packet_send_debug("Forced command: %.900s", forced_command);
359 options++;
360 goto next_option;
361 } 250 }
362 cp = "environment=\""; 251 /* cp now points to the comment part. */
363 if (strncmp(options, cp, strlen(cp)) == 0) 252
364 { 253 /* check the real bits */
365 int i; 254 if (bits != BN_num_bits(n))
366 char *s; 255 error("Warning: error in %s, line %ld: keysize mismatch: "
367 struct envstring *new_envstring; 256 "actual size %d vs. announced %d.",
368 options += strlen(cp); 257 file, linenum, BN_num_bits(n), bits);
369 s = xmalloc(strlen(options) + 1); 258
370 i = 0; 259 /* Check if the we have found the desired key (identified by its modulus). */
371 while (*options) 260 if (BN_cmp(n, client_n) != 0)
372 { 261 continue; /* Wrong key. */
373 if (*options == '"') 262
374 break; 263 /* We have found the desired key. */
375 if (*options == '\\' && options[1] == '"') 264
376 { 265 /* Perform the challenge-response dialog for this key. */
377 options += 2; 266 if (!auth_rsa_challenge_dialog(e, n)) {
378 s[i++] = '"'; 267 /* Wrong response. */
379 continue; 268 verbose("Wrong response to RSA authentication challenge.");
380 } 269 packet_send_debug("Wrong response to RSA authentication challenge.");
381 s[i++] = *options++; 270 continue;
382 }
383 if (!*options)
384 {
385 debug("%.100s, line %lu: missing end quote",
386 SSH_USER_PERMITTED_KEYS, linenum);
387 packet_send_debug("%.100s, line %lu: missing end quote",
388 SSH_USER_PERMITTED_KEYS, linenum);
389 continue;
390 }
391 s[i] = 0;
392 packet_send_debug("Adding to environment: %.900s", s);
393 debug("Adding to environment: %.900s", s);
394 options++;
395 new_envstring = xmalloc(sizeof(struct envstring));
396 new_envstring->s = s;
397 new_envstring->next = custom_environment;
398 custom_environment = new_envstring;
399 goto next_option;
400 } 271 }
401 cp = "from=\""; 272 /* Correct response. The client has been successfully
402 if (strncmp(options, cp, strlen(cp)) == 0) 273 authenticated. Note that we have not yet processed the
403 { 274 options; this will be reset if the options cause the
404 char *patterns = xmalloc(strlen(options) + 1); 275 authentication to be rejected. */
405 int i; 276 authenticated = 1;
406 options += strlen(cp); 277
407 i = 0; 278 /* RSA part of authentication was accepted. Now process the options. */
408 while (*options) 279 if (options) {
409 { 280 while (*options && *options != ' ' && *options != '\t') {
410 if (*options == '"') 281 cp = "no-port-forwarding";
411 break; 282 if (strncmp(options, cp, strlen(cp)) == 0) {
412 if (*options == '\\' && options[1] == '"') 283 packet_send_debug("Port forwarding disabled.");
413 { 284 no_port_forwarding_flag = 1;
414 options += 2; 285 options += strlen(cp);
415 patterns[i++] = '"'; 286 goto next_option;
416 continue; 287 }
288 cp = "no-agent-forwarding";
289 if (strncmp(options, cp, strlen(cp)) == 0) {
290 packet_send_debug("Agent forwarding disabled.");
291 no_agent_forwarding_flag = 1;
292 options += strlen(cp);
293 goto next_option;
294 }
295 cp = "no-X11-forwarding";
296 if (strncmp(options, cp, strlen(cp)) == 0) {
297 packet_send_debug("X11 forwarding disabled.");
298 no_x11_forwarding_flag = 1;
299 options += strlen(cp);
300 goto next_option;
301 }
302 cp = "no-pty";
303 if (strncmp(options, cp, strlen(cp)) == 0) {
304 packet_send_debug("Pty allocation disabled.");
305 no_pty_flag = 1;
306 options += strlen(cp);
307 goto next_option;
308 }
309 cp = "command=\"";
310 if (strncmp(options, cp, strlen(cp)) == 0) {
311 int i;
312 options += strlen(cp);
313 forced_command = xmalloc(strlen(options) + 1);
314 i = 0;
315 while (*options) {
316 if (*options == '"')
317 break;
318 if (*options == '\\' && options[1] == '"') {
319 options += 2;
320 forced_command[i++] = '"';
321 continue;
322 }
323 forced_command[i++] = *options++;
324 }
325 if (!*options) {
326 debug("%.100s, line %lu: missing end quote",
327 SSH_USER_PERMITTED_KEYS, linenum);
328 packet_send_debug("%.100s, line %lu: missing end quote",
329 SSH_USER_PERMITTED_KEYS, linenum);
330 continue;
331 }
332 forced_command[i] = 0;
333 packet_send_debug("Forced command: %.900s", forced_command);
334 options++;
335 goto next_option;
336 }
337 cp = "environment=\"";
338 if (strncmp(options, cp, strlen(cp)) == 0) {
339 int i;
340 char *s;
341 struct envstring *new_envstring;
342 options += strlen(cp);
343 s = xmalloc(strlen(options) + 1);
344 i = 0;
345 while (*options) {
346 if (*options == '"')
347 break;
348 if (*options == '\\' && options[1] == '"') {
349 options += 2;
350 s[i++] = '"';
351 continue;
352 }
353 s[i++] = *options++;
354 }
355 if (!*options) {
356 debug("%.100s, line %lu: missing end quote",
357 SSH_USER_PERMITTED_KEYS, linenum);
358 packet_send_debug("%.100s, line %lu: missing end quote",
359 SSH_USER_PERMITTED_KEYS, linenum);
360 continue;
361 }
362 s[i] = 0;
363 packet_send_debug("Adding to environment: %.900s", s);
364 debug("Adding to environment: %.900s", s);
365 options++;
366 new_envstring = xmalloc(sizeof(struct envstring));
367 new_envstring->s = s;
368 new_envstring->next = custom_environment;
369 custom_environment = new_envstring;
370 goto next_option;
371 }
372 cp = "from=\"";
373 if (strncmp(options, cp, strlen(cp)) == 0) {
374 char *patterns = xmalloc(strlen(options) + 1);
375 int i;
376 options += strlen(cp);
377 i = 0;
378 while (*options) {
379 if (*options == '"')
380 break;
381 if (*options == '\\' && options[1] == '"') {
382 options += 2;
383 patterns[i++] = '"';
384 continue;
385 }
386 patterns[i++] = *options++;
387 }
388 if (!*options) {
389 debug("%.100s, line %lu: missing end quote",
390 SSH_USER_PERMITTED_KEYS, linenum);
391 packet_send_debug("%.100s, line %lu: missing end quote",
392 SSH_USER_PERMITTED_KEYS, linenum);
393 continue;
394 }
395 patterns[i] = 0;
396 options++;
397 if (!match_hostname(get_canonical_hostname(), patterns,
398 strlen(patterns)) &&
399 !match_hostname(get_remote_ipaddr(), patterns,
400 strlen(patterns))) {
401 log("RSA authentication tried for %.100s with correct key but not from a permitted host (host=%.200s, ip=%.200s).",
402 pw->pw_name, get_canonical_hostname(),
403 get_remote_ipaddr());
404 packet_send_debug("Your host '%.200s' is not permitted to use this key for login.",
405 get_canonical_hostname());
406 xfree(patterns);
407 authenticated = 0;
408 break;
409 }
410 xfree(patterns);
411 /* Host name matches. */
412 goto next_option;
413 }
414 bad_option:
415 /* Unknown option. */
416 log("Bad options in %.100s file, line %lu: %.50s",
417 SSH_USER_PERMITTED_KEYS, linenum, options);
418 packet_send_debug("Bad options in %.100s file, line %lu: %.50s",
419 SSH_USER_PERMITTED_KEYS, linenum, options);
420 authenticated = 0;
421 break;
422
423 next_option:
424 /* Skip the comma, and move to the next option
425 (or break out if there are no more). */
426 if (!*options)
427 fatal("Bugs in auth-rsa.c option processing.");
428 if (*options == ' ' || *options == '\t')
429 break; /* End of options. */
430 if (*options != ',')
431 goto bad_option;
432 options++;
433 /* Process the next option. */
434 continue;
417 } 435 }
418 patterns[i++] = *options++;
419 }
420 if (!*options)
421 {
422 debug("%.100s, line %lu: missing end quote",
423 SSH_USER_PERMITTED_KEYS, linenum);
424 packet_send_debug("%.100s, line %lu: missing end quote",
425 SSH_USER_PERMITTED_KEYS, linenum);
426 continue;
427 }
428 patterns[i] = 0;
429 options++;
430 if (!match_hostname(get_canonical_hostname(), patterns,
431 strlen(patterns)) &&
432 !match_hostname(get_remote_ipaddr(), patterns,
433 strlen(patterns)))
434 {
435 log("RSA authentication tried for %.100s with correct key but not from a permitted host (host=%.200s, ip=%.200s).",
436 pw->pw_name, get_canonical_hostname(),
437 get_remote_ipaddr());
438 packet_send_debug("Your host '%.200s' is not permitted to use this key for login.",
439 get_canonical_hostname());
440 xfree(patterns);
441 authenticated = 0;
442 break;
443 }
444 xfree(patterns);
445 /* Host name matches. */
446 goto next_option;
447 } 436 }
448 bad_option: 437 /* Break out of the loop if authentication was successful;
449 /* Unknown option. */ 438 otherwise continue searching. */
450 log("Bad options in %.100s file, line %lu: %.50s", 439 if (authenticated)
451 SSH_USER_PERMITTED_KEYS, linenum, options); 440 break;
452 packet_send_debug("Bad options in %.100s file, line %lu: %.50s",
453 SSH_USER_PERMITTED_KEYS, linenum, options);
454 authenticated = 0;
455 break;
456
457 next_option:
458 /* Skip the comma, and move to the next option (or break out
459 if there are no more). */
460 if (!*options)
461 fatal("Bugs in auth-rsa.c option processing.");
462 if (*options == ' ' || *options == '\t')
463 break; /* End of options. */
464 if (*options != ',')
465 goto bad_option;
466 options++;
467 /* Process the next option. */
468 continue;
469 }
470 } 441 }
471 442
472 /* Break out of the loop if authentication was successful; otherwise 443 /* Restore the privileged uid. */
473 continue searching. */ 444 restore_uid();
474 if (authenticated)
475 break;
476 }
477 445
478 /* Restore the privileged uid. */ 446 /* Close the file. */
479 restore_uid(); 447 fclose(f);
480 448
481 /* Close the file. */ 449 /* Clear any mp-int variables. */
482 fclose(f); 450 BN_clear_free(n);
483 451 BN_clear_free(e);
484 /* Clear any mp-int variables. */
485 BN_clear_free(n);
486 BN_clear_free(e);
487 452
488 if (authenticated) 453 if (authenticated)
489 packet_send_debug("RSA authentication accepted."); 454 packet_send_debug("RSA authentication accepted.");
490 455
491 /* Return authentication result. */ 456 /* Return authentication result. */
492 return authenticated; 457 return authenticated;
493} 458}
diff --git a/auth-skey.c b/auth-skey.c
index 66e09bb59..457100ccc 100644
--- a/auth-skey.c
+++ b/auth-skey.c
@@ -1,7 +1,8 @@
1#include "includes.h"
2
1#ifdef SKEY 3#ifdef SKEY
2 4
3#include "includes.h" 5RCSID("$Id: auth-skey.c,v 1.3 1999/11/23 22:25:52 markus Exp $");
4RCSID("$Id: auth-skey.c,v 1.2 1999/10/16 20:57:52 deraadt Exp $");
5 6
6#include "ssh.h" 7#include "ssh.h"
7#include <sha1.h> 8#include <sha1.h>
@@ -32,6 +33,7 @@ hash_collapse(s)
32 33
33 return i; 34 return i;
34} 35}
36
35char * 37char *
36skey_fake_keyinfo(char *username) 38skey_fake_keyinfo(char *username)
37{ 39{
@@ -150,4 +152,4 @@ skey_fake_keyinfo(char *username)
150 return skeyprompt; 152 return skeyprompt;
151} 153}
152 154
153#endif SKEY 155#endif /* SKEY */
diff --git a/authfd.c b/authfd.c
index 33d09908e..17b0668be 100644
--- a/authfd.c
+++ b/authfd.c
@@ -1,20 +1,20 @@
1/* 1/*
2 2 *
3authfd.c 3 * authfd.c
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Wed Mar 29 01:30:28 1995 ylo 10 * Created: Wed Mar 29 01:30:28 1995 ylo
11 11 *
12Functions for connecting the local authentication agent. 12 * Functions for connecting the local authentication agent.
13 13 *
14*/ 14 */
15 15
16#include "includes.h" 16#include "includes.h"
17RCSID("$Id: authfd.c,v 1.6 1999/11/18 21:25:48 damien Exp $"); 17RCSID("$Id: authfd.c,v 1.7 1999/11/24 13:26:21 damien Exp $");
18 18
19#include "ssh.h" 19#include "ssh.h"
20#include "rsa.h" 20#include "rsa.h"
@@ -36,45 +36,42 @@ RCSID("$Id: authfd.c,v 1.6 1999/11/18 21:25:48 damien Exp $");
36int 36int
37ssh_get_authentication_socket() 37ssh_get_authentication_socket()
38{ 38{
39 const char *authsocket; 39 const char *authsocket;
40 int sock; 40 int sock;
41 struct sockaddr_un sunaddr; 41 struct sockaddr_un sunaddr;
42 42
43 authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME); 43 authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME);
44 if (!authsocket) 44 if (!authsocket)
45 return -1; 45 return -1;
46 46
47 sunaddr.sun_family = AF_UNIX; 47 sunaddr.sun_family = AF_UNIX;
48 strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path)); 48 strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
49 49
50 sock = socket(AF_UNIX, SOCK_STREAM, 0); 50 sock = socket(AF_UNIX, SOCK_STREAM, 0);
51 if (sock < 0) 51 if (sock < 0)
52 return -1; 52 return -1;
53 53
54 /* close on exec */ 54 /* close on exec */
55 if (fcntl(sock, F_SETFD, 1) == -1) 55 if (fcntl(sock, F_SETFD, 1) == -1) {
56 { 56 close(sock);
57 close(sock); 57 return -1;
58 return -1; 58 }
59 } 59 if (connect(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) {
60 60 close(sock);
61 if (connect(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) 61 return -1;
62 { 62 }
63 close(sock); 63 return sock;
64 return -1;
65 }
66
67 return sock;
68} 64}
69 65
70/* Closes the agent socket if it should be closed (depends on how it was 66/* Closes the agent socket if it should be closed (depends on how it was
71 obtained). The argument must have been returned by 67 obtained). The argument must have been returned by
72 ssh_get_authentication_socket(). */ 68 ssh_get_authentication_socket(). */
73 69
74void ssh_close_authentication_socket(int sock) 70void
71ssh_close_authentication_socket(int sock)
75{ 72{
76 if (getenv(SSH_AUTHSOCKET_ENV_NAME)) 73 if (getenv(SSH_AUTHSOCKET_ENV_NAME))
77 close(sock); 74 close(sock);
78} 75}
79 76
80/* Opens and connects a private socket for communication with the 77/* Opens and connects a private socket for communication with the
@@ -83,38 +80,39 @@ void ssh_close_authentication_socket(int sock)
83 Returns NULL if an error occurred and the connection could not be 80 Returns NULL if an error occurred and the connection could not be
84 opened. */ 81 opened. */
85 82
86AuthenticationConnection *ssh_get_authentication_connection() 83AuthenticationConnection *
84ssh_get_authentication_connection()
87{ 85{
88 AuthenticationConnection *auth; 86 AuthenticationConnection *auth;
89 int sock; 87 int sock;
90 88
91 sock = ssh_get_authentication_socket(); 89 sock = ssh_get_authentication_socket();
92 90
93 /* Fail if we couldn't obtain a connection. This happens if we exited 91 /* Fail if we couldn't obtain a connection. This happens if we
94 due to a timeout. */ 92 exited due to a timeout. */
95 if (sock < 0) 93 if (sock < 0)
96 return NULL; 94 return NULL;
97 95
98 /* Applocate the connection structure and initialize it. */ 96 /* Applocate the connection structure and initialize it. */
99 auth = xmalloc(sizeof(*auth)); 97 auth = xmalloc(sizeof(*auth));
100 auth->fd = sock; 98 auth->fd = sock;
101 buffer_init(&auth->packet); 99 buffer_init(&auth->packet);
102 buffer_init(&auth->identities); 100 buffer_init(&auth->identities);
103 auth->howmany = 0; 101 auth->howmany = 0;
104 102
105 return auth; 103 return auth;
106} 104}
107 105
108/* Closes the connection to the authentication agent and frees any associated 106/* Closes the connection to the authentication agent and frees any associated
109 memory. */ 107 memory. */
110 108
111void ssh_close_authentication_connection(AuthenticationConnection *ac) 109void
110ssh_close_authentication_connection(AuthenticationConnection *ac)
112{ 111{
113 buffer_free(&ac->packet); 112 buffer_free(&ac->packet);
114 buffer_free(&ac->identities); 113 buffer_free(&ac->identities);
115 close(ac->fd); 114 close(ac->fd);
116 /* Free the connection data structure. */ 115 xfree(ac);
117 xfree(ac);
118} 116}
119 117
120/* Returns the first authentication identity held by the agent. 118/* Returns the first authentication identity held by the agent.
@@ -126,67 +124,62 @@ int
126ssh_get_first_identity(AuthenticationConnection *auth, 124ssh_get_first_identity(AuthenticationConnection *auth,
127 BIGNUM *e, BIGNUM *n, char **comment) 125 BIGNUM *e, BIGNUM *n, char **comment)
128{ 126{
129 unsigned char msg[8192]; 127 unsigned char msg[8192];
130 int len, l; 128 int len, l;
131 129
132 /* Send a message to the agent requesting for a list of the identities 130 /* Send a message to the agent requesting for a list of the
133 it can represent. */ 131 identities it can represent. */
134 msg[0] = 0; 132 msg[0] = 0;
135 msg[1] = 0; 133 msg[1] = 0;
136 msg[2] = 0; 134 msg[2] = 0;
137 msg[3] = 1; 135 msg[3] = 1;
138 msg[4] = SSH_AGENTC_REQUEST_RSA_IDENTITIES; 136 msg[4] = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
139 if (write(auth->fd, msg, 5) != 5) 137 if (write(auth->fd, msg, 5) != 5) {
140 { 138 error("write auth->fd: %.100s", strerror(errno));
141 error("write auth->fd: %.100s", strerror(errno)); 139 return 0;
142 return 0; 140 }
143 } 141 /* Read the length of the response. XXX implement timeouts here. */
144 142 len = 4;
145 /* Read the length of the response. XXX implement timeouts here. */ 143 while (len > 0) {
146 len = 4; 144 l = read(auth->fd, msg + 4 - len, len);
147 while (len > 0) 145 if (l <= 0) {
148 { 146 error("read auth->fd: %.100s", strerror(errno));
149 l = read(auth->fd, msg + 4 - len, len); 147 return 0;
150 if (l <= 0) 148 }
151 { 149 len -= l;
152 error("read auth->fd: %.100s", strerror(errno)); 150 }
153 return 0; 151
152 /* Extract the length, and check it for sanity. (We cannot trust
153 authentication agents). */
154 len = GET_32BIT(msg);
155 if (len < 1 || len > 256 * 1024)
156 fatal("Authentication reply message too long: %d\n", len);
157
158 /* Read the packet itself. */
159 buffer_clear(&auth->identities);
160 while (len > 0) {
161 l = len;
162 if (l > sizeof(msg))
163 l = sizeof(msg);
164 l = read(auth->fd, msg, l);
165 if (l <= 0)
166 fatal("Incomplete authentication reply.");
167 buffer_append(&auth->identities, (char *) msg, l);
168 len -= l;
154 } 169 }
155 len -= l; 170
156 } 171 /* Get message type, and verify that we got a proper answer. */
157 172 buffer_get(&auth->identities, (char *) msg, 1);
158 /* Extract the length, and check it for sanity. (We cannot trust 173 if (msg[0] != SSH_AGENT_RSA_IDENTITIES_ANSWER)
159 authentication agents). */ 174 fatal("Bad authentication reply message type: %d", msg[0]);
160 len = GET_32BIT(msg); 175
161 if (len < 1 || len > 256*1024) 176 /* Get the number of entries in the response and check it for sanity. */
162 fatal("Authentication reply message too long: %d\n", len); 177 auth->howmany = buffer_get_int(&auth->identities);
163 178 if (auth->howmany > 1024)
164 /* Read the packet itself. */ 179 fatal("Too many identities in authentication reply: %d\n", auth->howmany);
165 buffer_clear(&auth->identities); 180
166 while (len > 0) 181 /* Return the first entry (if any). */
167 { 182 return ssh_get_next_identity(auth, e, n, comment);
168 l = len;
169 if (l > sizeof(msg))
170 l = sizeof(msg);
171 l = read(auth->fd, msg, l);
172 if (l <= 0)
173 fatal("Incomplete authentication reply.");
174 buffer_append(&auth->identities, (char *)msg, l);
175 len -= l;
176 }
177
178 /* Get message type, and verify that we got a proper answer. */
179 buffer_get(&auth->identities, (char *)msg, 1);
180 if (msg[0] != SSH_AGENT_RSA_IDENTITIES_ANSWER)
181 fatal("Bad authentication reply message type: %d", msg[0]);
182
183 /* Get the number of entries in the response and check it for sanity. */
184 auth->howmany = buffer_get_int(&auth->identities);
185 if (auth->howmany > 1024)
186 fatal("Too many identities in authentication reply: %d\n", auth->howmany);
187
188 /* Return the first entry (if any). */
189 return ssh_get_next_identity(auth, e, n, comment);
190} 183}
191 184
192/* Returns the next authentication identity for the agent. Other functions 185/* Returns the next authentication identity for the agent. Other functions
@@ -198,27 +191,27 @@ int
198ssh_get_next_identity(AuthenticationConnection *auth, 191ssh_get_next_identity(AuthenticationConnection *auth,
199 BIGNUM *e, BIGNUM *n, char **comment) 192 BIGNUM *e, BIGNUM *n, char **comment)
200{ 193{
201 unsigned int bits; 194 unsigned int bits;
202 195
203 /* Return failure if no more entries. */ 196 /* Return failure if no more entries. */
204 if (auth->howmany <= 0) 197 if (auth->howmany <= 0)
205 return 0; 198 return 0;
206 199
207 /* Get the next entry from the packet. These will abort with a fatal 200 /* Get the next entry from the packet. These will abort with a
208 error if the packet is too short or contains corrupt data. */ 201 fatal error if the packet is too short or contains corrupt data. */
209 bits = buffer_get_int(&auth->identities); 202 bits = buffer_get_int(&auth->identities);
210 buffer_get_bignum(&auth->identities, e); 203 buffer_get_bignum(&auth->identities, e);
211 buffer_get_bignum(&auth->identities, n); 204 buffer_get_bignum(&auth->identities, n);
212 *comment = buffer_get_string(&auth->identities, NULL); 205 *comment = buffer_get_string(&auth->identities, NULL);
213 206
214 if (bits != BN_num_bits(n)) 207 if (bits != BN_num_bits(n))
215 error("Warning: keysize mismatch: actual %d, announced %u", 208 error("Warning: keysize mismatch: actual %d, announced %u",
216 BN_num_bits(n), bits); 209 BN_num_bits(n), bits);
217 210
218 /* Decrement the number of remaining entries. */ 211 /* Decrement the number of remaining entries. */
219 auth->howmany--; 212 auth->howmany--;
220 213
221 return 1; 214 return 1;
222} 215}
223 216
224/* Generates a random challenge, sends it to the agent, and waits for response 217/* Generates a random challenge, sends it to the agent, and waits for response
@@ -229,355 +222,329 @@ ssh_get_next_identity(AuthenticationConnection *auth,
229 222
230int 223int
231ssh_decrypt_challenge(AuthenticationConnection *auth, 224ssh_decrypt_challenge(AuthenticationConnection *auth,
232 BIGNUM *e, BIGNUM *n, BIGNUM *challenge, 225 BIGNUM* e, BIGNUM *n, BIGNUM *challenge,
233 unsigned char session_id[16], 226 unsigned char session_id[16],
234 unsigned int response_type, 227 unsigned int response_type,
235 unsigned char response[16]) 228 unsigned char response[16])
236{ 229{
237 Buffer buffer; 230 Buffer buffer;
238 unsigned char buf[8192]; 231 unsigned char buf[8192];
239 int len, l, i; 232 int len, l, i;
240 233
241 /* Response type 0 is no longer supported. */ 234 /* Response type 0 is no longer supported. */
242 if (response_type == 0) 235 if (response_type == 0)
243 fatal("Compatibility with ssh protocol version 1.0 no longer supported."); 236 fatal("Compatibility with ssh protocol version 1.0 no longer supported.");
244 237
245 /* Format a message to the agent. */ 238 /* Format a message to the agent. */
246 buf[0] = SSH_AGENTC_RSA_CHALLENGE; 239 buf[0] = SSH_AGENTC_RSA_CHALLENGE;
247 buffer_init(&buffer); 240 buffer_init(&buffer);
248 buffer_append(&buffer, (char *)buf, 1); 241 buffer_append(&buffer, (char *) buf, 1);
249 buffer_put_int(&buffer, BN_num_bits(n)); 242 buffer_put_int(&buffer, BN_num_bits(n));
250 buffer_put_bignum(&buffer, e); 243 buffer_put_bignum(&buffer, e);
251 buffer_put_bignum(&buffer, n); 244 buffer_put_bignum(&buffer, n);
252 buffer_put_bignum(&buffer, challenge); 245 buffer_put_bignum(&buffer, challenge);
253 buffer_append(&buffer, (char *)session_id, 16); 246 buffer_append(&buffer, (char *) session_id, 16);
254 buffer_put_int(&buffer, response_type); 247 buffer_put_int(&buffer, response_type);
255 248
256 /* Get the length of the message, and format it in the buffer. */ 249 /* Get the length of the message, and format it in the buffer. */
257 len = buffer_len(&buffer); 250 len = buffer_len(&buffer);
258 PUT_32BIT(buf, len); 251 PUT_32BIT(buf, len);
259 252
260 /* Send the length and then the packet to the agent. */ 253 /* Send the length and then the packet to the agent. */
261 if (write(auth->fd, buf, 4) != 4 || 254 if (write(auth->fd, buf, 4) != 4 ||
262 write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) != 255 write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
263 buffer_len(&buffer)) 256 buffer_len(&buffer)) {
264 { 257 error("Error writing to authentication socket.");
265 error("Error writing to authentication socket."); 258error_cleanup:
266 error_cleanup: 259 buffer_free(&buffer);
267 buffer_free(&buffer); 260 return 0;
268 return 0; 261 }
269 } 262 /* Wait for response from the agent. First read the length of the
270 263 response packet. */
271 /* Wait for response from the agent. First read the length of the 264 len = 4;
272 response packet. */ 265 while (len > 0) {
273 len = 4; 266 l = read(auth->fd, buf + 4 - len, len);
274 while (len > 0) 267 if (l <= 0) {
275 { 268 error("Error reading response length from authentication socket.");
276 l = read(auth->fd, buf + 4 - len, len); 269 goto error_cleanup;
277 if (l <= 0) 270 }
278 { 271 len -= l;
279 error("Error reading response length from authentication socket."); 272 }
280 goto error_cleanup; 273
274 /* Extract the length, and check it for sanity. */
275 len = GET_32BIT(buf);
276 if (len > 256 * 1024)
277 fatal("Authentication response too long: %d", len);
278
279 /* Read the rest of the response in tothe buffer. */
280 buffer_clear(&buffer);
281 while (len > 0) {
282 l = len;
283 if (l > sizeof(buf))
284 l = sizeof(buf);
285 l = read(auth->fd, buf, l);
286 if (l <= 0) {
287 error("Error reading response from authentication socket.");
288 goto error_cleanup;
289 }
290 buffer_append(&buffer, (char *) buf, l);
291 len -= l;
281 } 292 }
282 len -= l; 293
283 } 294 /* Get the type of the packet. */
284 295 buffer_get(&buffer, (char *) buf, 1);
285 /* Extract the length, and check it for sanity. */ 296
286 len = GET_32BIT(buf); 297 /* Check for agent failure message. */
287 if (len > 256*1024) 298 if (buf[0] == SSH_AGENT_FAILURE) {
288 fatal("Authentication response too long: %d", len); 299 log("Agent admitted failure to authenticate using the key.");
289 300 goto error_cleanup;
290 /* Read the rest of the response in tothe buffer. */
291 buffer_clear(&buffer);
292 while (len > 0)
293 {
294 l = len;
295 if (l > sizeof(buf))
296 l = sizeof(buf);
297 l = read(auth->fd, buf, l);
298 if (l <= 0)
299 {
300 error("Error reading response from authentication socket.");
301 goto error_cleanup;
302 } 301 }
303 buffer_append(&buffer, (char *)buf, l); 302 /* Now it must be an authentication response packet. */
304 len -= l; 303 if (buf[0] != SSH_AGENT_RSA_RESPONSE)
305 } 304 fatal("Bad authentication response: %d", buf[0]);
306 305
307 /* Get the type of the packet. */ 306 /* Get the response from the packet. This will abort with a fatal
308 buffer_get(&buffer, (char *)buf, 1); 307 error if the packet is corrupt. */
309 308 for (i = 0; i < 16; i++)
310 /* Check for agent failure message. */ 309 response[i] = buffer_get_char(&buffer);
311 if (buf[0] == SSH_AGENT_FAILURE) 310
312 { 311 /* The buffer containing the packet is no longer needed. */
313 log("Agent admitted failure to authenticate using the key."); 312 buffer_free(&buffer);
314 goto error_cleanup; 313
315 } 314 /* Correct answer. */
316 315 return 1;
317 /* Now it must be an authentication response packet. */ 316}
318 if (buf[0] != SSH_AGENT_RSA_RESPONSE)
319 fatal("Bad authentication response: %d", buf[0]);
320
321 /* Get the response from the packet. This will abort with a fatal error
322 if the packet is corrupt. */
323 for (i = 0; i < 16; i++)
324 response[i] = buffer_get_char(&buffer);
325
326 /* The buffer containing the packet is no longer needed. */
327 buffer_free(&buffer);
328
329 /* Correct answer. */
330 return 1;
331}
332 317
333/* Adds an identity to the authentication server. This call is not meant to 318/* Adds an identity to the authentication server. This call is not meant to
334 be used by normal applications. */ 319 be used by normal applications. */
335 320
336int ssh_add_identity(AuthenticationConnection *auth, 321int
337 RSA *key, const char *comment) 322ssh_add_identity(AuthenticationConnection *auth,
323 RSA * key, const char *comment)
338{ 324{
339 Buffer buffer; 325 Buffer buffer;
340 unsigned char buf[8192]; 326 unsigned char buf[8192];
341 int len, l, type; 327 int len, l, type;
342 328
343 /* Format a message to the agent. */ 329 /* Format a message to the agent. */
344 buffer_init(&buffer); 330 buffer_init(&buffer);
345 buffer_put_char(&buffer, SSH_AGENTC_ADD_RSA_IDENTITY); 331 buffer_put_char(&buffer, SSH_AGENTC_ADD_RSA_IDENTITY);
346 buffer_put_int(&buffer, BN_num_bits(key->n)); 332 buffer_put_int(&buffer, BN_num_bits(key->n));
347 buffer_put_bignum(&buffer, key->n); 333 buffer_put_bignum(&buffer, key->n);
348 buffer_put_bignum(&buffer, key->e); 334 buffer_put_bignum(&buffer, key->e);
349 buffer_put_bignum(&buffer, key->d); 335 buffer_put_bignum(&buffer, key->d);
350 /* To keep within the protocol: p < q for ssh. in SSL p > q */ 336 /* To keep within the protocol: p < q for ssh. in SSL p > q */
351 buffer_put_bignum(&buffer, key->iqmp); /* ssh key->u */ 337 buffer_put_bignum(&buffer, key->iqmp); /* ssh key->u */
352 buffer_put_bignum(&buffer, key->q); /* ssh key->p, SSL key->q */ 338 buffer_put_bignum(&buffer, key->q); /* ssh key->p, SSL key->q */
353 buffer_put_bignum(&buffer, key->p); /* ssh key->q, SSL key->p */ 339 buffer_put_bignum(&buffer, key->p); /* ssh key->q, SSL key->p */
354 buffer_put_string(&buffer, comment, strlen(comment)); 340 buffer_put_string(&buffer, comment, strlen(comment));
355 341
356 /* Get the length of the message, and format it in the buffer. */ 342 /* Get the length of the message, and format it in the buffer. */
357 len = buffer_len(&buffer); 343 len = buffer_len(&buffer);
358 PUT_32BIT(buf, len); 344 PUT_32BIT(buf, len);
359 345
360 /* Send the length and then the packet to the agent. */ 346 /* Send the length and then the packet to the agent. */
361 if (write(auth->fd, buf, 4) != 4 || 347 if (write(auth->fd, buf, 4) != 4 ||
362 write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) != 348 write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
363 buffer_len(&buffer)) 349 buffer_len(&buffer)) {
364 { 350 error("Error writing to authentication socket.");
365 error("Error writing to authentication socket."); 351error_cleanup:
366 error_cleanup: 352 buffer_free(&buffer);
367 buffer_free(&buffer); 353 return 0;
368 return 0; 354 }
369 } 355 /* Wait for response from the agent. First read the length of the
370 356 response packet. */
371 /* Wait for response from the agent. First read the length of the 357 len = 4;
372 response packet. */ 358 while (len > 0) {
373 len = 4; 359 l = read(auth->fd, buf + 4 - len, len);
374 while (len > 0) 360 if (l <= 0) {
375 { 361 error("Error reading response length from authentication socket.");
376 l = read(auth->fd, buf + 4 - len, len); 362 goto error_cleanup;
377 if (l <= 0) 363 }
378 { 364 len -= l;
379 error("Error reading response length from authentication socket."); 365 }
380 goto error_cleanup; 366
367 /* Extract the length, and check it for sanity. */
368 len = GET_32BIT(buf);
369 if (len > 256 * 1024)
370 fatal("Add identity response too long: %d", len);
371
372 /* Read the rest of the response in tothe buffer. */
373 buffer_clear(&buffer);
374 while (len > 0) {
375 l = len;
376 if (l > sizeof(buf))
377 l = sizeof(buf);
378 l = read(auth->fd, buf, l);
379 if (l <= 0) {
380 error("Error reading response from authentication socket.");
381 goto error_cleanup;
382 }
383 buffer_append(&buffer, (char *) buf, l);
384 len -= l;
381 } 385 }
382 len -= l; 386
383 } 387 /* Get the type of the packet. */
384 388 type = buffer_get_char(&buffer);
385 /* Extract the length, and check it for sanity. */ 389 switch (type) {
386 len = GET_32BIT(buf); 390 case SSH_AGENT_FAILURE:
387 if (len > 256*1024) 391 buffer_free(&buffer);
388 fatal("Add identity response too long: %d", len); 392 return 0;
389 393 case SSH_AGENT_SUCCESS:
390 /* Read the rest of the response in tothe buffer. */ 394 buffer_free(&buffer);
391 buffer_clear(&buffer); 395 return 1;
392 while (len > 0) 396 default:
393 { 397 fatal("Bad response to add identity from authentication agent: %d",
394 l = len; 398 type);
395 if (l > sizeof(buf))
396 l = sizeof(buf);
397 l = read(auth->fd, buf, l);
398 if (l <= 0)
399 {
400 error("Error reading response from authentication socket.");
401 goto error_cleanup;
402 } 399 }
403 buffer_append(&buffer, (char *)buf, l); 400 /* NOTREACHED */
404 len -= l; 401 return 0;
405 } 402}
406 403
407 /* Get the type of the packet. */ 404/* Removes an identity from the authentication server. This call is not meant
408 type = buffer_get_char(&buffer);
409 switch (type)
410 {
411 case SSH_AGENT_FAILURE:
412 buffer_free(&buffer);
413 return 0;
414 case SSH_AGENT_SUCCESS:
415 buffer_free(&buffer);
416 return 1;
417 default:
418 fatal("Bad response to add identity from authentication agent: %d",
419 type);
420 }
421 /*NOTREACHED*/
422 return 0;
423}
424
425/* Removes an identity from the authentication server. This call is not meant
426 to be used by normal applications. */ 405 to be used by normal applications. */
427 406
428int ssh_remove_identity(AuthenticationConnection *auth, RSA *key) 407int
408ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
429{ 409{
430 Buffer buffer; 410 Buffer buffer;
431 unsigned char buf[8192]; 411 unsigned char buf[8192];
432 int len, l, type; 412 int len, l, type;
433 413
434 /* Format a message to the agent. */ 414 /* Format a message to the agent. */
435 buffer_init(&buffer); 415 buffer_init(&buffer);
436 buffer_put_char(&buffer, SSH_AGENTC_REMOVE_RSA_IDENTITY); 416 buffer_put_char(&buffer, SSH_AGENTC_REMOVE_RSA_IDENTITY);
437 buffer_put_int(&buffer, BN_num_bits(key->n)); 417 buffer_put_int(&buffer, BN_num_bits(key->n));
438 buffer_put_bignum(&buffer, key->e); 418 buffer_put_bignum(&buffer, key->e);
439 buffer_put_bignum(&buffer, key->n); 419 buffer_put_bignum(&buffer, key->n);
440 420
441 /* Get the length of the message, and format it in the buffer. */ 421 /* Get the length of the message, and format it in the buffer. */
442 len = buffer_len(&buffer); 422 len = buffer_len(&buffer);
443 PUT_32BIT(buf, len); 423 PUT_32BIT(buf, len);
444 424
445 /* Send the length and then the packet to the agent. */ 425 /* Send the length and then the packet to the agent. */
446 if (write(auth->fd, buf, 4) != 4 || 426 if (write(auth->fd, buf, 4) != 4 ||
447 write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) != 427 write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
448 buffer_len(&buffer)) 428 buffer_len(&buffer)) {
449 { 429 error("Error writing to authentication socket.");
450 error("Error writing to authentication socket."); 430error_cleanup:
451 error_cleanup: 431 buffer_free(&buffer);
452 buffer_free(&buffer); 432 return 0;
453 return 0; 433 }
454 } 434 /* Wait for response from the agent. First read the length of the
455 435 response packet. */
456 /* Wait for response from the agent. First read the length of the 436 len = 4;
457 response packet. */ 437 while (len > 0) {
458 len = 4; 438 l = read(auth->fd, buf + 4 - len, len);
459 while (len > 0) 439 if (l <= 0) {
460 { 440 error("Error reading response length from authentication socket.");
461 l = read(auth->fd, buf + 4 - len, len); 441 goto error_cleanup;
462 if (l <= 0) 442 }
463 { 443 len -= l;
464 error("Error reading response length from authentication socket."); 444 }
465 goto error_cleanup; 445
446 /* Extract the length, and check it for sanity. */
447 len = GET_32BIT(buf);
448 if (len > 256 * 1024)
449 fatal("Remove identity response too long: %d", len);
450
451 /* Read the rest of the response in tothe buffer. */
452 buffer_clear(&buffer);
453 while (len > 0) {
454 l = len;
455 if (l > sizeof(buf))
456 l = sizeof(buf);
457 l = read(auth->fd, buf, l);
458 if (l <= 0) {
459 error("Error reading response from authentication socket.");
460 goto error_cleanup;
461 }
462 buffer_append(&buffer, (char *) buf, l);
463 len -= l;
466 } 464 }
467 len -= l; 465
468 } 466 /* Get the type of the packet. */
469 467 type = buffer_get_char(&buffer);
470 /* Extract the length, and check it for sanity. */ 468 switch (type) {
471 len = GET_32BIT(buf); 469 case SSH_AGENT_FAILURE:
472 if (len > 256*1024) 470 buffer_free(&buffer);
473 fatal("Remove identity response too long: %d", len); 471 return 0;
474 472 case SSH_AGENT_SUCCESS:
475 /* Read the rest of the response in tothe buffer. */ 473 buffer_free(&buffer);
476 buffer_clear(&buffer); 474 return 1;
477 while (len > 0) 475 default:
478 { 476 fatal("Bad response to remove identity from authentication agent: %d",
479 l = len; 477 type);
480 if (l > sizeof(buf))
481 l = sizeof(buf);
482 l = read(auth->fd, buf, l);
483 if (l <= 0)
484 {
485 error("Error reading response from authentication socket.");
486 goto error_cleanup;
487 } 478 }
488 buffer_append(&buffer, (char *)buf, l); 479 /* NOTREACHED */
489 len -= l; 480 return 0;
490 } 481}
491 482
492 /* Get the type of the packet. */ 483/* Removes all identities from the agent. This call is not meant
493 type = buffer_get_char(&buffer);
494 switch (type)
495 {
496 case SSH_AGENT_FAILURE:
497 buffer_free(&buffer);
498 return 0;
499 case SSH_AGENT_SUCCESS:
500 buffer_free(&buffer);
501 return 1;
502 default:
503 fatal("Bad response to remove identity from authentication agent: %d",
504 type);
505 }
506 /*NOTREACHED*/
507 return 0;
508}
509
510/* Removes all identities from the agent. This call is not meant
511 to be used by normal applications. */ 484 to be used by normal applications. */
512 485
513int ssh_remove_all_identities(AuthenticationConnection *auth) 486int
487ssh_remove_all_identities(AuthenticationConnection *auth)
514{ 488{
515 Buffer buffer; 489 Buffer buffer;
516 unsigned char buf[8192]; 490 unsigned char buf[8192];
517 int len, l, type; 491 int len, l, type;
518 492
519 /* Get the length of the message, and format it in the buffer. */ 493 /* Get the length of the message, and format it in the buffer. */
520 PUT_32BIT(buf, 1); 494 PUT_32BIT(buf, 1);
521 buf[4] = SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES; 495 buf[4] = SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES;
522 496
523 /* Send the length and then the packet to the agent. */ 497 /* Send the length and then the packet to the agent. */
524 if (write(auth->fd, buf, 5) != 5) 498 if (write(auth->fd, buf, 5) != 5) {
525 { 499 error("Error writing to authentication socket.");
526 error("Error writing to authentication socket."); 500 return 0;
527 return 0; 501 }
528 } 502 /* Wait for response from the agent. First read the length of the
529 503 response packet. */
530 /* Wait for response from the agent. First read the length of the 504 len = 4;
531 response packet. */ 505 while (len > 0) {
532 len = 4; 506 l = read(auth->fd, buf + 4 - len, len);
533 while (len > 0) 507 if (l <= 0) {
534 { 508 error("Error reading response length from authentication socket.");
535 l = read(auth->fd, buf + 4 - len, len); 509 return 0;
536 if (l <= 0) 510 }
537 { 511 len -= l;
538 error("Error reading response length from authentication socket."); 512 }
539 return 0; 513
514 /* Extract the length, and check it for sanity. */
515 len = GET_32BIT(buf);
516 if (len > 256 * 1024)
517 fatal("Remove identity response too long: %d", len);
518
519 /* Read the rest of the response into the buffer. */
520 buffer_init(&buffer);
521 while (len > 0) {
522 l = len;
523 if (l > sizeof(buf))
524 l = sizeof(buf);
525 l = read(auth->fd, buf, l);
526 if (l <= 0) {
527 error("Error reading response from authentication socket.");
528 buffer_free(&buffer);
529 return 0;
530 }
531 buffer_append(&buffer, (char *) buf, l);
532 len -= l;
540 } 533 }
541 len -= l; 534
542 } 535 /* Get the type of the packet. */
543 536 type = buffer_get_char(&buffer);
544 /* Extract the length, and check it for sanity. */ 537 switch (type) {
545 len = GET_32BIT(buf); 538 case SSH_AGENT_FAILURE:
546 if (len > 256*1024) 539 buffer_free(&buffer);
547 fatal("Remove identity response too long: %d", len); 540 return 0;
548 541 case SSH_AGENT_SUCCESS:
549 /* Read the rest of the response into the buffer. */ 542 buffer_free(&buffer);
550 buffer_init(&buffer); 543 return 1;
551 while (len > 0) 544 default:
552 { 545 fatal("Bad response to remove identity from authentication agent: %d",
553 l = len; 546 type);
554 if (l > sizeof(buf))
555 l = sizeof(buf);
556 l = read(auth->fd, buf, l);
557 if (l <= 0)
558 {
559 error("Error reading response from authentication socket.");
560 buffer_free(&buffer);
561 return 0;
562 } 547 }
563 buffer_append(&buffer, (char *)buf, l); 548 /* NOTREACHED */
564 len -= l; 549 return 0;
565 } 550}
566
567 /* Get the type of the packet. */
568 type = buffer_get_char(&buffer);
569 switch (type)
570 {
571 case SSH_AGENT_FAILURE:
572 buffer_free(&buffer);
573 return 0;
574 case SSH_AGENT_SUCCESS:
575 buffer_free(&buffer);
576 return 1;
577 default:
578 fatal("Bad response to remove identity from authentication agent: %d",
579 type);
580 }
581 /*NOTREACHED*/
582 return 0;
583}
diff --git a/authfd.h b/authfd.h
index df589b1c4..bddb8bab8 100644
--- a/authfd.h
+++ b/authfd.h
@@ -1,19 +1,19 @@
1/* 1/*
2 2 *
3authfd.h 3 * authfd.h
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Wed Mar 29 01:17:41 1995 ylo 10 * Created: Wed Mar 29 01:17:41 1995 ylo
11 11 *
12Functions to interface with the SSH_AUTHENTICATION_FD socket. 12 * Functions to interface with the SSH_AUTHENTICATION_FD socket.
13 13 *
14*/ 14 */
15 15
16/* RCSID("$Id: authfd.h,v 1.2 1999/11/16 02:37:16 damien Exp $"); */ 16/* RCSID("$Id: authfd.h,v 1.3 1999/11/24 13:26:22 damien Exp $"); */
17 17
18#ifndef AUTHFD_H 18#ifndef AUTHFD_H
19#define AUTHFD_H 19#define AUTHFD_H
@@ -31,72 +31,73 @@ Functions to interface with the SSH_AUTHENTICATION_FD socket.
31#define SSH_AGENTC_REMOVE_RSA_IDENTITY 8 31#define SSH_AGENTC_REMOVE_RSA_IDENTITY 8
32#define SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES 9 32#define SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES 9
33 33
34typedef struct 34typedef struct {
35{ 35 int fd;
36 int fd; 36 Buffer packet;
37 Buffer packet; 37 Buffer identities;
38 Buffer identities; 38 int howmany;
39 int howmany; 39} AuthenticationConnection;
40} AuthenticationConnection;
41
42/* Returns the number of the authentication fd, or -1 if there is none. */ 40/* Returns the number of the authentication fd, or -1 if there is none. */
43int ssh_get_authentication_socket(); 41int ssh_get_authentication_socket();
44 42
45/* This should be called for any descriptor returned by 43/* This should be called for any descriptor returned by
46 ssh_get_authentication_socket(). Depending on the way the descriptor was 44 ssh_get_authentication_socket(). Depending on the way the descriptor was
47 obtained, this may close the descriptor. */ 45 obtained, this may close the descriptor. */
48void ssh_close_authentication_socket(int authfd); 46void ssh_close_authentication_socket(int authfd);
49 47
50/* Opens and connects a private socket for communication with the 48/* Opens and connects a private socket for communication with the
51 authentication agent. Returns NULL if an error occurred and the 49 authentication agent. Returns NULL if an error occurred and the
52 connection could not be opened. The connection should be closed by 50 connection could not be opened. The connection should be closed by
53 the caller by calling ssh_close_authentication_connection(). */ 51 the caller by calling ssh_close_authentication_connection(). */
54AuthenticationConnection *ssh_get_authentication_connection(); 52AuthenticationConnection *ssh_get_authentication_connection();
55 53
56/* Closes the connection to the authentication agent and frees any associated 54/* Closes the connection to the authentication agent and frees any associated
57 memory. */ 55 memory. */
58void ssh_close_authentication_connection(AuthenticationConnection *ac); 56void ssh_close_authentication_connection(AuthenticationConnection * ac);
59 57
60/* Returns the first authentication identity held by the agent. 58/* Returns the first authentication identity held by the agent.
61 Returns true if an identity is available, 0 otherwise. 59 Returns true if an identity is available, 0 otherwise.
62 The caller must initialize the integers before the call, and free the 60 The caller must initialize the integers before the call, and free the
63 comment after a successful call (before calling ssh_get_next_identity). */ 61 comment after a successful call (before calling ssh_get_next_identity). */
64int ssh_get_first_identity(AuthenticationConnection *connection, 62int
65 BIGNUM *e, BIGNUM *n, char **comment); 63ssh_get_first_identity(AuthenticationConnection * connection,
64 BIGNUM * e, BIGNUM * n, char **comment);
66 65
67/* Returns the next authentication identity for the agent. Other functions 66/* Returns the next authentication identity for the agent. Other functions
68 can be called between this and ssh_get_first_identity or two calls of this 67 can be called between this and ssh_get_first_identity or two calls of this
69 function. This returns 0 if there are no more identities. The caller 68 function. This returns 0 if there are no more identities. The caller
70 must free comment after a successful return. */ 69 must free comment after a successful return. */
71int ssh_get_next_identity(AuthenticationConnection *connection, 70int
72 BIGNUM *e, BIGNUM *n, char **comment); 71ssh_get_next_identity(AuthenticationConnection * connection,
72 BIGNUM * e, BIGNUM * n, char **comment);
73 73
74/* Requests the agent to decrypt the given challenge. Returns true if 74/* Requests the agent to decrypt the given challenge. Returns true if
75 the agent claims it was able to decrypt it. */ 75 the agent claims it was able to decrypt it. */
76int ssh_decrypt_challenge(AuthenticationConnection *auth, 76int
77 BIGNUM *e, BIGNUM *n, BIGNUM *challenge, 77ssh_decrypt_challenge(AuthenticationConnection * auth,
78 unsigned char session_id[16], 78 BIGNUM * e, BIGNUM * n, BIGNUM * challenge,
79 unsigned int response_type, 79 unsigned char session_id[16],
80 unsigned char response[16]); 80 unsigned int response_type,
81 unsigned char response[16]);
81 82
82/* Adds an identity to the authentication server. This call is not meant to 83/* Adds an identity to the authentication server. This call is not meant to
83 be used by normal applications. This returns true if the identity 84 be used by normal applications. This returns true if the identity
84 was successfully added. */ 85 was successfully added. */
85int ssh_add_identity(AuthenticationConnection *connection, 86 int ssh_add_identity(AuthenticationConnection * connection,
86 RSA *key, const char *comment); 87 RSA * key, const char *comment);
87 88
88/* Removes the identity from the authentication server. This call is 89/* Removes the identity from the authentication server. This call is
89 not meant to be used by normal applications. This returns true if the 90 not meant to be used by normal applications. This returns true if the
90 identity was successfully added. */ 91 identity was successfully added. */
91int ssh_remove_identity(AuthenticationConnection *connection, 92 int ssh_remove_identity(AuthenticationConnection * connection,
92 RSA *key); 93 RSA * key);
93 94
94/* Removes all identities from the authentication agent. This call is not 95/* Removes all identities from the authentication agent. This call is not
95 meant to be used by normal applications. This returns true if the 96 meant to be used by normal applications. This returns true if the
96 operation was successful. */ 97 operation was successful. */
97int ssh_remove_all_identities(AuthenticationConnection *connection); 98 int ssh_remove_all_identities(AuthenticationConnection * connection);
98 99
99/* Closes the connection to the authentication agent. */ 100/* Closes the connection to the authentication agent. */
100void ssh_close_authentication(AuthenticationConnection *connection); 101 void ssh_close_authentication(AuthenticationConnection * connection);
101 102
102#endif /* AUTHFD_H */ 103#endif /* AUTHFD_H */
diff --git a/authfile.c b/authfile.c
index 0e77edf99..35a05d389 100644
--- a/authfile.c
+++ b/authfile.c
@@ -1,21 +1,21 @@
1/* 1/*
2 2 *
3authfile.c 3 * authfile.c
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Mon Mar 27 03:52:05 1995 ylo 10 * Created: Mon Mar 27 03:52:05 1995 ylo
11 11 *
12This file contains functions for reading and writing identity files, and 12 * This file contains functions for reading and writing identity files, and
13for reading the passphrase from the user. 13 * for reading the passphrase from the user.
14 14 *
15*/ 15 */
16 16
17#include "includes.h" 17#include "includes.h"
18RCSID("$Id: authfile.c,v 1.3 1999/11/13 02:07:45 damien Exp $"); 18RCSID("$Id: authfile.c,v 1.4 1999/11/24 13:26:22 damien Exp $");
19 19
20#ifdef HAVE_OPENSSL 20#ifdef HAVE_OPENSSL
21#include <openssl/bn.h> 21#include <openssl/bn.h>
@@ -42,93 +42,93 @@ int
42save_private_key(const char *filename, const char *passphrase, 42save_private_key(const char *filename, const char *passphrase,
43 RSA *key, const char *comment) 43 RSA *key, const char *comment)
44{ 44{
45 Buffer buffer, encrypted; 45 Buffer buffer, encrypted;
46 char buf[100], *cp; 46 char buf[100], *cp;
47 int f, i; 47 int f, i;
48 CipherContext cipher; 48 CipherContext cipher;
49 int cipher_type; 49 int cipher_type;
50 u_int32_t rand; 50 u_int32_t rand;
51 51
52 /* If the passphrase is empty, use SSH_CIPHER_NONE to ease converting to 52 /* If the passphrase is empty, use SSH_CIPHER_NONE to ease
53 another cipher; otherwise use SSH_AUTHFILE_CIPHER. */ 53 converting to another cipher; otherwise use
54 if (strcmp(passphrase, "") == 0) 54 SSH_AUTHFILE_CIPHER. */
55 cipher_type = SSH_CIPHER_NONE; 55 if (strcmp(passphrase, "") == 0)
56 else 56 cipher_type = SSH_CIPHER_NONE;
57 cipher_type = SSH_AUTHFILE_CIPHER; 57 else
58 58 cipher_type = SSH_AUTHFILE_CIPHER;
59 /* This buffer is used to built the secret part of the private key. */ 59
60 buffer_init(&buffer); 60 /* This buffer is used to built the secret part of the private key. */
61 61 buffer_init(&buffer);
62 /* Put checkbytes for checking passphrase validity. */ 62
63 rand = arc4random(); 63 /* Put checkbytes for checking passphrase validity. */
64 buf[0] = rand & 0xff; 64 rand = arc4random();
65 buf[1] = (rand >> 8) & 0xff; 65 buf[0] = rand & 0xff;
66 buf[2] = buf[0]; 66 buf[1] = (rand >> 8) & 0xff;
67 buf[3] = buf[1]; 67 buf[2] = buf[0];
68 buffer_append(&buffer, buf, 4); 68 buf[3] = buf[1];
69 69 buffer_append(&buffer, buf, 4);
70 /* Store the private key (n and e will not be stored because they will 70
71 be stored in plain text, and storing them also in encrypted format 71 /* Store the private key (n and e will not be stored because they
72 would just give known plaintext). */ 72 will be stored in plain text, and storing them also in
73 buffer_put_bignum(&buffer, key->d); 73 encrypted format would just give known plaintext). */
74 buffer_put_bignum(&buffer, key->iqmp); 74 buffer_put_bignum(&buffer, key->d);
75 buffer_put_bignum(&buffer, key->q); /* reverse from SSL p */ 75 buffer_put_bignum(&buffer, key->iqmp);
76 buffer_put_bignum(&buffer, key->p); /* reverse from SSL q */ 76 buffer_put_bignum(&buffer, key->q); /* reverse from SSL p */
77 77 buffer_put_bignum(&buffer, key->p); /* reverse from SSL q */
78 /* Pad the part to be encrypted until its size is a multiple of 8. */ 78
79 while (buffer_len(&buffer) % 8 != 0) 79 /* Pad the part to be encrypted until its size is a multiple of 8. */
80 buffer_put_char(&buffer, 0); 80 while (buffer_len(&buffer) % 8 != 0)
81 81 buffer_put_char(&buffer, 0);
82 /* This buffer will be used to contain the data in the file. */ 82
83 buffer_init(&encrypted); 83 /* This buffer will be used to contain the data in the file. */
84 84 buffer_init(&encrypted);
85 /* First store keyfile id string. */ 85
86 cp = AUTHFILE_ID_STRING; 86 /* First store keyfile id string. */
87 for (i = 0; cp[i]; i++) 87 cp = AUTHFILE_ID_STRING;
88 buffer_put_char(&encrypted, cp[i]); 88 for (i = 0; cp[i]; i++)
89 buffer_put_char(&encrypted, 0); 89 buffer_put_char(&encrypted, cp[i]);
90 90 buffer_put_char(&encrypted, 0);
91 /* Store cipher type. */ 91
92 buffer_put_char(&encrypted, cipher_type); 92 /* Store cipher type. */
93 buffer_put_int(&encrypted, 0); /* For future extension */ 93 buffer_put_char(&encrypted, cipher_type);
94 94 buffer_put_int(&encrypted, 0); /* For future extension */
95 /* Store public key. This will be in plain text. */ 95
96 buffer_put_int(&encrypted, BN_num_bits(key->n)); 96 /* Store public key. This will be in plain text. */
97 buffer_put_bignum(&encrypted, key->n); 97 buffer_put_int(&encrypted, BN_num_bits(key->n));
98 buffer_put_bignum(&encrypted, key->e); 98 buffer_put_bignum(&encrypted, key->n);
99 buffer_put_string(&encrypted, comment, strlen(comment)); 99 buffer_put_bignum(&encrypted, key->e);
100 100 buffer_put_string(&encrypted, comment, strlen(comment));
101 /* Allocate space for the private part of the key in the buffer. */ 101
102 buffer_append_space(&encrypted, &cp, buffer_len(&buffer)); 102 /* Allocate space for the private part of the key in the buffer. */
103 103 buffer_append_space(&encrypted, &cp, buffer_len(&buffer));
104 cipher_set_key_string(&cipher, cipher_type, passphrase, 1); 104
105 cipher_encrypt(&cipher, (unsigned char *)cp, 105 cipher_set_key_string(&cipher, cipher_type, passphrase, 1);
106 (unsigned char *)buffer_ptr(&buffer), 106 cipher_encrypt(&cipher, (unsigned char *) cp,
107 buffer_len(&buffer)); 107 (unsigned char *) buffer_ptr(&buffer),
108 memset(&cipher, 0, sizeof(cipher)); 108 buffer_len(&buffer));
109 109 memset(&cipher, 0, sizeof(cipher));
110 /* Destroy temporary data. */ 110
111 memset(buf, 0, sizeof(buf)); 111 /* Destroy temporary data. */
112 buffer_free(&buffer); 112 memset(buf, 0, sizeof(buf));
113 113 buffer_free(&buffer);
114 /* Write to a file. */ 114
115 f = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0600); 115 /* Write to a file. */
116 if (f < 0) 116 f = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
117 return 0; 117 if (f < 0)
118 118 return 0;
119 if (write(f, buffer_ptr(&encrypted), buffer_len(&encrypted)) != 119
120 buffer_len(&encrypted)) 120 if (write(f, buffer_ptr(&encrypted), buffer_len(&encrypted)) !=
121 { 121 buffer_len(&encrypted)) {
122 debug("Write to key file %.200s failed: %.100s", filename, 122 debug("Write to key file %.200s failed: %.100s", filename,
123 strerror(errno)); 123 strerror(errno));
124 buffer_free(&encrypted); 124 buffer_free(&encrypted);
125 close(f); 125 close(f);
126 remove(filename); 126 remove(filename);
127 return 0; 127 return 0;
128 } 128 }
129 close(f); 129 close(f);
130 buffer_free(&encrypted); 130 buffer_free(&encrypted);
131 return 1; 131 return 1;
132} 132}
133 133
134/* Loads the public part of the key file. Returns 0 if an error 134/* 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,
136 non-zero otherwise. */ 136 non-zero otherwise. */
137 137
138int 138int
139load_public_key(const char *filename, RSA *pub, 139load_public_key(const char *filename, RSA * pub,
140 char **comment_return) 140 char **comment_return)
141{ 141{
142 int f, i; 142 int f, i;
143 off_t len; 143 off_t len;
144 Buffer buffer; 144 Buffer buffer;
145 char *cp; 145 char *cp;
146 146
147 /* Read data from the file into the buffer. */ 147 /* Read data from the file into the buffer. */
148 f = open(filename, O_RDONLY); 148 f = open(filename, O_RDONLY);
149 if (f < 0) 149 if (f < 0)
150 return 0; 150 return 0;
151 151
152 len = lseek(f, (off_t)0, SEEK_END); 152 len = lseek(f, (off_t) 0, SEEK_END);
153 lseek(f, (off_t)0, SEEK_SET); 153 lseek(f, (off_t) 0, SEEK_SET);
154 154
155 buffer_init(&buffer); 155 buffer_init(&buffer);
156 buffer_append_space(&buffer, &cp, len); 156 buffer_append_space(&buffer, &cp, len);
157 157
158 if (read(f, cp, (size_t)len) != (size_t)len) 158 if (read(f, cp, (size_t) len) != (size_t) len) {
159 { 159 debug("Read from key file %.200s failed: %.100s", filename,
160 debug("Read from key file %.200s failed: %.100s", filename, 160 strerror(errno));
161 strerror(errno)); 161 buffer_free(&buffer);
162 buffer_free(&buffer); 162 close(f);
163 close(f); 163 return 0;
164 return 0; 164 }
165 } 165 close(f);
166 close(f); 166
167 167 /* Check that it is at least big enought to contain the ID string. */
168 /* Check that it is at least big enought to contain the ID string. */ 168 if (len < strlen(AUTHFILE_ID_STRING) + 1) {
169 if (len < strlen(AUTHFILE_ID_STRING) + 1) 169 debug("Bad key file %.200s.", filename);
170 { 170 buffer_free(&buffer);
171 debug("Bad key file %.200s.", filename); 171 return 0;
172 buffer_free(&buffer); 172 }
173 return 0; 173 /* Make sure it begins with the id string. Consume the id string
174 } 174 from the buffer. */
175 175 for (i = 0; i < (unsigned int) strlen(AUTHFILE_ID_STRING) + 1; i++)
176 /* Make sure it begins with the id string. Consume the id string from 176 if (buffer_get_char(&buffer) != (unsigned char) AUTHFILE_ID_STRING[i]) {
177 the buffer. */ 177 debug("Bad key file %.200s.", filename);
178 for (i = 0; i < (unsigned int)strlen(AUTHFILE_ID_STRING) + 1; i++) 178 buffer_free(&buffer);
179 if (buffer_get_char(&buffer) != (unsigned char)AUTHFILE_ID_STRING[i]) 179 return 0;
180 { 180 }
181 debug("Bad key file %.200s.", filename); 181 /* Skip cipher type and reserved data. */
182 (void) buffer_get_char(&buffer); /* cipher type */
183 (void) buffer_get_int(&buffer); /* reserved */
184
185 /* Read the public key from the buffer. */
186 buffer_get_int(&buffer);
187 pub->n = BN_new();
188 buffer_get_bignum(&buffer, pub->n);
189 pub->e = BN_new();
190 buffer_get_bignum(&buffer, pub->e);
191 if (comment_return)
192 *comment_return = buffer_get_string(&buffer, NULL);
193 /* The encrypted private part is not parsed by this function. */
194
182 buffer_free(&buffer); 195 buffer_free(&buffer);
183 return 0; 196
184 } 197 return 1;
185
186 /* Skip cipher type and reserved data. */
187 (void)buffer_get_char(&buffer); /* cipher type */
188 (void)buffer_get_int(&buffer); /* reserved */
189
190 /* Read the public key from the buffer. */
191 buffer_get_int(&buffer);
192 pub->n = BN_new();
193 buffer_get_bignum(&buffer, pub->n);
194 pub->e = BN_new();
195 buffer_get_bignum(&buffer, pub->e);
196 if (comment_return)
197 *comment_return = buffer_get_string(&buffer, NULL);
198 /* The encrypted private part is not parsed by this function. */
199
200 buffer_free(&buffer);
201
202 return 1;
203} 198}
204 199
205/* Loads the private key from the file. Returns 0 if an error is encountered 200/* 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,
208 203
209int 204int
210load_private_key(const char *filename, const char *passphrase, 205load_private_key(const char *filename, const char *passphrase,
211 RSA *prv, char **comment_return) 206 RSA * prv, char **comment_return)
212{ 207{
213 int f, i, check1, check2, cipher_type; 208 int f, i, check1, check2, cipher_type;
214 off_t len; 209 off_t len;
215 Buffer buffer, decrypted; 210 Buffer buffer, decrypted;
216 char *cp; 211 char *cp;
217 CipherContext cipher; 212 CipherContext cipher;
218 BN_CTX *ctx; 213 BN_CTX *ctx;
219 BIGNUM *aux; 214 BIGNUM *aux;
220 struct stat st; 215 struct stat st;
221 216
222 /* Read the file into the buffer. */ 217 /* Read the file into the buffer. */
223 f = open(filename, O_RDONLY); 218 f = open(filename, O_RDONLY);
224 if (f < 0) 219 if (f < 0)
225 return 0; 220 return 0;
226 221
227 /* We assume we are called under uid of the owner of the file */ 222 /* We assume we are called under uid of the owner of the file */
228 if (fstat(f, &st) < 0 || 223 if (fstat(f, &st) < 0 ||
229 (st.st_uid != 0 && st.st_uid != getuid()) || 224 (st.st_uid != 0 && st.st_uid != getuid()) ||
230 (st.st_mode & 077) != 0) { 225 (st.st_mode & 077) != 0) {
231 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 226 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
232 error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @"); 227 error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @");
233 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 228 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
234 error("Bad ownership or mode(0%3.3o) for '%s'.", 229 error("Bad ownership or mode(0%3.3o) for '%s'.",
235 st.st_mode & 0777, filename); 230 st.st_mode & 0777, filename);
236 error("It is recommended that your private key files are NOT accessible by others."); 231 error("It is recommended that your private key files are NOT accessible by others.");
237 return 0; 232 return 0;
238 } 233 }
239 234 len = lseek(f, (off_t) 0, SEEK_END);
240 len = lseek(f, (off_t)0, SEEK_END); 235 lseek(f, (off_t) 0, SEEK_SET);
241 lseek(f, (off_t)0, SEEK_SET); 236
242 237 buffer_init(&buffer);
243 buffer_init(&buffer); 238 buffer_append_space(&buffer, &cp, len);
244 buffer_append_space(&buffer, &cp, len); 239
245 240 if (read(f, cp, (size_t) len) != (size_t) len) {
246 if (read(f, cp, (size_t)len) != (size_t)len) 241 debug("Read from key file %.200s failed: %.100s", filename,
247 { 242 strerror(errno));
248 debug("Read from key file %.200s failed: %.100s", filename, 243 buffer_free(&buffer);
249 strerror(errno)); 244 close(f);
250 buffer_free(&buffer); 245 return 0;
251 close(f); 246 }
252 return 0; 247 close(f);
253 } 248
254 close(f); 249 /* Check that it is at least big enought to contain the ID string. */
255 250 if (len < strlen(AUTHFILE_ID_STRING) + 1) {
256 /* Check that it is at least big enought to contain the ID string. */ 251 debug("Bad key file %.200s.", filename);
257 if (len < strlen(AUTHFILE_ID_STRING) + 1) 252 buffer_free(&buffer);
258 { 253 return 0;
259 debug("Bad key file %.200s.", filename); 254 }
260 buffer_free(&buffer); 255 /* Make sure it begins with the id string. Consume the id string
261 return 0; 256 from the buffer. */
262 } 257 for (i = 0; i < (unsigned int) strlen(AUTHFILE_ID_STRING) + 1; i++)
263 258 if (buffer_get_char(&buffer) != (unsigned char) AUTHFILE_ID_STRING[i]) {
264 /* Make sure it begins with the id string. Consume the id string from 259 debug("Bad key file %.200s.", filename);
265 the buffer. */ 260 buffer_free(&buffer);
266 for (i = 0; i < (unsigned int)strlen(AUTHFILE_ID_STRING) + 1; i++) 261 return 0;
267 if (buffer_get_char(&buffer) != (unsigned char)AUTHFILE_ID_STRING[i]) 262 }
268 { 263 /* Read cipher type. */
269 debug("Bad key file %.200s.", filename); 264 cipher_type = buffer_get_char(&buffer);
265 (void) buffer_get_int(&buffer); /* Reserved data. */
266
267 /* Read the public key from the buffer. */
268 buffer_get_int(&buffer);
269 prv->n = BN_new();
270 buffer_get_bignum(&buffer, prv->n);
271 prv->e = BN_new();
272 buffer_get_bignum(&buffer, prv->e);
273 if (comment_return)
274 *comment_return = buffer_get_string(&buffer, NULL);
275 else
276 xfree(buffer_get_string(&buffer, NULL));
277
278 /* Check that it is a supported cipher. */
279 if (((cipher_mask() | SSH_CIPHER_NONE | SSH_AUTHFILE_CIPHER) &
280 (1 << cipher_type)) == 0) {
281 debug("Unsupported cipher %.100s used in key file %.200s.",
282 cipher_name(cipher_type), filename);
283 buffer_free(&buffer);
284 goto fail;
285 }
286 /* Initialize space for decrypted data. */
287 buffer_init(&decrypted);
288 buffer_append_space(&decrypted, &cp, buffer_len(&buffer));
289
290 /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */
291 cipher_set_key_string(&cipher, cipher_type, passphrase, 0);
292 cipher_decrypt(&cipher, (unsigned char *) cp,
293 (unsigned char *) buffer_ptr(&buffer),
294 buffer_len(&buffer));
295
270 buffer_free(&buffer); 296 buffer_free(&buffer);
271 return 0; 297
272 } 298 check1 = buffer_get_char(&decrypted);
273 299 check2 = buffer_get_char(&decrypted);
274 /* Read cipher type. */ 300 if (check1 != buffer_get_char(&decrypted) ||
275 cipher_type = buffer_get_char(&buffer); 301 check2 != buffer_get_char(&decrypted)) {
276 (void)buffer_get_int(&buffer); /* Reserved data. */ 302 if (strcmp(passphrase, "") != 0)
277 303 debug("Bad passphrase supplied for key file %.200s.", filename);
278 /* Read the public key from the buffer. */ 304 /* Bad passphrase. */
279 buffer_get_int(&buffer); 305 buffer_free(&decrypted);
280 prv->n = BN_new(); 306fail:
281 buffer_get_bignum(&buffer, prv->n); 307 BN_clear_free(prv->n);
282 prv->e = BN_new(); 308 BN_clear_free(prv->e);
283 buffer_get_bignum(&buffer, prv->e); 309 if (comment_return)
284 if (comment_return) 310 xfree(*comment_return);
285 *comment_return = buffer_get_string(&buffer, NULL); 311 return 0;
286 else 312 }
287 xfree(buffer_get_string(&buffer, NULL)); 313 /* Read the rest of the private key. */
288 314 prv->d = BN_new();
289 /* Check that it is a supported cipher. */ 315 buffer_get_bignum(&decrypted, prv->d);
290 if (((cipher_mask() | SSH_CIPHER_NONE | SSH_AUTHFILE_CIPHER) & 316 prv->iqmp = BN_new();
291 (1 << cipher_type)) == 0) 317 buffer_get_bignum(&decrypted, prv->iqmp); /* u */
292 { 318 /* in SSL and SSH p and q are exchanged */
293 debug("Unsupported cipher %.100s used in key file %.200s.", 319 prv->q = BN_new();
294 cipher_name(cipher_type), filename); 320 buffer_get_bignum(&decrypted, prv->q); /* p */
295 buffer_free(&buffer); 321 prv->p = BN_new();
296 goto fail; 322 buffer_get_bignum(&decrypted, prv->p); /* q */
297 } 323
298 324 ctx = BN_CTX_new();
299 /* Initialize space for decrypted data. */ 325 aux = BN_new();
300 buffer_init(&decrypted); 326
301 buffer_append_space(&decrypted, &cp, buffer_len(&buffer)); 327 BN_sub(aux, prv->q, BN_value_one());
302 328 prv->dmq1 = BN_new();
303 /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ 329 BN_mod(prv->dmq1, prv->d, aux, ctx);
304 cipher_set_key_string(&cipher, cipher_type, passphrase, 0); 330
305 cipher_decrypt(&cipher, (unsigned char *)cp, 331 BN_sub(aux, prv->p, BN_value_one());
306 (unsigned char *)buffer_ptr(&buffer), 332 prv->dmp1 = BN_new();
307 buffer_len(&buffer)); 333 BN_mod(prv->dmp1, prv->d, aux, ctx);
308 334
309 buffer_free(&buffer); 335 BN_clear_free(aux);
310 336 BN_CTX_free(ctx);
311 check1 = buffer_get_char(&decrypted); 337
312 check2 = buffer_get_char(&decrypted); 338 buffer_free(&decrypted);
313 if (check1 != buffer_get_char(&decrypted) || 339
314 check2 != buffer_get_char(&decrypted)) 340 return 1;
315 {
316 if (strcmp(passphrase, "") != 0)
317 debug("Bad passphrase supplied for key file %.200s.", filename);
318 /* Bad passphrase. */
319 buffer_free(&decrypted);
320 fail:
321 BN_clear_free(prv->n);
322 BN_clear_free(prv->e);
323 if (comment_return)
324 xfree(*comment_return);
325 return 0;
326 }
327
328 /* Read the rest of the private key. */
329 prv->d = BN_new();
330 buffer_get_bignum(&decrypted, prv->d);
331 prv->iqmp = BN_new();
332 buffer_get_bignum(&decrypted, prv->iqmp); /* u */
333 /* in SSL and SSH p and q are exchanged */
334 prv->q = BN_new();
335 buffer_get_bignum(&decrypted, prv->q); /* p */
336 prv->p = BN_new();
337 buffer_get_bignum(&decrypted, prv->p); /* q */
338
339 ctx = BN_CTX_new();
340 aux = BN_new();
341
342 BN_sub(aux, prv->q, BN_value_one());
343 prv->dmq1 = BN_new();
344 BN_mod(prv->dmq1, prv->d, aux, ctx);
345
346 BN_sub(aux, prv->p, BN_value_one());
347 prv->dmp1 = BN_new();
348 BN_mod(prv->dmp1, prv->d, aux, ctx);
349
350 BN_clear_free(aux);
351 BN_CTX_free(ctx);
352
353 buffer_free(&decrypted);
354
355 return 1;
356} 341}
diff --git a/bufaux.c b/bufaux.c
index a1ba0fd58..d953a2ad2 100644
--- a/bufaux.c
+++ b/bufaux.c
@@ -1,21 +1,21 @@
1/* 1/*
2 2 *
3bufaux.c 3 * bufaux.c
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Wed Mar 29 02:24:47 1995 ylo 10 * Created: Wed Mar 29 02:24:47 1995 ylo
11 11 *
12Auxiliary functions for storing and retrieving various data types to/from 12 * Auxiliary functions for storing and retrieving various data types to/from
13Buffers. 13 * Buffers.
14 14 *
15*/ 15 */
16 16
17#include "includes.h" 17#include "includes.h"
18RCSID("$Id: bufaux.c,v 1.5 1999/11/13 02:22:46 damien Exp $"); 18RCSID("$Id: bufaux.c,v 1.6 1999/11/24 13:26:22 damien Exp $");
19 19
20#include "ssh.h" 20#include "ssh.h"
21 21
@@ -30,122 +30,136 @@ RCSID("$Id: bufaux.c,v 1.5 1999/11/13 02:22:46 damien Exp $");
30#include "xmalloc.h" 30#include "xmalloc.h"
31#include "getput.h" 31#include "getput.h"
32 32
33/* Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed 33/*
34 by (bits+7)/8 bytes of binary data, msb first. */ 34 * Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed
35 35 * by (bits+7)/8 bytes of binary data, msb first.
36 */
36void 37void
37buffer_put_bignum(Buffer *buffer, BIGNUM *value) 38buffer_put_bignum(Buffer *buffer, BIGNUM *value)
38{ 39{
39 int bits = BN_num_bits(value); 40 int bits = BN_num_bits(value);
40 int bin_size = (bits + 7) / 8; 41 int bin_size = (bits + 7) / 8;
41 char *buf = xmalloc(bin_size); 42 char *buf = xmalloc(bin_size);
42 int oi; 43 int oi;
43 char msg[2]; 44 char msg[2];
44 45
45 /* Get the value of in binary */ 46 /* Get the value of in binary */
46 oi = BN_bn2bin(value, buf); 47 oi = BN_bn2bin(value, buf);
47 if (oi != bin_size) 48 if (oi != bin_size)
48 fatal("buffer_put_bignum: BN_bn2bin() failed: oi %d != bin_size %d", 49 fatal("buffer_put_bignum: BN_bn2bin() failed: oi %d != bin_size %d",
49 oi, bin_size); 50 oi, bin_size);
50 51
51 /* Store the number of bits in the buffer in two bytes, msb first. */ 52 /* Store the number of bits in the buffer in two bytes, msb first. */
52 PUT_16BIT(msg, bits); 53 PUT_16BIT(msg, bits);
53 buffer_append(buffer, msg, 2); 54 buffer_append(buffer, msg, 2);
54 /* Store the binary data. */ 55 /* Store the binary data. */
55 buffer_append(buffer, buf, oi); 56 buffer_append(buffer, buf, oi);
56 /* Clear the temporary data. */ 57 /* Clear the temporary data. */
57 memset(buf, 0, bin_size); 58 memset(buf, 0, bin_size);
58 xfree(buf); 59 xfree(buf);
59} 60}
60 61
61/* Retrieves an BIGNUM from the buffer. */ 62/*
62 63 * Retrieves an BIGNUM from the buffer.
64 */
63int 65int
64buffer_get_bignum(Buffer *buffer, BIGNUM *value) 66buffer_get_bignum(Buffer *buffer, BIGNUM *value)
65{ 67{
66 int bits, bytes; 68 int bits, bytes;
67 unsigned char buf[2], *bin; 69 unsigned char buf[2], *bin;
68 70
69 /* Get the number for bits. */ 71 /* Get the number for bits. */
70 buffer_get(buffer, (char *)buf, 2); 72 buffer_get(buffer, (char *) buf, 2);
71 bits = GET_16BIT(buf); 73 bits = GET_16BIT(buf);
72 /* Compute the number of binary bytes that follow. */ 74 /* Compute the number of binary bytes that follow. */
73 bytes = (bits + 7) / 8; 75 bytes = (bits + 7) / 8;
74 if (buffer_len(buffer) < bytes) 76 if (buffer_len(buffer) < bytes)
75 fatal("buffer_get_bignum: input buffer too small"); 77 fatal("buffer_get_bignum: input buffer too small");
76 bin = buffer_ptr(buffer); 78 bin = buffer_ptr(buffer);
77 BN_bin2bn(bin, bytes, value); 79 BN_bin2bn(bin, bytes, value);
78 buffer_consume(buffer, bytes); 80 buffer_consume(buffer, bytes);
79 81
80 return 2 + bytes; 82 return 2 + bytes;
81} 83}
82 84
83/* Returns an integer from the buffer (4 bytes, msb first). */ 85/*
84 86 * Returns an integer from the buffer (4 bytes, msb first).
85unsigned int buffer_get_int(Buffer *buffer) 87 */
88unsigned int
89buffer_get_int(Buffer *buffer)
86{ 90{
87 unsigned char buf[4]; 91 unsigned char buf[4];
88 buffer_get(buffer, (char *)buf, 4); 92 buffer_get(buffer, (char *) buf, 4);
89 return GET_32BIT(buf); 93 return GET_32BIT(buf);
90} 94}
91 95
92/* Stores an integer in the buffer in 4 bytes, msb first. */ 96/*
93 97 * Stores an integer in the buffer in 4 bytes, msb first.
94void buffer_put_int(Buffer *buffer, unsigned int value) 98 */
99void
100buffer_put_int(Buffer *buffer, unsigned int value)
95{ 101{
96 char buf[4]; 102 char buf[4];
97 PUT_32BIT(buf, value); 103 PUT_32BIT(buf, value);
98 buffer_append(buffer, buf, 4); 104 buffer_append(buffer, buf, 4);
99} 105}
100 106
101/* Returns an arbitrary binary string from the buffer. The string cannot 107/*
102 be longer than 256k. The returned value points to memory allocated 108 * Returns an arbitrary binary string from the buffer. The string cannot
103 with xmalloc; it is the responsibility of the calling function to free 109 * be longer than 256k. The returned value points to memory allocated
104 the data. If length_ptr is non-NULL, the length of the returned data 110 * with xmalloc; it is the responsibility of the calling function to free
105 will be stored there. A null character will be automatically appended 111 * the data. If length_ptr is non-NULL, the length of the returned data
106 to the returned string, and is not counted in length. */ 112 * will be stored there. A null character will be automatically appended
107 113 * to the returned string, and is not counted in length.
108char *buffer_get_string(Buffer *buffer, unsigned int *length_ptr) 114 */
115char *
116buffer_get_string(Buffer *buffer, unsigned int *length_ptr)
109{ 117{
110 unsigned int len; 118 unsigned int len;
111 char *value; 119 char *value;
112 /* Get the length. */ 120 /* Get the length. */
113 len = buffer_get_int(buffer); 121 len = buffer_get_int(buffer);
114 if (len > 256*1024) 122 if (len > 256 * 1024)
115 fatal("Received packet with bad string length %d", len); 123 fatal("Received packet with bad string length %d", len);
116 /* Allocate space for the string. Add one byte for a null character. */ 124 /* Allocate space for the string. Add one byte for a null character. */
117 value = xmalloc(len + 1); 125 value = xmalloc(len + 1);
118 /* Get the string. */ 126 /* Get the string. */
119 buffer_get(buffer, value, len); 127 buffer_get(buffer, value, len);
120 /* Append a null character to make processing easier. */ 128 /* Append a null character to make processing easier. */
121 value[len] = 0; 129 value[len] = 0;
122 /* Optionally return the length of the string. */ 130 /* Optionally return the length of the string. */
123 if (length_ptr) 131 if (length_ptr)
124 *length_ptr = len; 132 *length_ptr = len;
125 return value; 133 return value;
126} 134}
127 135
128/* Stores and arbitrary binary string in the buffer. */ 136/*
129 137 * Stores and arbitrary binary string in the buffer.
130void buffer_put_string(Buffer *buffer, const void *buf, unsigned int len) 138 */
139void
140buffer_put_string(Buffer *buffer, const void *buf, unsigned int len)
131{ 141{
132 buffer_put_int(buffer, len); 142 buffer_put_int(buffer, len);
133 buffer_append(buffer, buf, len); 143 buffer_append(buffer, buf, len);
134} 144}
135 145
136/* Returns a character from the buffer (0 - 255). */ 146/*
137 147 * Returns a character from the buffer (0 - 255).
138int buffer_get_char(Buffer *buffer) 148 */
149int
150buffer_get_char(Buffer *buffer)
139{ 151{
140 char ch; 152 char ch;
141 buffer_get(buffer, &ch, 1); 153 buffer_get(buffer, &ch, 1);
142 return (unsigned char)ch; 154 return (unsigned char) ch;
143} 155}
144 156
145/* Stores a character in the buffer. */ 157/*
146 158 * Stores a character in the buffer.
147void buffer_put_char(Buffer *buffer, int value) 159 */
160void
161buffer_put_char(Buffer *buffer, int value)
148{ 162{
149 char ch = value; 163 char ch = value;
150 buffer_append(buffer, &ch, 1); 164 buffer_append(buffer, &ch, 1);
151} 165}
diff --git a/bufaux.h b/bufaux.h
index bfc668485..0b17a8ac7 100644
--- a/bufaux.h
+++ b/bufaux.h
@@ -1,17 +1,17 @@
1/* 1/*
2 2 *
3bufaux.h 3 * bufaux.h
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Wed Mar 29 02:18:23 1995 ylo 10 * Created: Wed Mar 29 02:18:23 1995 ylo
11 11 *
12*/ 12 */
13 13
14/* RCSID("$Id: bufaux.h,v 1.1 1999/10/27 03:42:43 damien Exp $"); */ 14/* RCSID("$Id: bufaux.h,v 1.2 1999/11/24 13:26:22 damien Exp $"); */
15 15
16#ifndef BUFAUX_H 16#ifndef BUFAUX_H
17#define BUFAUX_H 17#define BUFAUX_H
@@ -20,22 +20,22 @@ Created: Wed Mar 29 02:18:23 1995 ylo
20 20
21/* Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed 21/* Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed
22 by (bits+7)/8 bytes of binary data, msb first. */ 22 by (bits+7)/8 bytes of binary data, msb first. */
23void buffer_put_bignum(Buffer *buffer, BIGNUM *value); 23void buffer_put_bignum(Buffer * buffer, BIGNUM * value);
24 24
25/* Retrieves an BIGNUM from the buffer. */ 25/* Retrieves an BIGNUM from the buffer. */
26int buffer_get_bignum(Buffer *buffer, BIGNUM *value); 26int buffer_get_bignum(Buffer * buffer, BIGNUM * value);
27 27
28/* Returns an integer from the buffer (4 bytes, msb first). */ 28/* Returns an integer from the buffer (4 bytes, msb first). */
29unsigned int buffer_get_int(Buffer *buffer); 29unsigned int buffer_get_int(Buffer * buffer);
30 30
31/* Stores an integer in the buffer in 4 bytes, msb first. */ 31/* Stores an integer in the buffer in 4 bytes, msb first. */
32void buffer_put_int(Buffer *buffer, unsigned int value); 32void buffer_put_int(Buffer * buffer, unsigned int value);
33 33
34/* Returns a character from the buffer (0 - 255). */ 34/* Returns a character from the buffer (0 - 255). */
35int buffer_get_char(Buffer *buffer); 35int buffer_get_char(Buffer * buffer);
36 36
37/* Stores a character in the buffer. */ 37/* Stores a character in the buffer. */
38void buffer_put_char(Buffer *buffer, int value); 38void buffer_put_char(Buffer * buffer, int value);
39 39
40/* Returns an arbitrary binary string from the buffer. The string cannot 40/* Returns an arbitrary binary string from the buffer. The string cannot
41 be longer than 256k. The returned value points to memory allocated 41 be longer than 256k. The returned value points to memory allocated
@@ -43,9 +43,9 @@ void buffer_put_char(Buffer *buffer, int value);
43 the data. If length_ptr is non-NULL, the length of the returned data 43 the data. If length_ptr is non-NULL, the length of the returned data
44 will be stored there. A null character will be automatically appended 44 will be stored there. A null character will be automatically appended
45 to the returned string, and is not counted in length. */ 45 to the returned string, and is not counted in length. */
46char *buffer_get_string(Buffer *buffer, unsigned int *length_ptr); 46char *buffer_get_string(Buffer * buffer, unsigned int *length_ptr);
47 47
48/* Stores and arbitrary binary string in the buffer. */ 48/* Stores and arbitrary binary string in the buffer. */
49void buffer_put_string(Buffer *buffer, const void *buf, unsigned int len); 49void buffer_put_string(Buffer * buffer, const void *buf, unsigned int len);
50 50
51#endif /* BUFAUX_H */ 51#endif /* BUFAUX_H */
diff --git a/buffer.c b/buffer.c
index e183d1017..6ad9bb2e9 100644
--- a/buffer.c
+++ b/buffer.c
@@ -1,20 +1,20 @@
1/* 1/*
2 2 *
3buffer.c 3 * buffer.c
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Sat Mar 18 04:15:33 1995 ylo 10 * Created: Sat Mar 18 04:15:33 1995 ylo
11 11 *
12Functions for manipulating fifo buffers (that can grow if needed). 12 * Functions for manipulating fifo buffers (that can grow if needed).
13 13 *
14*/ 14 */
15 15
16#include "includes.h" 16#include "includes.h"
17RCSID("$Id: buffer.c,v 1.1 1999/10/27 03:42:43 damien Exp $"); 17RCSID("$Id: buffer.c,v 1.2 1999/11/24 13:26:22 damien Exp $");
18 18
19#include "xmalloc.h" 19#include "xmalloc.h"
20#include "buffer.h" 20#include "buffer.h"
@@ -22,129 +22,134 @@ RCSID("$Id: buffer.c,v 1.1 1999/10/27 03:42:43 damien Exp $");
22 22
23/* Initializes the buffer structure. */ 23/* Initializes the buffer structure. */
24 24
25void buffer_init(Buffer *buffer) 25void
26buffer_init(Buffer *buffer)
26{ 27{
27 buffer->alloc = 4096; 28 buffer->alloc = 4096;
28 buffer->buf = xmalloc(buffer->alloc); 29 buffer->buf = xmalloc(buffer->alloc);
29 buffer->offset = 0; 30 buffer->offset = 0;
30 buffer->end = 0; 31 buffer->end = 0;
31} 32}
32 33
33/* Frees any memory used for the buffer. */ 34/* Frees any memory used for the buffer. */
34 35
35void buffer_free(Buffer *buffer) 36void
37buffer_free(Buffer *buffer)
36{ 38{
37 memset(buffer->buf, 0, buffer->alloc); 39 memset(buffer->buf, 0, buffer->alloc);
38 xfree(buffer->buf); 40 xfree(buffer->buf);
39} 41}
40 42
41/* Clears any data from the buffer, making it empty. This does not actually 43/* Clears any data from the buffer, making it empty. This does not actually
42 zero the memory. */ 44 zero the memory. */
43 45
44void buffer_clear(Buffer *buffer) 46void
47buffer_clear(Buffer *buffer)
45{ 48{
46 buffer->offset = 0; 49 buffer->offset = 0;
47 buffer->end = 0; 50 buffer->end = 0;
48} 51}
49 52
50/* Appends data to the buffer, expanding it if necessary. */ 53/* Appends data to the buffer, expanding it if necessary. */
51 54
52void buffer_append(Buffer *buffer, const char *data, unsigned int len) 55void
56buffer_append(Buffer *buffer, const char *data, unsigned int len)
53{ 57{
54 char *cp; 58 char *cp;
55 buffer_append_space(buffer, &cp, len); 59 buffer_append_space(buffer, &cp, len);
56 memcpy(cp, data, len); 60 memcpy(cp, data, len);
57} 61}
58 62
59/* Appends space to the buffer, expanding the buffer if necessary. 63/* Appends space to the buffer, expanding the buffer if necessary.
60 This does not actually copy the data into the buffer, but instead 64 This does not actually copy the data into the buffer, but instead
61 returns a pointer to the allocated region. */ 65 returns a pointer to the allocated region. */
62 66
63void buffer_append_space(Buffer *buffer, char **datap, unsigned int len) 67void
68buffer_append_space(Buffer *buffer, char **datap, unsigned int len)
64{ 69{
65 /* If the buffer is empty, start using it from the beginning. */ 70 /* If the buffer is empty, start using it from the beginning. */
66 if (buffer->offset == buffer->end) 71 if (buffer->offset == buffer->end) {
67 { 72 buffer->offset = 0;
68 buffer->offset = 0; 73 buffer->end = 0;
69 buffer->end = 0; 74 }
70 } 75restart:
71 76 /* If there is enough space to store all data, store it now. */
72 restart: 77 if (buffer->end + len < buffer->alloc) {
73 /* If there is enough space to store all data, store it now. */ 78 *datap = buffer->buf + buffer->end;
74 if (buffer->end + len < buffer->alloc) 79 buffer->end += len;
75 { 80 return;
76 *datap = buffer->buf + buffer->end; 81 }
77 buffer->end += len; 82 /* If the buffer is quite empty, but all data is at the end, move
78 return; 83 the data to the beginning and retry. */
79 } 84 if (buffer->offset > buffer->alloc / 2) {
80 85 memmove(buffer->buf, buffer->buf + buffer->offset,
81 /* If the buffer is quite empty, but all data is at the end, move the 86 buffer->end - buffer->offset);
82 data to the beginning and retry. */ 87 buffer->end -= buffer->offset;
83 if (buffer->offset > buffer->alloc / 2) 88 buffer->offset = 0;
84 { 89 goto restart;
85 memmove(buffer->buf, buffer->buf + buffer->offset, 90 }
86 buffer->end - buffer->offset); 91 /* Increase the size of the buffer and retry. */
87 buffer->end -= buffer->offset; 92 buffer->alloc += len + 32768;
88 buffer->offset = 0; 93 buffer->buf = xrealloc(buffer->buf, buffer->alloc);
89 goto restart; 94 goto restart;
90 }
91
92 /* Increase the size of the buffer and retry. */
93 buffer->alloc += len + 32768;
94 buffer->buf = xrealloc(buffer->buf, buffer->alloc);
95 goto restart;
96} 95}
97 96
98/* Returns the number of bytes of data in the buffer. */ 97/* Returns the number of bytes of data in the buffer. */
99 98
100unsigned int buffer_len(Buffer *buffer) 99unsigned int
100buffer_len(Buffer *buffer)
101{ 101{
102 return buffer->end - buffer->offset; 102 return buffer->end - buffer->offset;
103} 103}
104 104
105/* Gets data from the beginning of the buffer. */ 105/* Gets data from the beginning of the buffer. */
106 106
107void buffer_get(Buffer *buffer, char *buf, unsigned int len) 107void
108buffer_get(Buffer *buffer, char *buf, unsigned int len)
108{ 109{
109 if (len > buffer->end - buffer->offset) 110 if (len > buffer->end - buffer->offset)
110 fatal("buffer_get trying to get more bytes than in buffer"); 111 fatal("buffer_get trying to get more bytes than in buffer");
111 memcpy(buf, buffer->buf + buffer->offset, len); 112 memcpy(buf, buffer->buf + buffer->offset, len);
112 buffer->offset += len; 113 buffer->offset += len;
113} 114}
114 115
115/* Consumes the given number of bytes from the beginning of the buffer. */ 116/* Consumes the given number of bytes from the beginning of the buffer. */
116 117
117void buffer_consume(Buffer *buffer, unsigned int bytes) 118void
119buffer_consume(Buffer *buffer, unsigned int bytes)
118{ 120{
119 if (bytes > buffer->end - buffer->offset) 121 if (bytes > buffer->end - buffer->offset)
120 fatal("buffer_get trying to get more bytes than in buffer"); 122 fatal("buffer_get trying to get more bytes than in buffer");
121 buffer->offset += bytes; 123 buffer->offset += bytes;
122} 124}
123 125
124/* Consumes the given number of bytes from the end of the buffer. */ 126/* Consumes the given number of bytes from the end of the buffer. */
125 127
126void buffer_consume_end(Buffer *buffer, unsigned int bytes) 128void
129buffer_consume_end(Buffer *buffer, unsigned int bytes)
127{ 130{
128 if (bytes > buffer->end - buffer->offset) 131 if (bytes > buffer->end - buffer->offset)
129 fatal("buffer_get trying to get more bytes than in buffer"); 132 fatal("buffer_get trying to get more bytes than in buffer");
130 buffer->end -= bytes; 133 buffer->end -= bytes;
131} 134}
132 135
133/* Returns a pointer to the first used byte in the buffer. */ 136/* Returns a pointer to the first used byte in the buffer. */
134 137
135char *buffer_ptr(Buffer *buffer) 138char *
139buffer_ptr(Buffer *buffer)
136{ 140{
137 return buffer->buf + buffer->offset; 141 return buffer->buf + buffer->offset;
138} 142}
139 143
140/* Dumps the contents of the buffer to stderr. */ 144/* Dumps the contents of the buffer to stderr. */
141 145
142void buffer_dump(Buffer *buffer) 146void
147buffer_dump(Buffer *buffer)
143{ 148{
144 int i; 149 int i;
145 unsigned char *ucp = (unsigned char *)buffer->buf; 150 unsigned char *ucp = (unsigned char *) buffer->buf;
146 151
147 for (i = buffer->offset; i < buffer->end; i++) 152 for (i = buffer->offset; i < buffer->end; i++)
148 fprintf(stderr, " %02x", ucp[i]); 153 fprintf(stderr, " %02x", ucp[i]);
149 fprintf(stderr, "\n"); 154 fprintf(stderr, "\n");
150} 155}
diff --git a/buffer.h b/buffer.h
index d0369dc35..affe1012c 100644
--- a/buffer.h
+++ b/buffer.h
@@ -1,66 +1,64 @@
1/* 1/*
2 2 *
3buffer.h 3 * buffer.h
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Sat Mar 18 04:12:25 1995 ylo 10 * Created: Sat Mar 18 04:12:25 1995 ylo
11 11 *
12Code for manipulating FIFO buffers. 12 * Code for manipulating FIFO buffers.
13 13 *
14*/ 14 */
15 15
16/* RCSID("$Id: buffer.h,v 1.1 1999/10/27 03:42:43 damien Exp $"); */ 16/* RCSID("$Id: buffer.h,v 1.2 1999/11/24 13:26:22 damien Exp $"); */
17 17
18#ifndef BUFFER_H 18#ifndef BUFFER_H
19#define BUFFER_H 19#define BUFFER_H
20 20
21typedef struct 21typedef struct {
22{ 22 char *buf; /* Buffer for data. */
23 char *buf; /* Buffer for data. */ 23 unsigned int alloc; /* Number of bytes allocated for data. */
24 unsigned int alloc; /* Number of bytes allocated for data. */ 24 unsigned int offset; /* Offset of first byte containing data. */
25 unsigned int offset; /* Offset of first byte containing data. */ 25 unsigned int end; /* Offset of last byte containing data. */
26 unsigned int end; /* Offset of last byte containing data. */ 26} Buffer;
27} Buffer;
28
29/* Initializes the buffer structure. */ 27/* Initializes the buffer structure. */
30void buffer_init(Buffer *buffer); 28void buffer_init(Buffer * buffer);
31 29
32/* Frees any memory used for the buffer. */ 30/* Frees any memory used for the buffer. */
33void buffer_free(Buffer *buffer); 31void buffer_free(Buffer * buffer);
34 32
35/* Clears any data from the buffer, making it empty. This does not actually 33/* Clears any data from the buffer, making it empty. This does not actually
36 zero the memory. */ 34 zero the memory. */
37void buffer_clear(Buffer *buffer); 35void buffer_clear(Buffer * buffer);
38 36
39/* Appends data to the buffer, expanding it if necessary. */ 37/* Appends data to the buffer, expanding it if necessary. */
40void buffer_append(Buffer *buffer, const char *data, unsigned int len); 38void buffer_append(Buffer * buffer, const char *data, unsigned int len);
41 39
42/* Appends space to the buffer, expanding the buffer if necessary. 40/* Appends space to the buffer, expanding the buffer if necessary.
43 This does not actually copy the data into the buffer, but instead 41 This does not actually copy the data into the buffer, but instead
44 returns a pointer to the allocated region. */ 42 returns a pointer to the allocated region. */
45void buffer_append_space(Buffer *buffer, char **datap, unsigned int len); 43void buffer_append_space(Buffer * buffer, char **datap, unsigned int len);
46 44
47/* Returns the number of bytes of data in the buffer. */ 45/* Returns the number of bytes of data in the buffer. */
48unsigned int buffer_len(Buffer *buffer); 46unsigned int buffer_len(Buffer * buffer);
49 47
50/* Gets data from the beginning of the buffer. */ 48/* Gets data from the beginning of the buffer. */
51void buffer_get(Buffer *buffer, char *buf, unsigned int len); 49void buffer_get(Buffer * buffer, char *buf, unsigned int len);
52 50
53/* Consumes the given number of bytes from the beginning of the buffer. */ 51/* Consumes the given number of bytes from the beginning of the buffer. */
54void buffer_consume(Buffer *buffer, unsigned int bytes); 52void buffer_consume(Buffer * buffer, unsigned int bytes);
55 53
56/* Consumes the given number of bytes from the end of the buffer. */ 54/* Consumes the given number of bytes from the end of the buffer. */
57void buffer_consume_end(Buffer *buffer, unsigned int bytes); 55void buffer_consume_end(Buffer * buffer, unsigned int bytes);
58 56
59/* Returns a pointer to the first used byte in the buffer. */ 57/* Returns a pointer to the first used byte in the buffer. */
60char *buffer_ptr(Buffer *buffer); 58char *buffer_ptr(Buffer * buffer);
61 59
62/* Dumps the contents of the buffer to stderr in hex. This intended for 60/* Dumps the contents of the buffer to stderr in hex. This intended for
63 debugging purposes only. */ 61 debugging purposes only. */
64void buffer_dump(Buffer *buffer); 62void buffer_dump(Buffer * buffer);
65 63
66#endif /* BUFFER_H */ 64#endif /* BUFFER_H */
diff --git a/canohost.c b/canohost.c
index 08f798758..3179ddc25 100644
--- a/canohost.c
+++ b/canohost.c
@@ -1,233 +1,228 @@
1/* 1/*
2 2 *
3canohost.c 3 * canohost.c
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Sun Jul 2 17:52:22 1995 ylo 10 * Created: Sun Jul 2 17:52:22 1995 ylo
11 11 *
12Functions for returning the canonical host name of the remote site. 12 * Functions for returning the canonical host name of the remote site.
13 13 *
14*/ 14 */
15 15
16#include "includes.h" 16#include "includes.h"
17RCSID("$Id: canohost.c,v 1.2 1999/11/15 04:25:10 damien Exp $"); 17RCSID("$Id: canohost.c,v 1.3 1999/11/24 13:26:22 damien Exp $");
18 18
19#include "packet.h" 19#include "packet.h"
20#include "xmalloc.h" 20#include "xmalloc.h"
21#include "ssh.h" 21#include "ssh.h"
22 22
23/* Return the canonical name of the host at the other end of the socket. 23/* Return the canonical name of the host at the other end of the socket.
24 The caller should free the returned string with xfree. */ 24 The caller should free the returned string with xfree. */
25 25
26char *get_remote_hostname(int socket) 26char *
27get_remote_hostname(int socket)
27{ 28{
28 struct sockaddr_in from; 29 struct sockaddr_in from;
29 int fromlen, i; 30 int fromlen, i;
30 struct hostent *hp; 31 struct hostent *hp;
31 char name[MAXHOSTNAMELEN]; 32 char name[MAXHOSTNAMELEN];
32 33
33 /* Get IP address of client. */ 34 /* Get IP address of client. */
34 fromlen = sizeof(from); 35 fromlen = sizeof(from);
35 memset(&from, 0, sizeof(from)); 36 memset(&from, 0, sizeof(from));
36 if (getpeername(socket, (struct sockaddr *)&from, &fromlen) < 0) 37 if (getpeername(socket, (struct sockaddr *) & from, &fromlen) < 0) {
37 { 38 debug("getpeername failed: %.100s", strerror(errno));
38 debug("getpeername failed: %.100s", strerror(errno)); 39 fatal_cleanup();
39 fatal_cleanup(); 40 }
40 } 41 /* Map the IP address to a host name. */
41 42 hp = gethostbyaddr((char *) &from.sin_addr, sizeof(struct in_addr),
42 /* Map the IP address to a host name. */ 43 from.sin_family);
43 hp = gethostbyaddr((char *)&from.sin_addr, sizeof(struct in_addr), 44 if (hp) {
44 from.sin_family); 45 /* Got host name, find canonic host name. */
45 if (hp) 46 if (strchr(hp->h_name, '.') != 0)
46 { 47 strlcpy(name, hp->h_name, sizeof(name));
47 /* Got host name, find canonic host name. */ 48 else if (hp->h_aliases != 0
48 if (strchr(hp->h_name, '.') != 0) 49 && hp->h_aliases[0] != 0
49 strlcpy(name, hp->h_name, sizeof(name)); 50 && strchr(hp->h_aliases[0], '.') != 0)
50 else if (hp->h_aliases != 0 51 strlcpy(name, hp->h_aliases[0], sizeof(name));
51 && hp->h_aliases[0] != 0 52 else
52 && strchr(hp->h_aliases[0], '.') != 0) 53 strlcpy(name, hp->h_name, sizeof(name));
53 strlcpy(name, hp->h_aliases[0], sizeof(name)); 54
54 else 55 /* Convert it to all lowercase (which is expected by the
55 strlcpy(name, hp->h_name, sizeof(name)); 56 rest of this software). */
56 57 for (i = 0; name[i]; i++)
57 /* Convert it to all lowercase (which is expected by the rest of this 58 if (isupper(name[i]))
58 software). */ 59 name[i] = tolower(name[i]);
59 for (i = 0; name[i]; i++) 60
60 if (isupper(name[i])) 61 /* Map it back to an IP address and check that the given
61 name[i] = tolower(name[i]); 62 address actually is an address of this host. This is
62 63 necessary because anyone with access to a name server
63 /* Map it back to an IP address and check that the given address actually 64 can define arbitrary names for an IP address. Mapping
64 is an address of this host. This is necessary because anyone with 65 from name to IP address can be trusted better (but can
65 access to a name server can define arbitrary names for an IP address. 66 still be fooled if the intruder has access to the name
66 Mapping from name to IP address can be trusted better (but can still 67 server of the domain). */
67 be fooled if the intruder has access to the name server of the 68 hp = gethostbyname(name);
68 domain). */ 69 if (!hp) {
69 hp = gethostbyname(name); 70 log("reverse mapping checking gethostbyname for %.700s failed - POSSIBLE BREAKIN ATTEMPT!", name);
70 if (!hp) 71 strlcpy(name, inet_ntoa(from.sin_addr), sizeof name);
71 { 72 goto check_ip_options;
72 log("reverse mapping checking gethostbyname for %.700s failed - POSSIBLE BREAKIN ATTEMPT!", name); 73 }
73 strlcpy(name, inet_ntoa(from.sin_addr), sizeof name); 74 /* Look for the address from the list of addresses. */
74 goto check_ip_options; 75 for (i = 0; hp->h_addr_list[i]; i++)
76 if (memcmp(hp->h_addr_list[i], &from.sin_addr, sizeof(from.sin_addr))
77 == 0)
78 break;
79 /* If we reached the end of the list, the address was not
80 there. */
81 if (!hp->h_addr_list[i]) {
82 /* Address not found for the host name. */
83 log("Address %.100s maps to %.600s, but this does not map back to the address - POSSIBLE BREAKIN ATTEMPT!",
84 inet_ntoa(from.sin_addr), name);
85 strlcpy(name, inet_ntoa(from.sin_addr), sizeof name);
86 goto check_ip_options;
87 }
88 /* Address was found for the host name. We accept the host name. */
89 } else {
90 /* Host name not found. Use ascii representation of the address. */
91 strlcpy(name, inet_ntoa(from.sin_addr), sizeof name);
92 log("Could not reverse map address %.100s.", name);
75 } 93 }
76 /* Look for the address from the list of addresses. */ 94
77 for (i = 0; hp->h_addr_list[i]; i++) 95check_ip_options:
78 if (memcmp(hp->h_addr_list[i], &from.sin_addr, sizeof(from.sin_addr)) 96
79 == 0) 97 /* If IP options are supported, make sure there are none (log and
80 break; 98 disconnect them if any are found). Basically we are worried
81 /* If we reached the end of the list, the address was not there. */ 99 about source routing; it can be used to pretend you are
82 if (!hp->h_addr_list[i]) 100 somebody (ip-address) you are not. That itself may be "almost
101 acceptable" under certain circumstances, but rhosts
102 autentication is useless if source routing is accepted. Notice
103 also that if we just dropped source routing here, the other
104 side could use IP spoofing to do rest of the interaction and
105 could still bypass security. So we exit here if we detect any
106 IP options. */
83 { 107 {
84 /* Address not found for the host name. */ 108 unsigned char options[200], *ucp;
85 log("Address %.100s maps to %.600s, but this does not map back to the address - POSSIBLE BREAKIN ATTEMPT!", 109 char text[1024], *cp;
86 inet_ntoa(from.sin_addr), name); 110 int option_size, ipproto;
87 strlcpy(name, inet_ntoa(from.sin_addr), sizeof name); 111 struct protoent *ip;
88 goto check_ip_options; 112
113 if ((ip = getprotobyname("ip")) != NULL)
114 ipproto = ip->p_proto;
115 else
116 ipproto = IPPROTO_IP;
117 option_size = sizeof(options);
118 if (getsockopt(0, ipproto, IP_OPTIONS, (char *) options,
119 &option_size) >= 0 && option_size != 0) {
120 cp = text;
121 /* Note: "text" buffer must be at least 3x as big as options. */
122 for (ucp = options; option_size > 0; ucp++, option_size--, cp += 3)
123 sprintf(cp, " %2.2x", *ucp);
124 log("Connection from %.100s with IP options:%.800s",
125 inet_ntoa(from.sin_addr), text);
126 packet_disconnect("Connection from %.100s with IP options:%.800s",
127 inet_ntoa(from.sin_addr), text);
128 }
89 } 129 }
90 /* Address was found for the host name. We accept the host name. */ 130
91 } 131 return xstrdup(name);
92 else
93 {
94 /* Host name not found. Use ascii representation of the address. */
95 strlcpy(name, inet_ntoa(from.sin_addr), sizeof name);
96 log("Could not reverse map address %.100s.", name);
97 }
98
99 check_ip_options:
100
101 /* If IP options are supported, make sure there are none (log and disconnect
102 them if any are found). Basically we are worried about source routing;
103 it can be used to pretend you are somebody (ip-address) you are not.
104 That itself may be "almost acceptable" under certain circumstances,
105 but rhosts autentication is useless if source routing is accepted.
106 Notice also that if we just dropped source routing here, the other
107 side could use IP spoofing to do rest of the interaction and could still
108 bypass security. So we exit here if we detect any IP options. */
109 {
110 unsigned char options[200], *ucp;
111 char text[1024], *cp;
112 int option_size, ipproto;
113 struct protoent *ip;
114
115 if ((ip = getprotobyname("ip")) != NULL)
116 ipproto = ip->p_proto;
117 else
118 ipproto = IPPROTO_IP;
119 option_size = sizeof(options);
120 if (getsockopt(0, ipproto, IP_OPTIONS, (char *)options,
121 &option_size) >= 0 && option_size != 0)
122 {
123 cp = text;
124 /* Note: "text" buffer must be at least 3x as big as options. */
125 for (ucp = options; option_size > 0; ucp++, option_size--, cp += 3)
126 sprintf(cp, " %2.2x", *ucp);
127 log("Connection from %.100s with IP options:%.800s",
128 inet_ntoa(from.sin_addr), text);
129 packet_disconnect("Connection from %.100s with IP options:%.800s",
130 inet_ntoa(from.sin_addr), text);
131 }
132 }
133
134 return xstrdup(name);
135} 132}
136 133
137static char *canonical_host_name = NULL; 134static char *canonical_host_name = NULL;
138static char *canonical_host_ip = NULL; 135static char *canonical_host_ip = NULL;
139 136
140/* Return the canonical name of the host in the other side of the current 137/* Return the canonical name of the host in the other side of the current
141 connection. The host name is cached, so it is efficient to call this 138 connection. The host name is cached, so it is efficient to call this
142 several times. */ 139 several times. */
143 140
144const char *get_canonical_hostname() 141const char *
142get_canonical_hostname()
145{ 143{
146 /* Check if we have previously retrieved this same name. */ 144 /* Check if we have previously retrieved this same name. */
147 if (canonical_host_name != NULL) 145 if (canonical_host_name != NULL)
148 return canonical_host_name; 146 return canonical_host_name;
149 147
150 /* Get the real hostname if socket; otherwise return UNKNOWN. */ 148 /* Get the real hostname if socket; otherwise return UNKNOWN. */
151 if (packet_get_connection_in() == packet_get_connection_out()) 149 if (packet_get_connection_in() == packet_get_connection_out())
152 canonical_host_name = get_remote_hostname(packet_get_connection_in()); 150 canonical_host_name = get_remote_hostname(packet_get_connection_in());
153 else 151 else
154 canonical_host_name = xstrdup("UNKNOWN"); 152 canonical_host_name = xstrdup("UNKNOWN");
155 153
156 return canonical_host_name; 154 return canonical_host_name;
157} 155}
158 156
159/* Returns the IP-address of the remote host as a string. The returned 157/* Returns the IP-address of the remote host as a string. The returned
160 string need not be freed. */ 158 string need not be freed. */
161 159
162const char *get_remote_ipaddr() 160const char *
161get_remote_ipaddr()
163{ 162{
164 struct sockaddr_in from; 163 struct sockaddr_in from;
165 int fromlen, socket; 164 int fromlen, socket;
166 165
167 /* Check if we have previously retrieved this same name. */ 166 /* Check if we have previously retrieved this same name. */
168 if (canonical_host_ip != NULL) 167 if (canonical_host_ip != NULL)
169 return canonical_host_ip; 168 return canonical_host_ip;
170 169
171 /* If not a socket, return UNKNOWN. */ 170 /* If not a socket, return UNKNOWN. */
172 if (packet_get_connection_in() != packet_get_connection_out()) 171 if (packet_get_connection_in() != packet_get_connection_out()) {
173 { 172 canonical_host_ip = xstrdup("UNKNOWN");
174 canonical_host_ip = xstrdup("UNKNOWN"); 173 return canonical_host_ip;
175 return canonical_host_ip; 174 }
176 } 175 /* Get client socket. */
177 176 socket = packet_get_connection_in();
178 /* Get client socket. */ 177
179 socket = packet_get_connection_in(); 178 /* Get IP address of client. */
180 179 fromlen = sizeof(from);
181 /* Get IP address of client. */ 180 memset(&from, 0, sizeof(from));
182 fromlen = sizeof(from); 181 if (getpeername(socket, (struct sockaddr *) & from, &fromlen) < 0) {
183 memset(&from, 0, sizeof(from)); 182 debug("getpeername failed: %.100s", strerror(errno));
184 if (getpeername(socket, (struct sockaddr *)&from, &fromlen) < 0) 183 fatal_cleanup();
185 { 184 }
186 debug("getpeername failed: %.100s", strerror(errno)); 185 /* Get the IP address in ascii. */
187 fatal_cleanup(); 186 canonical_host_ip = xstrdup(inet_ntoa(from.sin_addr));
188 } 187
189 188 /* Return ip address string. */
190 /* Get the IP address in ascii. */ 189 return canonical_host_ip;
191 canonical_host_ip = xstrdup(inet_ntoa(from.sin_addr));
192
193 /* Return ip address string. */
194 return canonical_host_ip;
195} 190}
196 191
197/* Returns the port of the peer of the socket. */ 192/* Returns the port of the peer of the socket. */
198 193
199int get_peer_port(int sock) 194int
195get_peer_port(int sock)
200{ 196{
201 struct sockaddr_in from; 197 struct sockaddr_in from;
202 int fromlen; 198 int fromlen;
203 199
204 /* Get IP address of client. */ 200 /* Get IP address of client. */
205 fromlen = sizeof(from); 201 fromlen = sizeof(from);
206 memset(&from, 0, sizeof(from)); 202 memset(&from, 0, sizeof(from));
207 if (getpeername(sock, (struct sockaddr *)&from, &fromlen) < 0) 203 if (getpeername(sock, (struct sockaddr *) & from, &fromlen) < 0) {
208 { 204 debug("getpeername failed: %.100s", strerror(errno));
209 debug("getpeername failed: %.100s", strerror(errno)); 205 fatal_cleanup();
210 fatal_cleanup(); 206 }
211 } 207 /* Return port number. */
212 208 return ntohs(from.sin_port);
213 /* Return port number. */
214 return ntohs(from.sin_port);
215} 209}
216 210
217/* Returns the port number of the remote host. */ 211/* Returns the port number of the remote host. */
218 212
219int get_remote_port() 213int
214get_remote_port()
220{ 215{
221 int socket; 216 int socket;
222 217
223 /* If the connection is not a socket, return 65535. This is intentionally 218 /* If the connection is not a socket, return 65535. This is
224 chosen to be an unprivileged port number. */ 219 intentionally chosen to be an unprivileged port number. */
225 if (packet_get_connection_in() != packet_get_connection_out()) 220 if (packet_get_connection_in() != packet_get_connection_out())
226 return 65535; 221 return 65535;
227 222
228 /* Get client socket. */ 223 /* Get client socket. */
229 socket = packet_get_connection_in(); 224 socket = packet_get_connection_in();
230 225
231 /* Get and return the peer port number. */ 226 /* Get and return the peer port number. */
232 return get_peer_port(socket); 227 return get_peer_port(socket);
233} 228}
diff --git a/channels.c b/channels.c
index 3e3b5f369..0a37d1abd 100644
--- a/channels.c
+++ b/channels.c
@@ -1,22 +1,22 @@
1/* 1/*
2 2 *
3channels.c 3 * channels.c
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Fri Mar 24 16:35:24 1995 ylo 10 * Created: Fri Mar 24 16:35:24 1995 ylo
11 11 *
12This file contains functions for generic socket connection forwarding. 12 * This file contains functions for generic socket connection forwarding.
13There is also code for initiating connection forwarding for X11 connections, 13 * There is also code for initiating connection forwarding for X11 connections,
14arbitrary tcp/ip connections, and the authentication agent connection. 14 * arbitrary tcp/ip connections, and the authentication agent connection.
15 15 *
16*/ 16 */
17 17
18#include "includes.h" 18#include "includes.h"
19RCSID("$Id: channels.c,v 1.6 1999/11/21 02:23:53 damien Exp $"); 19RCSID("$Id: channels.c,v 1.7 1999/11/24 13:26:22 damien Exp $");
20 20
21#include "ssh.h" 21#include "ssh.h"
22#include "packet.h" 22#include "packet.h"
@@ -52,7 +52,7 @@ static int channel_max_fd_value = 0;
52 52
53/* Name and directory of socket for authentication agent forwarding. */ 53/* Name and directory of socket for authentication agent forwarding. */
54static char *channel_forwarded_auth_socket_name = NULL; 54static char *channel_forwarded_auth_socket_name = NULL;
55static char *channel_forwarded_auth_socket_dir = NULL; 55static char *channel_forwarded_auth_socket_dir = NULL;
56 56
57/* Saved X11 authentication protocol name. */ 57/* Saved X11 authentication protocol name. */
58char *x11_saved_proto = NULL; 58char *x11_saved_proto = NULL;
@@ -70,10 +70,9 @@ unsigned int x11_fake_data_len;
70 The local sides of any remote forwards are stored in this array to prevent 70 The local sides of any remote forwards are stored in this array to prevent
71 a corrupt remote server from accessing arbitrary TCP/IP ports on our 71 a corrupt remote server from accessing arbitrary TCP/IP ports on our
72 local network (which might be behind a firewall). */ 72 local network (which might be behind a firewall). */
73typedef struct 73typedef struct {
74{ 74 char *host; /* Host name. */
75 char *host; /* Host name. */ 75 int port; /* Port number. */
76 int port; /* Port number. */
77} ForwardPermission; 76} ForwardPermission;
78 77
79/* List of all permitted host/port pairs to connect. */ 78/* List of all permitted host/port pairs to connect. */
@@ -90,1056 +89,1015 @@ static int have_hostname_in_open = 0;
90 89
91/* Sets specific protocol options. */ 90/* Sets specific protocol options. */
92 91
93void channel_set_options(int hostname_in_open) 92void
93channel_set_options(int hostname_in_open)
94{ 94{
95 have_hostname_in_open = hostname_in_open; 95 have_hostname_in_open = hostname_in_open;
96} 96}
97 97
98/* Permits opening to any host/port in SSH_MSG_PORT_OPEN. This is usually 98/* Permits opening to any host/port in SSH_MSG_PORT_OPEN. This is usually
99 called by the server, because the user could connect to any port anyway, 99 called by the server, because the user could connect to any port anyway,
100 and the server has no way to know but to trust the client anyway. */ 100 and the server has no way to know but to trust the client anyway. */
101 101
102void channel_permit_all_opens() 102void
103channel_permit_all_opens()
103{ 104{
104 all_opens_permitted = 1; 105 all_opens_permitted = 1;
105} 106}
106 107
107/* Allocate a new channel object and set its type and socket. 108/* Allocate a new channel object and set its type and socket.
108 This will cause remote_name to be freed. */ 109 This will cause remote_name to be freed. */
109 110
110int channel_allocate(int type, int sock, char *remote_name) 111int
112channel_allocate(int type, int sock, char *remote_name)
111{ 113{
112 int i, found; 114 int i, found;
113 Channel *c; 115 Channel *c;
114 116
115 /* Update the maximum file descriptor value. */ 117 /* Update the maximum file descriptor value. */
116 if (sock > channel_max_fd_value) 118 if (sock > channel_max_fd_value)
117 channel_max_fd_value = sock; 119 channel_max_fd_value = sock;
118 120
119 /* Do initial allocation if this is the first call. */ 121 /* Do initial allocation if this is the first call. */
120 if (channels_alloc == 0) 122 if (channels_alloc == 0) {
121 { 123 channels_alloc = 10;
122 channels_alloc = 10; 124 channels = xmalloc(channels_alloc * sizeof(Channel));
123 channels = xmalloc(channels_alloc * sizeof(Channel)); 125 for (i = 0; i < channels_alloc; i++)
124 for (i = 0; i < channels_alloc; i++) 126 channels[i].type = SSH_CHANNEL_FREE;
125 channels[i].type = SSH_CHANNEL_FREE; 127
126 128 /* Kludge: arrange a call to channel_stop_listening if we
127 /* Kludge: arrange a call to channel_stop_listening if we terminate 129 terminate with fatal(). */
128 with fatal(). */ 130 fatal_add_cleanup((void (*) (void *)) channel_stop_listening, NULL);
129 fatal_add_cleanup((void (*)(void *))channel_stop_listening, NULL); 131 }
130 } 132 /* Try to find a free slot where to put the new channel. */
131 133 for (found = -1, i = 0; i < channels_alloc; i++)
132 /* Try to find a free slot where to put the new channel. */ 134 if (channels[i].type == SSH_CHANNEL_FREE) {
133 for (found = -1, i = 0; i < channels_alloc; i++) 135 /* Found a free slot. */
134 if (channels[i].type == SSH_CHANNEL_FREE) 136 found = i;
135 { 137 break;
136 /* Found a free slot. */ 138 }
137 found = i; 139 if (found == -1) {
138 break; 140 /* There are no free slots. Take last+1 slot and expand
139 } 141 the array. */
140 142 found = channels_alloc;
141 if (found == -1) 143 channels_alloc += 10;
142 { 144 debug("channel: expanding %d", channels_alloc);
143 /* There are no free slots. Take last+1 slot and expand the array. */ 145 channels = xrealloc(channels, channels_alloc * sizeof(Channel));
144 found = channels_alloc; 146 for (i = found; i < channels_alloc; i++)
145 channels_alloc += 10; 147 channels[i].type = SSH_CHANNEL_FREE;
146 debug("channel: expanding %d", channels_alloc); 148 }
147 channels = xrealloc(channels, channels_alloc * sizeof(Channel)); 149 /* Initialize and return new channel number. */
148 for (i = found; i < channels_alloc; i++) 150 c = &channels[found];
149 channels[i].type = SSH_CHANNEL_FREE; 151 buffer_init(&c->input);
150 } 152 buffer_init(&c->output);
151 153 chan_init_iostates(c);
152 /* Initialize and return new channel number. */ 154 c->self = found;
153 c=&channels[found]; 155 c->type = type;
154 buffer_init(&c->input); 156 c->sock = sock;
155 buffer_init(&c->output); 157 c->remote_id = -1;
156 chan_init_iostates(c); 158 c->remote_name = remote_name;
157 c->self = found; 159 debug("channel %d: new [%s]", found, remote_name);
158 c->type = type; 160 return found;
159 c->sock = sock;
160 c->remote_id = -1;
161 c->remote_name = remote_name;
162 debug("channel %d: new [%s]", found, remote_name);
163 return found;
164} 161}
165 162
166/* Free the channel and close its socket. */ 163/* Free the channel and close its socket. */
167 164
168void channel_free(int channel) 165void
166channel_free(int channel)
169{ 167{
170 if (channel < 0 || channel >= channels_alloc || 168 if (channel < 0 || channel >= channels_alloc ||
171 channels[channel].type == SSH_CHANNEL_FREE) 169 channels[channel].type == SSH_CHANNEL_FREE)
172 packet_disconnect("channel free: bad local channel %d", channel); 170 packet_disconnect("channel free: bad local channel %d", channel);
173 171
174 if(compat13) 172 if (compat13)
175 shutdown(channels[channel].sock, SHUT_RDWR); 173 shutdown(channels[channel].sock, SHUT_RDWR);
176 close(channels[channel].sock); 174 close(channels[channel].sock);
177 buffer_free(&channels[channel].input); 175 buffer_free(&channels[channel].input);
178 buffer_free(&channels[channel].output); 176 buffer_free(&channels[channel].output);
179 channels[channel].type = SSH_CHANNEL_FREE; 177 channels[channel].type = SSH_CHANNEL_FREE;
180 if (channels[channel].remote_name) 178 if (channels[channel].remote_name) {
181 { 179 xfree(channels[channel].remote_name);
182 xfree(channels[channel].remote_name); 180 channels[channel].remote_name = NULL;
183 channels[channel].remote_name = NULL; 181 }
184 }
185} 182}
186 183
187/* This is called just before select() to add any bits relevant to 184/* This is called just before select() to add any bits relevant to
188 channels in the select bitmasks. */ 185 channels in the select bitmasks. */
189 186
190void channel_prepare_select(fd_set *readset, fd_set *writeset) 187void
188channel_prepare_select(fd_set * readset, fd_set * writeset)
191{ 189{
192 int i; 190 int i;
193 Channel *ch; 191 Channel *ch;
194 unsigned char *ucp; 192 unsigned char *ucp;
195 unsigned int proto_len, data_len; 193 unsigned int proto_len, data_len;
196 194
197 for (i = 0; i < channels_alloc; i++) 195 for (i = 0; i < channels_alloc; i++) {
198 { 196 ch = &channels[i];
199 ch = &channels[i]; 197redo:
200 redo: 198 switch (ch->type) {
201 switch (ch->type) 199 case SSH_CHANNEL_X11_LISTENER:
202 { 200 case SSH_CHANNEL_PORT_LISTENER:
203 case SSH_CHANNEL_X11_LISTENER: 201 case SSH_CHANNEL_AUTH_SOCKET:
204 case SSH_CHANNEL_PORT_LISTENER: 202 FD_SET(ch->sock, readset);
205 case SSH_CHANNEL_AUTH_SOCKET: 203 break;
206 FD_SET(ch->sock, readset); 204
207 break; 205 case SSH_CHANNEL_OPEN:
208 206 if (compat13) {
209 case SSH_CHANNEL_OPEN: 207 if (buffer_len(&ch->input) < packet_get_maxsize())
210 if(compat13){ 208 FD_SET(ch->sock, readset);
211 if (buffer_len(&ch->input) < packet_get_maxsize()) 209 if (buffer_len(&ch->output) > 0)
212 FD_SET(ch->sock, readset); 210 FD_SET(ch->sock, writeset);
213 if (buffer_len(&ch->output) > 0) 211 break;
214 FD_SET(ch->sock, writeset); 212 }
215 break; 213 /* test whether sockets are 'alive' for read/write */
216 } 214 if (ch->istate == CHAN_INPUT_OPEN)
217 /* test whether sockets are 'alive' for read/write */ 215 if (buffer_len(&ch->input) < packet_get_maxsize())
218 if (ch->istate == CHAN_INPUT_OPEN) 216 FD_SET(ch->sock, readset);
219 if (buffer_len(&ch->input) < packet_get_maxsize()) 217 if (ch->ostate == CHAN_OUTPUT_OPEN ||
220 FD_SET(ch->sock, readset); 218 ch->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
221 if (ch->ostate == CHAN_OUTPUT_OPEN || ch->ostate == CHAN_OUTPUT_WAIT_DRAIN){ 219 if (buffer_len(&ch->output) > 0) {
222 if (buffer_len(&ch->output) > 0){ 220 FD_SET(ch->sock, writeset);
223 FD_SET(ch->sock, writeset); 221 } else if (ch->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
224 }else if(ch->ostate == CHAN_OUTPUT_WAIT_DRAIN) { 222 chan_obuf_empty(ch);
225 chan_obuf_empty(ch); 223 }
226 } 224 }
227 } 225 break;
228 break; 226
229 227 case SSH_CHANNEL_INPUT_DRAINING:
230 case SSH_CHANNEL_INPUT_DRAINING: 228 if (!compat13)
231 if (!compat13) 229 fatal("cannot happen: IN_DRAIN");
232 fatal("cannot happen: IN_DRAIN"); 230 if (buffer_len(&ch->input) == 0) {
233 if (buffer_len(&ch->input) == 0) 231 packet_start(SSH_MSG_CHANNEL_CLOSE);
234 { 232 packet_put_int(ch->remote_id);
235 packet_start(SSH_MSG_CHANNEL_CLOSE); 233 packet_send();
236 packet_put_int(ch->remote_id); 234 ch->type = SSH_CHANNEL_CLOSED;
237 packet_send(); 235 debug("Closing channel %d after input drain.", i);
238 ch->type = SSH_CHANNEL_CLOSED; 236 break;
239 debug("Closing channel %d after input drain.", i); 237 }
240 break; 238 break;
241 } 239
242 break; 240 case SSH_CHANNEL_OUTPUT_DRAINING:
243 241 if (!compat13)
244 case SSH_CHANNEL_OUTPUT_DRAINING: 242 fatal("cannot happen: OUT_DRAIN");
245 if (!compat13) 243 if (buffer_len(&ch->output) == 0) {
246 fatal("cannot happen: OUT_DRAIN"); 244 channel_free(i);
247 if (buffer_len(&ch->output) == 0) 245 break;
248 { 246 }
249 /* debug("Freeing channel %d after output drain.", i); */ 247 FD_SET(ch->sock, writeset);
250 channel_free(i); 248 break;
251 break; 249
252 } 250 case SSH_CHANNEL_X11_OPEN:
253 FD_SET(ch->sock, writeset); 251 /* This is a special state for X11 authentication
254 break; 252 spoofing. An opened X11 connection (when
255 253 authentication spoofing is being done) remains
256 case SSH_CHANNEL_X11_OPEN: 254 in this state until the first packet has been
257 /* This is a special state for X11 authentication spoofing. An 255 completely read. The authentication data in
258 opened X11 connection (when authentication spoofing is being 256 that packet is then substituted by the real
259 done) remains in this state until the first packet has been 257 data if it matches the fake data, and the
260 completely read. The authentication data in that packet is 258 channel is put into normal mode. */
261 then substituted by the real data if it matches the fake data, 259
262 and the channel is put into normal mode. */ 260 /* Check if the fixed size part of the packet is in buffer. */
263 261 if (buffer_len(&ch->output) < 12)
264 /* Check if the fixed size part of the packet is in buffer. */ 262 break;
265 if (buffer_len(&ch->output) < 12) 263
266 break; 264 /* Parse the lengths of variable-length fields. */
267 265 ucp = (unsigned char *) buffer_ptr(&ch->output);
268 /* Parse the lengths of variable-length fields. */ 266 if (ucp[0] == 0x42) { /* Byte order MSB first. */
269 ucp = (unsigned char *)buffer_ptr(&ch->output); 267 proto_len = 256 * ucp[6] + ucp[7];
270 if (ucp[0] == 0x42) 268 data_len = 256 * ucp[8] + ucp[9];
271 { /* Byte order MSB first. */ 269 } else if (ucp[0] == 0x6c) { /* Byte order LSB first. */
272 proto_len = 256 * ucp[6] + ucp[7]; 270 proto_len = ucp[6] + 256 * ucp[7];
273 data_len = 256 * ucp[8] + ucp[9]; 271 data_len = ucp[8] + 256 * ucp[9];
274 } 272 } else {
275 else 273 debug("Initial X11 packet contains bad byte order byte: 0x%x",
276 if (ucp[0] == 0x6c) 274 ucp[0]);
277 { /* Byte order LSB first. */ 275 ch->type = SSH_CHANNEL_OPEN;
278 proto_len = ucp[6] + 256 * ucp[7]; 276 goto reject;
279 data_len = ucp[8] + 256 * ucp[9]; 277 }
280 } 278
281 else 279 /* Check if the whole packet is in buffer. */
282 { 280 if (buffer_len(&ch->output) <
283 debug("Initial X11 packet contains bad byte order byte: 0x%x", 281 12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3))
284 ucp[0]); 282 break;
285 ch->type = SSH_CHANNEL_OPEN; 283
286 goto reject; 284 /* Check if authentication protocol matches. */
287 } 285 if (proto_len != strlen(x11_saved_proto) ||
288 286 memcmp(ucp + 12, x11_saved_proto, proto_len) != 0) {
289 /* Check if the whole packet is in buffer. */ 287 debug("X11 connection uses different authentication protocol.");
290 if (buffer_len(&ch->output) < 288 ch->type = SSH_CHANNEL_OPEN;
291 12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3)) 289 goto reject;
292 break; 290 }
293 291 /* Check if authentication data matches our fake data. */
294 /* Check if authentication protocol matches. */ 292 if (data_len != x11_fake_data_len ||
295 if (proto_len != strlen(x11_saved_proto) || 293 memcmp(ucp + 12 + ((proto_len + 3) & ~3),
296 memcmp(ucp + 12, x11_saved_proto, proto_len) != 0) 294 x11_fake_data, x11_fake_data_len) != 0) {
297 { 295 debug("X11 auth data does not match fake data.");
298 debug("X11 connection uses different authentication protocol."); 296 ch->type = SSH_CHANNEL_OPEN;
299 ch->type = SSH_CHANNEL_OPEN; 297 goto reject;
300 goto reject; 298 }
301 } 299 /* Check fake data length */
302 300 if (x11_fake_data_len != x11_saved_data_len) {
303 /* Check if authentication data matches our fake data. */ 301 error("X11 fake_data_len %d != saved_data_len %d",
304 if (data_len != x11_fake_data_len || 302 x11_fake_data_len, x11_saved_data_len);
305 memcmp(ucp + 12 + ((proto_len + 3) & ~3), 303 ch->type = SSH_CHANNEL_OPEN;
306 x11_fake_data, x11_fake_data_len) != 0) 304 goto reject;
307 { 305 }
308 debug("X11 auth data does not match fake data."); 306 /* Received authentication protocol and data match
309 ch->type = SSH_CHANNEL_OPEN; 307 our fake data. Substitute the fake data with
310 goto reject; 308 real data. */
311 } 309 memcpy(ucp + 12 + ((proto_len + 3) & ~3),
312 310 x11_saved_data, x11_saved_data_len);
313 /* Check fake data length */ 311
314 if (x11_fake_data_len != x11_saved_data_len) 312 /* Start normal processing for the channel. */
315 { 313 ch->type = SSH_CHANNEL_OPEN;
316 error("X11 fake_data_len %d != saved_data_len %d", 314 goto redo;
317 x11_fake_data_len, x11_saved_data_len); 315
318 ch->type = SSH_CHANNEL_OPEN;
319 goto reject;
320 }
321
322 /* Received authentication protocol and data match our fake data.
323 Substitute the fake data with real data. */
324 memcpy(ucp + 12 + ((proto_len + 3) & ~3),
325 x11_saved_data, x11_saved_data_len);
326
327 /* Start normal processing for the channel. */
328 ch->type = SSH_CHANNEL_OPEN;
329 goto redo;
330
331 reject: 316 reject:
332 /* We have received an X11 connection that has bad authentication 317 /* We have received an X11 connection that has bad
333 information. */ 318 authentication information. */
334 log("X11 connection rejected because of wrong authentication.\r\n"); 319 log("X11 connection rejected because of wrong authentication.\r\n");
335 buffer_clear(&ch->input); 320 buffer_clear(&ch->input);
336 buffer_clear(&ch->output); 321 buffer_clear(&ch->output);
337 if (compat13) { 322 if (compat13) {
338 close(ch->sock); 323 close(ch->sock);
339 ch->sock = -1; 324 ch->sock = -1;
340 ch->type = SSH_CHANNEL_CLOSED; 325 ch->type = SSH_CHANNEL_CLOSED;
341 packet_start(SSH_MSG_CHANNEL_CLOSE); 326 packet_start(SSH_MSG_CHANNEL_CLOSE);
342 packet_put_int(ch->remote_id); 327 packet_put_int(ch->remote_id);
343 packet_send(); 328 packet_send();
344 }else{ 329 } else {
345 debug("X11 rejected %d i%d/o%d", ch->self, ch->istate, ch->ostate); 330 debug("X11 rejected %d i%d/o%d", ch->self, ch->istate, ch->ostate);
346 chan_read_failed(ch); 331 chan_read_failed(ch);
347 chan_write_failed(ch); 332 chan_write_failed(ch);
348 debug("X11 rejected %d i%d/o%d", ch->self, ch->istate, ch->ostate); 333 debug("X11 rejected %d i%d/o%d", ch->self, ch->istate, ch->ostate);
349 } 334 }
350 break; 335 break;
351 336
352 case SSH_CHANNEL_FREE: 337 case SSH_CHANNEL_FREE:
353 default: 338 default:
354 continue; 339 continue;
340 }
355 } 341 }
356 }
357} 342}
358 343
359/* After select, perform any appropriate operations for channels which 344/* After select, perform any appropriate operations for channels which
360 have events pending. */ 345 have events pending. */
361 346
362void channel_after_select(fd_set *readset, fd_set *writeset) 347void
348channel_after_select(fd_set * readset, fd_set * writeset)
363{ 349{
364 struct sockaddr addr; 350 struct sockaddr addr;
365 int addrlen, newsock, i, newch, len; 351 int addrlen, newsock, i, newch, len;
366 Channel *ch; 352 Channel *ch;
367 char buf[16384], *remote_hostname; 353 char buf[16384], *remote_hostname;
368 354
369 /* Loop over all channels... */ 355 /* Loop over all channels... */
370 for (i = 0; i < channels_alloc; i++) 356 for (i = 0; i < channels_alloc; i++) {
371 { 357 ch = &channels[i];
372 ch = &channels[i]; 358 switch (ch->type) {
373 switch (ch->type) 359 case SSH_CHANNEL_X11_LISTENER:
374 { 360 /* This is our fake X11 server socket. */
375 case SSH_CHANNEL_X11_LISTENER: 361 if (FD_ISSET(ch->sock, readset)) {
376 /* This is our fake X11 server socket. */ 362 debug("X11 connection requested.");
377 if (FD_ISSET(ch->sock, readset)) 363 addrlen = sizeof(addr);
378 { 364 newsock = accept(ch->sock, &addr, &addrlen);
379 debug("X11 connection requested."); 365 if (newsock < 0) {
380 addrlen = sizeof(addr); 366 error("accept: %.100s", strerror(errno));
381 newsock = accept(ch->sock, &addr, &addrlen); 367 break;
382 if (newsock < 0) 368 }
383 { 369 remote_hostname = get_remote_hostname(newsock);
384 error("accept: %.100s", strerror(errno)); 370 snprintf(buf, sizeof buf, "X11 connection from %.200s port %d",
385 break; 371 remote_hostname, get_peer_port(newsock));
386 } 372 xfree(remote_hostname);
387 remote_hostname = get_remote_hostname(newsock); 373 newch = channel_allocate(SSH_CHANNEL_OPENING, newsock,
388 snprintf(buf, sizeof buf, "X11 connection from %.200s port %d", 374 xstrdup(buf));
389 remote_hostname, get_peer_port(newsock)); 375 packet_start(SSH_SMSG_X11_OPEN);
390 xfree(remote_hostname); 376 packet_put_int(newch);
391 newch = channel_allocate(SSH_CHANNEL_OPENING, newsock, 377 if (have_hostname_in_open)
392 xstrdup(buf)); 378 packet_put_string(buf, strlen(buf));
393 packet_start(SSH_SMSG_X11_OPEN); 379 packet_send();
394 packet_put_int(newch); 380 }
395 if (have_hostname_in_open) 381 break;
396 packet_put_string(buf, strlen(buf)); 382
397 packet_send(); 383 case SSH_CHANNEL_PORT_LISTENER:
398 } 384 /* This socket is listening for connections to a
399 break; 385 forwarded TCP/IP port. */
400 386 if (FD_ISSET(ch->sock, readset)) {
401 case SSH_CHANNEL_PORT_LISTENER: 387 debug("Connection to port %d forwarding to %.100s:%d requested.",
402 /* This socket is listening for connections to a forwarded TCP/IP 388 ch->listening_port, ch->path, ch->host_port);
403 port. */ 389 addrlen = sizeof(addr);
404 if (FD_ISSET(ch->sock, readset)) 390 newsock = accept(ch->sock, &addr, &addrlen);
405 { 391 if (newsock < 0) {
406 debug("Connection to port %d forwarding to %.100s:%d requested.", 392 error("accept: %.100s", strerror(errno));
407 ch->listening_port, ch->path, ch->host_port); 393 break;
408 addrlen = sizeof(addr); 394 }
409 newsock = accept(ch->sock, &addr, &addrlen); 395 remote_hostname = get_remote_hostname(newsock);
410 if (newsock < 0) 396 snprintf(buf, sizeof buf, "listen port %d:%.100s:%d, connect from %.200s:%d",
411 { 397 ch->listening_port, ch->path, ch->host_port,
412 error("accept: %.100s", strerror(errno)); 398 remote_hostname, get_peer_port(newsock));
413 break; 399 xfree(remote_hostname);
414 } 400 newch = channel_allocate(SSH_CHANNEL_OPENING, newsock,
415 remote_hostname = get_remote_hostname(newsock); 401 xstrdup(buf));
416 snprintf(buf, sizeof buf, "listen port %d:%.100s:%d, connect from %.200s:%d", 402 packet_start(SSH_MSG_PORT_OPEN);
417 ch->listening_port, ch->path, ch->host_port, 403 packet_put_int(newch);
418 remote_hostname, get_peer_port(newsock)); 404 packet_put_string(ch->path, strlen(ch->path));
419 xfree(remote_hostname); 405 packet_put_int(ch->host_port);
420 newch = channel_allocate(SSH_CHANNEL_OPENING, newsock, 406 if (have_hostname_in_open)
421 xstrdup(buf)); 407 packet_put_string(buf, strlen(buf));
422 packet_start(SSH_MSG_PORT_OPEN); 408 packet_send();
423 packet_put_int(newch); 409 }
424 packet_put_string(ch->path, strlen(ch->path)); 410 break;
425 packet_put_int(ch->host_port); 411
426 if (have_hostname_in_open) 412 case SSH_CHANNEL_AUTH_SOCKET:
427 packet_put_string(buf, strlen(buf)); 413 /* This is the authentication agent socket
428 packet_send(); 414 listening for connections from clients. */
429 } 415 if (FD_ISSET(ch->sock, readset)) {
430 break; 416 int nchan;
431 417 len = sizeof(addr);
432 case SSH_CHANNEL_AUTH_SOCKET: 418 newsock = accept(ch->sock, &addr, &len);
433 /* This is the authentication agent socket listening for connections 419 if (newsock < 0) {
434 from clients. */ 420 error("accept from auth socket: %.100s", strerror(errno));
435 if (FD_ISSET(ch->sock, readset)) 421 break;
436 { 422 }
437 int nchan; 423 nchan = channel_allocate(SSH_CHANNEL_OPENING, newsock,
438 len = sizeof(addr); 424 xstrdup("accepted auth socket"));
439 newsock = accept(ch->sock, &addr, &len); 425 packet_start(SSH_SMSG_AGENT_OPEN);
440 if (newsock < 0) 426 packet_put_int(nchan);
441 { 427 packet_send();
442 error("accept from auth socket: %.100s", strerror(errno)); 428 }
443 break; 429 break;
430
431 case SSH_CHANNEL_OPEN:
432 /* This is an open two-way communication channel.
433 It is not of interest to us at this point what
434 kind of data is being transmitted. */
435
436 /* Read available incoming data and append it to
437 buffer; shutdown socket, if read or write
438 failes */
439 if (FD_ISSET(ch->sock, readset)) {
440 len = read(ch->sock, buf, sizeof(buf));
441 if (len <= 0) {
442 if (compat13) {
443 buffer_consume(&ch->output, buffer_len(&ch->output));
444 ch->type = SSH_CHANNEL_INPUT_DRAINING;
445 debug("Channel %d status set to input draining.", i);
446 } else {
447 chan_read_failed(ch);
448 }
449 break;
450 }
451 buffer_append(&ch->input, buf, len);
452 }
453 /* Send buffered output data to the socket. */
454 if (FD_ISSET(ch->sock, writeset) && buffer_len(&ch->output) > 0) {
455 len = write(ch->sock, buffer_ptr(&ch->output),
456 buffer_len(&ch->output));
457 if (len <= 0) {
458 if (compat13) {
459 buffer_consume(&ch->output, buffer_len(&ch->output));
460 debug("Channel %d status set to input draining.", i);
461 ch->type = SSH_CHANNEL_INPUT_DRAINING;
462 } else {
463 chan_write_failed(ch);
464 }
465 break;
466 }
467 buffer_consume(&ch->output, len);
468 }
469 break;
470
471 case SSH_CHANNEL_OUTPUT_DRAINING:
472 if (!compat13)
473 fatal("cannot happen: OUT_DRAIN");
474 /* Send buffered output data to the socket. */
475 if (FD_ISSET(ch->sock, writeset) && buffer_len(&ch->output) > 0) {
476 len = write(ch->sock, buffer_ptr(&ch->output),
477 buffer_len(&ch->output));
478 if (len <= 0)
479 buffer_consume(&ch->output, buffer_len(&ch->output));
480 else
481 buffer_consume(&ch->output, len);
482 }
483 break;
484
485 case SSH_CHANNEL_X11_OPEN:
486 case SSH_CHANNEL_FREE:
487 default:
488 continue;
444 } 489 }
445
446 nchan = channel_allocate(SSH_CHANNEL_OPENING, newsock,
447 xstrdup("accepted auth socket"));
448 packet_start(SSH_SMSG_AGENT_OPEN);
449 packet_put_int(nchan);
450 packet_send();
451 }
452 break;
453
454 case SSH_CHANNEL_OPEN:
455 /* This is an open two-way communication channel. It is not of
456 interest to us at this point what kind of data is being
457 transmitted. */
458
459 /* Read available incoming data and append it to buffer;
460 shutdown socket, if read or write failes */
461 if (FD_ISSET(ch->sock, readset))
462 {
463 len = read(ch->sock, buf, sizeof(buf));
464 if (len <= 0)
465 {
466 if (compat13) {
467 buffer_consume(&ch->output, buffer_len(&ch->output));
468 ch->type = SSH_CHANNEL_INPUT_DRAINING;
469 debug("Channel %d status set to input draining.", i);
470 }else{
471 chan_read_failed(ch);
472 }
473 break;
474 }
475 buffer_append(&ch->input, buf, len);
476 }
477 /* Send buffered output data to the socket. */
478 if (FD_ISSET(ch->sock, writeset) && buffer_len(&ch->output) > 0)
479 {
480 len = write(ch->sock, buffer_ptr(&ch->output),
481 buffer_len(&ch->output));
482 if (len <= 0)
483 {
484 if (compat13) {
485 buffer_consume(&ch->output, buffer_len(&ch->output));
486 debug("Channel %d status set to input draining.", i);
487 ch->type = SSH_CHANNEL_INPUT_DRAINING;
488 }else{
489 chan_write_failed(ch);
490 }
491 break;
492 }
493 buffer_consume(&ch->output, len);
494 }
495 break;
496
497 case SSH_CHANNEL_OUTPUT_DRAINING:
498 if (!compat13)
499 fatal("cannot happen: OUT_DRAIN");
500 /* Send buffered output data to the socket. */
501 if (FD_ISSET(ch->sock, writeset) && buffer_len(&ch->output) > 0)
502 {
503 len = write(ch->sock, buffer_ptr(&ch->output),
504 buffer_len(&ch->output));
505 if (len <= 0)
506 buffer_consume(&ch->output, buffer_len(&ch->output));
507 else
508 buffer_consume(&ch->output, len);
509 }
510 break;
511
512 case SSH_CHANNEL_X11_OPEN:
513 case SSH_CHANNEL_FREE:
514 default:
515 continue;
516 } 490 }
517 }
518} 491}
519 492
520/* If there is data to send to the connection, send some of it now. */ 493/* If there is data to send to the connection, send some of it now. */
521 494
522void channel_output_poll() 495void
496channel_output_poll()
523{ 497{
524 int len, i; 498 int len, i;
525 Channel *ch; 499 Channel *ch;
526 500
527 for (i = 0; i < channels_alloc; i++) 501 for (i = 0; i < channels_alloc; i++) {
528 { 502 ch = &channels[i];
529 ch = &channels[i]; 503 /* We are only interested in channels that can have
530 /* We are only interested in channels that can have buffered incoming 504 buffered incoming data. */
531 data. */ 505 if (ch->type != SSH_CHANNEL_OPEN &&
532 if (ch->type != SSH_CHANNEL_OPEN && 506 ch->type != SSH_CHANNEL_INPUT_DRAINING)
533 ch->type != SSH_CHANNEL_INPUT_DRAINING) 507 continue;
534 continue; 508
535 509 /* Get the amount of buffered data for this channel. */
536 /* Get the amount of buffered data for this channel. */ 510 len = buffer_len(&ch->input);
537 len = buffer_len(&ch->input); 511 if (len > 0) {
538 if (len > 0) 512 /* Send some data for the other side over the
539 { 513 secure connection. */
540 /* Send some data for the other side over the secure connection. */ 514 if (packet_is_interactive()) {
541 if (packet_is_interactive()) 515 if (len > 1024)
542 { 516 len = 512;
543 if (len > 1024) 517 } else {
544 len = 512; 518 /* Keep the packets at reasonable size. */
545 } 519 if (len > 16384)
546 else 520 len = 16384;
547 { 521 }
548 if (len > 16384) 522 packet_start(SSH_MSG_CHANNEL_DATA);
549 len = 16384; /* Keep the packets at reasonable size. */ 523 packet_put_int(ch->remote_id);
550 } 524 packet_put_string(buffer_ptr(&ch->input), len);
551 packet_start(SSH_MSG_CHANNEL_DATA); 525 packet_send();
552 packet_put_int(ch->remote_id); 526 buffer_consume(&ch->input, len);
553 packet_put_string(buffer_ptr(&ch->input), len); 527 } else if (ch->istate == CHAN_INPUT_WAIT_DRAIN) {
554 packet_send(); 528 if (compat13)
555 buffer_consume(&ch->input, len); 529 fatal("cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3");
530 /* input-buffer is empty and read-socket shutdown:
531 tell peer, that we will not send more data:
532 send IEOF */
533 chan_ibuf_empty(ch);
534 }
556 } 535 }
557 else if(ch->istate == CHAN_INPUT_WAIT_DRAIN)
558 {
559 if (compat13)
560 fatal("cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3");
561 /* input-buffer is empty and read-socket shutdown:
562 tell peer, that we will not send more data: send IEOF */
563 chan_ibuf_empty(ch);
564 }
565 }
566} 536}
567 537
568/* This is called when a packet of type CHANNEL_DATA has just been received. 538/* This is called when a packet of type CHANNEL_DATA has just been received.
569 The message type has already been consumed, but channel number and data 539 The message type has already been consumed, but channel number and data
570 is still there. */ 540 is still there. */
571 541
572void channel_input_data(int payload_len) 542void
543channel_input_data(int payload_len)
573{ 544{
574 int channel; 545 int channel;
575 char *data; 546 char *data;
576 unsigned int data_len; 547 unsigned int data_len;
577 548
578 /* Get the channel number and verify it. */ 549 /* Get the channel number and verify it. */
579 channel = packet_get_int(); 550 channel = packet_get_int();
580 if (channel < 0 || channel >= channels_alloc || 551 if (channel < 0 || channel >= channels_alloc ||
581 channels[channel].type == SSH_CHANNEL_FREE) 552 channels[channel].type == SSH_CHANNEL_FREE)
582 packet_disconnect("Received data for nonexistent channel %d.", channel); 553 packet_disconnect("Received data for nonexistent channel %d.", channel);
583 554
584 /* Ignore any data for non-open channels (might happen on close) */ 555 /* Ignore any data for non-open channels (might happen on close) */
585 if (channels[channel].type != SSH_CHANNEL_OPEN && 556 if (channels[channel].type != SSH_CHANNEL_OPEN &&
586 channels[channel].type != SSH_CHANNEL_X11_OPEN) 557 channels[channel].type != SSH_CHANNEL_X11_OPEN)
587 return; 558 return;
588 559
589 /* Get the data. */ 560 /* Get the data. */
590 data = packet_get_string(&data_len); 561 data = packet_get_string(&data_len);
591 packet_integrity_check(payload_len, 4 + 4+data_len, SSH_MSG_CHANNEL_DATA); 562 packet_integrity_check(payload_len, 4 + 4 + data_len, SSH_MSG_CHANNEL_DATA);
592 buffer_append(&channels[channel].output, data, data_len); 563 buffer_append(&channels[channel].output, data, data_len);
593 xfree(data); 564 xfree(data);
594} 565}
595 566
596/* Returns true if no channel has too much buffered data, and false if 567/* Returns true if no channel has too much buffered data, and false if
597 one or more channel is overfull. */ 568 one or more channel is overfull. */
598 569
599int channel_not_very_much_buffered_data() 570int
571channel_not_very_much_buffered_data()
600{ 572{
601 unsigned int i; 573 unsigned int i;
602 Channel *ch; 574 Channel *ch;
603 575
604 for (i = 0; i < channels_alloc; i++) 576 for (i = 0; i < channels_alloc; i++) {
605 { 577 ch = &channels[i];
606 ch = &channels[i]; 578 switch (ch->type) {
607 switch (ch->type) 579 case SSH_CHANNEL_X11_LISTENER:
608 { 580 case SSH_CHANNEL_PORT_LISTENER:
609 case SSH_CHANNEL_X11_LISTENER: 581 case SSH_CHANNEL_AUTH_SOCKET:
610 case SSH_CHANNEL_PORT_LISTENER: 582 continue;
611 case SSH_CHANNEL_AUTH_SOCKET: 583 case SSH_CHANNEL_OPEN:
612 continue; 584 if (buffer_len(&ch->input) > packet_get_maxsize())
613 case SSH_CHANNEL_OPEN: 585 return 0;
614 if (buffer_len(&ch->input) > packet_get_maxsize()) 586 if (buffer_len(&ch->output) > packet_get_maxsize())
615 return 0; 587 return 0;
616 if (buffer_len(&ch->output) > packet_get_maxsize()) 588 continue;
617 return 0; 589 case SSH_CHANNEL_INPUT_DRAINING:
618 continue; 590 case SSH_CHANNEL_OUTPUT_DRAINING:
619 case SSH_CHANNEL_INPUT_DRAINING: 591 case SSH_CHANNEL_X11_OPEN:
620 case SSH_CHANNEL_OUTPUT_DRAINING: 592 case SSH_CHANNEL_FREE:
621 case SSH_CHANNEL_X11_OPEN: 593 default:
622 case SSH_CHANNEL_FREE: 594 continue;
623 default: 595 }
624 continue;
625 } 596 }
626 } 597 return 1;
627 return 1;
628} 598}
629 599
630/* This is called after receiving CHANNEL_CLOSE/IEOF. */ 600/* This is called after receiving CHANNEL_CLOSE/IEOF. */
631 601
632void channel_input_close() 602void
603channel_input_close()
633{ 604{
634 int channel; 605 int channel;
635 606
636 /* Get the channel number and verify it. */ 607 /* Get the channel number and verify it. */
637 channel = packet_get_int(); 608 channel = packet_get_int();
638 if (channel < 0 || channel >= channels_alloc || 609 if (channel < 0 || channel >= channels_alloc ||
639 channels[channel].type == SSH_CHANNEL_FREE) 610 channels[channel].type == SSH_CHANNEL_FREE)
640 packet_disconnect("Received data for nonexistent channel %d.", channel); 611 packet_disconnect("Received data for nonexistent channel %d.", channel);
641 612
642 if(!compat13){ 613 if (!compat13) {
643 /* proto version 1.5 overloads CLOSE with IEOF */ 614 /* proto version 1.5 overloads CLOSE with IEOF */
644 chan_rcvd_ieof(&channels[channel]); 615 chan_rcvd_ieof(&channels[channel]);
645 return; 616 return;
646 } 617 }
647 618 /* Send a confirmation that we have closed the channel and no more
648 /* Send a confirmation that we have closed the channel and no more data is 619 data is coming for it. */
649 coming for it. */ 620 packet_start(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION);
650 packet_start(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION); 621 packet_put_int(channels[channel].remote_id);
651 packet_put_int(channels[channel].remote_id); 622 packet_send();
652 packet_send(); 623
653 624 /* If the channel is in closed state, we have sent a close
654 /* If the channel is in closed state, we have sent a close request, and 625 request, and the other side will eventually respond with a
655 the other side will eventually respond with a confirmation. Thus, 626 confirmation. Thus, we cannot free the channel here, because
656 we cannot free the channel here, because then there would be no-one to 627 then there would be no-one to receive the confirmation. The
657 receive the confirmation. The channel gets freed when the confirmation 628 channel gets freed when the confirmation arrives. */
658 arrives. */ 629 if (channels[channel].type != SSH_CHANNEL_CLOSED) {
659 if (channels[channel].type != SSH_CHANNEL_CLOSED) 630 /* Not a closed channel - mark it as draining, which will
660 { 631 cause it to be freed later. */
661 /* Not a closed channel - mark it as draining, which will cause it to 632 buffer_consume(&channels[channel].input,
662 be freed later. */ 633 buffer_len(&channels[channel].input));
663 buffer_consume(&channels[channel].input, 634 channels[channel].type = SSH_CHANNEL_OUTPUT_DRAINING;
664 buffer_len(&channels[channel].input)); 635 }
665 channels[channel].type = SSH_CHANNEL_OUTPUT_DRAINING;
666 /* debug("Setting status to output draining; output len = %d",
667 buffer_len(&channels[channel].output)); */
668 }
669} 636}
670 637
671/* This is called after receiving CHANNEL_CLOSE_CONFIRMATION/OCLOSE. */ 638/* This is called after receiving CHANNEL_CLOSE_CONFIRMATION/OCLOSE. */
672 639
673void channel_input_close_confirmation() 640void
641channel_input_close_confirmation()
674{ 642{
675 int channel; 643 int channel;
676 644
677 /* Get the channel number and verify it. */ 645 /* Get the channel number and verify it. */
678 channel = packet_get_int(); 646 channel = packet_get_int();
679 if (channel < 0 || channel >= channels_alloc) 647 if (channel < 0 || channel >= channels_alloc)
680 packet_disconnect("Received close confirmation for out-of-range channel %d.", 648 packet_disconnect("Received close confirmation for out-of-range channel %d.",
681 channel); 649 channel);
682 650
683 if(!compat13){ 651 if (!compat13) {
684 /* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */ 652 /* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */
685 chan_rcvd_oclose(&channels[channel]); 653 chan_rcvd_oclose(&channels[channel]);
686 return; 654 return;
687 } 655 }
688 656 if (channels[channel].type != SSH_CHANNEL_CLOSED)
689 if (channels[channel].type != SSH_CHANNEL_CLOSED) 657 packet_disconnect("Received close confirmation for non-closed channel %d (type %d).",
690 packet_disconnect("Received close confirmation for non-closed channel %d (type %d).", 658 channel, channels[channel].type);
691 channel, channels[channel].type); 659
692 660 /* Free the channel. */
693 /* Free the channel. */ 661 channel_free(channel);
694 channel_free(channel);
695} 662}
696 663
697/* This is called after receiving CHANNEL_OPEN_CONFIRMATION. */ 664/* This is called after receiving CHANNEL_OPEN_CONFIRMATION. */
698 665
699void channel_input_open_confirmation() 666void
667channel_input_open_confirmation()
700{ 668{
701 int channel, remote_channel; 669 int channel, remote_channel;
702 670
703 /* Get the channel number and verify it. */ 671 /* Get the channel number and verify it. */
704 channel = packet_get_int(); 672 channel = packet_get_int();
705 if (channel < 0 || channel >= channels_alloc || 673 if (channel < 0 || channel >= channels_alloc ||
706 channels[channel].type != SSH_CHANNEL_OPENING) 674 channels[channel].type != SSH_CHANNEL_OPENING)
707 packet_disconnect("Received open confirmation for non-opening channel %d.", 675 packet_disconnect("Received open confirmation for non-opening channel %d.",
708 channel); 676 channel);
709 677
710 /* Get remote side's id for this channel. */ 678 /* Get remote side's id for this channel. */
711 remote_channel = packet_get_int(); 679 remote_channel = packet_get_int();
712 680
713 /* Record the remote channel number and mark that the channel is now open. */ 681 /* Record the remote channel number and mark that the channel is
714 channels[channel].remote_id = remote_channel; 682 now open. */
715 channels[channel].type = SSH_CHANNEL_OPEN; 683 channels[channel].remote_id = remote_channel;
684 channels[channel].type = SSH_CHANNEL_OPEN;
716} 685}
717 686
718/* This is called after receiving CHANNEL_OPEN_FAILURE from the other side. */ 687/* This is called after receiving CHANNEL_OPEN_FAILURE from the other side. */
719 688
720void channel_input_open_failure() 689void
690channel_input_open_failure()
721{ 691{
722 int channel; 692 int channel;
723 693
724 /* Get the channel number and verify it. */ 694 /* Get the channel number and verify it. */
725 channel = packet_get_int(); 695 channel = packet_get_int();
726 if (channel < 0 || channel >= channels_alloc || 696 if (channel < 0 || channel >= channels_alloc ||
727 channels[channel].type != SSH_CHANNEL_OPENING) 697 channels[channel].type != SSH_CHANNEL_OPENING)
728 packet_disconnect("Received open failure for non-opening channel %d.", 698 packet_disconnect("Received open failure for non-opening channel %d.",
729 channel); 699 channel);
730 700
731 /* Free the channel. This will also close the socket. */ 701 /* Free the channel. This will also close the socket. */
732 channel_free(channel); 702 channel_free(channel);
733} 703}
734 704
735/* Stops listening for channels, and removes any unix domain sockets that 705/* Stops listening for channels, and removes any unix domain sockets that
736 we might have. */ 706 we might have. */
737 707
738void channel_stop_listening() 708void
709channel_stop_listening()
739{ 710{
740 int i; 711 int i;
741 for (i = 0; i < channels_alloc; i++) 712 for (i = 0; i < channels_alloc; i++) {
742 { 713 switch (channels[i].type) {
743 switch (channels[i].type) 714 case SSH_CHANNEL_AUTH_SOCKET:
744 { 715 close(channels[i].sock);
745 case SSH_CHANNEL_AUTH_SOCKET: 716 remove(channels[i].path);
746 close(channels[i].sock); 717 channel_free(i);
747 remove(channels[i].path); 718 break;
748 channel_free(i); 719 case SSH_CHANNEL_PORT_LISTENER:
749 break; 720 case SSH_CHANNEL_X11_LISTENER:
750 case SSH_CHANNEL_PORT_LISTENER: 721 close(channels[i].sock);
751 case SSH_CHANNEL_X11_LISTENER: 722 channel_free(i);
752 close(channels[i].sock); 723 break;
753 channel_free(i); 724 default:
754 break; 725 break;
755 default: 726 }
756 break;
757 } 727 }
758 }
759} 728}
760 729
761/* Closes the sockets of all channels. This is used to close extra file 730/* Closes the sockets of all channels. This is used to close extra file
762 descriptors after a fork. */ 731 descriptors after a fork. */
763 732
764void channel_close_all() 733void
734channel_close_all()
765{ 735{
766 int i; 736 int i;
767 for (i = 0; i < channels_alloc; i++) 737 for (i = 0; i < channels_alloc; i++) {
768 { 738 if (channels[i].type != SSH_CHANNEL_FREE)
769 if (channels[i].type != SSH_CHANNEL_FREE) 739 close(channels[i].sock);
770 close(channels[i].sock); 740 }
771 }
772} 741}
773 742
774/* Returns the maximum file descriptor number used by the channels. */ 743/* Returns the maximum file descriptor number used by the channels. */
775 744
776int channel_max_fd() 745int
746channel_max_fd()
777{ 747{
778 return channel_max_fd_value; 748 return channel_max_fd_value;
779} 749}
780 750
781/* Returns true if any channel is still open. */ 751/* Returns true if any channel is still open. */
782 752
783int channel_still_open() 753int
754channel_still_open()
784{ 755{
785 unsigned int i; 756 unsigned int i;
786 for (i = 0; i < channels_alloc; i++) 757 for (i = 0; i < channels_alloc; i++)
787 switch (channels[i].type) 758 switch (channels[i].type) {
788 { 759 case SSH_CHANNEL_FREE:
789 case SSH_CHANNEL_FREE: 760 case SSH_CHANNEL_X11_LISTENER:
790 case SSH_CHANNEL_X11_LISTENER: 761 case SSH_CHANNEL_PORT_LISTENER:
791 case SSH_CHANNEL_PORT_LISTENER: 762 case SSH_CHANNEL_CLOSED:
792 case SSH_CHANNEL_CLOSED: 763 case SSH_CHANNEL_AUTH_SOCKET:
793 case SSH_CHANNEL_AUTH_SOCKET: 764 continue;
794 continue; 765 case SSH_CHANNEL_OPENING:
795 case SSH_CHANNEL_OPENING: 766 case SSH_CHANNEL_OPEN:
796 case SSH_CHANNEL_OPEN: 767 case SSH_CHANNEL_X11_OPEN:
797 case SSH_CHANNEL_X11_OPEN: 768 return 1;
798 return 1; 769 case SSH_CHANNEL_INPUT_DRAINING:
799 case SSH_CHANNEL_INPUT_DRAINING: 770 case SSH_CHANNEL_OUTPUT_DRAINING:
800 case SSH_CHANNEL_OUTPUT_DRAINING: 771 if (!compat13)
801 if (!compat13) 772 fatal("cannot happen: OUT_DRAIN");
802 fatal("cannot happen: OUT_DRAIN"); 773 return 1;
803 return 1; 774 default:
804 default: 775 fatal("channel_still_open: bad channel type %d", channels[i].type);
805 fatal("channel_still_open: bad channel type %d", channels[i].type); 776 /* NOTREACHED */
806 /*NOTREACHED*/ 777 }
807 } 778 return 0;
808 return 0;
809} 779}
810 780
811/* Returns a message describing the currently open forwarded 781/* Returns a message describing the currently open forwarded
812 connections, suitable for sending to the client. The message 782 connections, suitable for sending to the client. The message
813 contains crlf pairs for newlines. */ 783 contains crlf pairs for newlines. */
814 784
815char *channel_open_message() 785char *
786channel_open_message()
816{ 787{
817 Buffer buffer; 788 Buffer buffer;
818 int i; 789 int i;
819 char buf[512], *cp; 790 char buf[512], *cp;
820 791
821 buffer_init(&buffer); 792 buffer_init(&buffer);
822 snprintf(buf, sizeof buf, "The following connections are open:\r\n"); 793 snprintf(buf, sizeof buf, "The following connections are open:\r\n");
823 buffer_append(&buffer, buf, strlen(buf));
824 for (i = 0; i < channels_alloc; i++){
825 Channel *c=&channels[i];
826 switch (c->type)
827 {
828 case SSH_CHANNEL_FREE:
829 case SSH_CHANNEL_X11_LISTENER:
830 case SSH_CHANNEL_PORT_LISTENER:
831 case SSH_CHANNEL_CLOSED:
832 case SSH_CHANNEL_AUTH_SOCKET:
833 continue;
834 case SSH_CHANNEL_OPENING:
835 case SSH_CHANNEL_OPEN:
836 case SSH_CHANNEL_X11_OPEN:
837 case SSH_CHANNEL_INPUT_DRAINING:
838 case SSH_CHANNEL_OUTPUT_DRAINING:
839 snprintf(buf, sizeof buf, " #%d %.300s (t%d r%d i%d o%d)\r\n",
840 c->self,c->remote_name,
841 c->type,c->remote_id, c->istate,c->ostate);
842 buffer_append(&buffer, buf, strlen(buf)); 794 buffer_append(&buffer, buf, strlen(buf));
843 continue; 795 for (i = 0; i < channels_alloc; i++) {
844 default: 796 Channel *c = &channels[i];
845 fatal("channel_still_open: bad channel type %d", c->type); 797 switch (c->type) {
846 /*NOTREACHED*/ 798 case SSH_CHANNEL_FREE:
847 } 799 case SSH_CHANNEL_X11_LISTENER:
848 } 800 case SSH_CHANNEL_PORT_LISTENER:
849 buffer_append(&buffer, "\0", 1); 801 case SSH_CHANNEL_CLOSED:
850 cp = xstrdup(buffer_ptr(&buffer)); 802 case SSH_CHANNEL_AUTH_SOCKET:
851 buffer_free(&buffer); 803 continue;
852 return cp; 804 case SSH_CHANNEL_OPENING:
805 case SSH_CHANNEL_OPEN:
806 case SSH_CHANNEL_X11_OPEN:
807 case SSH_CHANNEL_INPUT_DRAINING:
808 case SSH_CHANNEL_OUTPUT_DRAINING:
809 snprintf(buf, sizeof buf, " #%d %.300s (t%d r%d i%d o%d)\r\n",
810 c->self, c->remote_name,
811 c->type, c->remote_id, c->istate, c->ostate);
812 buffer_append(&buffer, buf, strlen(buf));
813 continue;
814 default:
815 fatal("channel_still_open: bad channel type %d", c->type);
816 /* NOTREACHED */
817 }
818 }
819 buffer_append(&buffer, "\0", 1);
820 cp = xstrdup(buffer_ptr(&buffer));
821 buffer_free(&buffer);
822 return cp;
853} 823}
854 824
855/* Initiate forwarding of connections to local port "port" through the secure 825/* Initiate forwarding of connections to local port "port" through the secure
856 channel to host:port from remote side. */ 826 channel to host:port from remote side. */
857 827
858void channel_request_local_forwarding(int port, const char *host, 828void
859 int host_port) 829channel_request_local_forwarding(int port, const char *host,
830 int host_port)
860{ 831{
861 int ch, sock; 832 int ch, sock;
862 struct sockaddr_in sin; 833 struct sockaddr_in sin;
863 extern Options options; 834 extern Options options;
864 835
865 if (strlen(host) > sizeof(channels[0].path) - 1) 836 if (strlen(host) > sizeof(channels[0].path) - 1)
866 packet_disconnect("Forward host name too long."); 837 packet_disconnect("Forward host name too long.");
867 838
868 /* Create a port to listen for the host. */ 839 /* Create a port to listen for the host. */
869 sock = socket(AF_INET, SOCK_STREAM, 0); 840 sock = socket(AF_INET, SOCK_STREAM, 0);
870 if (sock < 0) 841 if (sock < 0)
871 packet_disconnect("socket: %.100s", strerror(errno)); 842 packet_disconnect("socket: %.100s", strerror(errno));
872 843
873 /* Initialize socket address. */ 844 /* Initialize socket address. */
874 memset(&sin, 0, sizeof(sin)); 845 memset(&sin, 0, sizeof(sin));
875 sin.sin_family = AF_INET; 846 sin.sin_family = AF_INET;
876 if (options.gateway_ports == 1) 847 if (options.gateway_ports == 1)
877 sin.sin_addr.s_addr = htonl(INADDR_ANY); 848 sin.sin_addr.s_addr = htonl(INADDR_ANY);
878 else 849 else
879 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 850 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
880 sin.sin_port = htons(port); 851 sin.sin_port = htons(port);
881 852
882 /* Bind the socket to the address. */ 853 /* Bind the socket to the address. */
883 if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) 854 if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0)
884 packet_disconnect("bind: %.100s", strerror(errno)); 855 packet_disconnect("bind: %.100s", strerror(errno));
885 856
886 /* Start listening for connections on the socket. */ 857 /* Start listening for connections on the socket. */
887 if (listen(sock, 5) < 0) 858 if (listen(sock, 5) < 0)
888 packet_disconnect("listen: %.100s", strerror(errno)); 859 packet_disconnect("listen: %.100s", strerror(errno));
889 860
890 /* Allocate a channel number for the socket. */ 861 /* Allocate a channel number for the socket. */
891 ch = channel_allocate(SSH_CHANNEL_PORT_LISTENER, sock, 862 ch = channel_allocate(SSH_CHANNEL_PORT_LISTENER, sock,
892 xstrdup("port listener")); 863 xstrdup("port listener"));
893 strcpy(channels[ch].path, host); /* note: host name stored here */ 864 strcpy(channels[ch].path, host);
894 channels[ch].host_port = host_port; /* port on host to connect to */ 865 channels[ch].host_port = host_port;
895 channels[ch].listening_port = port; /* port being listened */ 866 channels[ch].listening_port = port;
896} 867}
897 868
898/* Initiate forwarding of connections to port "port" on remote host through 869/* Initiate forwarding of connections to port "port" on remote host through
899 the secure channel to host:port from local side. */ 870 the secure channel to host:port from local side. */
900 871
901void channel_request_remote_forwarding(int port, const char *host, 872void
902 int remote_port) 873channel_request_remote_forwarding(int port, const char *host,
874 int remote_port)
903{ 875{
904 int payload_len; 876 int payload_len;
905 /* Record locally that connection to this host/port is permitted. */ 877 /* Record locally that connection to this host/port is permitted. */
906 if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION) 878 if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION)
907 fatal("channel_request_remote_forwarding: too many forwards"); 879 fatal("channel_request_remote_forwarding: too many forwards");
908 permitted_opens[num_permitted_opens].host = xstrdup(host); 880
909 permitted_opens[num_permitted_opens].port = remote_port; 881 permitted_opens[num_permitted_opens].host = xstrdup(host);
910 num_permitted_opens++; 882 permitted_opens[num_permitted_opens].port = remote_port;
911 883 num_permitted_opens++;
912 /* Send the forward request to the remote side. */ 884
913 packet_start(SSH_CMSG_PORT_FORWARD_REQUEST); 885 /* Send the forward request to the remote side. */
914 packet_put_int(port); 886 packet_start(SSH_CMSG_PORT_FORWARD_REQUEST);
915 packet_put_string(host, strlen(host)); 887 packet_put_int(port);
916 packet_put_int(remote_port); 888 packet_put_string(host, strlen(host));
917 packet_send(); 889 packet_put_int(remote_port);
918 packet_write_wait(); 890 packet_send();
919 891 packet_write_wait();
920 /* Wait for response from the remote side. It will send a disconnect 892
921 message on failure, and we will never see it here. */ 893 /* Wait for response from the remote side. It will send a
922 packet_read_expect(&payload_len, SSH_SMSG_SUCCESS); 894 disconnect message on failure, and we will never see it here. */
895 packet_read_expect(&payload_len, SSH_SMSG_SUCCESS);
923} 896}
924 897
925/* This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates 898/* This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates
926 listening for the port, and sends back a success reply (or disconnect 899 listening for the port, and sends back a success reply (or disconnect
927 message if there was an error). This never returns if there was an 900 message if there was an error). This never returns if there was an
928 error. */ 901 error. */
929 902
930void channel_input_port_forward_request(int is_root) 903void
904channel_input_port_forward_request(int is_root)
931{ 905{
932 int port, host_port; 906 int port, host_port;
933 char *hostname; 907 char *hostname;
934 908
935 /* Get arguments from the packet. */ 909 /* Get arguments from the packet. */
936 port = packet_get_int(); 910 port = packet_get_int();
937 hostname = packet_get_string(NULL); 911 hostname = packet_get_string(NULL);
938 host_port = packet_get_int(); 912 host_port = packet_get_int();
939 913
940 /* Port numbers are 16 bit quantities. */ 914 /* Port numbers are 16 bit quantities. */
941 if ((port & 0xffff) != port) 915 if ((port & 0xffff) != port)
942 packet_disconnect("Requested forwarding of nonexistent port %d.", port); 916 packet_disconnect("Requested forwarding of nonexistent port %d.", port);
943 917
944 /* Check that an unprivileged user is not trying to forward a privileged 918 /* Check that an unprivileged user is not trying to forward a
945 port. */ 919 privileged port. */
946 if (port < IPPORT_RESERVED && !is_root) 920 if (port < IPPORT_RESERVED && !is_root)
947 packet_disconnect("Requested forwarding of port %d but user is not root.", 921 packet_disconnect("Requested forwarding of port %d but user is not root.",
948 port); 922 port);
949 923
950 /* Initiate forwarding. */ 924 /* Initiate forwarding. */
951 channel_request_local_forwarding(port, hostname, host_port); 925 channel_request_local_forwarding(port, hostname, host_port);
952 926
953 /* Free the argument string. */ 927 /* Free the argument string. */
954 xfree(hostname); 928 xfree(hostname);
955} 929}
956 930
957/* This is called after receiving PORT_OPEN message. This attempts to connect 931/* This is called after receiving PORT_OPEN message. This attempts to connect
958 to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION or 932 to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION or
959 CHANNEL_OPEN_FAILURE. */ 933 CHANNEL_OPEN_FAILURE. */
960 934
961void channel_input_port_open(int payload_len) 935void
936channel_input_port_open(int payload_len)
962{ 937{
963 int remote_channel, sock, newch, host_port, i; 938 int remote_channel, sock, newch, host_port, i;
964 struct sockaddr_in sin; 939 struct sockaddr_in sin;
965 char *host, *originator_string; 940 char *host, *originator_string;
966 struct hostent *hp; 941 struct hostent *hp;
967 int host_len, originator_len; 942 int host_len, originator_len;
968 943
969 /* Get remote channel number. */ 944 /* Get remote channel number. */
970 remote_channel = packet_get_int(); 945 remote_channel = packet_get_int();
971 946
972 /* Get host name to connect to. */ 947 /* Get host name to connect to. */
973 host = packet_get_string(&host_len); 948 host = packet_get_string(&host_len);
974 949
975 /* Get port to connect to. */ 950 /* Get port to connect to. */
976 host_port = packet_get_int(); 951 host_port = packet_get_int();
977 952
978 /* Get remote originator name. */ 953 /* Get remote originator name. */
979 if (have_hostname_in_open) 954 if (have_hostname_in_open)
980 originator_string = packet_get_string(&originator_len); 955 originator_string = packet_get_string(&originator_len);
981 else 956 else
982 originator_string = xstrdup("unknown (remote did not supply name)"); 957 originator_string = xstrdup("unknown (remote did not supply name)");
983 958
984 packet_integrity_check(payload_len, 959 packet_integrity_check(payload_len,
985 4 + 4 + host_len + 4 + 4 + originator_len, 960 4 + 4 + host_len + 4 + 4 + originator_len,
986 SSH_MSG_PORT_OPEN); 961 SSH_MSG_PORT_OPEN);
987 962
988 /* Check if opening that port is permitted. */ 963 /* Check if opening that port is permitted. */
989 if (!all_opens_permitted) 964 if (!all_opens_permitted) {
990 { 965 /* Go trough all permitted ports. */
991 /* Go trough all permitted ports. */ 966 for (i = 0; i < num_permitted_opens; i++)
992 for (i = 0; i < num_permitted_opens; i++) 967 if (permitted_opens[i].port == host_port &&
993 if (permitted_opens[i].port == host_port && 968 strcmp(permitted_opens[i].host, host) == 0)
994 strcmp(permitted_opens[i].host, host) == 0) 969 break;
995 break; 970
996 971 /* Check if we found the requested port among those permitted. */
997 /* Check if we found the requested port among those permitted. */ 972 if (i >= num_permitted_opens) {
998 if (i >= num_permitted_opens) 973 /* The port is not permitted. */
999 { 974 log("Received request to connect to %.100s:%d, but the request was denied.",
1000 /* The port is not permitted. */ 975 host, host_port);
1001 log("Received request to connect to %.100s:%d, but the request was denied.", 976 packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
1002 host, host_port); 977 packet_put_int(remote_channel);
1003 packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); 978 packet_send();
1004 packet_put_int(remote_channel); 979 }
1005 packet_send();
1006 } 980 }
1007 } 981 memset(&sin, 0, sizeof(sin));
1008 982 sin.sin_addr.s_addr = inet_addr(host);
1009 memset(&sin, 0, sizeof(sin)); 983 if ((sin.sin_addr.s_addr & 0xffffffff) != 0xffffffff) {
1010 sin.sin_addr.s_addr = inet_addr(host); 984 /* It was a valid numeric host address. */
1011 if ((sin.sin_addr.s_addr & 0xffffffff) != 0xffffffff) 985 sin.sin_family = AF_INET;
1012 { 986 } else {
1013 /* It was a valid numeric host address. */ 987 /* Look up the host address from the name servers. */
1014 sin.sin_family = AF_INET; 988 hp = gethostbyname(host);
1015 } 989 if (!hp) {
1016 else 990 error("%.100s: unknown host.", host);
1017 { 991 goto fail;
1018 /* Look up the host address from the name servers. */ 992 }
1019 hp = gethostbyname(host); 993 if (!hp->h_addr_list[0]) {
1020 if (!hp) 994 error("%.100s: host has no IP address.", host);
1021 { 995 goto fail;
1022 error("%.100s: unknown host.", host); 996 }
1023 goto fail; 997 sin.sin_family = hp->h_addrtype;
998 memcpy(&sin.sin_addr, hp->h_addr_list[0],
999 sizeof(sin.sin_addr));
1024 } 1000 }
1025 if (!hp->h_addr_list[0]) 1001 sin.sin_port = htons(host_port);
1026 { 1002
1027 error("%.100s: host has no IP address.", host); 1003 /* Create the socket. */
1028 goto fail; 1004 sock = socket(sin.sin_family, SOCK_STREAM, 0);
1005 if (sock < 0) {
1006 error("socket: %.100s", strerror(errno));
1007 goto fail;
1008 }
1009 /* Connect to the host/port. */
1010 if (connect(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) {
1011 error("connect %.100s:%d: %.100s", host, host_port,
1012 strerror(errno));
1013 close(sock);
1014 goto fail;
1029 } 1015 }
1030 sin.sin_family = hp->h_addrtype; 1016 /* Successful connection. */
1031 memcpy(&sin.sin_addr, hp->h_addr_list[0], 1017
1032 sizeof(sin.sin_addr)); 1018 /* Allocate a channel for this connection. */
1033 } 1019 newch = channel_allocate(SSH_CHANNEL_OPEN, sock, originator_string);
1034 sin.sin_port = htons(host_port); 1020 channels[newch].remote_id = remote_channel;
1035 1021
1036 /* Create the socket. */ 1022 /* Send a confirmation to the remote host. */
1037 sock = socket(sin.sin_family, SOCK_STREAM, 0); 1023 packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
1038 if (sock < 0) 1024 packet_put_int(remote_channel);
1039 { 1025 packet_put_int(newch);
1040 error("socket: %.100s", strerror(errno)); 1026 packet_send();
1041 goto fail; 1027
1042 } 1028 /* Free the argument string. */
1043 1029 xfree(host);
1044 /* Connect to the host/port. */ 1030
1045 if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) 1031 return;
1046 { 1032
1047 error("connect %.100s:%d: %.100s", host, host_port, 1033fail:
1048 strerror(errno)); 1034 /* Free the argument string. */
1049 close(sock); 1035 xfree(host);
1050 goto fail; 1036
1051 } 1037 /* Send refusal to the remote host. */
1052 1038 packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
1053 /* Successful connection. */ 1039 packet_put_int(remote_channel);
1054 1040 packet_send();
1055 /* Allocate a channel for this connection. */
1056 newch = channel_allocate(SSH_CHANNEL_OPEN, sock, originator_string);
1057 channels[newch].remote_id = remote_channel;
1058
1059 /* Send a confirmation to the remote host. */
1060 packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
1061 packet_put_int(remote_channel);
1062 packet_put_int(newch);
1063 packet_send();
1064
1065 /* Free the argument string. */
1066 xfree(host);
1067
1068 return;
1069
1070 fail:
1071 /* Free the argument string. */
1072 xfree(host);
1073
1074 /* Send refusal to the remote host. */
1075 packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
1076 packet_put_int(remote_channel);
1077 packet_send();
1078} 1041}
1079 1042
1080/* Creates an internet domain socket for listening for X11 connections. 1043/* Creates an internet domain socket for listening for X11 connections.
1081 Returns a suitable value for the DISPLAY variable, or NULL if an error 1044 Returns a suitable value for the DISPLAY variable, or NULL if an error
1082 occurs. */ 1045 occurs. */
1083 1046
1084char *x11_create_display_inet(int screen_number) 1047char *
1048x11_create_display_inet(int screen_number)
1085{ 1049{
1086 extern ServerOptions options; 1050 extern ServerOptions options;
1087 int display_number, port, sock; 1051 int display_number, port, sock;
1088 struct sockaddr_in sin; 1052 struct sockaddr_in sin;
1089 char buf[512]; 1053 char buf[512];
1090 char hostname[MAXHOSTNAMELEN]; 1054 char hostname[MAXHOSTNAMELEN];
1091 1055
1092 for (display_number = options.x11_display_offset; display_number < MAX_DISPLAYS; display_number++) 1056 for (display_number = options.x11_display_offset;
1093 { 1057 display_number < MAX_DISPLAYS;
1094 port = 6000 + display_number; 1058 display_number++) {
1095 memset(&sin, 0, sizeof(sin)); 1059 port = 6000 + display_number;
1096 sin.sin_family = AF_INET; 1060 memset(&sin, 0, sizeof(sin));
1097 sin.sin_addr.s_addr = htonl(INADDR_ANY); 1061 sin.sin_family = AF_INET;
1098 sin.sin_port = htons(port); 1062 sin.sin_addr.s_addr = htonl(INADDR_ANY);
1099 1063 sin.sin_port = htons(port);
1100 sock = socket(AF_INET, SOCK_STREAM, 0); 1064
1101 if (sock < 0) 1065 sock = socket(AF_INET, SOCK_STREAM, 0);
1102 { 1066 if (sock < 0) {
1103 error("socket: %.100s", strerror(errno)); 1067 error("socket: %.100s", strerror(errno));
1104 return NULL; 1068 return NULL;
1069 }
1070 if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) {
1071 debug("bind port %d: %.100s", port, strerror(errno));
1072 shutdown(sock, SHUT_RDWR);
1073 close(sock);
1074 continue;
1075 }
1076 break;
1077 }
1078 if (display_number >= MAX_DISPLAYS) {
1079 error("Failed to allocate internet-domain X11 display socket.");
1080 return NULL;
1105 } 1081 }
1106 1082 /* Start listening for connections on the socket. */
1107 if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) 1083 if (listen(sock, 5) < 0) {
1108 { 1084 error("listen: %.100s", strerror(errno));
1109 debug("bind port %d: %.100s", port, strerror(errno)); 1085 shutdown(sock, SHUT_RDWR);
1110 shutdown(sock, SHUT_RDWR); 1086 close(sock);
1111 close(sock); 1087 return NULL;
1112 continue;
1113 } 1088 }
1114 break; 1089 /* Set up a suitable value for the DISPLAY variable. */
1115 } 1090 if (gethostname(hostname, sizeof(hostname)) < 0)
1116 if (display_number >= MAX_DISPLAYS) 1091 fatal("gethostname: %.100s", strerror(errno));
1117 { 1092 snprintf(buf, sizeof buf, "%.400s:%d.%d", hostname,
1118 error("Failed to allocate internet-domain X11 display socket."); 1093 display_number, screen_number);
1119 return NULL; 1094
1120 } 1095 /* Allocate a channel for the socket. */
1121 1096 (void) channel_allocate(SSH_CHANNEL_X11_LISTENER, sock,
1122 /* Start listening for connections on the socket. */ 1097 xstrdup("X11 inet listener"));
1123 if (listen(sock, 5) < 0) 1098
1124 { 1099 /* Return a suitable value for the DISPLAY environment variable. */
1125 error("listen: %.100s", strerror(errno)); 1100 return xstrdup(buf);
1126 shutdown(sock, SHUT_RDWR);
1127 close(sock);
1128 return NULL;
1129 }
1130
1131 /* Set up a suitable value for the DISPLAY variable. */
1132 if (gethostname(hostname, sizeof(hostname)) < 0)
1133 fatal("gethostname: %.100s", strerror(errno));
1134 snprintf(buf, sizeof buf, "%.400s:%d.%d", hostname,
1135 display_number, screen_number);
1136
1137 /* Allocate a channel for the socket. */
1138 (void)channel_allocate(SSH_CHANNEL_X11_LISTENER, sock,
1139 xstrdup("X11 inet listener"));
1140
1141 /* Return a suitable value for the DISPLAY environment variable. */
1142 return xstrdup(buf);
1143} 1101}
1144 1102
1145#ifndef X_UNIX_PATH 1103#ifndef X_UNIX_PATH
@@ -1150,30 +1108,29 @@ static
1150int 1108int
1151connect_local_xsocket(unsigned dnr) 1109connect_local_xsocket(unsigned dnr)
1152{ 1110{
1153 static const char *const x_sockets[] = { 1111 static const char *const x_sockets[] = {
1154 X_UNIX_PATH "%u", 1112 X_UNIX_PATH "%u",
1155 "/var/X/.X11-unix/X" "%u", 1113 "/var/X/.X11-unix/X" "%u",
1156 "/usr/spool/sockets/X11/" "%u", 1114 "/usr/spool/sockets/X11/" "%u",
1157 NULL 1115 NULL
1158 }; 1116 };
1159 int sock; 1117 int sock;
1160 struct sockaddr_un addr; 1118 struct sockaddr_un addr;
1161 const char *const *path; 1119 const char *const * path;
1162 1120
1163 for (path = x_sockets; *path; ++path) 1121 for (path = x_sockets; *path; ++path) {
1164 { 1122 sock = socket(AF_UNIX, SOCK_STREAM, 0);
1165 sock = socket(AF_UNIX, SOCK_STREAM, 0); 1123 if (sock < 0)
1166 if (sock < 0) 1124 error("socket: %.100s", strerror(errno));
1167 error("socket: %.100s", strerror(errno)); 1125 memset(&addr, 0, sizeof(addr));
1168 memset(&addr, 0, sizeof(addr)); 1126 addr.sun_family = AF_UNIX;
1169 addr.sun_family = AF_UNIX; 1127 snprintf(addr.sun_path, sizeof addr.sun_path, *path, dnr);
1170 snprintf(addr.sun_path, sizeof addr.sun_path, *path, dnr); 1128 if (connect(sock, (struct sockaddr *) & addr, sizeof(addr)) == 0)
1171 if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) 1129 return sock;
1172 return sock; 1130 close(sock);
1173 close(sock); 1131 }
1174 } 1132 error("connect %.100s: %.100s", addr.sun_path, strerror(errno));
1175 error("connect %.100s: %.100s", addr.sun_path, strerror(errno)); 1133 return -1;
1176 return -1;
1177} 1134}
1178 1135
1179 1136
@@ -1181,327 +1138,317 @@ connect_local_xsocket(unsigned dnr)
1181 the remote channel number. We should do whatever we want, and respond 1138 the remote channel number. We should do whatever we want, and respond
1182 with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE. */ 1139 with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE. */
1183 1140
1184void x11_input_open(int payload_len) 1141void
1142x11_input_open(int payload_len)
1185{ 1143{
1186 int remote_channel, display_number, sock, newch; 1144 int remote_channel, display_number, sock, newch;
1187 const char *display; 1145 const char *display;
1188 struct sockaddr_in sin; 1146 struct sockaddr_in sin;
1189 char buf[1024], *cp, *remote_host; 1147 char buf[1024], *cp, *remote_host;
1190 struct hostent *hp; 1148 struct hostent *hp;
1191 int remote_len; 1149 int remote_len;
1192 1150
1193 /* Get remote channel number. */ 1151 /* Get remote channel number. */
1194 remote_channel = packet_get_int(); 1152 remote_channel = packet_get_int();
1195 1153
1196 /* Get remote originator name. */ 1154 /* Get remote originator name. */
1197 if (have_hostname_in_open) 1155 if (have_hostname_in_open)
1198 remote_host = packet_get_string(&remote_len); 1156 remote_host = packet_get_string(&remote_len);
1199 else 1157 else
1200 remote_host = xstrdup("unknown (remote did not supply name)"); 1158 remote_host = xstrdup("unknown (remote did not supply name)");
1201 1159
1202 debug("Received X11 open request."); 1160 debug("Received X11 open request.");
1203 packet_integrity_check(payload_len, 4 + 4+remote_len, SSH_SMSG_X11_OPEN); 1161 packet_integrity_check(payload_len, 4 + 4 + remote_len, SSH_SMSG_X11_OPEN);
1204 1162
1205 /* Try to open a socket for the local X server. */ 1163 /* Try to open a socket for the local X server. */
1206 display = getenv("DISPLAY"); 1164 display = getenv("DISPLAY");
1207 if (!display) 1165 if (!display) {
1208 { 1166 error("DISPLAY not set.");
1209 error("DISPLAY not set."); 1167 goto fail;
1210 goto fail; 1168 }
1211 } 1169 /* Now we decode the value of the DISPLAY variable and make a
1212 1170 connection to the real X server. */
1213 /* Now we decode the value of the DISPLAY variable and make a connection 1171
1214 to the real X server. */ 1172 /* Check if it is a unix domain socket. Unix domain displays are
1215 1173 in one of the following formats: unix:d[.s], :d[.s], ::d[.s] */
1216 /* Check if it is a unix domain socket. Unix domain displays are in one 1174 if (strncmp(display, "unix:", 5) == 0 ||
1217 of the following formats: unix:d[.s], :d[.s], ::d[.s] */ 1175 display[0] == ':') {
1218 if (strncmp(display, "unix:", 5) == 0 || 1176 /* Connect to the unix domain socket. */
1219 display[0] == ':') 1177 if (sscanf(strrchr(display, ':') + 1, "%d", &display_number) != 1) {
1220 { 1178 error("Could not parse display number from DISPLAY: %.100s",
1221 /* Connect to the unix domain socket. */ 1179 display);
1222 if (sscanf(strrchr(display, ':') + 1, "%d", &display_number) != 1) 1180 goto fail;
1223 { 1181 }
1224 error("Could not parse display number from DISPLAY: %.100s", 1182 /* Create a socket. */
1225 display); 1183 sock = connect_local_xsocket(display_number);
1226 goto fail; 1184 if (sock < 0)
1185 goto fail;
1186
1187 /* OK, we now have a connection to the display. */
1188 goto success;
1189 }
1190 /* Connect to an inet socket. The DISPLAY value is supposedly
1191 hostname:d[.s], where hostname may also be numeric IP address. */
1192 strncpy(buf, display, sizeof(buf));
1193 buf[sizeof(buf) - 1] = 0;
1194 cp = strchr(buf, ':');
1195 if (!cp) {
1196 error("Could not find ':' in DISPLAY: %.100s", display);
1197 goto fail;
1198 }
1199 *cp = 0;
1200 /* buf now contains the host name. But first we parse the display
1201 number. */
1202 if (sscanf(cp + 1, "%d", &display_number) != 1) {
1203 error("Could not parse display number from DISPLAY: %.100s",
1204 display);
1205 goto fail;
1206 }
1207 /* Try to parse the host name as a numeric IP address. */
1208 memset(&sin, 0, sizeof(sin));
1209 sin.sin_addr.s_addr = inet_addr(buf);
1210 if ((sin.sin_addr.s_addr & 0xffffffff) != 0xffffffff) {
1211 /* It was a valid numeric host address. */
1212 sin.sin_family = AF_INET;
1213 } else {
1214 /* Not a numeric IP address. */
1215 /* Look up the host address from the name servers. */
1216 hp = gethostbyname(buf);
1217 if (!hp) {
1218 error("%.100s: unknown host.", buf);
1219 goto fail;
1220 }
1221 if (!hp->h_addr_list[0]) {
1222 error("%.100s: host has no IP address.", buf);
1223 goto fail;
1224 }
1225 sin.sin_family = hp->h_addrtype;
1226 memcpy(&sin.sin_addr, hp->h_addr_list[0],
1227 sizeof(sin.sin_addr));
1227 } 1228 }
1228 /* Create a socket. */ 1229 /* Set port number. */
1229 sock = connect_local_xsocket(display_number); 1230 sin.sin_port = htons(6000 + display_number);
1230 if (sock < 0) 1231
1231 goto fail; 1232 /* Create a socket. */
1232 1233 sock = socket(sin.sin_family, SOCK_STREAM, 0);
1233 /* OK, we now have a connection to the display. */ 1234 if (sock < 0) {
1234 goto success; 1235 error("socket: %.100s", strerror(errno));
1235 } 1236 goto fail;
1236
1237 /* Connect to an inet socket. The DISPLAY value is supposedly
1238 hostname:d[.s], where hostname may also be numeric IP address. */
1239 strncpy(buf, display, sizeof(buf));
1240 buf[sizeof(buf) - 1] = 0;
1241 cp = strchr(buf, ':');
1242 if (!cp)
1243 {
1244 error("Could not find ':' in DISPLAY: %.100s", display);
1245 goto fail;
1246 }
1247 *cp = 0;
1248 /* buf now contains the host name. But first we parse the display number. */
1249 if (sscanf(cp + 1, "%d", &display_number) != 1)
1250 {
1251 error("Could not parse display number from DISPLAY: %.100s",
1252 display);
1253 goto fail;
1254 }
1255
1256 /* Try to parse the host name as a numeric IP address. */
1257 memset(&sin, 0, sizeof(sin));
1258 sin.sin_addr.s_addr = inet_addr(buf);
1259 if ((sin.sin_addr.s_addr & 0xffffffff) != 0xffffffff)
1260 {
1261 /* It was a valid numeric host address. */
1262 sin.sin_family = AF_INET;
1263 }
1264 else
1265 {
1266 /* Not a numeric IP address. */
1267 /* Look up the host address from the name servers. */
1268 hp = gethostbyname(buf);
1269 if (!hp)
1270 {
1271 error("%.100s: unknown host.", buf);
1272 goto fail;
1273 } 1237 }
1274 if (!hp->h_addr_list[0]) 1238 /* Connect it to the display. */
1275 { 1239 if (connect(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) {
1276 error("%.100s: host has no IP address.", buf); 1240 error("connect %.100s:%d: %.100s", buf, 6000 + display_number,
1277 goto fail; 1241 strerror(errno));
1242 close(sock);
1243 goto fail;
1278 } 1244 }
1279 sin.sin_family = hp->h_addrtype; 1245success:
1280 memcpy(&sin.sin_addr, hp->h_addr_list[0], 1246 /* We have successfully obtained a connection to the real X display. */
1281 sizeof(sin.sin_addr)); 1247
1282 } 1248 /* Allocate a channel for this connection. */
1283 /* Set port number. */ 1249 if (x11_saved_proto == NULL)
1284 sin.sin_port = htons(6000 + display_number); 1250 newch = channel_allocate(SSH_CHANNEL_OPEN, sock, remote_host);
1285 1251 else
1286 /* Create a socket. */ 1252 newch = channel_allocate(SSH_CHANNEL_X11_OPEN, sock, remote_host);
1287 sock = socket(sin.sin_family, SOCK_STREAM, 0); 1253 channels[newch].remote_id = remote_channel;
1288 if (sock < 0) 1254
1289 { 1255 /* Send a confirmation to the remote host. */
1290 error("socket: %.100s", strerror(errno)); 1256 packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
1291 goto fail; 1257 packet_put_int(remote_channel);
1292 } 1258 packet_put_int(newch);
1293 /* Connect it to the display. */ 1259 packet_send();
1294 if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) 1260
1295 { 1261 return;
1296 error("connect %.100s:%d: %.100s", buf, 6000 + display_number, 1262
1297 strerror(errno)); 1263fail:
1298 close(sock); 1264 /* Send refusal to the remote host. */
1299 goto fail; 1265 packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
1300 } 1266 packet_put_int(remote_channel);
1301 1267 packet_send();
1302 success:
1303 /* We have successfully obtained a connection to the real X display. */
1304
1305 /* Allocate a channel for this connection. */
1306 if (x11_saved_proto == NULL)
1307 newch = channel_allocate(SSH_CHANNEL_OPEN, sock, remote_host);
1308 else
1309 newch = channel_allocate(SSH_CHANNEL_X11_OPEN, sock, remote_host);
1310 channels[newch].remote_id = remote_channel;
1311
1312 /* Send a confirmation to the remote host. */
1313 packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
1314 packet_put_int(remote_channel);
1315 packet_put_int(newch);
1316 packet_send();
1317
1318 return;
1319
1320 fail:
1321 /* Send refusal to the remote host. */
1322 packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
1323 packet_put_int(remote_channel);
1324 packet_send();
1325} 1268}
1326 1269
1327/* Requests forwarding of X11 connections, generates fake authentication 1270/* Requests forwarding of X11 connections, generates fake authentication
1328 data, and enables authentication spoofing. */ 1271 data, and enables authentication spoofing. */
1329 1272
1330void x11_request_forwarding_with_spoofing(const char *proto, const char *data) 1273void
1274x11_request_forwarding_with_spoofing(const char *proto, const char *data)
1331{ 1275{
1332 unsigned int data_len = (unsigned int)strlen(data) / 2; 1276 unsigned int data_len = (unsigned int) strlen(data) / 2;
1333 unsigned int i, value; 1277 unsigned int i, value;
1334 char *new_data; 1278 char *new_data;
1335 int screen_number; 1279 int screen_number;
1336 const char *cp; 1280 const char *cp;
1337 u_int32_t rand = 0; 1281 u_int32_t rand = 0;
1338 1282
1339 cp = getenv("DISPLAY"); 1283 cp = getenv("DISPLAY");
1340 if (cp) 1284 if (cp)
1341 cp = strchr(cp, ':'); 1285 cp = strchr(cp, ':');
1342 if (cp) 1286 if (cp)
1343 cp = strchr(cp, '.'); 1287 cp = strchr(cp, '.');
1344 if (cp) 1288 if (cp)
1345 screen_number = atoi(cp + 1); 1289 screen_number = atoi(cp + 1);
1346 else 1290 else
1347 screen_number = 0; 1291 screen_number = 0;
1348 1292
1349 /* Save protocol name. */ 1293 /* Save protocol name. */
1350 x11_saved_proto = xstrdup(proto); 1294 x11_saved_proto = xstrdup(proto);
1351 1295
1352 /* Extract real authentication data and generate fake data of the same 1296 /* Extract real authentication data and generate fake data of the
1353 length. */ 1297 same length. */
1354 x11_saved_data = xmalloc(data_len); 1298 x11_saved_data = xmalloc(data_len);
1355 x11_fake_data = xmalloc(data_len); 1299 x11_fake_data = xmalloc(data_len);
1356 for (i = 0; i < data_len; i++) 1300 for (i = 0; i < data_len; i++) {
1357 { 1301 if (sscanf(data + 2 * i, "%2x", &value) != 1)
1358 if (sscanf(data + 2 * i, "%2x", &value) != 1) 1302 fatal("x11_request_forwarding: bad authentication data: %.100s", data);
1359 fatal("x11_request_forwarding: bad authentication data: %.100s", data); 1303 if (i % 4 == 0)
1360 if (i % 4 == 0) 1304 rand = arc4random();
1361 rand = arc4random(); 1305 x11_saved_data[i] = value;
1362 x11_saved_data[i] = value; 1306 x11_fake_data[i] = rand & 0xff;
1363 x11_fake_data[i] = rand & 0xff; 1307 rand >>= 8;
1364 rand >>= 8; 1308 }
1365 } 1309 x11_saved_data_len = data_len;
1366 x11_saved_data_len = data_len; 1310 x11_fake_data_len = data_len;
1367 x11_fake_data_len = data_len; 1311
1368 1312 /* Convert the fake data into hex. */
1369 /* Convert the fake data into hex. */ 1313 new_data = xmalloc(2 * data_len + 1);
1370 new_data = xmalloc(2 * data_len + 1); 1314 for (i = 0; i < data_len; i++)
1371 for (i = 0; i < data_len; i++) 1315 sprintf(new_data + 2 * i, "%02x", (unsigned char) x11_fake_data[i]);
1372 sprintf(new_data + 2 * i, "%02x", (unsigned char)x11_fake_data[i]); 1316
1373 1317 /* Send the request packet. */
1374 /* Send the request packet. */ 1318 packet_start(SSH_CMSG_X11_REQUEST_FORWARDING);
1375 packet_start(SSH_CMSG_X11_REQUEST_FORWARDING); 1319 packet_put_string(proto, strlen(proto));
1376 packet_put_string(proto, strlen(proto)); 1320 packet_put_string(new_data, strlen(new_data));
1377 packet_put_string(new_data, strlen(new_data)); 1321 packet_put_int(screen_number);
1378 packet_put_int(screen_number); 1322 packet_send();
1379 packet_send(); 1323 packet_write_wait();
1380 packet_write_wait(); 1324 xfree(new_data);
1381 xfree(new_data);
1382} 1325}
1383 1326
1384/* Sends a message to the server to request authentication fd forwarding. */ 1327/* Sends a message to the server to request authentication fd forwarding. */
1385 1328
1386void auth_request_forwarding() 1329void
1330auth_request_forwarding()
1387{ 1331{
1388 packet_start(SSH_CMSG_AGENT_REQUEST_FORWARDING); 1332 packet_start(SSH_CMSG_AGENT_REQUEST_FORWARDING);
1389 packet_send(); 1333 packet_send();
1390 packet_write_wait(); 1334 packet_write_wait();
1391} 1335}
1392 1336
1393/* Returns the name of the forwarded authentication socket. Returns NULL 1337/* Returns the name of the forwarded authentication socket. Returns NULL
1394 if there is no forwarded authentication socket. The returned value 1338 if there is no forwarded authentication socket. The returned value
1395 points to a static buffer. */ 1339 points to a static buffer. */
1396 1340
1397char *auth_get_socket_name() 1341char *
1342auth_get_socket_name()
1398{ 1343{
1399 return channel_forwarded_auth_socket_name; 1344 return channel_forwarded_auth_socket_name;
1400} 1345}
1401 1346
1402/* removes the agent forwarding socket */ 1347/* removes the agent forwarding socket */
1403 1348
1404void cleanup_socket(void) { 1349void
1405 remove(channel_forwarded_auth_socket_name); 1350cleanup_socket(void)
1406 rmdir(channel_forwarded_auth_socket_dir); 1351{
1352 remove(channel_forwarded_auth_socket_name);
1353 rmdir(channel_forwarded_auth_socket_dir);
1407} 1354}
1408 1355
1409/* This if called to process SSH_CMSG_AGENT_REQUEST_FORWARDING on the server. 1356/* This if called to process SSH_CMSG_AGENT_REQUEST_FORWARDING on the server.
1410 This starts forwarding authentication requests. */ 1357 This starts forwarding authentication requests. */
1411 1358
1412void auth_input_request_forwarding(struct passwd *pw) 1359void
1360auth_input_request_forwarding(struct passwd * pw)
1413{ 1361{
1414 int sock, newch; 1362 int sock, newch;
1415 struct sockaddr_un sunaddr; 1363 struct sockaddr_un sunaddr;
1416 1364
1417 if (auth_get_socket_name() != NULL) 1365 if (auth_get_socket_name() != NULL)
1418 fatal("Protocol error: authentication forwarding requested twice."); 1366 fatal("Protocol error: authentication forwarding requested twice.");
1419 1367
1420 /* Temporarily drop privileged uid for mkdir/bind. */ 1368 /* Temporarily drop privileged uid for mkdir/bind. */
1421 temporarily_use_uid(pw->pw_uid); 1369 temporarily_use_uid(pw->pw_uid);
1422 1370
1423 /* Allocate a buffer for the socket name, and format the name. */ 1371 /* Allocate a buffer for the socket name, and format the name. */
1424 channel_forwarded_auth_socket_name = xmalloc(MAX_SOCKET_NAME); 1372 channel_forwarded_auth_socket_name = xmalloc(MAX_SOCKET_NAME);
1425 channel_forwarded_auth_socket_dir = xmalloc(MAX_SOCKET_NAME); 1373 channel_forwarded_auth_socket_dir = xmalloc(MAX_SOCKET_NAME);
1426 strlcpy(channel_forwarded_auth_socket_dir, "/tmp/ssh-XXXXXXXX", MAX_SOCKET_NAME); 1374 strlcpy(channel_forwarded_auth_socket_dir, "/tmp/ssh-XXXXXXXX", MAX_SOCKET_NAME);
1427 1375
1428 /* Create private directory for socket */ 1376 /* Create private directory for socket */
1429 if (mkdtemp(channel_forwarded_auth_socket_dir) == NULL) 1377 if (mkdtemp(channel_forwarded_auth_socket_dir) == NULL)
1430 packet_disconnect("mkdtemp: %.100s", strerror(errno)); 1378 packet_disconnect("mkdtemp: %.100s", strerror(errno));
1431 snprintf(channel_forwarded_auth_socket_name, MAX_SOCKET_NAME, 1379 snprintf(channel_forwarded_auth_socket_name, MAX_SOCKET_NAME, "%s/agent.%d",
1432 "%s/agent.%d", channel_forwarded_auth_socket_dir, (int)getpid()); 1380 channel_forwarded_auth_socket_dir, (int) getpid());
1433 1381
1434 if (atexit(cleanup_socket) < 0) { 1382 if (atexit(cleanup_socket) < 0) {
1435 int saved=errno; 1383 int saved = errno;
1436 cleanup_socket(); 1384 cleanup_socket();
1437 packet_disconnect("socket: %.100s", strerror(saved)); 1385 packet_disconnect("socket: %.100s", strerror(saved));
1438 } 1386 }
1439 1387 /* Create the socket. */
1440 /* Create the socket. */ 1388 sock = socket(AF_UNIX, SOCK_STREAM, 0);
1441 sock = socket(AF_UNIX, SOCK_STREAM, 0); 1389 if (sock < 0)
1442 if (sock < 0) 1390 packet_disconnect("socket: %.100s", strerror(errno));
1443 packet_disconnect("socket: %.100s", strerror(errno)); 1391
1444 1392 /* Bind it to the name. */
1445 /* Bind it to the name. */ 1393 memset(&sunaddr, 0, sizeof(sunaddr));
1446 memset(&sunaddr, 0, sizeof(sunaddr)); 1394 sunaddr.sun_family = AF_UNIX;
1447 sunaddr.sun_family = AF_UNIX; 1395 strncpy(sunaddr.sun_path, channel_forwarded_auth_socket_name,
1448 strncpy(sunaddr.sun_path, channel_forwarded_auth_socket_name, 1396 sizeof(sunaddr.sun_path));
1449 sizeof(sunaddr.sun_path)); 1397
1450 1398 if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0)
1451 if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) 1399 packet_disconnect("bind: %.100s", strerror(errno));
1452 packet_disconnect("bind: %.100s", strerror(errno)); 1400
1453 1401 /* Restore the privileged uid. */
1454 /* Restore the privileged uid. */ 1402 restore_uid();
1455 restore_uid(); 1403
1456 1404 /* Start listening on the socket. */
1457 /* Start listening on the socket. */ 1405 if (listen(sock, 5) < 0)
1458 if (listen(sock, 5) < 0) 1406 packet_disconnect("listen: %.100s", strerror(errno));
1459 packet_disconnect("listen: %.100s", strerror(errno)); 1407
1460 1408 /* Allocate a channel for the authentication agent socket. */
1461 /* Allocate a channel for the authentication agent socket. */ 1409 newch = channel_allocate(SSH_CHANNEL_AUTH_SOCKET, sock,
1462 newch = channel_allocate(SSH_CHANNEL_AUTH_SOCKET, sock, 1410 xstrdup("auth socket"));
1463 xstrdup("auth socket")); 1411 strcpy(channels[newch].path, channel_forwarded_auth_socket_name);
1464 strcpy(channels[newch].path, channel_forwarded_auth_socket_name);
1465} 1412}
1466 1413
1467/* This is called to process an SSH_SMSG_AGENT_OPEN message. */ 1414/* This is called to process an SSH_SMSG_AGENT_OPEN message. */
1468 1415
1469void auth_input_open_request() 1416void
1417auth_input_open_request()
1470{ 1418{
1471 int remch, sock, newch; 1419 int remch, sock, newch;
1472 char *dummyname; 1420 char *dummyname;
1473 1421
1474 /* Read the remote channel number from the message. */ 1422 /* Read the remote channel number from the message. */
1475 remch = packet_get_int(); 1423 remch = packet_get_int();
1476 1424
1477 /* Get a connection to the local authentication agent (this may again get 1425 /* Get a connection to the local authentication agent (this may
1478 forwarded). */ 1426 again get forwarded). */
1479 sock = ssh_get_authentication_socket(); 1427 sock = ssh_get_authentication_socket();
1480 1428
1481 /* If we could not connect the agent, send an error message back to 1429 /* If we could not connect the agent, send an error message back
1482 the server. This should never happen unless the agent 1430 to the server. This should never happen unless the agent dies,
1483 dies, because authentication forwarding is only enabled if we have an 1431 because authentication forwarding is only enabled if we have an
1484 agent. */ 1432 agent. */
1485 if (sock < 0){ 1433 if (sock < 0) {
1486 packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); 1434 packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
1487 packet_put_int(remch); 1435 packet_put_int(remch);
1488 packet_send(); 1436 packet_send();
1489 return; 1437 return;
1490 } 1438 }
1491 1439 debug("Forwarding authentication connection.");
1492 debug("Forwarding authentication connection."); 1440
1493 1441 /* Dummy host name. This will be freed when the channel is freed;
1494 /* Dummy host name. This will be freed when the channel is freed; it will 1442 it will still be valid in the packet_put_string below since the
1495 still be valid in the packet_put_string below since the channel cannot 1443 channel cannot yet be freed at that point. */
1496 yet be freed at that point. */ 1444 dummyname = xstrdup("authentication agent connection");
1497 dummyname = xstrdup("authentication agent connection"); 1445
1498 1446 newch = channel_allocate(SSH_CHANNEL_OPEN, sock, dummyname);
1499 newch = channel_allocate(SSH_CHANNEL_OPEN, sock, dummyname); 1447 channels[newch].remote_id = remch;
1500 channels[newch].remote_id = remch; 1448
1501 1449 /* Send a confirmation to the remote host. */
1502 /* Send a confirmation to the remote host. */ 1450 packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
1503 packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); 1451 packet_put_int(remch);
1504 packet_put_int(remch); 1452 packet_put_int(newch);
1505 packet_put_int(newch); 1453 packet_send();
1506 packet_send();
1507} 1454}
diff --git a/channels.h b/channels.h
index 608c774db..5851257ca 100644
--- a/channels.h
+++ b/channels.h
@@ -1,40 +1,46 @@
1/* RCSID("$Id: channels.h,v 1.2 1999/10/30 01:39:56 damien Exp $"); */ 1/* RCSID("$Id: channels.h,v 1.3 1999/11/24 13:26:22 damien Exp $"); */
2 2
3#ifndef CHANNELS_H 3#ifndef CHANNELS_H
4#define CHANNELS_H 4#define CHANNELS_H
5 5
6/* Definitions for channel types. */ 6/* Definitions for channel types. */
7#define SSH_CHANNEL_FREE 0 /* This channel is free (unused). */ 7#define SSH_CHANNEL_FREE 0 /* This channel is free
8#define SSH_CHANNEL_X11_LISTENER 1 /* Listening for inet X11 conn. */ 8 * (unused). */
9#define SSH_CHANNEL_PORT_LISTENER 2 /* Listening on a port. */ 9#define SSH_CHANNEL_X11_LISTENER 1 /* Listening for inet X11
10#define SSH_CHANNEL_OPENING 3 /* waiting for confirmation */ 10 * conn. */
11#define SSH_CHANNEL_OPEN 4 /* normal open two-way channel */ 11#define SSH_CHANNEL_PORT_LISTENER 2 /* Listening on a port. */
12#define SSH_CHANNEL_CLOSED 5 /* waiting for close confirmation */ 12#define SSH_CHANNEL_OPENING 3 /* waiting for confirmation */
13#define SSH_CHANNEL_OPEN 4 /* normal open two-way channel */
14#define SSH_CHANNEL_CLOSED 5 /* waiting for close
15 * confirmation */
13/* SSH_CHANNEL_AUTH_FD 6 authentication fd */ 16/* SSH_CHANNEL_AUTH_FD 6 authentication fd */
14#define SSH_CHANNEL_AUTH_SOCKET 7 /* authentication socket */ 17#define SSH_CHANNEL_AUTH_SOCKET 7 /* authentication socket */
15/* SSH_CHANNEL_AUTH_SOCKET_FD 8 connection to auth socket */ 18/* SSH_CHANNEL_AUTH_SOCKET_FD 8 connection to auth socket */
16#define SSH_CHANNEL_X11_OPEN 9 /* reading first X11 packet */ 19#define SSH_CHANNEL_X11_OPEN 9 /* reading first X11 packet */
17#define SSH_CHANNEL_INPUT_DRAINING 10 /* sending remaining data to conn */ 20#define SSH_CHANNEL_INPUT_DRAINING 10 /* sending remaining data to
18#define SSH_CHANNEL_OUTPUT_DRAINING 11 /* sending remaining data to app */ 21 * conn */
22#define SSH_CHANNEL_OUTPUT_DRAINING 11 /* sending remaining data to
23 * app */
19 24
20/* Data structure for channel data. This is iniailized in channel_allocate 25/* Data structure for channel data. This is iniailized in channel_allocate
21 and cleared in channel_free. */ 26 and cleared in channel_free. */
22 27
23typedef struct Channel 28typedef struct Channel {
24{ 29 int type; /* channel type/state */
25 int type; /* channel type/state */ 30 int self; /* my own channel identifier */
26 int self; /* my own channel identifier */ 31 int remote_id; /* channel identifier for remote peer */
27 int remote_id; /* channel identifier for remote peer */ 32 /* peer can be reached over encrypted connection, via packet-sent */
28 /* peer can be reached over encrypted connection, via packet-sent */ 33 int istate; /* input from channel (state of receive half) */
29 int istate; /* input from channel (state of receive half) */ 34 int ostate; /* output to channel (state of transmit half) */
30 int ostate; /* output to channel (state of transmit half) */ 35 int sock; /* data socket, linked to this channel */
31 int sock; /* data socket, linked to this channel */ 36 Buffer input; /* data read from socket, to be sent over
32 Buffer input; /* data read from socket, to be sent over encrypted connection */ 37 * encrypted connection */
33 Buffer output; /* data received over encrypted connection for send on socket */ 38 Buffer output; /* data received over encrypted connection for
34 char path[200]; /* path for unix domain sockets, or host name for forwards */ 39 * send on socket */
35 int listening_port; /* port being listened for forwards */ 40 char path[200]; /* path for unix domain sockets, or host name
36 int host_port; /* remote port to connect for forwards */ 41 * for forwards */
37 char *remote_name; /* remote hostname */ 42 int listening_port; /* port being listened for forwards */
38} Channel; 43 int host_port; /* remote port to connect for forwards */
39 44 char *remote_name; /* remote hostname */
45} Channel;
40#endif 46#endif
diff --git a/cipher.c b/cipher.c
index a33188e46..92fcd4740 100644
--- a/cipher.c
+++ b/cipher.c
@@ -1,18 +1,18 @@
1/* 1/*
2 2 *
3cipher.c 3 * cipher.c
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Wed Apr 19 17:41:39 1995 ylo 10 * Created: Wed Apr 19 17:41:39 1995 ylo
11 11 *
12*/ 12 */
13 13
14#include "includes.h" 14#include "includes.h"
15RCSID("$Id: cipher.c,v 1.6 1999/11/16 02:37:16 damien Exp $"); 15RCSID("$Id: cipher.c,v 1.7 1999/11/24 13:26:22 damien Exp $");
16 16
17#include "ssh.h" 17#include "ssh.h"
18#include "cipher.h" 18#include "cipher.h"
@@ -38,124 +38,124 @@ RCSID("$Id: cipher.c,v 1.6 1999/11/16 02:37:16 damien Exp $");
38 */ 38 */
39void 39void
40SSH_3CBC_ENCRYPT(des_key_schedule ks1, 40SSH_3CBC_ENCRYPT(des_key_schedule ks1,
41 des_key_schedule ks2, des_cblock *iv2, 41 des_key_schedule ks2, des_cblock * iv2,
42 des_key_schedule ks3, des_cblock *iv3, 42 des_key_schedule ks3, des_cblock * iv3,
43 void *dest, void *src, 43 void *dest, void *src,
44 unsigned int len) 44 unsigned int len)
45{ 45{
46 des_cblock iv1; 46 des_cblock iv1;
47 47
48 memcpy(&iv1, iv2, 8); 48 memcpy(&iv1, iv2, 8);
49 49
50 des_cbc_encrypt(src, dest, len, ks1, &iv1, DES_ENCRYPT); 50 des_cbc_encrypt(src, dest, len, ks1, &iv1, DES_ENCRYPT);
51 memcpy(&iv1, dest + len - 8, 8); 51 memcpy(&iv1, dest + len - 8, 8);
52 52
53 des_cbc_encrypt(dest, dest, len, ks2, iv2, DES_DECRYPT); 53 des_cbc_encrypt(dest, dest, len, ks2, iv2, DES_DECRYPT);
54 memcpy(iv2, &iv1, 8); /* Note how iv1 == iv2 on entry and exit. */ 54 memcpy(iv2, &iv1, 8); /* Note how iv1 == iv2 on entry and exit. */
55 55
56 des_cbc_encrypt(dest, dest, len, ks3, iv3, DES_ENCRYPT); 56 des_cbc_encrypt(dest, dest, len, ks3, iv3, DES_ENCRYPT);
57 memcpy(iv3, dest + len - 8, 8); 57 memcpy(iv3, dest + len - 8, 8);
58} 58}
59 59
60void 60void
61SSH_3CBC_DECRYPT(des_key_schedule ks1, 61SSH_3CBC_DECRYPT(des_key_schedule ks1,
62 des_key_schedule ks2, des_cblock *iv2, 62 des_key_schedule ks2, des_cblock * iv2,
63 des_key_schedule ks3, des_cblock *iv3, 63 des_key_schedule ks3, des_cblock * iv3,
64 void *dest, void *src, 64 void *dest, void *src,
65 unsigned int len) 65 unsigned int len)
66{ 66{
67 des_cblock iv1; 67 des_cblock iv1;
68 68
69 memcpy(&iv1, iv2, 8); 69 memcpy(&iv1, iv2, 8);
70 70
71 des_cbc_encrypt(src, dest, len, ks3, iv3, DES_DECRYPT); 71 des_cbc_encrypt(src, dest, len, ks3, iv3, DES_DECRYPT);
72 memcpy(iv3, src + len - 8, 8); 72 memcpy(iv3, src + len - 8, 8);
73 73
74 des_cbc_encrypt(dest, dest, len, ks2, iv2, DES_ENCRYPT); 74 des_cbc_encrypt(dest, dest, len, ks2, iv2, DES_ENCRYPT);
75 memcpy(iv2, dest + len - 8, 8); 75 memcpy(iv2, dest + len - 8, 8);
76 76
77 des_cbc_encrypt(dest, dest, len, ks1, &iv1, DES_DECRYPT); 77 des_cbc_encrypt(dest, dest, len, ks1, &iv1, DES_DECRYPT);
78 /* memcpy(&iv1, iv2, 8); */ /* Note how iv1 == iv2 on entry and exit. */ 78 /* memcpy(&iv1, iv2, 8); */
79 /* Note how iv1 == iv2 on entry and exit. */
79} 80}
80 81
81/* 82/*
82 * SSH uses a variation on Blowfish, all bytes must be swapped before 83 * SSH uses a variation on Blowfish, all bytes must be swapped before
83 * and after encryption/decryption. Thus the swap_bytes stuff (yuk). 84 * and after encryption/decryption. Thus the swap_bytes stuff (yuk).
84 */ 85 */
85static 86static void
86void
87swap_bytes(const unsigned char *src, unsigned char *dst_, int n) 87swap_bytes(const unsigned char *src, unsigned char *dst_, int n)
88{ 88{
89 u_int32_t *dst = (u_int32_t *)dst_; /* dst must be properly aligned. */ 89 /* dst must be properly aligned. */
90 union { 90 u_int32_t *dst = (u_int32_t *) dst_;
91 u_int32_t i; 91 union {
92 char c[4]; 92 u_int32_t i;
93 } t; 93 char c[4];
94 94 } t;
95 /* Process 8 bytes every lap. */ 95
96 for (n = n / 8; n > 0; n--) 96 /* Process 8 bytes every lap. */
97 { 97 for (n = n / 8; n > 0; n--) {
98 t.c[3] = *src++; 98 t.c[3] = *src++;
99 t.c[2] = *src++; 99 t.c[2] = *src++;
100 t.c[1] = *src++; 100 t.c[1] = *src++;
101 t.c[0] = *src++; 101 t.c[0] = *src++;
102 *dst++ = t.i; 102 *dst++ = t.i;
103 103
104 t.c[3] = *src++; 104 t.c[3] = *src++;
105 t.c[2] = *src++; 105 t.c[2] = *src++;
106 t.c[1] = *src++; 106 t.c[1] = *src++;
107 t.c[0] = *src++; 107 t.c[0] = *src++;
108 *dst++ = t.i; 108 *dst++ = t.i;
109 } 109 }
110} 110}
111 111
112void (*cipher_attack_detected)(const char *fmt, ...) = fatal; 112void (*cipher_attack_detected) (const char *fmt,...) = fatal;
113 113
114static inline 114static inline void
115void
116detect_cbc_attack(const unsigned char *src, 115detect_cbc_attack(const unsigned char *src,
117 unsigned int len) 116 unsigned int len)
118{ 117{
119 return; 118 return;
120 119
121 log("CRC-32 CBC insertion attack detected"); 120 log("CRC-32 CBC insertion attack detected");
122 cipher_attack_detected("CRC-32 CBC insertion attack detected"); 121 cipher_attack_detected("CRC-32 CBC insertion attack detected");
123} 122}
124 123
125/* Names of all encryption algorithms. These must match the numbers defined 124/* Names of all encryption algorithms. These must match the numbers defined
126 int cipher.h. */ 125 int cipher.h. */
127static char *cipher_names[] = 126static char *cipher_names[] =
128{ 127{
129 "none", 128 "none",
130 "idea", 129 "idea",
131 "des", 130 "des",
132 "3des", 131 "3des",
133 "tss", 132 "tss",
134 "rc4", 133 "rc4",
135 "blowfish" 134 "blowfish"
136}; 135};
137 136
138/* Returns a bit mask indicating which ciphers are supported by this 137/* Returns a bit mask indicating which ciphers are supported by this
139 implementation. The bit mask has the corresponding bit set of each 138 implementation. The bit mask has the corresponding bit set of each
140 supported cipher. */ 139 supported cipher. */
141 140
142unsigned int cipher_mask() 141unsigned int
142cipher_mask()
143{ 143{
144 unsigned int mask = 0; 144 unsigned int mask = 0;
145 mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */ 145 mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */
146 mask |= 1 << SSH_CIPHER_BLOWFISH; 146 mask |= 1 << SSH_CIPHER_BLOWFISH;
147 return mask; 147 return mask;
148} 148}
149 149
150/* Returns the name of the cipher. */ 150/* Returns the name of the cipher. */
151 151
152const 152const char *
153char *cipher_name(int cipher) 153cipher_name(int cipher)
154{ 154{
155 if (cipher < 0 || cipher >= sizeof(cipher_names) / sizeof(cipher_names[0]) || 155 if (cipher < 0 || cipher >= sizeof(cipher_names) / sizeof(cipher_names[0]) ||
156 cipher_names[cipher] == NULL) 156 cipher_names[cipher] == NULL)
157 fatal("cipher_name: bad cipher number: %d", cipher); 157 fatal("cipher_name: bad cipher number: %d", cipher);
158 return cipher_names[cipher]; 158 return cipher_names[cipher];
159} 159}
160 160
161/* Parses the name of the cipher. Returns the number of the corresponding 161/* Parses the name of the cipher. Returns the number of the corresponding
@@ -164,146 +164,151 @@ char *cipher_name(int cipher)
164int 164int
165cipher_number(const char *name) 165cipher_number(const char *name)
166{ 166{
167 int i; 167 int i;
168 for (i = 0; i < sizeof(cipher_names) / sizeof(cipher_names[0]); i++) 168 for (i = 0; i < sizeof(cipher_names) / sizeof(cipher_names[0]); i++)
169 if (strcmp(cipher_names[i], name) == 0 && 169 if (strcmp(cipher_names[i], name) == 0 &&
170 (cipher_mask() & (1 << i))) 170 (cipher_mask() & (1 << i)))
171 return i; 171 return i;
172 return -1; 172 return -1;
173} 173}
174 174
175/* Selects the cipher, and keys if by computing the MD5 checksum of the 175/* Selects the cipher, and keys if by computing the MD5 checksum of the
176 passphrase and using the resulting 16 bytes as the key. */ 176 passphrase and using the resulting 16 bytes as the key. */
177 177
178void cipher_set_key_string(CipherContext *context, int cipher, 178void
179 const char *passphrase, int for_encryption) 179cipher_set_key_string(CipherContext *context, int cipher,
180 const char *passphrase, int for_encryption)
180{ 181{
181 MD5_CTX md; 182 MD5_CTX md;
182 unsigned char digest[16]; 183 unsigned char digest[16];
183 184
184 MD5_Init(&md); 185 MD5_Init(&md);
185 MD5_Update(&md, (const unsigned char *)passphrase, strlen(passphrase)); 186 MD5_Update(&md, (const unsigned char *) passphrase, strlen(passphrase));
186 MD5_Final(digest, &md); 187 MD5_Final(digest, &md);
187 188
188 cipher_set_key(context, cipher, digest, 16, for_encryption); 189 cipher_set_key(context, cipher, digest, 16, for_encryption);
189 190
190 memset(digest, 0, sizeof(digest)); 191 memset(digest, 0, sizeof(digest));
191 memset(&md, 0, sizeof(md)); 192 memset(&md, 0, sizeof(md));
192} 193}
193 194
194/* Selects the cipher to use and sets the key. */ 195/* Selects the cipher to use and sets the key. */
195 196
196void cipher_set_key(CipherContext *context, int cipher, 197void
197 const unsigned char *key, int keylen, int for_encryption) 198cipher_set_key(CipherContext *context, int cipher,
199 const unsigned char *key, int keylen, int for_encryption)
198{ 200{
199 unsigned char padded[32]; 201 unsigned char padded[32];
200 202
201 /* Set cipher type. */ 203 /* Set cipher type. */
202 context->type = cipher; 204 context->type = cipher;
203 205
204 /* Get 32 bytes of key data. Pad if necessary. (So that code below does 206 /* Get 32 bytes of key data. Pad if necessary. (So that code
205 not need to worry about key size). */ 207 below does not need to worry about key size). */
206 memset(padded, 0, sizeof(padded)); 208 memset(padded, 0, sizeof(padded));
207 memcpy(padded, key, keylen < sizeof(padded) ? keylen : sizeof(padded)); 209 memcpy(padded, key, keylen < sizeof(padded) ? keylen : sizeof(padded));
208 210
209 /* Initialize the initialization vector. */ 211 /* Initialize the initialization vector. */
210 switch (cipher) 212 switch (cipher) {
211 { 213 case SSH_CIPHER_NONE:
212 case SSH_CIPHER_NONE: 214 /* Has to stay for authfile saving of private key with
213 /* Has to stay for authfile saving of private key with no passphrase */ 215 no passphrase */
214 break; 216 break;
215 217
216 case SSH_CIPHER_3DES: 218 case SSH_CIPHER_3DES:
217 /* Note: the least significant bit of each byte of key is parity, 219 /* Note: the least significant bit of each byte of key is
218 and must be ignored by the implementation. 16 bytes of key are 220 parity, and must be ignored by the implementation. 16
219 used (first and last keys are the same). */ 221 bytes of key are used (first and last keys are the
220 if (keylen < 16) 222 same). */
221 error("Key length %d is insufficient for 3DES.", keylen); 223 if (keylen < 16)
222 des_set_key((void*)padded, context->u.des3.key1); 224 error("Key length %d is insufficient for 3DES.", keylen);
223 des_set_key((void*)(padded + 8), context->u.des3.key2); 225 des_set_key((void *) padded, context->u.des3.key1);
224 if (keylen <= 16) 226 des_set_key((void *) (padded + 8), context->u.des3.key2);
225 des_set_key((void*)padded, context->u.des3.key3); 227 if (keylen <= 16)
226 else 228 des_set_key((void *) padded, context->u.des3.key3);
227 des_set_key((void*)(padded + 16), context->u.des3.key3); 229 else
228 memset(context->u.des3.iv2, 0, sizeof(context->u.des3.iv2)); 230 des_set_key((void *) (padded + 16), context->u.des3.key3);
229 memset(context->u.des3.iv3, 0, sizeof(context->u.des3.iv3)); 231 memset(context->u.des3.iv2, 0, sizeof(context->u.des3.iv2));
230 break; 232 memset(context->u.des3.iv3, 0, sizeof(context->u.des3.iv3));
231 233 break;
232 case SSH_CIPHER_BLOWFISH: 234
233 BF_set_key(&context->u.bf.key, keylen, padded); 235 case SSH_CIPHER_BLOWFISH:
234 memset(context->u.bf.iv, 0, 8); 236 BF_set_key(&context->u.bf.key, keylen, padded);
235 break; 237 memset(context->u.bf.iv, 0, 8);
236 238 break;
237 default: 239
238 fatal("cipher_set_key: unknown cipher: %s", cipher_name(cipher)); 240 default:
239 } 241 fatal("cipher_set_key: unknown cipher: %s", cipher_name(cipher));
240 memset(padded, 0, sizeof(padded)); 242 }
243 memset(padded, 0, sizeof(padded));
241} 244}
242 245
243/* Encrypts data using the cipher. */ 246/* Encrypts data using the cipher. */
244 247
245void cipher_encrypt(CipherContext *context, unsigned char *dest, 248void
246 const unsigned char *src, unsigned int len) 249cipher_encrypt(CipherContext *context, unsigned char *dest,
250 const unsigned char *src, unsigned int len)
247{ 251{
248 if ((len & 7) != 0) 252 if ((len & 7) != 0)
249 fatal("cipher_encrypt: bad plaintext length %d", len); 253 fatal("cipher_encrypt: bad plaintext length %d", len);
250 254
251 switch (context->type) 255 switch (context->type) {
252 { 256 case SSH_CIPHER_NONE:
253 case SSH_CIPHER_NONE: 257 memcpy(dest, src, len);
254 memcpy(dest, src, len); 258 break;
255 break; 259
256 260 case SSH_CIPHER_3DES:
257 case SSH_CIPHER_3DES: 261 SSH_3CBC_ENCRYPT(context->u.des3.key1,
258 SSH_3CBC_ENCRYPT(context->u.des3.key1, 262 context->u.des3.key2, &context->u.des3.iv2,
259 context->u.des3.key2, &context->u.des3.iv2, 263 context->u.des3.key3, &context->u.des3.iv3,
260 context->u.des3.key3, &context->u.des3.iv3, 264 dest, (void *) src, len);
261 dest, (void*)src, len); 265 break;
262 break; 266
263 267 case SSH_CIPHER_BLOWFISH:
264 case SSH_CIPHER_BLOWFISH: 268 swap_bytes(src, dest, len);
265 swap_bytes(src, dest, len); 269 BF_cbc_encrypt(dest, dest, len,
266 BF_cbc_encrypt(dest, dest, len, 270 &context->u.bf.key, context->u.bf.iv,
267 &context->u.bf.key, context->u.bf.iv, BF_ENCRYPT); 271 BF_ENCRYPT);
268 swap_bytes(dest, dest, len); 272 swap_bytes(dest, dest, len);
269 break; 273 break;
270 274
271 default: 275 default:
272 fatal("cipher_encrypt: unknown cipher: %d", context->type); 276 fatal("cipher_encrypt: unknown cipher: %s", cipher_name(context->type));
273 } 277 }
274} 278}
275 279
276/* Decrypts data using the cipher. */ 280/* Decrypts data using the cipher. */
277 281
278void cipher_decrypt(CipherContext *context, unsigned char *dest, 282void
279 const unsigned char *src, unsigned int len) 283cipher_decrypt(CipherContext *context, unsigned char *dest,
284 const unsigned char *src, unsigned int len)
280{ 285{
281 if ((len & 7) != 0) 286 if ((len & 7) != 0)
282 fatal("cipher_decrypt: bad ciphertext length %d", len); 287 fatal("cipher_decrypt: bad ciphertext length %d", len);
283 288
284 switch (context->type) 289 switch (context->type) {
285 { 290 case SSH_CIPHER_NONE:
286 case SSH_CIPHER_NONE: 291 memcpy(dest, src, len);
287 memcpy(dest, src, len); 292 break;
288 break; 293
289 294 case SSH_CIPHER_3DES:
290 case SSH_CIPHER_3DES: 295 /* CRC-32 attack? */
291 /* CRC-32 attack? */ 296 SSH_3CBC_DECRYPT(context->u.des3.key1,
292 SSH_3CBC_DECRYPT(context->u.des3.key1, 297 context->u.des3.key2, &context->u.des3.iv2,
293 context->u.des3.key2, &context->u.des3.iv2, 298 context->u.des3.key3, &context->u.des3.iv3,
294 context->u.des3.key3, &context->u.des3.iv3, 299 dest, (void *) src, len);
295 dest, (void*)src, len); 300 break;
296 break; 301
297 302 case SSH_CIPHER_BLOWFISH:
298 case SSH_CIPHER_BLOWFISH: 303 detect_cbc_attack(src, len);
299 detect_cbc_attack(src, len); 304 swap_bytes(src, dest, len);
300 swap_bytes(src, dest, len); 305 BF_cbc_encrypt((void *) dest, dest, len,
301 BF_cbc_encrypt((void*)dest, dest, len, 306 &context->u.bf.key, context->u.bf.iv,
302 &context->u.bf.key, context->u.bf.iv, BF_DECRYPT); 307 BF_DECRYPT);
303 swap_bytes(dest, dest, len); 308 swap_bytes(dest, dest, len);
304 break; 309 break;
305 310
306 default: 311 default:
307 fatal("cipher_decrypt: unknown cipher: %d", context->type); 312 fatal("cipher_decrypt: unknown cipher: %s", cipher_name(context->type));
308 } 313 }
309} 314}
diff --git a/cipher.h b/cipher.h
index 5bfb74241..ae37b0bb8 100644
--- a/cipher.h
+++ b/cipher.h
@@ -1,17 +1,17 @@
1/* 1/*
2 2 *
3cipher.h 3 * cipher.h
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Wed Apr 19 16:50:42 1995 ylo 10 * Created: Wed Apr 19 16:50:42 1995 ylo
11 11 *
12*/ 12 */
13 13
14/* RCSID("$Id: cipher.h,v 1.3 1999/11/16 02:37:16 damien Exp $"); */ 14/* RCSID("$Id: cipher.h,v 1.4 1999/11/24 13:26:22 damien Exp $"); */
15 15
16#ifndef CIPHER_H 16#ifndef CIPHER_H
17#define CIPHER_H 17#define CIPHER_H
@@ -29,32 +29,31 @@ Created: Wed Apr 19 16:50:42 1995 ylo
29 29
30/* Cipher types. New types can be added, but old types should not be removed 30/* Cipher types. New types can be added, but old types should not be removed
31 for compatibility. The maximum allowed value is 31. */ 31 for compatibility. The maximum allowed value is 31. */
32#define SSH_CIPHER_NOT_SET -1 /* None selected (invalid number). */ 32#define SSH_CIPHER_NOT_SET -1 /* None selected (invalid number). */
33#define SSH_CIPHER_NONE 0 /* no encryption */ 33#define SSH_CIPHER_NONE 0 /* no encryption */
34#define SSH_CIPHER_IDEA 1 /* IDEA CFB */ 34#define SSH_CIPHER_IDEA 1 /* IDEA CFB */
35#define SSH_CIPHER_DES 2 /* DES CBC */ 35#define SSH_CIPHER_DES 2 /* DES CBC */
36#define SSH_CIPHER_3DES 3 /* 3DES CBC */ 36#define SSH_CIPHER_3DES 3 /* 3DES CBC */
37#define SSH_CIPHER_BROKEN_TSS 4 /* TRI's Simple Stream encryption CBC */ 37#define SSH_CIPHER_BROKEN_TSS 4 /* TRI's Simple Stream encryption CBC */
38#define SSH_CIPHER_BROKEN_RC4 5 /* Alleged RC4 */ 38#define SSH_CIPHER_BROKEN_RC4 5 /* Alleged RC4 */
39#define SSH_CIPHER_BLOWFISH 6 39#define SSH_CIPHER_BLOWFISH 6
40 40
41typedef struct { 41typedef struct {
42 unsigned int type; 42 unsigned int type;
43 union { 43 union {
44 struct { 44 struct {
45 des_key_schedule key1; 45 des_key_schedule key1;
46 des_key_schedule key2; 46 des_key_schedule key2;
47 des_cblock iv2; 47 des_cblock iv2;
48 des_key_schedule key3; 48 des_key_schedule key3;
49 des_cblock iv3; 49 des_cblock iv3;
50 } des3; 50 } des3;
51 struct { 51 struct {
52 struct bf_key_st key; 52 struct bf_key_st key;
53 unsigned char iv[8]; 53 unsigned char iv[8];
54 } bf; 54 } bf;
55 } u; 55 } u;
56} CipherContext; 56} CipherContext;
57
58/* Returns a bit mask indicating which ciphers are supported by this 57/* Returns a bit mask indicating which ciphers are supported by this
59 implementation. The bit mask has the corresponding bit set of each 58 implementation. The bit mask has the corresponding bit set of each
60 supported cipher. */ 59 supported cipher. */
@@ -65,28 +64,32 @@ const char *cipher_name(int cipher);
65 64
66/* Parses the name of the cipher. Returns the number of the corresponding 65/* Parses the name of the cipher. Returns the number of the corresponding
67 cipher, or -1 on error. */ 66 cipher, or -1 on error. */
68int cipher_number(const char *name); 67int cipher_number(const char *name);
69 68
70/* Selects the cipher to use and sets the key. If for_encryption is true, 69/* Selects the cipher to use and sets the key. If for_encryption is true,
71 the key is setup for encryption; otherwise it is setup for decryption. */ 70 the key is setup for encryption; otherwise it is setup for decryption. */
72void cipher_set_key(CipherContext *context, int cipher, 71void
73 const unsigned char *key, int keylen, int for_encryption); 72cipher_set_key(CipherContext * context, int cipher,
73 const unsigned char *key, int keylen, int for_encryption);
74 74
75/* Sets key for the cipher by computing the MD5 checksum of the passphrase, 75/* Sets key for the cipher by computing the MD5 checksum of the passphrase,
76 and using the resulting 16 bytes as the key. */ 76 and using the resulting 16 bytes as the key. */
77void cipher_set_key_string(CipherContext *context, int cipher, 77void
78 const char *passphrase, int for_encryption); 78cipher_set_key_string(CipherContext * context, int cipher,
79 const char *passphrase, int for_encryption);
79 80
80/* Encrypts data using the cipher. */ 81/* Encrypts data using the cipher. */
81void cipher_encrypt(CipherContext *context, unsigned char *dest, 82void
82 const unsigned char *src, unsigned int len); 83cipher_encrypt(CipherContext * context, unsigned char *dest,
84 const unsigned char *src, unsigned int len);
83 85
84/* Decrypts data using the cipher. */ 86/* Decrypts data using the cipher. */
85void cipher_decrypt(CipherContext *context, unsigned char *dest, 87void
86 const unsigned char *src, unsigned int len); 88cipher_decrypt(CipherContext * context, unsigned char *dest,
89 const unsigned char *src, unsigned int len);
87 90
88/* If and CRC-32 attack is detected this function is called. Defaults 91/* If and CRC-32 attack is detected this function is called. Defaults
89 * to fatal, changed to packet_disconnect in sshd and ssh. */ 92 * to fatal, changed to packet_disconnect in sshd and ssh. */
90extern void (*cipher_attack_detected)(const char *fmt, ...); 93extern void (*cipher_attack_detected) (const char *fmt,...);
91 94
92#endif /* CIPHER_H */ 95#endif /* CIPHER_H */
diff --git a/clientloop.c b/clientloop.c
index 8e8d7627d..c49346c2c 100644
--- a/clientloop.c
+++ b/clientloop.c
@@ -1,21 +1,21 @@
1/* 1/*
2 2 *
3clientloop.c 3 * clientloop.c
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10 10 *
11Created: Sat Sep 23 12:23:57 1995 ylo 11 * Created: Sat Sep 23 12:23:57 1995 ylo
12 12 *
13The main loop for the interactive session (client side). 13 * The main loop for the interactive session (client side).
14 14 *
15*/ 15 */
16 16
17#include "includes.h" 17#include "includes.h"
18RCSID("$Id: clientloop.c,v 1.4 1999/11/21 02:23:53 damien Exp $"); 18RCSID("$Id: clientloop.c,v 1.5 1999/11/24 13:26:22 damien Exp $");
19 19
20#include "xmalloc.h" 20#include "xmalloc.h"
21#include "ssh.h" 21#include "ssh.h"
@@ -49,292 +49,294 @@ static int in_raw_mode = 0;
49static int in_non_blocking_mode = 0; 49static int in_non_blocking_mode = 0;
50 50
51/* Common data for the client loop code. */ 51/* Common data for the client loop code. */
52static int escape_pending; /* Last character was the escape character */ 52static int escape_pending; /* Last character was the escape character */
53static int last_was_cr; /* Last character was a newline. */ 53static int last_was_cr; /* Last character was a newline. */
54static int exit_status; /* Used to store the exit status of the command. */ 54static int exit_status; /* Used to store the exit status of the command. */
55static int stdin_eof; /* EOF has been encountered on standard error. */ 55static int stdin_eof; /* EOF has been encountered on standard error. */
56static Buffer stdin_buffer; /* Buffer for stdin data. */ 56static Buffer stdin_buffer; /* Buffer for stdin data. */
57static Buffer stdout_buffer; /* Buffer for stdout data. */ 57static Buffer stdout_buffer; /* Buffer for stdout data. */
58static Buffer stderr_buffer; /* Buffer for stderr data. */ 58static Buffer stderr_buffer; /* Buffer for stderr data. */
59static unsigned int buffer_high; /* Soft max buffer size. */ 59static unsigned int buffer_high;/* Soft max buffer size. */
60static int max_fd; /* Maximum file descriptor number in select(). */ 60static int max_fd; /* Maximum file descriptor number in select(). */
61static int connection_in; /* Connection to server (input). */ 61static int connection_in; /* Connection to server (input). */
62static int connection_out; /* Connection to server (output). */ 62static int connection_out; /* Connection to server (output). */
63static unsigned long stdin_bytes, stdout_bytes, stderr_bytes; 63static unsigned long stdin_bytes, stdout_bytes, stderr_bytes;
64static int quit_pending; /* Set to non-zero to quit the client loop. */ 64static int quit_pending; /* Set to non-zero to quit the client loop. */
65static int escape_char; /* Escape character. */ 65static int escape_char; /* Escape character. */
66 66
67/* Returns the user\'s terminal to normal mode if it had been put in raw 67/* Returns the user\'s terminal to normal mode if it had been put in raw
68 mode. */ 68 mode. */
69 69
70void leave_raw_mode() 70void
71leave_raw_mode()
71{ 72{
72 if (!in_raw_mode) 73 if (!in_raw_mode)
73 return; 74 return;
74 in_raw_mode = 0; 75 in_raw_mode = 0;
75 if (tcsetattr(fileno(stdin), TCSADRAIN, &saved_tio) < 0) 76 if (tcsetattr(fileno(stdin), TCSADRAIN, &saved_tio) < 0)
76 perror("tcsetattr"); 77 perror("tcsetattr");
77 78
78 fatal_remove_cleanup((void (*)(void *))leave_raw_mode, NULL); 79 fatal_remove_cleanup((void (*) (void *)) leave_raw_mode, NULL);
79} 80}
80 81
81/* Puts the user\'s terminal in raw mode. */ 82/* Puts the user\'s terminal in raw mode. */
82 83
83void enter_raw_mode() 84void
85enter_raw_mode()
84{ 86{
85 struct termios tio; 87 struct termios tio;
86 88
87 if (tcgetattr(fileno(stdin), &tio) < 0) 89 if (tcgetattr(fileno(stdin), &tio) < 0)
88 perror("tcgetattr"); 90 perror("tcgetattr");
89 saved_tio = tio; 91 saved_tio = tio;
90 tio.c_iflag |= IGNPAR; 92 tio.c_iflag |= IGNPAR;
91 tio.c_iflag &= ~(ISTRIP|INLCR|IGNCR|ICRNL|IXON|IXANY|IXOFF); 93 tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
92 tio.c_lflag &= ~(ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHONL); 94 tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
93#ifdef IEXTEN 95#ifdef IEXTEN
94 tio.c_lflag &= ~IEXTEN; 96 tio.c_lflag &= ~IEXTEN;
95#endif /* IEXTEN */ 97#endif /* IEXTEN */
96 tio.c_oflag &= ~OPOST; 98 tio.c_oflag &= ~OPOST;
97 tio.c_cc[VMIN] = 1; 99 tio.c_cc[VMIN] = 1;
98 tio.c_cc[VTIME] = 0; 100 tio.c_cc[VTIME] = 0;
99 if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) < 0) 101 if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) < 0)
100 perror("tcsetattr"); 102 perror("tcsetattr");
101 in_raw_mode = 1; 103 in_raw_mode = 1;
102 104
103 fatal_add_cleanup((void (*)(void *))leave_raw_mode, NULL); 105 fatal_add_cleanup((void (*) (void *)) leave_raw_mode, NULL);
104} 106}
105
106/* Puts stdin terminal in non-blocking mode. */
107 107
108/* Restores stdin to blocking mode. */ 108/* Restores stdin to blocking mode. */
109 109
110void leave_non_blocking() 110void
111leave_non_blocking()
111{ 112{
112 if (in_non_blocking_mode) 113 if (in_non_blocking_mode) {
113 { 114 (void) fcntl(fileno(stdin), F_SETFL, 0);
114 (void)fcntl(fileno(stdin), F_SETFL, 0); 115 in_non_blocking_mode = 0;
115 in_non_blocking_mode = 0; 116 fatal_remove_cleanup((void (*) (void *)) leave_non_blocking, NULL);
116 fatal_remove_cleanup((void (*)(void *))leave_non_blocking, NULL); 117 }
117 }
118} 118}
119 119
120void enter_non_blocking() 120/* Puts stdin terminal in non-blocking mode. */
121
122void
123enter_non_blocking()
121{ 124{
122 in_non_blocking_mode = 1; 125 in_non_blocking_mode = 1;
123 (void)fcntl(fileno(stdin), F_SETFL, O_NONBLOCK); 126 (void) fcntl(fileno(stdin), F_SETFL, O_NONBLOCK);
124 fatal_add_cleanup((void (*)(void *))leave_non_blocking, NULL); 127 fatal_add_cleanup((void (*) (void *)) leave_non_blocking, NULL);
125} 128}
126 129
127/* Signal handler for the window change signal (SIGWINCH). This just 130/* Signal handler for the window change signal (SIGWINCH). This just
128 sets a flag indicating that the window has changed. */ 131 sets a flag indicating that the window has changed. */
129 132
130void window_change_handler(int sig) 133void
134window_change_handler(int sig)
131{ 135{
132 received_window_change_signal = 1; 136 received_window_change_signal = 1;
133 signal(SIGWINCH, window_change_handler); 137 signal(SIGWINCH, window_change_handler);
134} 138}
135 139
136/* Signal handler for signals that cause the program to terminate. These 140/* Signal handler for signals that cause the program to terminate. These
137 signals must be trapped to restore terminal modes. */ 141 signals must be trapped to restore terminal modes. */
138 142
139void signal_handler(int sig) 143void
144signal_handler(int sig)
140{ 145{
141 if (in_raw_mode) 146 if (in_raw_mode)
142 leave_raw_mode(); 147 leave_raw_mode();
143 if (in_non_blocking_mode) 148 if (in_non_blocking_mode)
144 leave_non_blocking(); 149 leave_non_blocking();
145 channel_stop_listening(); 150 channel_stop_listening();
146 packet_close(); 151 packet_close();
147 fatal("Killed by signal %d.", sig); 152 fatal("Killed by signal %d.", sig);
148} 153}
149 154
150/* Returns current time in seconds from Jan 1, 1970 with the maximum available 155/* Returns current time in seconds from Jan 1, 1970 with the maximum available
151 resolution. */ 156 resolution. */
152 157
153double get_current_time() 158double
159get_current_time()
154{ 160{
155 struct timeval tv; 161 struct timeval tv;
156 gettimeofday(&tv, NULL); 162 gettimeofday(&tv, NULL);
157 return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0; 163 return (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0;
158} 164}
159 165
160/* This is called when the interactive is entered. This checks if there 166/* This is called when the interactive is entered. This checks if there
161 is an EOF coming on stdin. We must check this explicitly, as select() 167 is an EOF coming on stdin. We must check this explicitly, as select()
162 does not appear to wake up when redirecting from /dev/null. */ 168 does not appear to wake up when redirecting from /dev/null. */
163 169
164void client_check_initial_eof_on_stdin() 170void
171client_check_initial_eof_on_stdin()
165{ 172{
166 int len; 173 int len;
167 char buf[1]; 174 char buf[1];
168 175
169 /* If standard input is to be "redirected from /dev/null", we simply 176 /* If standard input is to be "redirected from /dev/null", we
170 mark that we have seen an EOF and send an EOF message to the server. 177 simply mark that we have seen an EOF and send an EOF message to
171 Otherwise, we try to read a single character; it appears that for some 178 the server. Otherwise, we try to read a single character; it
172 files, such /dev/null, select() never wakes up for read for this 179 appears that for some files, such /dev/null, select() never
173 descriptor, which means that we never get EOF. This way we will get 180 wakes up for read for this descriptor, which means that we
174 the EOF if stdin comes from /dev/null or similar. */ 181 never get EOF. This way we will get the EOF if stdin comes
175 if (stdin_null_flag) 182 from /dev/null or similar. */
176 { 183 if (stdin_null_flag) {
177 /* Fake EOF on stdin. */ 184 /* Fake EOF on stdin. */
178 debug("Sending eof."); 185 debug("Sending eof.");
179 stdin_eof = 1; 186 stdin_eof = 1;
180 packet_start(SSH_CMSG_EOF); 187 packet_start(SSH_CMSG_EOF);
181 packet_send(); 188 packet_send();
182 } 189 } else {
183 else 190 /* Enter non-blocking mode for stdin. */
184 { 191 enter_non_blocking();
185 /* Enter non-blocking mode for stdin. */ 192
186 enter_non_blocking(); 193 /* Check for immediate EOF on stdin. */
187 194 len = read(fileno(stdin), buf, 1);
188 /* Check for immediate EOF on stdin. */ 195 if (len == 0) {
189 len = read(fileno(stdin), buf, 1); 196 /* EOF. Record that we have seen it and send EOF
190 if (len == 0) 197 to server. */
191 { 198 debug("Sending eof.");
192 /* EOF. Record that we have seen it and send EOF to server. */ 199 stdin_eof = 1;
193 debug("Sending eof."); 200 packet_start(SSH_CMSG_EOF);
194 stdin_eof = 1; 201 packet_send();
195 packet_start(SSH_CMSG_EOF); 202 } else if (len > 0) {
196 packet_send(); 203 /* Got data. We must store the data in the
204 buffer, and also process it as an escape
205 character if appropriate. */
206 if ((unsigned char) buf[0] == escape_char)
207 escape_pending = 1;
208 else {
209 buffer_append(&stdin_buffer, buf, 1);
210 stdin_bytes += 1;
211 }
212 }
213 /* Leave non-blocking mode. */
214 leave_non_blocking();
197 } 215 }
198 else
199 if (len > 0)
200 {
201 /* Got data. We must store the data in the buffer, and also
202 process it as an escape character if appropriate. */
203 if ((unsigned char)buf[0] == escape_char)
204 escape_pending = 1;
205 else
206 {
207 buffer_append(&stdin_buffer, buf, 1);
208 stdin_bytes += 1;
209 }
210 }
211
212 /* Leave non-blocking mode. */
213 leave_non_blocking();
214 }
215} 216}
216 217
217/* Get packets from the connection input buffer, and process them as long 218/* Get packets from the connection input buffer, and process them as long
218 as there are packets available. */ 219 as there are packets available. */
219 220
220void client_process_buffered_input_packets() 221void
222client_process_buffered_input_packets()
221{ 223{
222 int type; 224 int type;
223 char *data; 225 char *data;
224 unsigned int data_len; 226 unsigned int data_len;
225 int payload_len; 227 int payload_len;
226 228
227 /* Process any buffered packets from the server. */ 229 /* Process any buffered packets from the server. */
228 while (!quit_pending && (type = packet_read_poll(&payload_len)) != SSH_MSG_NONE) 230 while (!quit_pending &&
229 { 231 (type = packet_read_poll(&payload_len)) != SSH_MSG_NONE) {
230 switch (type) 232 switch (type) {
231 { 233
232 234 case SSH_SMSG_STDOUT_DATA:
233 case SSH_SMSG_STDOUT_DATA: 235 data = packet_get_string(&data_len);
234 data = packet_get_string(&data_len); 236 packet_integrity_check(payload_len, 4 + data_len, type);
235 packet_integrity_check(payload_len, 4 + data_len, type); 237 buffer_append(&stdout_buffer, data, data_len);
236 buffer_append(&stdout_buffer, data, data_len); 238 stdout_bytes += data_len;
237 stdout_bytes += data_len; 239 memset(data, 0, data_len);
238 memset(data, 0, data_len); 240 xfree(data);
239 xfree(data); 241 break;
240 break; 242
241 243 case SSH_SMSG_STDERR_DATA:
242 case SSH_SMSG_STDERR_DATA: 244 data = packet_get_string(&data_len);
243 data = packet_get_string(&data_len); 245 packet_integrity_check(payload_len, 4 + data_len, type);
244 packet_integrity_check(payload_len, 4 + data_len, type); 246 buffer_append(&stderr_buffer, data, data_len);
245 buffer_append(&stderr_buffer, data, data_len); 247 stdout_bytes += data_len;
246 stdout_bytes += data_len; 248 memset(data, 0, data_len);
247 memset(data, 0, data_len); 249 xfree(data);
248 xfree(data); 250 break;
249 break; 251
250 252 case SSH_SMSG_EXITSTATUS:
251 case SSH_SMSG_EXITSTATUS: 253 packet_integrity_check(payload_len, 4, type);
252 packet_integrity_check(payload_len, 4, type); 254 exit_status = packet_get_int();
253 exit_status = packet_get_int(); 255 /* Acknowledge the exit. */
254 /* Acknowledge the exit. */ 256 packet_start(SSH_CMSG_EXIT_CONFIRMATION);
255 packet_start(SSH_CMSG_EXIT_CONFIRMATION); 257 packet_send();
256 packet_send(); 258 /* Must wait for packet to be sent since we are
257 /* Must wait for packet to be sent since we are exiting the 259 exiting the loop. */
258 loop. */ 260 packet_write_wait();
259 packet_write_wait(); 261 /* Flag that we want to exit. */
260 /* Flag that we want to exit. */ 262 quit_pending = 1;
261 quit_pending = 1; 263 break;
262 break; 264
263 265 case SSH_SMSG_X11_OPEN:
264 case SSH_SMSG_X11_OPEN: 266 x11_input_open(payload_len);
265 x11_input_open(payload_len); 267 break;
266 break; 268
267 269 case SSH_MSG_PORT_OPEN:
268 case SSH_MSG_PORT_OPEN: 270 channel_input_port_open(payload_len);
269 channel_input_port_open(payload_len); 271 break;
270 break; 272
271 273 case SSH_SMSG_AGENT_OPEN:
272 case SSH_SMSG_AGENT_OPEN: 274 packet_integrity_check(payload_len, 4, type);
273 packet_integrity_check(payload_len, 4, type); 275 auth_input_open_request();
274 auth_input_open_request(); 276 break;
275 break; 277
276 278 case SSH_MSG_CHANNEL_OPEN_CONFIRMATION:
277 case SSH_MSG_CHANNEL_OPEN_CONFIRMATION: 279 packet_integrity_check(payload_len, 4 + 4, type);
278 packet_integrity_check(payload_len, 4 + 4, type); 280 channel_input_open_confirmation();
279 channel_input_open_confirmation(); 281 break;
280 break; 282
281 283 case SSH_MSG_CHANNEL_OPEN_FAILURE:
282 case SSH_MSG_CHANNEL_OPEN_FAILURE: 284 packet_integrity_check(payload_len, 4, type);
283 packet_integrity_check(payload_len, 4, type); 285 channel_input_open_failure();
284 channel_input_open_failure(); 286 break;
285 break; 287
286 288 case SSH_MSG_CHANNEL_DATA:
287 case SSH_MSG_CHANNEL_DATA: 289 channel_input_data(payload_len);
288 channel_input_data(payload_len); 290 break;
289 break; 291
290 292 case SSH_MSG_CHANNEL_CLOSE:
291 case SSH_MSG_CHANNEL_CLOSE: 293 packet_integrity_check(payload_len, 4, type);
292 packet_integrity_check(payload_len, 4, type); 294 channel_input_close();
293 channel_input_close(); 295 break;
294 break; 296
295 297 case SSH_MSG_CHANNEL_CLOSE_CONFIRMATION:
296 case SSH_MSG_CHANNEL_CLOSE_CONFIRMATION: 298 packet_integrity_check(payload_len, 4, type);
297 packet_integrity_check(payload_len, 4, type); 299 channel_input_close_confirmation();
298 channel_input_close_confirmation(); 300 break;
299 break; 301
300 302 default:
301 default: 303 /* Any unknown packets received during the actual
302 /* Any unknown packets received during the actual session 304 session cause the session to terminate. This
303 cause the session to terminate. This is intended to make 305 is intended to make debugging easier since no
304 debugging easier since no confirmations are sent. Any 306 confirmations are sent. Any compatible
305 compatible protocol extensions must be negotiated during 307 protocol extensions must be negotiated during
306 the preparatory phase. */ 308 the preparatory phase. */
307 packet_disconnect("Protocol error during session: type %d", 309 packet_disconnect("Protocol error during session: type %d",
308 type); 310 type);
311 }
309 } 312 }
310 }
311} 313}
312 314
313/* Make packets from buffered stdin data, and buffer them for sending to 315/* Make packets from buffered stdin data, and buffer them for sending to
314 the connection. */ 316 the connection. */
315 317
316void client_make_packets_from_stdin_data() 318void
319client_make_packets_from_stdin_data()
317{ 320{
318 unsigned int len; 321 unsigned int len;
319 322
320 /* Send buffered stdin data to the server. */ 323 /* Send buffered stdin data to the server. */
321 while (buffer_len(&stdin_buffer) > 0 && 324 while (buffer_len(&stdin_buffer) > 0 &&
322 packet_not_very_much_data_to_write()) 325 packet_not_very_much_data_to_write()) {
323 { 326 len = buffer_len(&stdin_buffer);
324 len = buffer_len(&stdin_buffer); 327 /* Keep the packets at reasonable size. */
325 if (len > packet_get_maxsize()) 328 if (len > packet_get_maxsize())
326 len = packet_get_maxsize(); /* Keep the packets at reasonable size. */ 329 len = packet_get_maxsize();
327 packet_start(SSH_CMSG_STDIN_DATA); 330 packet_start(SSH_CMSG_STDIN_DATA);
328 packet_put_string(buffer_ptr(&stdin_buffer), len); 331 packet_put_string(buffer_ptr(&stdin_buffer), len);
329 packet_send(); 332 packet_send();
330 buffer_consume(&stdin_buffer, len); 333 buffer_consume(&stdin_buffer, len);
331 /* If we have a pending EOF, send it now. */ 334 /* If we have a pending EOF, send it now. */
332 if (stdin_eof && buffer_len(&stdin_buffer) == 0) 335 if (stdin_eof && buffer_len(&stdin_buffer) == 0) {
333 { 336 packet_start(SSH_CMSG_EOF);
334 packet_start(SSH_CMSG_EOF); 337 packet_send();
335 packet_send(); 338 }
336 } 339 }
337 }
338} 340}
339 341
340/* Checks if the client window has changed, and sends a packet about it to 342/* Checks if the client window has changed, and sends a packet about it to
@@ -342,303 +344,286 @@ void client_make_packets_from_stdin_data()
342 interrupt on Unix); this just checks the flag and sends a message if 344 interrupt on Unix); this just checks the flag and sends a message if
343 appropriate. */ 345 appropriate. */
344 346
345void client_check_window_change() 347void
348client_check_window_change()
346{ 349{
347 /* Send possible window change message to the server. */ 350 /* Send possible window change message to the server. */
348 if (received_window_change_signal) 351 if (received_window_change_signal) {
349 { 352 struct winsize ws;
350 struct winsize ws; 353
351 354 /* Clear the window change indicator. */
352 /* Clear the window change indicator. */ 355 received_window_change_signal = 0;
353 received_window_change_signal = 0; 356
354 357 /* Read new window size. */
355 /* Read new window size. */ 358 if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) >= 0) {
356 if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) >= 0) 359 /* Successful, send the packet now. */
357 { 360 packet_start(SSH_CMSG_WINDOW_SIZE);
358 /* Successful, send the packet now. */ 361 packet_put_int(ws.ws_row);
359 packet_start(SSH_CMSG_WINDOW_SIZE); 362 packet_put_int(ws.ws_col);
360 packet_put_int(ws.ws_row); 363 packet_put_int(ws.ws_xpixel);
361 packet_put_int(ws.ws_col); 364 packet_put_int(ws.ws_ypixel);
362 packet_put_int(ws.ws_xpixel); 365 packet_send();
363 packet_put_int(ws.ws_ypixel); 366 }
364 packet_send();
365 } 367 }
366 }
367} 368}
368 369
369/* Waits until the client can do something (some data becomes available on 370/* Waits until the client can do something (some data becomes available on
370 one of the file descriptors). */ 371 one of the file descriptors). */
371 372
372void client_wait_until_can_do_something(fd_set *readset, fd_set *writeset) 373void
374client_wait_until_can_do_something(fd_set * readset, fd_set * writeset)
373{ 375{
374 /* Initialize select masks. */ 376 /* Initialize select masks. */
375 FD_ZERO(readset); 377 FD_ZERO(readset);
376 378
377 /* Read from the connection, unless our buffers are full. */ 379 /* Read from the connection, unless our buffers are full. */
378 if (buffer_len(&stdout_buffer) < buffer_high && 380 if (buffer_len(&stdout_buffer) < buffer_high &&
379 buffer_len(&stderr_buffer) < buffer_high && 381 buffer_len(&stderr_buffer) < buffer_high &&
380 channel_not_very_much_buffered_data()) 382 channel_not_very_much_buffered_data())
381 FD_SET(connection_in, readset); 383 FD_SET(connection_in, readset);
382 384
383 /* Read from stdin, unless we have seen EOF or have very much buffered 385 /* Read from stdin, unless we have seen EOF or have very much
384 data to send to the server. */ 386 buffered data to send to the server. */
385 if (!stdin_eof && packet_not_very_much_data_to_write()) 387 if (!stdin_eof && packet_not_very_much_data_to_write())
386 FD_SET(fileno(stdin), readset); 388 FD_SET(fileno(stdin), readset);
387 389
388 FD_ZERO(writeset); 390 FD_ZERO(writeset);
389 391
390 /* Add any selections by the channel mechanism. */ 392 /* Add any selections by the channel mechanism. */
391 channel_prepare_select(readset, writeset); 393 channel_prepare_select(readset, writeset);
392 394
393 /* Select server connection if have data to write to the server. */ 395 /* Select server connection if have data to write to the server. */
394 if (packet_have_data_to_write()) 396 if (packet_have_data_to_write())
395 FD_SET(connection_out, writeset); 397 FD_SET(connection_out, writeset);
396 398
397 /* Select stdout if have data in buffer. */ 399 /* Select stdout if have data in buffer. */
398 if (buffer_len(&stdout_buffer) > 0) 400 if (buffer_len(&stdout_buffer) > 0)
399 FD_SET(fileno(stdout), writeset); 401 FD_SET(fileno(stdout), writeset);
400 402
401 /* Select stderr if have data in buffer. */ 403 /* Select stderr if have data in buffer. */
402 if (buffer_len(&stderr_buffer) > 0) 404 if (buffer_len(&stderr_buffer) > 0)
403 FD_SET(fileno(stderr), writeset); 405 FD_SET(fileno(stderr), writeset);
404 406
405 /* Update maximum file descriptor number, if appropriate. */ 407 /* Update maximum file descriptor number, if appropriate. */
406 if (channel_max_fd() > max_fd) 408 if (channel_max_fd() > max_fd)
407 max_fd = channel_max_fd(); 409 max_fd = channel_max_fd();
408 410
409 /* Wait for something to happen. This will suspend the process until 411 /* Wait for something to happen. This will suspend the process
410 some selected descriptor can be read, written, or has some other 412 until some selected descriptor can be read, written, or has
411 event pending. Note: if you want to implement SSH_MSG_IGNORE 413 some other event pending.
412 messages to fool traffic analysis, this might be the place to do 414 Note: if you want to implement SSH_MSG_IGNORE messages to fool
413 it: just have a random timeout for the select, and send a random 415 traffic analysis, this might be the place to do it:
414 SSH_MSG_IGNORE packet when the timeout expires. */ 416 just have a random timeout for the select, and send a random
415 if (select(max_fd + 1, readset, writeset, NULL, NULL) < 0) 417 SSH_MSG_IGNORE packet when the timeout expires. */
416 { 418
417 char buf[100]; 419 if (select(max_fd + 1, readset, writeset, NULL, NULL) < 0) {
418 /* Some systems fail to clear these automatically. */ 420 char buf[100];
419 FD_ZERO(readset); 421 /* Some systems fail to clear these automatically. */
420 FD_ZERO(writeset); 422 FD_ZERO(readset);
421 if (errno == EINTR) 423 FD_ZERO(writeset);
422 return; 424 if (errno == EINTR)
423 /* Note: we might still have data in the buffers. */ 425 return;
424 snprintf(buf, sizeof buf, "select: %s\r\n", strerror(errno)); 426 /* Note: we might still have data in the buffers. */
425 buffer_append(&stderr_buffer, buf, strlen(buf)); 427 snprintf(buf, sizeof buf, "select: %s\r\n", strerror(errno));
426 stderr_bytes += strlen(buf); 428 buffer_append(&stderr_buffer, buf, strlen(buf));
427 quit_pending = 1; 429 stderr_bytes += strlen(buf);
428 } 430 quit_pending = 1;
431 }
429} 432}
430 433
431void client_suspend_self() 434void
435client_suspend_self()
432{ 436{
433 struct winsize oldws, newws; 437 struct winsize oldws, newws;
434 438
435 /* Flush stdout and stderr buffers. */ 439 /* Flush stdout and stderr buffers. */
436 if (buffer_len(&stdout_buffer) > 0) 440 if (buffer_len(&stdout_buffer) > 0)
437 write(fileno(stdout), 441 write(fileno(stdout),
438 buffer_ptr(&stdout_buffer), 442 buffer_ptr(&stdout_buffer),
439 buffer_len(&stdout_buffer)); 443 buffer_len(&stdout_buffer));
440 if (buffer_len(&stderr_buffer) > 0) 444 if (buffer_len(&stderr_buffer) > 0)
441 write(fileno(stderr), 445 write(fileno(stderr),
442 buffer_ptr(&stderr_buffer), 446 buffer_ptr(&stderr_buffer),
443 buffer_len(&stderr_buffer)); 447 buffer_len(&stderr_buffer));
444 448
445 /* Leave raw mode. */ 449 /* Leave raw mode. */
446 leave_raw_mode(); 450 leave_raw_mode();
447 451
448 /* Free (and clear) the buffer to reduce the 452 /* Free (and clear) the buffer to reduce the amount of data that
449 amount of data that gets written to swap. */ 453 gets written to swap. */
450 buffer_free(&stdin_buffer); 454 buffer_free(&stdin_buffer);
451 buffer_free(&stdout_buffer); 455 buffer_free(&stdout_buffer);
452 buffer_free(&stderr_buffer); 456 buffer_free(&stderr_buffer);
453 457
454 /* Save old window size. */ 458 /* Save old window size. */
455 ioctl(fileno(stdin), TIOCGWINSZ, &oldws); 459 ioctl(fileno(stdin), TIOCGWINSZ, &oldws);
456 460
457 /* Send the suspend signal to the program 461 /* Send the suspend signal to the program itself. */
458 itself. */ 462 kill(getpid(), SIGTSTP);
459 kill(getpid(), SIGTSTP); 463
460 464 /* Check if the window size has changed. */
461 /* Check if the window size has changed. */ 465 if (ioctl(fileno(stdin), TIOCGWINSZ, &newws) >= 0 &&
462 if (ioctl(fileno(stdin), TIOCGWINSZ, &newws) >= 0 && 466 (oldws.ws_row != newws.ws_row ||
463 (oldws.ws_row != newws.ws_row || oldws.ws_col != newws.ws_col || 467 oldws.ws_col != newws.ws_col ||
464 oldws.ws_xpixel != newws.ws_xpixel || 468 oldws.ws_xpixel != newws.ws_xpixel ||
465 oldws.ws_ypixel != newws.ws_ypixel)) 469 oldws.ws_ypixel != newws.ws_ypixel))
466 received_window_change_signal = 1; 470 received_window_change_signal = 1;
467 471
468 /* OK, we have been continued by the user. 472 /* OK, we have been continued by the user. Reinitialize buffers. */
469 Reinitialize buffers. */ 473 buffer_init(&stdin_buffer);
470 buffer_init(&stdin_buffer); 474 buffer_init(&stdout_buffer);
471 buffer_init(&stdout_buffer); 475 buffer_init(&stderr_buffer);
472 buffer_init(&stderr_buffer); 476
473 477 /* Re-enter raw mode. */
474 /* Re-enter raw mode. */ 478 enter_raw_mode();
475 enter_raw_mode();
476} 479}
477 480
478void client_process_input(fd_set *readset) 481void
482client_process_input(fd_set * readset)
479{ 483{
480 int len, pid; 484 int len, pid;
481 char buf[8192], *s; 485 char buf[8192], *s;
482 486
483 /* Read input from the server, and add any such data to the buffer of the 487 /* Read input from the server, and add any such data to the buffer
484 packet subsystem. */ 488 of the packet subsystem. */
485 if (FD_ISSET(connection_in, readset)) 489 if (FD_ISSET(connection_in, readset)) {
486 { 490 /* Read as much as possible. */
487 /* Read as much as possible. */ 491 len = read(connection_in, buf, sizeof(buf));
488 len = read(connection_in, buf, sizeof(buf)); 492 if (len == 0) {
489 if (len == 0) 493 /* Received EOF. The remote host has closed the connection. */
490 { 494 snprintf(buf, sizeof buf, "Connection to %.300s closed by remote host.\r\n",
491 /* Received EOF. The remote host has closed the connection. */ 495 host);
492 snprintf(buf, sizeof buf, "Connection to %.300s closed by remote host.\r\n",
493 host);
494 buffer_append(&stderr_buffer, buf, strlen(buf));
495 stderr_bytes += strlen(buf);
496 quit_pending = 1;
497 return;
498 }
499
500 /* There is a kernel bug on Solaris that causes select to sometimes
501 wake up even though there is no data available. */
502 if (len < 0 && errno == EAGAIN)
503 len = 0;
504
505 if (len < 0)
506 {
507 /* An error has encountered. Perhaps there is a network
508 problem. */
509 snprintf(buf, sizeof buf, "Read from remote host %.300s: %.100s\r\n",
510 host, strerror(errno));
511 buffer_append(&stderr_buffer, buf, strlen(buf));
512 stderr_bytes += strlen(buf);
513 quit_pending = 1;
514 return;
515 }
516 packet_process_incoming(buf, len);
517 }
518
519 /* Read input from stdin. */
520 if (FD_ISSET(fileno(stdin), readset))
521 {
522 /* Read as much as possible. */
523 len = read(fileno(stdin), buf, sizeof(buf));
524 if (len <= 0)
525 {
526 /* Received EOF or error. They are treated similarly,
527 except that an error message is printed if it was
528 an error condition. */
529 if (len < 0)
530 {
531 snprintf(buf, sizeof buf, "read: %.100s\r\n", strerror(errno));
532 buffer_append(&stderr_buffer, buf, strlen(buf));
533 stderr_bytes += strlen(buf);
534 }
535 /* Mark that we have seen EOF. */
536 stdin_eof = 1;
537 /* Send an EOF message to the server unless there is data
538 in the buffer. If there is data in the buffer, no message
539 will be sent now. Code elsewhere will send the EOF
540 when the buffer becomes empty if stdin_eof is set. */
541 if (buffer_len(&stdin_buffer) == 0)
542 {
543 packet_start(SSH_CMSG_EOF);
544 packet_send();
545 }
546 }
547 else
548 if (escape_char == -1)
549 {
550 /* Normal successful read, and no escape character. Just
551 append the data to buffer. */
552 buffer_append(&stdin_buffer, buf, len);
553 stdin_bytes += len;
554 }
555 else
556 {
557 /* Normal, successful read. But we have an escape character
558 and have to process the characters one by one. */
559 unsigned int i;
560 for (i = 0; i < len; i++)
561 {
562 unsigned char ch;
563 /* Get one character at a time. */
564 ch = buf[i];
565
566 /* Check if we have a pending escape character. */
567 if (escape_pending)
568 {
569 /* We have previously seen an escape character. */
570 /* Clear the flag now. */
571 escape_pending = 0;
572 /* Process the escaped character. */
573 switch (ch)
574 {
575 case '.':
576 /* Terminate the connection. */
577 snprintf(buf, sizeof buf, "%c.\r\n", escape_char);
578 buffer_append(&stderr_buffer, buf, strlen(buf)); 496 buffer_append(&stderr_buffer, buf, strlen(buf));
579 stderr_bytes += strlen(buf); 497 stderr_bytes += strlen(buf);
580 quit_pending = 1; 498 quit_pending = 1;
581 return; 499 return;
582 500 }
583 case 'Z' - 64: 501 /* There is a kernel bug on Solaris that causes select to
584 /* Suspend the program. */ 502 sometimes wake up even though there is no data
585 /* Print a message to that effect to the user. */ 503 available. */
586 snprintf(buf, sizeof buf, "%c^Z\r\n", escape_char); 504 if (len < 0 && errno == EAGAIN)
587 buffer_append(&stderr_buffer, buf, strlen(buf)); 505 len = 0;
588 stderr_bytes += strlen(buf); 506
589 507 if (len < 0) {
590 /* Restore terminal modes and suspend. */ 508 /* An error has encountered. Perhaps there is a network problem. */
591 client_suspend_self(); 509 snprintf(buf, sizeof buf, "Read from remote host %.300s: %.100s\r\n",
592 510 host, strerror(errno));
593 /* We have been continued. */ 511 buffer_append(&stderr_buffer, buf, strlen(buf));
594 continue; 512 stderr_bytes += strlen(buf);
595 513 quit_pending = 1;
596 case '&': 514 return;
597 /* Detach the program (continue to serve connections, 515 }
598 but put in background and no more new 516 packet_process_incoming(buf, len);
599 connections). */ 517 }
600 if (!stdin_eof) 518 /* Read input from stdin. */
601 { 519 if (FD_ISSET(fileno(stdin), readset)) {
602 /* Sending SSH_CMSG_EOF alone does not always 520 /* Read as much as possible. */
603 appear to be enough. So we try to send an 521 len = read(fileno(stdin), buf, sizeof(buf));
604 EOF character first. */ 522 if (len <= 0) {
605 packet_start(SSH_CMSG_STDIN_DATA); 523 /* Received EOF or error. They are treated
606 packet_put_string("\004", 1); 524 similarly, except that an error message is
607 packet_send(); 525 printed if it was an error condition. */
608 /* Close stdin. */ 526 if (len < 0) {
609 stdin_eof = 1; 527 snprintf(buf, sizeof buf, "read: %.100s\r\n", strerror(errno));
610 if (buffer_len(&stdin_buffer) == 0) 528 buffer_append(&stderr_buffer, buf, strlen(buf));
611 { 529 stderr_bytes += strlen(buf);
530 }
531 /* Mark that we have seen EOF. */
532 stdin_eof = 1;
533 /* Send an EOF message to the server unless there
534 is data in the buffer. If there is data in the
535 buffer, no message will be sent now. Code
536 elsewhere will send the EOF when the buffer
537 becomes empty if stdin_eof is set. */
538 if (buffer_len(&stdin_buffer) == 0) {
612 packet_start(SSH_CMSG_EOF); 539 packet_start(SSH_CMSG_EOF);
613 packet_send(); 540 packet_send();
614 } 541 }
615 } 542 } else if (escape_char == -1) {
616 /* Restore tty modes. */ 543 /* Normal successful read, and no escape
617 leave_raw_mode(); 544 character. Just append the data to buffer. */
618 545 buffer_append(&stdin_buffer, buf, len);
619 /* Stop listening for new connections. */ 546 stdin_bytes += len;
620 channel_stop_listening(); 547 } else {
621 548 /* Normal, successful read. But we have an escape
622 printf("%c& [backgrounded]\n", escape_char); 549 character and have to process the characters
623 550 one by one. */
624 /* Fork into background. */ 551 unsigned int i;
625 pid = fork(); 552 for (i = 0; i < len; i++) {
626 if (pid < 0) 553 unsigned char ch;
627 { 554 /* Get one character at a time. */
628 error("fork: %.100s", strerror(errno)); 555 ch = buf[i];
629 continue; 556
630 } 557 /* Check if we have a pending escape
631 if (pid != 0) 558 character. */
632 { /* This is the parent. */ 559 if (escape_pending) {
633 /* The parent just exits. */ 560 /* We have previously seen an escape character. */
634 exit(0); 561 /* Clear the flag now. */
635 } 562 escape_pending = 0;
636 563 /* Process the escaped character. */
637 /* The child continues serving connections. */ 564 switch (ch) {
638 continue; 565 case '.':
639 566 /* Terminate the connection. */
640 case '?': 567 snprintf(buf, sizeof buf, "%c.\r\n", escape_char);
641 snprintf(buf, sizeof buf, "%c?\r\n\ 568 buffer_append(&stderr_buffer, buf, strlen(buf));
569 stderr_bytes += strlen(buf);
570 quit_pending = 1;
571 return;
572
573 case 'Z' - 64:
574 /* Suspend the program. */
575 /* Print a message to that effect to the user. */
576 snprintf(buf, sizeof buf, "%c^Z\r\n", escape_char);
577 buffer_append(&stderr_buffer, buf, strlen(buf));
578 stderr_bytes += strlen(buf);
579
580 /* Restore terminal modes and suspend. */
581 client_suspend_self();
582
583 /* We have been continued. */
584 continue;
585
586 case '&':
587 /* Detach the program (continue to serve connections,
588 but put in background and no more new connections). */
589 if (!stdin_eof) {
590 /* Sending SSH_CMSG_EOF alone does not always appear
591 to be enough. So we try to send an EOF character
592 first. */
593 packet_start(SSH_CMSG_STDIN_DATA);
594 packet_put_string("\004", 1);
595 packet_send();
596 /* Close stdin. */
597 stdin_eof = 1;
598 if (buffer_len(&stdin_buffer) == 0) {
599 packet_start(SSH_CMSG_EOF);
600 packet_send();
601 }
602 }
603 /* Restore tty modes. */
604 leave_raw_mode();
605
606 /* Stop listening for new connections. */
607 channel_stop_listening();
608
609 printf("%c& [backgrounded]\n", escape_char);
610
611 /* Fork into background. */
612 pid = fork();
613 if (pid < 0) {
614 error("fork: %.100s", strerror(errno));
615 continue;
616 }
617 if (pid != 0) { /* This is the parent. */
618 /* The parent just exits. */
619 exit(0);
620 }
621 /* The child continues serving connections. */
622 continue;
623
624 case '?':
625 snprintf(buf, sizeof buf,
626"%c?\r\n\
642Supported escape sequences:\r\n\ 627Supported escape sequences:\r\n\
643~. - terminate connection\r\n\ 628~. - terminate connection\r\n\
644~^Z - suspend ssh\r\n\ 629~^Z - suspend ssh\r\n\
@@ -647,110 +632,100 @@ Supported escape sequences:\r\n\
647~? - this message\r\n\ 632~? - this message\r\n\
648~~ - send the escape character by typing it twice\r\n\ 633~~ - send the escape character by typing it twice\r\n\
649(Note that escapes are only recognized immediately after newline.)\r\n", 634(Note that escapes are only recognized immediately after newline.)\r\n",
650 escape_char); 635 escape_char);
651 buffer_append(&stderr_buffer, buf, strlen(buf)); 636 buffer_append(&stderr_buffer, buf, strlen(buf));
652 continue; 637 continue;
653 638
654 case '#': 639 case '#':
655 snprintf(buf, sizeof buf, "%c#\r\n", escape_char); 640 snprintf(buf, sizeof buf, "%c#\r\n", escape_char);
656 buffer_append(&stderr_buffer, buf, strlen(buf)); 641 buffer_append(&stderr_buffer, buf, strlen(buf));
657 s = channel_open_message(); 642 s = channel_open_message();
658 buffer_append(&stderr_buffer, s, strlen(s)); 643 buffer_append(&stderr_buffer, s, strlen(s));
659 xfree(s); 644 xfree(s);
660 continue; 645 continue;
661 646
662 default: 647 default:
663 if (ch != escape_char) 648 if (ch != escape_char) {
664 { 649 /* Escape character followed by non-special character.
665 /* Escape character followed by non-special 650 Append both to the input buffer. */
666 character. Append both to the input 651 buf[0] = escape_char;
667 buffer. */ 652 buf[1] = ch;
668 buf[0] = escape_char; 653 buffer_append(&stdin_buffer, buf, 2);
669 buf[1] = ch; 654 stdin_bytes += 2;
670 buffer_append(&stdin_buffer, buf, 2); 655 continue;
671 stdin_bytes += 2; 656 }
672 continue; 657 /* Note that escape character typed twice
673 } 658 falls through here; the latter gets processed
674 /* Note that escape character typed twice falls through 659 as a normal character below. */
675 here; the latter gets processed as a normal 660 break;
676 character below. */ 661 }
677 break; 662 } else {
678 } 663 /* The previous character was not an escape char. Check if this
679 } 664 is an escape. */
680 else 665 if (last_was_cr && ch == escape_char) {
681 { 666 /* It is. Set the flag and continue to next character. */
682 /* The previous character was not an escape char. 667 escape_pending = 1;
683 Check if this is an escape. */ 668 continue;
684 if (last_was_cr && ch == escape_char) 669 }
685 { 670 }
686 /* It is. Set the flag and continue to next 671
687 character. */ 672 /* Normal character. Record whether it was a newline, and append it to the
688 escape_pending = 1; 673 buffer. */
689 continue; 674 last_was_cr = (ch == '\r' || ch == '\n');
690 } 675 buf[0] = ch;
691 } 676 buffer_append(&stdin_buffer, buf, 1);
692 677 stdin_bytes += 1;
693 /* Normal character. Record whether it was a newline, 678 continue;
694 and append it to the buffer. */ 679 }
695 last_was_cr = (ch == '\r' || ch == '\n'); 680 }
696 buf[0] = ch; 681 }
697 buffer_append(&stdin_buffer, buf, 1);
698 stdin_bytes += 1;
699 continue;
700 }
701 }
702 }
703} 682}
704 683
705void client_process_output(fd_set *writeset) 684void
685client_process_output(fd_set * writeset)
706{ 686{
707 int len; 687 int len;
708 char buf[100]; 688 char buf[100];
709 689
710 /* Write buffered output to stdout. */ 690 /* Write buffered output to stdout. */
711 if (FD_ISSET(fileno(stdout), writeset)) 691 if (FD_ISSET(fileno(stdout), writeset)) {
712 { 692 /* Write as much data as possible. */
713 /* Write as much data as possible. */ 693 len = write(fileno(stdout), buffer_ptr(&stdout_buffer),
714 len = write(fileno(stdout), buffer_ptr(&stdout_buffer), 694 buffer_len(&stdout_buffer));
715 buffer_len(&stdout_buffer)); 695 if (len <= 0) {
716 if (len <= 0) 696 if (errno == EAGAIN)
717 { 697 len = 0;
718 if (errno == EAGAIN) 698 else {
719 len = 0; 699 /* An error or EOF was encountered. Put
720 else 700 an error message to stderr buffer. */
721 { 701 snprintf(buf, sizeof buf, "write stdout: %.50s\r\n", strerror(errno));
722 /* An error or EOF was encountered. Put an error message 702 buffer_append(&stderr_buffer, buf, strlen(buf));
723 to stderr buffer. */ 703 stderr_bytes += strlen(buf);
724 snprintf(buf, sizeof buf, "write stdout: %.50s\r\n", strerror(errno)); 704 quit_pending = 1;
725 buffer_append(&stderr_buffer, buf, strlen(buf)); 705 return;
726 stderr_bytes += strlen(buf); 706 }
727 quit_pending = 1; 707 }
728 return; 708 /* Consume printed data from the buffer. */
729 } 709 buffer_consume(&stdout_buffer, len);
710 }
711 /* Write buffered output to stderr. */
712 if (FD_ISSET(fileno(stderr), writeset)) {
713 /* Write as much data as possible. */
714 len = write(fileno(stderr), buffer_ptr(&stderr_buffer),
715 buffer_len(&stderr_buffer));
716 if (len <= 0) {
717 if (errno == EAGAIN)
718 len = 0;
719 else {
720 /* EOF or error, but can't even print
721 error message. */
722 quit_pending = 1;
723 return;
724 }
725 }
726 /* Consume printed characters from the buffer. */
727 buffer_consume(&stderr_buffer, len);
730 } 728 }
731 /* Consume printed data from the buffer. */
732 buffer_consume(&stdout_buffer, len);
733 }
734
735 /* Write buffered output to stderr. */
736 if (FD_ISSET(fileno(stderr), writeset))
737 {
738 /* Write as much data as possible. */
739 len = write(fileno(stderr), buffer_ptr(&stderr_buffer),
740 buffer_len(&stderr_buffer));
741 if (len <= 0) {
742 if (errno == EAGAIN)
743 len = 0;
744 else
745 {
746 /* EOF or error, but can't even print error message. */
747 quit_pending = 1;
748 return;
749 }
750 }
751 /* Consume printed characters from the buffer. */
752 buffer_consume(&stderr_buffer, len);
753 }
754} 729}
755 730
756/* Implements the interactive session with the server. This is called 731/* Implements the interactive session with the server. This is called
@@ -759,165 +734,160 @@ void client_process_output(fd_set *writeset)
759 used as an escape character for terminating or suspending the 734 used as an escape character for terminating or suspending the
760 session. */ 735 session. */
761 736
762int client_loop(int have_pty, int escape_char_arg) 737int
738client_loop(int have_pty, int escape_char_arg)
763{ 739{
764 extern Options options; 740 extern Options options;
765 double start_time, total_time; 741 double start_time, total_time;
766 int len; 742 int len;
767 char buf[100]; 743 char buf[100];
768 744
769 debug("Entering interactive session."); 745 debug("Entering interactive session.");
770 746
771 start_time = get_current_time(); 747 start_time = get_current_time();
772 748
773 /* Initialize variables. */ 749 /* Initialize variables. */
774 escape_pending = 0; 750 escape_pending = 0;
775 last_was_cr = 1; 751 last_was_cr = 1;
776 exit_status = -1; 752 exit_status = -1;
777 stdin_eof = 0; 753 stdin_eof = 0;
778 buffer_high = 64 * 1024; 754 buffer_high = 64 * 1024;
779 connection_in = packet_get_connection_in(); 755 connection_in = packet_get_connection_in();
780 connection_out = packet_get_connection_out(); 756 connection_out = packet_get_connection_out();
781 max_fd = connection_in; 757 max_fd = connection_in;
782 if (connection_out > max_fd) 758 if (connection_out > max_fd)
783 max_fd = connection_out; 759 max_fd = connection_out;
784 stdin_bytes = 0; 760 stdin_bytes = 0;
785 stdout_bytes = 0; 761 stdout_bytes = 0;
786 stderr_bytes = 0; 762 stderr_bytes = 0;
787 quit_pending = 0; 763 quit_pending = 0;
788 escape_char = escape_char_arg; 764 escape_char = escape_char_arg;
789 765
790 /* Initialize buffers. */ 766 /* Initialize buffers. */
791 buffer_init(&stdin_buffer); 767 buffer_init(&stdin_buffer);
792 buffer_init(&stdout_buffer); 768 buffer_init(&stdout_buffer);
793 buffer_init(&stderr_buffer); 769 buffer_init(&stderr_buffer);
794 770
795 /* Set signal handlers to restore non-blocking mode. */ 771 /* Set signal handlers to restore non-blocking mode. */
796 signal(SIGINT, signal_handler); 772 signal(SIGINT, signal_handler);
797 signal(SIGQUIT, signal_handler); 773 signal(SIGQUIT, signal_handler);
798 signal(SIGTERM, signal_handler); 774 signal(SIGTERM, signal_handler);
799 signal(SIGPIPE, SIG_IGN); 775 signal(SIGPIPE, SIG_IGN);
800 if (have_pty) 776 if (have_pty)
801 signal(SIGWINCH, window_change_handler); 777 signal(SIGWINCH, window_change_handler);
802 778
803 /* Enter raw mode if have a pseudo terminal. */ 779 /* Enter raw mode if have a pseudo terminal. */
804 if (have_pty) 780 if (have_pty)
805 enter_raw_mode(); 781 enter_raw_mode();
806 782
807 /* Check if we should immediately send of on stdin. */ 783 /* Check if we should immediately send of on stdin. */
808 client_check_initial_eof_on_stdin(); 784 client_check_initial_eof_on_stdin();
809 785
810 /* Main loop of the client for the interactive session mode. */ 786 /* Main loop of the client for the interactive session mode. */
811 while (!quit_pending) 787 while (!quit_pending) {
812 { 788 fd_set readset, writeset;
813 fd_set readset, writeset; 789
814 790 /* Precess buffered packets sent by the server. */
815 /* Precess buffered packets sent by the server. */ 791 client_process_buffered_input_packets();
816 client_process_buffered_input_packets(); 792
817 793 /* Make packets of buffered stdin data, and buffer them
818 /* Make packets of buffered stdin data, and buffer them for sending 794 for sending to the server. */
819 to the server. */ 795 client_make_packets_from_stdin_data();
820 client_make_packets_from_stdin_data(); 796
821 797 /* Make packets from buffered channel data, and buffer
822 /* Make packets from buffered channel data, and buffer them for sending 798 them for sending to the server. */
823 to the server. */ 799 if (packet_not_very_much_data_to_write())
824 if (packet_not_very_much_data_to_write()) 800 channel_output_poll();
825 channel_output_poll(); 801
826 802 /* Check if the window size has changed, and buffer a
827 /* Check if the window size has changed, and buffer a message about 803 message about it to the server if so. */
828 it to the server if so. */ 804 client_check_window_change();
829 client_check_window_change(); 805
830 806 if (quit_pending)
831 if (quit_pending) 807 break;
832 break; 808
833 809 /* Wait until we have something to do (something becomes
834 /* Wait until we have something to do (something becomes available 810 available on one of the descriptors). */
835 on one of the descriptors). */ 811 client_wait_until_can_do_something(&readset, &writeset);
836 client_wait_until_can_do_something(&readset, &writeset); 812
837 813 if (quit_pending)
838 if (quit_pending) 814 break;
839 break; 815
840 816 /* Do channel operations. */
841 /* Do channel operations. */ 817 channel_after_select(&readset, &writeset);
842 channel_after_select(&readset, &writeset); 818
843 819 /* Process input from the connection and from stdin.
844 /* Process input from the connection and from stdin. Buffer any data 820 Buffer any data that is available. */
845 that is available. */ 821 client_process_input(&readset);
846 client_process_input(&readset); 822
847 823 /* Process output to stdout and stderr. Output to the
848 /* Process output to stdout and stderr. Output to the connection 824 connection is processed elsewhere (above). */
849 is processed elsewhere (above). */ 825 client_process_output(&writeset);
850 client_process_output(&writeset); 826
851 827 /* Send as much buffered packet data as possible to the
852 /* Send as much buffered packet data as possible to the sender. */ 828 sender. */
853 if (FD_ISSET(connection_out, &writeset)) 829 if (FD_ISSET(connection_out, &writeset))
854 packet_write_poll(); 830 packet_write_poll();
855 } 831 }
856 832
857 /* Terminate the session. */ 833 /* Terminate the session. */
858 834
859 /* Stop watching for window change. */ 835 /* Stop watching for window change. */
860 if (have_pty) 836 if (have_pty)
861 signal(SIGWINCH, SIG_DFL); 837 signal(SIGWINCH, SIG_DFL);
862 838
863 /* Stop listening for connections. */ 839 /* Stop listening for connections. */
864 channel_stop_listening(); 840 channel_stop_listening();
865 841
866 /* In interactive mode (with pseudo tty) display a message indicating that 842 /* In interactive mode (with pseudo tty) display a message
867 the connection has been closed. */ 843 indicating that the connection has been closed. */
868 if (have_pty && options.log_level != SYSLOG_LEVEL_QUIET) 844 if (have_pty && options.log_level != SYSLOG_LEVEL_QUIET) {
869 { 845 snprintf(buf, sizeof buf, "Connection to %.64s closed.\r\n", host);
870 snprintf(buf, sizeof buf, "Connection to %.64s closed.\r\n", host); 846 buffer_append(&stderr_buffer, buf, strlen(buf));
871 buffer_append(&stderr_buffer, buf, strlen(buf)); 847 stderr_bytes += strlen(buf);
872 stderr_bytes += strlen(buf);
873 }
874
875 /* Output any buffered data for stdout. */
876 while (buffer_len(&stdout_buffer) > 0)
877 {
878 len = write(fileno(stdout), buffer_ptr(&stdout_buffer),
879 buffer_len(&stdout_buffer));
880 if (len <= 0)
881 {
882 error("Write failed flushing stdout buffer.");
883 break;
884 } 848 }
885 buffer_consume(&stdout_buffer, len); 849 /* Output any buffered data for stdout. */
886 } 850 while (buffer_len(&stdout_buffer) > 0) {
887 851 len = write(fileno(stdout), buffer_ptr(&stdout_buffer),
888 /* Output any buffered data for stderr. */ 852 buffer_len(&stdout_buffer));
889 while (buffer_len(&stderr_buffer) > 0) 853 if (len <= 0) {
890 { 854 error("Write failed flushing stdout buffer.");
891 len = write(fileno(stderr), buffer_ptr(&stderr_buffer), 855 break;
892 buffer_len(&stderr_buffer)); 856 }
893 if (len <= 0) 857 buffer_consume(&stdout_buffer, len);
894 {
895 error("Write failed flushing stderr buffer.");
896 break;
897 } 858 }
898 buffer_consume(&stderr_buffer, len); 859
899 } 860 /* Output any buffered data for stderr. */
900 861 while (buffer_len(&stderr_buffer) > 0) {
901 /* Leave raw mode. */ 862 len = write(fileno(stderr), buffer_ptr(&stderr_buffer),
902 if (have_pty) 863 buffer_len(&stderr_buffer));
903 leave_raw_mode(); 864 if (len <= 0) {
904 865 error("Write failed flushing stderr buffer.");
905 /* Clear and free any buffers. */ 866 break;
906 memset(buf, 0, sizeof(buf)); 867 }
907 buffer_free(&stdin_buffer); 868 buffer_consume(&stderr_buffer, len);
908 buffer_free(&stdout_buffer); 869 }
909 buffer_free(&stderr_buffer); 870
910 871 /* Leave raw mode. */
911 /* Report bytes transferred, and transfer rates. */ 872 if (have_pty)
912 total_time = get_current_time() - start_time; 873 leave_raw_mode();
913 debug("Transferred: stdin %lu, stdout %lu, stderr %lu bytes in %.1f seconds", 874
914 stdin_bytes, stdout_bytes, stderr_bytes, total_time); 875 /* Clear and free any buffers. */
915 if (total_time > 0) 876 memset(buf, 0, sizeof(buf));
916 debug("Bytes per second: stdin %.1f, stdout %.1f, stderr %.1f", 877 buffer_free(&stdin_buffer);
917 stdin_bytes / total_time, stdout_bytes / total_time, 878 buffer_free(&stdout_buffer);
918 stderr_bytes / total_time); 879 buffer_free(&stderr_buffer);
919 880
920 /* Return the exit status of the program. */ 881 /* Report bytes transferred, and transfer rates. */
921 debug("Exit status %d", exit_status); 882 total_time = get_current_time() - start_time;
922 return exit_status; 883 debug("Transferred: stdin %lu, stdout %lu, stderr %lu bytes in %.1f seconds",
884 stdin_bytes, stdout_bytes, stderr_bytes, total_time);
885 if (total_time > 0)
886 debug("Bytes per second: stdin %.1f, stdout %.1f, stderr %.1f",
887 stdin_bytes / total_time, stdout_bytes / total_time,
888 stderr_bytes / total_time);
889
890 /* Return the exit status of the program. */
891 debug("Exit status %d", exit_status);
892 return exit_status;
923} 893}
diff --git a/compat.c b/compat.c
index 4974b1cba..0935154c7 100644
--- a/compat.c
+++ b/compat.c
@@ -1,10 +1,13 @@
1#include "includes.h" 1#include "includes.h"
2RCSID("$Id: compat.c,v 1.1 1999/10/27 03:42:44 damien Exp $"); 2RCSID("$Id: compat.c,v 1.2 1999/11/24 13:26:22 damien Exp $");
3 3
4#include "ssh.h" 4#include "ssh.h"
5 5
6int compat13=0; 6int compat13 = 0;
7void enable_compat13(void){ 7
8 log("Enabling compatibility mode for protocol 1.3"); 8void
9 compat13=1; 9enable_compat13(void)
10{
11 verbose("Enabling compatibility mode for protocol 1.3");
12 compat13 = 1;
10} 13}
diff --git a/compat.h b/compat.h
index 9d896c7dd..4f6c10ff6 100644
--- a/compat.h
+++ b/compat.h
@@ -1,7 +1,7 @@
1/* RCSID("$Id: compat.h,v 1.1 1999/10/27 03:42:44 damien Exp $"); */ 1/* RCSID("$Id: compat.h,v 1.2 1999/11/24 13:26:22 damien Exp $"); */
2 2
3#ifndef COMPAT_H 3#ifndef COMPAT_H
4#define COMPAT_H 4#define COMPAT_H
5void enable_compat13(void); 5void enable_compat13(void);
6extern int compat13; 6extern int compat13;
7#endif 7#endif
diff --git a/compress.c b/compress.c
index c3267f73f..463e7374e 100644
--- a/compress.c
+++ b/compress.c
@@ -1,20 +1,20 @@
1/* 1/*
2 2 *
3compress.c 3 * compress.c
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Wed Oct 25 22:12:46 1995 ylo 10 * Created: Wed Oct 25 22:12:46 1995 ylo
11 11 *
12Interface to packet compression for ssh. 12 * Interface to packet compression for ssh.
13 13 *
14*/ 14 */
15 15
16#include "includes.h" 16#include "includes.h"
17RCSID("$Id: compress.c,v 1.1 1999/10/27 03:42:44 damien Exp $"); 17RCSID("$Id: compress.c,v 1.2 1999/11/24 13:26:22 damien Exp $");
18 18
19#include "ssh.h" 19#include "ssh.h"
20#include "buffer.h" 20#include "buffer.h"
@@ -23,32 +23,34 @@ RCSID("$Id: compress.c,v 1.1 1999/10/27 03:42:44 damien Exp $");
23static z_stream incoming_stream; 23static z_stream incoming_stream;
24static z_stream outgoing_stream; 24static z_stream outgoing_stream;
25 25
26/* Initializes compression; level is compression level from 1 to 9 (as in 26/* Initializes compression; level is compression level from 1 to 9
27 gzip). */ 27 (as in gzip). */
28 28
29void buffer_compress_init(int level) 29void
30buffer_compress_init(int level)
30{ 31{
31 debug("Enabling compression at level %d.", level); 32 debug("Enabling compression at level %d.", level);
32 if (level < 1 || level > 9) 33 if (level < 1 || level > 9)
33 fatal("Bad compression level %d.", level); 34 fatal("Bad compression level %d.", level);
34 inflateInit(&incoming_stream); 35 inflateInit(&incoming_stream);
35 deflateInit(&outgoing_stream, level); 36 deflateInit(&outgoing_stream, level);
36} 37}
37 38
38/* Frees any data structures allocated for compression. */ 39/* Frees any data structures allocated for compression. */
39 40
40void buffer_compress_uninit() 41void
42buffer_compress_uninit()
41{ 43{
42 debug("compress outgoing: raw data %lu, compressed %lu, factor %.2f", 44 debug("compress outgoing: raw data %lu, compressed %lu, factor %.2f",
43 outgoing_stream.total_in, outgoing_stream.total_out, 45 outgoing_stream.total_in, outgoing_stream.total_out,
44 outgoing_stream.total_in == 0 ? 0.0 : 46 outgoing_stream.total_in == 0 ? 0.0 :
45 (double)outgoing_stream.total_out / outgoing_stream.total_in); 47 (double) outgoing_stream.total_out / outgoing_stream.total_in);
46 debug("compress incoming: raw data %lu, compressed %lu, factor %.2f", 48 debug("compress incoming: raw data %lu, compressed %lu, factor %.2f",
47 incoming_stream.total_out, incoming_stream.total_in, 49 incoming_stream.total_out, incoming_stream.total_in,
48 incoming_stream.total_out == 0 ? 0.0 : 50 incoming_stream.total_out == 0 ? 0.0 :
49 (double)incoming_stream.total_in / incoming_stream.total_out); 51 (double) incoming_stream.total_in / incoming_stream.total_out);
50 inflateEnd(&incoming_stream); 52 inflateEnd(&incoming_stream);
51 deflateEnd(&outgoing_stream); 53 deflateEnd(&outgoing_stream);
52} 54}
53 55
54/* Compresses the contents of input_buffer into output_buffer. All 56/* Compresses the contents of input_buffer into output_buffer. All
@@ -59,50 +61,49 @@ void buffer_compress_uninit()
59 form a single compression stream) by the receiver. This appends 61 form a single compression stream) by the receiver. This appends
60 the compressed data to the output buffer. */ 62 the compressed data to the output buffer. */
61 63
62void buffer_compress(Buffer *input_buffer, Buffer *output_buffer) 64void
65buffer_compress(Buffer * input_buffer, Buffer * output_buffer)
63{ 66{
64 char buf[4096]; 67 char buf[4096];
65 int status; 68 int status;
66 69
67 /* This case is not handled below. */ 70 /* This case is not handled below. */
68 if (buffer_len(input_buffer) == 0) 71 if (buffer_len(input_buffer) == 0)
69 return; 72 return;
70 73
71 /* Input is the contents of the input buffer. */ 74 /* Input is the contents of the input buffer. */
72 outgoing_stream.next_in = buffer_ptr(input_buffer); 75 outgoing_stream.next_in = buffer_ptr(input_buffer);
73 outgoing_stream.avail_in = buffer_len(input_buffer); 76 outgoing_stream.avail_in = buffer_len(input_buffer);
74 77
75 /* Loop compressing until deflate() returns with avail_out != 0. */ 78 /* Loop compressing until deflate() returns with avail_out != 0. */
76 do 79 do {
77 { 80 /* Set up fixed-size output buffer. */
78 /* Set up fixed-size output buffer. */ 81 outgoing_stream.next_out = buf;
79 outgoing_stream.next_out = buf; 82 outgoing_stream.avail_out = sizeof(buf);
80 outgoing_stream.avail_out = sizeof(buf); 83
81 84 /* Compress as much data into the buffer as possible. */
82 /* Compress as much data into the buffer as possible. */ 85 status = deflate(&outgoing_stream, Z_PARTIAL_FLUSH);
83 status = deflate(&outgoing_stream, Z_PARTIAL_FLUSH); 86 switch (status) {
84 switch (status) 87 case Z_OK:
85 { 88 /* Append compressed data to output_buffer. */
86 case Z_OK: 89 buffer_append(output_buffer, buf,
87 /* Append compressed data to output_buffer. */ 90 sizeof(buf) - outgoing_stream.avail_out);
88 buffer_append(output_buffer, buf, 91 break;
89 sizeof(buf) - outgoing_stream.avail_out); 92 case Z_STREAM_END:
90 break; 93 fatal("buffer_compress: deflate returned Z_STREAM_END");
91 case Z_STREAM_END: 94 /* NOTREACHED */
92 fatal("buffer_compress: deflate returned Z_STREAM_END"); 95 case Z_STREAM_ERROR:
93 /*NOTREACHED*/ 96 fatal("buffer_compress: deflate returned Z_STREAM_ERROR");
94 case Z_STREAM_ERROR: 97 /* NOTREACHED */
95 fatal("buffer_compress: deflate returned Z_STREAM_ERROR"); 98 case Z_BUF_ERROR:
96 /*NOTREACHED*/ 99 fatal("buffer_compress: deflate returned Z_BUF_ERROR");
97 case Z_BUF_ERROR: 100 /* NOTREACHED */
98 fatal("buffer_compress: deflate returned Z_BUF_ERROR"); 101 default:
99 /*NOTREACHED*/ 102 fatal("buffer_compress: deflate returned %d", status);
100 default: 103 /* NOTREACHED */
101 fatal("buffer_compress: deflate returned %d", status); 104 }
102 /*NOTREACHED*/
103 } 105 }
104 } 106 while (outgoing_stream.avail_out == 0);
105 while (outgoing_stream.avail_out == 0);
106} 107}
107 108
108/* Uncompresses the contents of input_buffer into output_buffer. All 109/* Uncompresses the contents of input_buffer into output_buffer. All
@@ -113,48 +114,46 @@ void buffer_compress(Buffer *input_buffer, Buffer *output_buffer)
113 same order that buffers compressed with that. This appends the 114 same order that buffers compressed with that. This appends the
114 uncompressed data to the output buffer. */ 115 uncompressed data to the output buffer. */
115 116
116void buffer_uncompress(Buffer *input_buffer, Buffer *output_buffer) 117void
118buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer)
117{ 119{
118 char buf[4096]; 120 char buf[4096];
119 int status; 121 int status;
120 122
121 incoming_stream.next_in = buffer_ptr(input_buffer); 123 incoming_stream.next_in = buffer_ptr(input_buffer);
122 incoming_stream.avail_in = buffer_len(input_buffer); 124 incoming_stream.avail_in = buffer_len(input_buffer);
123 125
124 incoming_stream.next_out = buf; 126 incoming_stream.next_out = buf;
125 incoming_stream.avail_out = sizeof(buf); 127 incoming_stream.avail_out = sizeof(buf);
126 128
127 for (;;) 129 for (;;) {
128 { 130 status = inflate(&incoming_stream, Z_PARTIAL_FLUSH);
129 status = inflate(&incoming_stream, Z_PARTIAL_FLUSH); 131 switch (status) {
130 switch (status) 132 case Z_OK:
131 { 133 buffer_append(output_buffer, buf,
132 case Z_OK: 134 sizeof(buf) - incoming_stream.avail_out);
133 buffer_append(output_buffer, buf, 135 incoming_stream.next_out = buf;
134 sizeof(buf) - incoming_stream.avail_out); 136 incoming_stream.avail_out = sizeof(buf);
135 incoming_stream.next_out = buf; 137 break;
136 incoming_stream.avail_out = sizeof(buf); 138 case Z_STREAM_END:
137 break; 139 fatal("buffer_uncompress: inflate returned Z_STREAM_END");
138 case Z_STREAM_END: 140 /* NOTREACHED */
139 fatal("buffer_uncompress: inflate returned Z_STREAM_END"); 141 case Z_DATA_ERROR:
140 /*NOTREACHED*/ 142 fatal("buffer_uncompress: inflate returned Z_DATA_ERROR");
141 case Z_DATA_ERROR: 143 /* NOTREACHED */
142 fatal("buffer_uncompress: inflate returned Z_DATA_ERROR"); 144 case Z_STREAM_ERROR:
143 /*NOTREACHED*/ 145 fatal("buffer_uncompress: inflate returned Z_STREAM_ERROR");
144 case Z_STREAM_ERROR: 146 /* NOTREACHED */
145 fatal("buffer_uncompress: inflate returned Z_STREAM_ERROR"); 147 case Z_BUF_ERROR:
146 /*NOTREACHED*/ 148 /* Comments in zlib.h say that we should keep
147 case Z_BUF_ERROR: 149 calling inflate() until we get an error. This
148 /* Comments in zlib.h say that we should keep calling inflate() 150 appears to be the error that we get. */
149 until we get an error. This appears to be the error that we 151 return;
150 get. */ 152 case Z_MEM_ERROR:
151 return; 153 fatal("buffer_uncompress: inflate returned Z_MEM_ERROR");
152 case Z_MEM_ERROR: 154 /* NOTREACHED */
153 fatal("buffer_uncompress: inflate returned Z_MEM_ERROR"); 155 default:
154 /*NOTREACHED*/ 156 fatal("buffer_uncompress: inflate returned %d", status);
155 default: 157 }
156 fatal("buffer_uncompress: inflate returned %d", status);
157 } 158 }
158 }
159} 159}
160
diff --git a/compress.h b/compress.h
index b3144d621..e028f71a5 100644
--- a/compress.h
+++ b/compress.h
@@ -1,29 +1,29 @@
1/* 1/*
2 2 *
3compress.h 3 * compress.h
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Wed Oct 25 22:12:46 1995 ylo 10 * Created: Wed Oct 25 22:12:46 1995 ylo
11 11 *
12Interface to packet compression for ssh. 12 * Interface to packet compression for ssh.
13 13 *
14*/ 14 */
15 15
16/* RCSID("$Id: compress.h,v 1.1 1999/10/27 03:42:44 damien Exp $"); */ 16/* RCSID("$Id: compress.h,v 1.2 1999/11/24 13:26:22 damien Exp $"); */
17 17
18#ifndef COMPRESS_H 18#ifndef COMPRESS_H
19#define COMPRESS_H 19#define COMPRESS_H
20 20
21/* Initializes compression; level is compression level from 1 to 9 (as in 21/* Initializes compression; level is compression level from 1 to 9 (as in
22 gzip). */ 22 gzip). */
23void buffer_compress_init(int level); 23void buffer_compress_init(int level);
24 24
25/* Frees any data structures allocated by buffer_compress_init. */ 25/* Frees any data structures allocated by buffer_compress_init. */
26void buffer_compress_uninit(); 26void buffer_compress_uninit();
27 27
28/* Compresses the contents of input_buffer into output_buffer. All 28/* Compresses the contents of input_buffer into output_buffer. All
29 packets compressed using this function will form a single 29 packets compressed using this function will form a single
@@ -32,7 +32,7 @@ void buffer_compress_uninit();
32 independently (but in the appropriate order since they together 32 independently (but in the appropriate order since they together
33 form a single compression stream) by the receiver. This appends 33 form a single compression stream) by the receiver. This appends
34 the compressed data to the output buffer. */ 34 the compressed data to the output buffer. */
35void buffer_compress(Buffer *input_buffer, Buffer *output_buffer); 35void buffer_compress(Buffer * input_buffer, Buffer * output_buffer);
36 36
37/* Uncompresses the contents of input_buffer into output_buffer. All 37/* Uncompresses the contents of input_buffer into output_buffer. All
38 packets uncompressed using this function will form a single 38 packets uncompressed using this function will form a single
@@ -41,6 +41,6 @@ void buffer_compress(Buffer *input_buffer, Buffer *output_buffer);
41 same size units that the buffer_compress was called, and in the 41 same size units that the buffer_compress was called, and in the
42 same order that buffers compressed with that. This appends the 42 same order that buffers compressed with that. This appends the
43 uncompressed data to the output buffer. */ 43 uncompressed data to the output buffer. */
44void buffer_uncompress(Buffer *input_buffer, Buffer *output_buffer); 44void buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer);
45 45
46#endif /* COMPRESS_H */ 46#endif /* COMPRESS_H */
diff --git a/configure.in b/configure.in
index 73635272a..9f545d733 100644
--- a/configure.in
+++ b/configure.in
@@ -55,7 +55,7 @@ AC_CHECK_LIB(dl, dlopen, , )
55AC_CHECK_LIB(pam, pam_authenticate, , ) 55AC_CHECK_LIB(pam, pam_authenticate, , )
56 56
57dnl Checks for header files. 57dnl Checks for header files.
58AC_CHECK_HEADERS(pty.h endian.h paths.h lastlog.h shadow.h netgroup.h maillock.h utmp.h sys/select.h sys/time.h) 58AC_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)
59 59
60dnl Checks for library functions. 60dnl Checks for library functions.
61AC_CHECK_FUNCS(openpty strlcpy strlcat mkdtemp arc4random setproctitle setlogin setenv) 61AC_CHECK_FUNCS(openpty strlcpy strlcat mkdtemp arc4random setproctitle setlogin setenv)
diff --git a/crc32.c b/crc32.c
index dbb1e6b7b..2d3867d0b 100644
--- a/crc32.c
+++ b/crc32.c
@@ -1,9 +1,12 @@
1/* The implementation here was originally done by Gary S. Brown. I have 1/*
2 borrowed the tables directly, and made some minor changes to the 2 * The implementation here was originally done by Gary S. Brown.
3 crc32-function (including changing the interface). //ylo */ 3 * I have borrowed the tables directly, and made some minor changes
4 * to the crc32-function (including changing the interface).
5 * //ylo
6 */
4 7
5#include "includes.h" 8#include "includes.h"
6RCSID("$Id: crc32.c,v 1.1 1999/10/27 03:42:44 damien Exp $"); 9RCSID("$Id: crc32.c,v 1.2 1999/11/24 13:26:22 damien Exp $");
7 10
8#include "crc32.h" 11#include "crc32.h"
9 12
@@ -48,73 +51,71 @@ RCSID("$Id: crc32.c,v 1.1 1999/10/27 03:42:44 damien Exp $");
48 /* -------------------------------------------------------------------- */ 51 /* -------------------------------------------------------------------- */
49 52
50static unsigned int crc32_tab[] = { 53static unsigned int crc32_tab[] = {
51 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 54 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
52 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, 55 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
53 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 56 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
54 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 57 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
55 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, 58 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
56 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 59 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
57 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 60 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
58 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, 61 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
59 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 62 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
60 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, 63 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
61 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 64 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
62 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 65 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
63 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, 66 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
64 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 67 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
65 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 68 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
66 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, 69 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
67 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 70 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
68 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, 71 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
69 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 72 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
70 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 73 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
71 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, 74 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
72 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 75 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
73 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 76 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
74 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, 77 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
75 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 78 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
76 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, 79 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
77 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 80 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
78 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 81 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
79 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, 82 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
80 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 83 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
81 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 84 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
82 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, 85 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
83 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 86 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
84 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, 87 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
85 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 88 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
86 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 89 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
87 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, 90 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
88 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 91 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
89 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 92 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
90 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, 93 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
91 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 94 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
92 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, 95 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
93 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 96 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
94 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 97 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
95 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, 98 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
96 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 99 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
97 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 100 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
98 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 101 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
99 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 102 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
100 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, 103 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
101 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 104 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
102 0x2d02ef8dL 105 0x2d02ef8dL
103 }; 106};
104 107
105/* Return a 32-bit CRC of the contents of the buffer. */ 108/* Return a 32-bit CRC of the contents of the buffer. */
106 109
107unsigned int crc32(const unsigned char *s, unsigned int len) 110unsigned int
111crc32(const unsigned char *s, unsigned int len)
108{ 112{
109 unsigned int i; 113 unsigned int i;
110 unsigned int crc32val; 114 unsigned int crc32val;
111 115
112 crc32val = 0; 116 crc32val = 0;
113 for (i = 0; i < len; i ++) 117 for (i = 0; i < len; i ++) {
114 { 118 crc32val = crc32_tab[(crc32val ^ s[i]) & 0xff] ^ (crc32val >> 8);
115 crc32val = 119 }
116 crc32_tab[(crc32val ^ s[i]) & 0xff] ^ 120 return crc32val;
117 (crc32val >> 8);
118 }
119 return crc32val;
120} 121}
diff --git a/crc32.h b/crc32.h
index 456b20b86..6aa3aa620 100644
--- a/crc32.h
+++ b/crc32.h
@@ -1,19 +1,19 @@
1/* 1/*
2 2 *
3crc32.h 3 * crc32.h
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1992 Tatu Ylonen, Espoo, Finland 7 * Copyright (c) 1992 Tatu Ylonen, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Tue Feb 11 14:37:27 1992 ylo 10 * Created: Tue Feb 11 14:37:27 1992 ylo
11 11 *
12Functions for computing 32-bit CRC. 12 * Functions for computing 32-bit CRC.
13 13 *
14*/ 14 */
15 15
16/* RCSID("$Id: crc32.h,v 1.1 1999/10/27 03:42:44 damien Exp $"); */ 16/* RCSID("$Id: crc32.h,v 1.2 1999/11/24 13:26:22 damien Exp $"); */
17 17
18#ifndef CRC32_H 18#ifndef CRC32_H
19#define CRC32_H 19#define CRC32_H
@@ -22,4 +22,4 @@ Functions for computing 32-bit CRC.
22 CRC. The polynomial used is 0xedb88320. */ 22 CRC. The polynomial used is 0xedb88320. */
23unsigned int crc32(const unsigned char *buf, unsigned int len); 23unsigned int crc32(const unsigned char *buf, unsigned int len);
24 24
25#endif /* CRC32_H */ 25#endif /* CRC32_H */
diff --git a/deattack.c b/deattack.c
index afd96e4e4..81b1c8efb 100644
--- a/deattack.c
+++ b/deattack.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * $Id: deattack.c,v 1.2 1999/11/08 05:15:55 damien Exp $ 2 * $Id: deattack.c,v 1.3 1999/11/24 13:26:22 damien Exp $
3 * Cryptographic attack detector for ssh - source code 3 * Cryptographic attack detector for ssh - source code
4 * 4 *
5 * Copyright (c) 1998 CORE SDI S.A., Buenos Aires, Argentina. 5 * Copyright (c) 1998 CORE SDI S.A., Buenos Aires, Argentina.
@@ -15,7 +15,8 @@
15 * SOFTWARE. 15 * SOFTWARE.
16 * 16 *
17 * Ariel Futoransky <futo@core-sdi.com> 17 * Ariel Futoransky <futo@core-sdi.com>
18 * <http://www.core-sdi.com> */ 18 * <http://www.core-sdi.com>
19 */
19 20
20#include "includes.h" 21#include "includes.h"
21#include "deattack.h" 22#include "deattack.h"
@@ -25,157 +26,130 @@
25#include "xmalloc.h" 26#include "xmalloc.h"
26 27
27/* SSH Constants */ 28/* SSH Constants */
28#define SSH_MAXBLOCKS (32 * 1024) 29#define SSH_MAXBLOCKS (32 * 1024)
29#define SSH_BLOCKSIZE (8) 30#define SSH_BLOCKSIZE (8)
30 31
31/* Hashing constants */ 32/* Hashing constants */
32#define HASH_MINSIZE (8 * 1024) 33#define HASH_MINSIZE (8 * 1024)
33#define HASH_ENTRYSIZE (2) 34#define HASH_ENTRYSIZE (2)
34#define HASH_FACTOR(x) ((x)*3/2) 35#define HASH_FACTOR(x) ((x)*3/2)
35#define HASH_UNUSEDCHAR (0xff) 36#define HASH_UNUSEDCHAR (0xff)
36#define HASH_UNUSED (0xffff) 37#define HASH_UNUSED (0xffff)
37#define HASH_IV (0xfffe) 38#define HASH_IV (0xfffe)
38 39
39#define HASH_MINBLOCKS (7*SSH_BLOCKSIZE) 40#define HASH_MINBLOCKS (7*SSH_BLOCKSIZE)
40 41
41 42
42/* Hash function (Input keys are cipher results) */ 43/* Hash function (Input keys are cipher results) */
43#define HASH(x) GET_32BIT(x) 44#define HASH(x) GET_32BIT(x)
44 45
45#define CMP(a,b) (memcmp(a, b, SSH_BLOCKSIZE)) 46#define CMP(a,b) (memcmp(a, b, SSH_BLOCKSIZE))
46 47
47 48
48void 49void
49crc_update(u_int32_t * a, u_int32_t b) 50crc_update(u_int32_t *a, u_int32_t b)
50{ 51{
51 b ^= *a; 52 b ^= *a;
52 *a = crc32((unsigned char *) &b, sizeof(b)); 53 *a = crc32((unsigned char *) &b, sizeof(b));
53} 54}
54 55
55/* 56/* detect if a block is used in a particular pattern */
56 check_crc
57 detects if a block is used in a particular pattern
58 */
59
60int 57int
61check_crc(unsigned char *S, unsigned char *buf, u_int32_t len, unsigned char *IV) 58check_crc(unsigned char *S, unsigned char *buf, u_int32_t len,
59 unsigned char *IV)
62{ 60{
63 u_int32_t crc; 61 u_int32_t crc;
64 unsigned char *c; 62 unsigned char *c;
65 63
66 crc = 0; 64 crc = 0;
67 if (IV && !CMP(S, IV)) 65 if (IV && !CMP(S, IV)) {
68 { 66 crc_update(&crc, 1);
69 crc_update(&crc, 1); 67 crc_update(&crc, 0);
70 crc_update(&crc, 0); 68 }
71 } 69 for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) {
72 for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) 70 if (!CMP(S, c)) {
73 { 71 crc_update(&crc, 1);
74 if (!CMP(S, c)) 72 crc_update(&crc, 0);
75 { 73 } else {
76 crc_update(&crc, 1); 74 crc_update(&crc, 0);
77 crc_update(&crc, 0); 75 crc_update(&crc, 0);
78 } else 76 }
79 { 77 }
80 crc_update(&crc, 0); 78 return (crc == 0);
81 crc_update(&crc, 0);
82 }
83 }
84
85 return (crc == 0);
86} 79}
87 80
88 81
89/* 82/* Detect a crc32 compensation attack on a packet */
90 detect_attack
91 Detects a crc32 compensation attack on a packet
92 */
93int 83int
94detect_attack(unsigned char *buf, u_int32_t len, unsigned char *IV) 84detect_attack(unsigned char *buf, u_int32_t len, unsigned char *IV)
95{ 85{
96 static u_int16_t *h = (u_int16_t *) NULL; 86 static u_int16_t *h = (u_int16_t *) NULL;
97 static u_int16_t n = HASH_MINSIZE / HASH_ENTRYSIZE; 87 static u_int16_t n = HASH_MINSIZE / HASH_ENTRYSIZE;
98 register u_int32_t i, j; 88 register u_int32_t i, j;
99 u_int32_t l; 89 u_int32_t l;
100 register unsigned char *c; 90 register unsigned char *c;
101 unsigned char *d; 91 unsigned char *d;
102 92
103 if (len > (SSH_MAXBLOCKS * SSH_BLOCKSIZE) || 93 if (len > (SSH_MAXBLOCKS * SSH_BLOCKSIZE) ||
104 len % SSH_BLOCKSIZE != 0) { 94 len % SSH_BLOCKSIZE != 0) {
105 fatal("detect_attack: bad length %d", len); 95 fatal("detect_attack: bad length %d", len);
106 } 96 }
107 97 for (l = n; l < HASH_FACTOR(len / SSH_BLOCKSIZE); l = l << 2)
108 for (l = n; l < HASH_FACTOR(len / SSH_BLOCKSIZE); l = l << 2); 98 ;
109 99
110 if (h == NULL) 100 if (h == NULL) {
111 { 101 debug("Installing crc compensation attack detector.");
112 debug("Installing crc compensation attack detector."); 102 n = l;
113 n = l; 103 h = (u_int16_t *) xmalloc(n * HASH_ENTRYSIZE);
114 h = (u_int16_t *) xmalloc(n * HASH_ENTRYSIZE); 104 } else {
115 } else 105 if (l > n) {
116 { 106 n = l;
117 if (l > n) 107 h = (u_int16_t *) xrealloc(h, n * HASH_ENTRYSIZE);
118 { 108 }
119 n = l; 109 }
120 h = (u_int16_t *) xrealloc(h, n * HASH_ENTRYSIZE); 110
121 } 111 if (len <= HASH_MINBLOCKS) {
122 } 112 for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) {
123 113 if (IV && (!CMP(c, IV))) {
124 114 if ((check_crc(c, buf, len, IV)))
125 if (len <= HASH_MINBLOCKS) 115 return (DEATTACK_DETECTED);
126 { 116 else
127 for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) 117 break;
128 { 118 }
129 if (IV && (!CMP(c, IV))) 119 for (d = buf; d < c; d += SSH_BLOCKSIZE) {
130 { 120 if (!CMP(c, d)) {
131 if ((check_crc(c, buf, len, IV))) 121 if ((check_crc(c, buf, len, IV)))
132 return (DEATTACK_DETECTED); 122 return (DEATTACK_DETECTED);
133 else 123 else
134 break; 124 break;
135 } 125 }
136 for (d = buf; d < c; d += SSH_BLOCKSIZE) 126 }
137 { 127 }
138 if (!CMP(c, d)) 128 return (DEATTACK_OK);
139 {
140 if ((check_crc(c, buf, len, IV)))
141 return (DEATTACK_DETECTED);
142 else
143 break;
144 } 129 }
145 } 130 memset(h, HASH_UNUSEDCHAR, n * HASH_ENTRYSIZE);
146 } 131
147 return (DEATTACK_OK); 132 if (IV)
148 } 133 h[HASH(IV) & (n - 1)] = HASH_IV;
149 memset(h, HASH_UNUSEDCHAR, n * HASH_ENTRYSIZE); 134
150 135 for (c = buf, j = 0; c < (buf + len); c += SSH_BLOCKSIZE, j++) {
151 if (IV) 136 for (i = HASH(c) & (n - 1); h[i] != HASH_UNUSED;
152 h[HASH(IV) & (n - 1)] = HASH_IV; 137 i = (i + 1) & (n - 1)) {
153 138 if (h[i] == HASH_IV) {
154 139 if (!CMP(c, IV)) {
155 for (c = buf, j = 0; c < (buf + len); c += SSH_BLOCKSIZE, j++) 140 if (check_crc(c, buf, len, IV))
156 { 141 return (DEATTACK_DETECTED);
157 for (i = HASH(c) & (n - 1); h[i] != HASH_UNUSED; 142 else
158 i = (i + 1) & (n - 1)) 143 break;
159 { 144 }
160 if (h[i] == HASH_IV) 145 } else if (!CMP(c, buf + h[i] * SSH_BLOCKSIZE)) {
161 { 146 if (check_crc(c, buf, len, IV))
162 if (!CMP(c, IV)) 147 return (DEATTACK_DETECTED);
163 { 148 else
164 if (check_crc(c, buf, len, IV)) 149 break;
165 return (DEATTACK_DETECTED); 150 }
166 else 151 }
167 break; 152 h[i] = j;
168 } 153 }
169 } else if (!CMP(c, buf + h[i] * SSH_BLOCKSIZE)) 154 return (DEATTACK_OK);
170 {
171 if (check_crc(c, buf, len, IV))
172 return (DEATTACK_DETECTED);
173 else
174 break;
175 }
176 }
177 h[i] = j;
178 }
179
180 return (DEATTACK_OK);
181} 155}
diff --git a/deattack.h b/deattack.h
index a0dcf5b6f..6ce54dedb 100644
--- a/deattack.h
+++ b/deattack.h
@@ -1,4 +1,4 @@
1/* $Id: deattack.h,v 1.1 1999/10/27 03:42:44 damien Exp $ 1/*
2 * Cryptographic attack detector for ssh - Header file 2 * Cryptographic attack detector for ssh - Header file
3 * 3 *
4 * Copyright (c) 1998 CORE SDI S.A., Buenos Aires, Argentina. 4 * Copyright (c) 1998 CORE SDI S.A., Buenos Aires, Argentina.
@@ -14,7 +14,8 @@
14 * SOFTWARE. 14 * SOFTWARE.
15 * 15 *
16 * Ariel Futoransky <futo@core-sdi.com> 16 * Ariel Futoransky <futo@core-sdi.com>
17 * <http://www.core-sdi.com> */ 17 * <http://www.core-sdi.com>
18 */
18 19
19#ifndef _DEATTACK_H 20#ifndef _DEATTACK_H
20#define _DEATTACK_H 21#define _DEATTACK_H
@@ -23,5 +24,5 @@
23#define DEATTACK_OK 0 24#define DEATTACK_OK 0
24#define DEATTACK_DETECTED 1 25#define DEATTACK_DETECTED 1
25 26
26int detect_attack(unsigned char *buf, u_int32_t len, unsigned char IV[8]); 27int detect_attack(unsigned char *buf, u_int32_t len, unsigned char IV[8]);
27#endif 28#endif
diff --git a/fingerprint.c b/fingerprint.c
index 9a9b63583..54fc7e9b0 100644
--- a/fingerprint.c
+++ b/fingerprint.c
@@ -1,5 +1,5 @@
1#include "includes.h" 1#include "includes.h"
2RCSID("$Id: fingerprint.c,v 1.1 1999/11/17 06:29:08 damien Exp $"); 2RCSID("$Id: fingerprint.c,v 1.3 1999/11/24 00:26:01 deraadt Exp $");
3 3
4#include "ssh.h" 4#include "ssh.h"
5#include "xmalloc.h" 5#include "xmalloc.h"
@@ -13,17 +13,18 @@ RCSID("$Id: fingerprint.c,v 1.1 1999/11/17 06:29:08 damien Exp $");
13 13
14#define FPRINT "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x" 14#define FPRINT "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
15 15
16/* Generate key fingerprint in ascii format. 16/*
17 Based on ideas and code from Bjoern Groenvall <bg@sics.se> */ 17 * Generate key fingerprint in ascii format.
18 18 * Based on ideas and code from Bjoern Groenvall <bg@sics.se>
19 */
19char * 20char *
20fingerprint(BIGNUM *e, BIGNUM *n) 21fingerprint(BIGNUM *e, BIGNUM *n)
21{ 22{
22 static char retval[80]; 23 static char retval[80];
23 MD5_CTX md; 24 MD5_CTX md;
24 unsigned char d[16]; 25 unsigned char d[16];
25 char *buf; 26 char *buf;
26 int nlen, elen; 27 int nlen, elen;
27 28
28 nlen = BN_num_bytes(n); 29 nlen = BN_num_bytes(n);
29 elen = BN_num_bytes(e); 30 elen = BN_num_bytes(e);
@@ -37,8 +38,8 @@ fingerprint(BIGNUM *e, BIGNUM *n)
37 MD5_Update(&md, buf, nlen + elen); 38 MD5_Update(&md, buf, nlen + elen);
38 MD5_Final(d, &md); 39 MD5_Final(d, &md);
39 snprintf(retval, sizeof(retval), FPRINT, 40 snprintf(retval, sizeof(retval), FPRINT,
40 d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], 41 d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7],
41 d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]); 42 d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
42 memset(buf, 0, nlen + elen); 43 memset(buf, 0, nlen + elen);
43 xfree(buf); 44 xfree(buf);
44 return retval; 45 return retval;
diff --git a/fingerprint.h b/fingerprint.h
index c4ec22fc4..8c603aa16 100644
--- a/fingerprint.h
+++ b/fingerprint.h
@@ -1,6 +1,6 @@
1/* RCSID("$Id: fingerprint.h,v 1.1 1999/11/16 22:49:28 markus Exp $"); */ 1/* RCSID("$Id: fingerprint.h,v 1.2 1999/11/24 00:26:02 deraadt Exp $"); */
2 2
3#ifndef FINGERPRINT_H 3#ifndef FINGERPRINT_H
4#define FINGERPRINT_H 4#define FINGERPRINT_H
5char * fingerprint(BIGNUM *e, BIGNUM *n); 5char *fingerprint(BIGNUM * e, BIGNUM * n);
6#endif 6#endif
diff --git a/getput.h b/getput.h
index 7b5d74252..9ab5a22c1 100644
--- a/getput.h
+++ b/getput.h
@@ -1,19 +1,19 @@
1/* 1/*
2 2 *
3getput.h 3 * getput.h
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Wed Jun 28 22:36:30 1995 ylo 10 * Created: Wed Jun 28 22:36:30 1995 ylo
11 11 *
12Macros for storing and retrieving data in msb first and lsb first order. 12 * Macros for storing and retrieving data in msb first and lsb first order.
13 13 *
14*/ 14 */
15 15
16/* RCSID("$Id: getput.h,v 1.1 1999/10/27 03:42:44 damien Exp $"); */ 16/* RCSID("$Id: getput.h,v 1.2 1999/11/24 13:26:22 damien Exp $"); */
17 17
18#ifndef GETPUT_H 18#ifndef GETPUT_H
19#define GETPUT_H 19#define GETPUT_H
@@ -60,5 +60,4 @@ Macros for storing and retrieving data in msb first and lsb first order.
60 (cp)[0] = (value); \ 60 (cp)[0] = (value); \
61 (cp)[1] = (value) >> 8; } while (0) 61 (cp)[1] = (value) >> 8; } while (0)
62 62
63#endif /* GETPUT_H */ 63#endif /* GETPUT_H */
64
diff --git a/hostfile.c b/hostfile.c
index de21c904e..61046f071 100644
--- a/hostfile.c
+++ b/hostfile.c
@@ -1,20 +1,20 @@
1/* 1/*
2 2 *
3hostfile.c 3 * hostfile.c
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Thu Jun 29 07:10:56 1995 ylo 10 * Created: Thu Jun 29 07:10:56 1995 ylo
11 11 *
12Functions for manipulating the known hosts files. 12 * Functions for manipulating the known hosts files.
13 13 *
14*/ 14 */
15 15
16#include "includes.h" 16#include "includes.h"
17RCSID("$Id: hostfile.c,v 1.4 1999/11/17 06:29:08 damien Exp $"); 17RCSID("$Id: hostfile.c,v 1.5 1999/11/24 13:26:22 damien Exp $");
18 18
19#include "packet.h" 19#include "packet.h"
20#include "ssh.h" 20#include "ssh.h"
@@ -26,140 +26,136 @@ RCSID("$Id: hostfile.c,v 1.4 1999/11/17 06:29:08 damien Exp $");
26 modify the buffer containing the number. */ 26 modify the buffer containing the number. */
27 27
28int 28int
29auth_rsa_read_bignum(char **cpp, BIGNUM *value) 29auth_rsa_read_bignum(char **cpp, BIGNUM * value)
30{ 30{
31 char *cp = *cpp; 31 char *cp = *cpp;
32 int len, old; 32 int len, old;
33
34 /* Skip any leading whitespace. */
35 for (; *cp == ' ' || *cp == '\t'; cp++);
33 36
34 /* Skip any leading whitespace. */ 37 /* Check that it begins with a hex digit. */
35 for (; *cp == ' ' || *cp == '\t'; cp++) 38 if (*cp < '0' || *cp > '9')
36 ; 39 return 0;
37 40
38 /* Check that it begins with a hex digit. */ 41 /* Save starting position. */
39 if (*cp < '0' || *cp > '9') 42 *cpp = cp;
40 return 0;
41 43
42 /* Save starting position. */ 44 /* Move forward until all hex digits skipped. */
43 *cpp = cp; 45 for (; *cp >= '0' && *cp <= '9'; cp++);
44 46
45 /* Move forward until all hex digits skipped. */ 47 /* Compute the length of the hex number. */
46 for (; *cp >= '0' && *cp <= '9'; cp++) 48 len = cp - *cpp;
47 ;
48 49
49 /* Compute the length of the hex number. */ 50 /* Save the old terminating character, and replace it by \0. */
50 len = cp - *cpp; 51 old = *cp;
52 *cp = 0;
51 53
52 /* Save the old terminating character, and replace it by \0. */
53 old = *cp;
54 *cp = 0;
55 54
56 55 /* Parse the number. */
57 /* Parse the number. */ 56 if (BN_dec2bn(&value, *cpp) == 0)
58 if (BN_dec2bn(&value, *cpp) == 0) 57 return 0;
59 return 0;
60 58
61 /* Restore old terminating character. */ 59 /* Restore old terminating character. */
62 *cp = old; 60 *cp = old;
63 61
64 /* Move beyond the number and return success. */ 62 /* Move beyond the number and return success. */
65 *cpp = cp; 63 *cpp = cp;
66 return 1; 64 return 1;
67} 65}
68 66
69/* Parses an RSA key (number of bits, e, n) from a string. Moves the pointer 67/* Parses an RSA key (number of bits, e, n) from a string. Moves the pointer
70 over the key. Skips any whitespace at the beginning and at end. */ 68 over the key. Skips any whitespace at the beginning and at end. */
71 69
72int 70int
73auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM *e, BIGNUM *n) 71auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n)
74{ 72{
75 unsigned int bits; 73 unsigned int bits;
76 char *cp; 74 char *cp;
77 75
78 /* Skip leading whitespace. */ 76 /* Skip leading whitespace. */
79 for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++) 77 for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++);
80 ; 78
81 79 /* Get number of bits. */
82 /* Get number of bits. */ 80 if (*cp < '0' || *cp > '9')
83 if (*cp < '0' || *cp > '9') 81 return 0; /* Bad bit count... */
84 return 0; /* Bad bit count... */ 82 for (bits = 0; *cp >= '0' && *cp <= '9'; cp++)
85 for (bits = 0; *cp >= '0' && *cp <= '9'; cp++) 83 bits = 10 * bits + *cp - '0';
86 bits = 10 * bits + *cp - '0'; 84
87 85 /* Get public exponent. */
88 /* Get public exponent. */ 86 if (!auth_rsa_read_bignum(&cp, e))
89 if (!auth_rsa_read_bignum(&cp, e)) 87 return 0;
90 return 0; 88
91 89 /* Get public modulus. */
92 /* Get public modulus. */ 90 if (!auth_rsa_read_bignum(&cp, n))
93 if (!auth_rsa_read_bignum(&cp, n)) 91 return 0;
94 return 0; 92
95 93 /* Skip trailing whitespace. */
96 /* Skip trailing whitespace. */ 94 for (; *cp == ' ' || *cp == '\t'; cp++);
97 for (; *cp == ' ' || *cp == '\t'; cp++) 95
98 ; 96 /* Return results. */
99 97 *cpp = cp;
100 /* Return results. */ 98 *bitsp = bits;
101 *cpp = cp; 99 return 1;
102 *bitsp = bits;
103 return 1;
104} 100}
105 101
106/* Tries to match the host name (which must be in all lowercase) against the 102/* Tries to match the host name (which must be in all lowercase) against the
107 comma-separated sequence of subpatterns (each possibly preceded by ! to 103 comma-separated sequence of subpatterns (each possibly preceded by ! to
108 indicate negation). Returns true if there is a positive match; zero 104 indicate negation). Returns true if there is a positive match; zero
109 otherwise. */ 105 otherwise. */
110 106
111int 107int
112match_hostname(const char *host, const char *pattern, unsigned int len) 108match_hostname(const char *host, const char *pattern, unsigned int len)
113{ 109{
114 char sub[1024]; 110 char sub[1024];
115 int negated; 111 int negated;
116 int got_positive; 112 int got_positive;
117 unsigned int i, subi; 113 unsigned int i, subi;
118 114
119 got_positive = 0; 115 got_positive = 0;
120 for (i = 0; i < len;) 116 for (i = 0; i < len;) {
121 { 117 /* Check if the subpattern is negated. */
122 /* Check if the subpattern is negated. */ 118 if (pattern[i] == '!') {
123 if (pattern[i] == '!') 119 negated = 1;
124 { 120 i++;
125 negated = 1; 121 } else
126 i++; 122 negated = 0;
123
124 /* Extract the subpattern up to a comma or end. Convert
125 the subpattern to lowercase. */
126 for (subi = 0;
127 i < len && subi < sizeof(sub) - 1 && pattern[i] != ',';
128 subi++, i++)
129 sub[subi] = isupper(pattern[i]) ? tolower(pattern[i]) : pattern[i];
130 /* If subpattern too long, return failure (no match). */
131 if (subi >= sizeof(sub) - 1)
132 return 0;
133
134 /* If the subpattern was terminated by a comma, skip the
135 comma. */
136 if (i < len && pattern[i] == ',')
137 i++;
138
139 /* Null-terminate the subpattern. */
140 sub[subi] = '\0';
141
142 /* Try to match the subpattern against the host name. */
143 if (match_pattern(host, sub)) {
144 if (negated)
145 return 0; /* Fail if host matches
146 any negated subpattern. */
147 else
148 got_positive = 1;
149 }
127 } 150 }
128 else 151
129 negated = 0; 152 /* Return success if got a positive match. If there was a
130 153 negative match, we have already returned zero and never get
131 /* Extract the subpattern up to a comma or end. Convert the subpattern 154 here. */
132 to lowercase. */ 155 return got_positive;
133 for (subi = 0;
134 i < len && subi < sizeof(sub) - 1 && pattern[i] != ',';
135 subi++, i++)
136 sub[subi] = isupper(pattern[i]) ? tolower(pattern[i]) : pattern[i];
137 /* If subpattern too long, return failure (no match). */
138 if (subi >= sizeof(sub) - 1)
139 return 0;
140
141 /* If the subpattern was terminated by a comma, skip the comma. */
142 if (i < len && pattern[i] == ',')
143 i++;
144
145 /* Null-terminate the subpattern. */
146 sub[subi] = '\0';
147
148 /* Try to match the subpattern against the host name. */
149 if (match_pattern(host, sub)) {
150 if (negated)
151 return 0; /* Fail if host matches any negated subpattern. */
152 else
153 got_positive = 1;
154 }
155 }
156
157 /* Return success if got a positive match. If there was a negative match,
158 we have already returned zero and never get here. */
159 return got_positive;
160} 156}
161 157
162/* Checks whether the given host (which must be in all lowercase) is 158/* Checks whether the given host (which must be in all lowercase) is
163 already in the list of our known hosts. 159 already in the list of our known hosts.
164 Returns HOST_OK if the host is known and has the specified key, 160 Returns HOST_OK if the host is known and has the specified key,
165 HOST_NEW if the host is not known, and HOST_CHANGED if the host is known 161 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)
167 163
168HostStatus 164HostStatus
169check_host_in_hostfile(const char *filename, const char *host, 165check_host_in_hostfile(const char *filename, const char *host,
170 BIGNUM *e, BIGNUM *n, BIGNUM *ke, BIGNUM *kn) 166 BIGNUM * e, BIGNUM * n, BIGNUM * ke, BIGNUM * kn)
171{ 167{
172 FILE *f; 168 FILE *f;
173 char line[8192]; 169 char line[8192];
174 int linenum = 0; 170 int linenum = 0;
175 unsigned int bits, kbits, hostlen; 171 unsigned int bits, kbits, hostlen;
176 char *cp, *cp2; 172 char *cp, *cp2;
177 HostStatus end_return; 173 HostStatus end_return;
178 174
179 /* Open the file containing the list of known hosts. */ 175 /* Open the file containing the list of known hosts. */
180 f = fopen(filename, "r"); 176 f = fopen(filename, "r");
181 if (!f) 177 if (!f)
182 return HOST_NEW; 178 return HOST_NEW;
183 179
184 /* Cache the length of the host name. */ 180 /* Cache the length of the host name. */
185 hostlen = strlen(host); 181 hostlen = strlen(host);
186 182
187 /* Return value when the loop terminates. This is set to HOST_CHANGED if 183 /* Return value when the loop terminates. This is set to
188 we have seen a different key for the host and have not found the proper 184 HOST_CHANGED if we have seen a different key for the host and
189 one. */ 185 have not found the proper one. */
190 end_return = HOST_NEW; 186 end_return = HOST_NEW;
191 187
192 /* size of modulus 'n' */ 188 /* size of modulus 'n' */
193 bits = BN_num_bits(n); 189 bits = BN_num_bits(n);
194 190
195 /* Go trough the file. */ 191 /* Go trough the file. */
196 while (fgets(line, sizeof(line), f)) 192 while (fgets(line, sizeof(line), f)) {
197 { 193 cp = line;
198 cp = line; 194 linenum++;
199 linenum++; 195
200 196 /* Skip any leading whitespace. */
201 /* Skip any leading whitespace. */ 197 for (; *cp == ' ' || *cp == '\t'; cp++);
202 for (; *cp == ' ' || *cp == '\t'; cp++) 198
203 ; 199 /* Ignore comment lines and empty lines. */
204 200 if (!*cp || *cp == '#' || *cp == '\n')
205 /* Ignore comment lines and empty lines. */ 201 continue;
206 if (!*cp || *cp == '#' || *cp == '\n') 202
207 continue; 203 /* Find the end of the host name portion. */
208 204 for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++);
209 /* Find the end of the host name portion. */ 205
210 for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++) 206 /* Check if the host name matches. */
211 ; 207 if (!match_hostname(host, cp, (unsigned int) (cp2 - cp)))
212 208 continue;
213 /* Check if the host name matches. */ 209
214 if (!match_hostname(host, cp, (unsigned int)(cp2 - cp))) 210 /* Got a match. Skip host name. */
215 continue; 211 cp = cp2;
216 212
217 /* Got a match. Skip host name. */ 213 /* Extract the key from the line. This will skip any
218 cp = cp2; 214 leading whitespace. Ignore badly formatted lines. */
219 215 if (!auth_rsa_read_key(&cp, &kbits, ke, kn))
220 /* Extract the key from the line. This will skip any leading 216 continue;
221 whitespace. Ignore badly formatted lines. */ 217
222 if (!auth_rsa_read_key(&cp, &kbits, ke, kn)) 218 if (kbits != BN_num_bits(kn)) {
223 continue; 219 error("Warning: error in %s, line %d: keysize mismatch for host %s: "
224 220 "actual size %d vs. announced %d.",
225 if (kbits != BN_num_bits(kn)) { 221 filename, linenum, host, BN_num_bits(kn), kbits);
226 error("Warning: error in %s, line %d: keysize mismatch for host %s: " 222 error("Warning: replace %d with %d in %s, line %d.",
227 "actual size %d vs. announced %d.", 223 kbits, BN_num_bits(kn), filename, linenum);
228 filename, linenum, host, BN_num_bits(kn), kbits); 224 }
229 error("Warning: replace %d with %d in %s, line %d.", 225 /* Check if the current key is the same as the given key. */
230 kbits, BN_num_bits(kn), filename, linenum); 226 if (BN_cmp(ke, e) == 0 && BN_cmp(kn, n) == 0) {
231 } 227 /* Ok, they match. */
232 228 fclose(f);
233 /* Check if the current key is the same as the given key. */ 229 return HOST_OK;
234 if (BN_cmp(ke, e) == 0 && BN_cmp(kn, n) == 0) 230 }
235 { 231 /* They do not match. We will continue to go through the
236 /* Ok, they match. */ 232 file; however, we note that we will not return that it
237 fclose(f); 233 is new. */
238 return HOST_OK; 234 end_return = HOST_CHANGED;
239 } 235 }
240 236 /* Clear variables and close the file. */
241 /* They do not match. We will continue to go through the file; however, 237 fclose(f);
242 we note that we will not return that it is new. */ 238
243 end_return = HOST_CHANGED; 239 /* Return either HOST_NEW or HOST_CHANGED, depending on whether we
244 } 240 saw a different key for the host. */
245 /* Clear variables and close the file. */ 241 return end_return;
246 fclose(f);
247
248 /* Return either HOST_NEW or HOST_CHANGED, depending on whether we saw a
249 different key for the host. */
250 return end_return;
251} 242}
252 243
253/* Appends an entry to the host file. Returns false if the entry 244/* 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,
255 246
256int 247int
257add_host_to_hostfile(const char *filename, const char *host, 248add_host_to_hostfile(const char *filename, const char *host,
258 BIGNUM *e, BIGNUM *n) 249 BIGNUM * e, BIGNUM * n)
259{ 250{
260 FILE *f; 251 FILE *f;
261 char *buf; 252 char *buf;
262 unsigned int bits; 253 unsigned int bits;
263 254
264 /* Open the file for appending. */ 255 /* Open the file for appending. */
265 f = fopen(filename, "a"); 256 f = fopen(filename, "a");
266 if (!f) 257 if (!f)
267 return 0; 258 return 0;
268 259
269 /* size of modulus 'n' */ 260 /* size of modulus 'n' */
270 bits = BN_num_bits(n); 261 bits = BN_num_bits(n);
271 262
272 /* Print the host name and key to the file. */ 263 /* Print the host name and key to the file. */
273 fprintf(f, "%s %u ", host, bits); 264 fprintf(f, "%s %u ", host, bits);
274 buf = BN_bn2dec(e); 265 buf = BN_bn2dec(e);
275 if (buf == NULL) { 266 if (buf == NULL) {
276 error("add_host_to_hostfile: BN_bn2dec(e) failed"); 267 error("add_host_to_hostfile: BN_bn2dec(e) failed");
277 fclose(f); 268 fclose(f);
278 return 0; 269 return 0;
279 } 270 }
280 fprintf(f, "%s ", buf); 271 fprintf(f, "%s ", buf);
281 free (buf); 272 free(buf);
282 buf = BN_bn2dec(n); 273 buf = BN_bn2dec(n);
283 if (buf == NULL) { 274 if (buf == NULL) {
284 error("add_host_to_hostfile: BN_bn2dec(n) failed"); 275 error("add_host_to_hostfile: BN_bn2dec(n) failed");
285 fclose(f); 276 fclose(f);
286 return 0; 277 return 0;
287 } 278 }
288 fprintf(f, "%s\n", buf); 279 fprintf(f, "%s\n", buf);
289 free (buf); 280 free(buf);
290 281
291 /* Close the file. */ 282 /* Close the file. */
292 fclose(f); 283 fclose(f);
293 return 1; 284 return 1;
294} 285}
diff --git a/includes.h b/includes.h
index 722c6b3bd..4a2539696 100644
--- a/includes.h
+++ b/includes.h
@@ -1,17 +1,17 @@
1/* 1/*
2 2 *
3includes.h 3 * includes.h
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Thu Mar 23 16:29:37 1995 ylo 10 * Created: Thu Mar 23 16:29:37 1995 ylo
11 11 *
12This file includes most of the needed system headers. 12 * This file includes most of the needed system headers.
13 13 *
14*/ 14 */
15 15
16#ifndef INCLUDES_H 16#ifndef INCLUDES_H
17#define INCLUDES_H 17#define INCLUDES_H
@@ -91,4 +91,4 @@ static /**/const char *const rcsid[] = { (char *)rcsid, "\100(#)" msg }
91 client program. Socketpairs do not seem to work on all systems. */ 91 client program. Socketpairs do not seem to work on all systems. */
92#define USE_PIPES 1 92#define USE_PIPES 1
93 93
94#endif /* INCLUDES_H */ 94#endif /* INCLUDES_H */
diff --git a/log-client.c b/log-client.c
index 63cc79445..4d40cf268 100644
--- a/log-client.c
+++ b/log-client.c
@@ -1,21 +1,21 @@
1/* 1/*
2 2 *
3log-client.c 3 * log-client.c
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Mon Mar 20 21:13:40 1995 ylo 10 * Created: Mon Mar 20 21:13:40 1995 ylo
11 11 *
12Client-side versions of debug(), log(), etc. These print to stderr. 12 * Client-side versions of debug(), log(), etc. These print to stderr.
13This is a stripped down version of log-server.c. 13 * This is a stripped down version of log-server.c.
14 14 *
15*/ 15 */
16 16
17#include "includes.h" 17#include "includes.h"
18RCSID("$Id: log-client.c,v 1.2 1999/11/11 06:57:39 damien Exp $"); 18RCSID("$Id: log-client.c,v 1.3 1999/11/24 13:26:22 damien Exp $");
19 19
20#include "xmalloc.h" 20#include "xmalloc.h"
21#include "ssh.h" 21#include "ssh.h"
@@ -23,27 +23,26 @@ RCSID("$Id: log-client.c,v 1.2 1999/11/11 06:57:39 damien Exp $");
23static LogLevel log_level = SYSLOG_LEVEL_INFO; 23static LogLevel log_level = SYSLOG_LEVEL_INFO;
24 24
25/* Initialize the log. 25/* Initialize the log.
26 av0 program name (should be argv[0]) 26 * av0 program name (should be argv[0])
27 level logging level 27 * level logging level
28 */ 28 */
29 29
30void 30void
31log_init(char *av0, LogLevel level, SyslogFacility ignored1, int ignored2) 31log_init(char *av0, LogLevel level, SyslogFacility ignored1, int ignored2)
32{ 32{
33 switch (level) 33 switch (level) {
34 { 34 case SYSLOG_LEVEL_QUIET:
35 case SYSLOG_LEVEL_QUIET: 35 case SYSLOG_LEVEL_ERROR:
36 case SYSLOG_LEVEL_ERROR: 36 case SYSLOG_LEVEL_FATAL:
37 case SYSLOG_LEVEL_FATAL: 37 case SYSLOG_LEVEL_INFO:
38 case SYSLOG_LEVEL_INFO: 38 case SYSLOG_LEVEL_VERBOSE:
39 case SYSLOG_LEVEL_CHAT: 39 case SYSLOG_LEVEL_DEBUG:
40 case SYSLOG_LEVEL_DEBUG: 40 log_level = level;
41 log_level = level; 41 break;
42 break; 42 default:
43 default: 43 /* unchanged */
44 /* unchanged */ 44 break;
45 break; 45 }
46 }
47} 46}
48 47
49#define MSGBUFSIZE 1024 48#define MSGBUFSIZE 1024
@@ -51,13 +50,13 @@ log_init(char *av0, LogLevel level, SyslogFacility ignored1, int ignored2)
51void 50void
52do_log(LogLevel level, const char *fmt, va_list args) 51do_log(LogLevel level, const char *fmt, va_list args)
53{ 52{
54 char msgbuf[MSGBUFSIZE]; 53 char msgbuf[MSGBUFSIZE];
55 54
56 if (level > log_level) 55 if (level > log_level)
57 return; 56 return;
58 if (level == SYSLOG_LEVEL_DEBUG) 57 if (level == SYSLOG_LEVEL_DEBUG)
59 fprintf(stderr, "debug: "); 58 fprintf(stderr, "debug: ");
60 vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); 59 vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
61 fprintf(stderr, "%s", msgbuf); 60 fprintf(stderr, "%s", msgbuf);
62 fprintf(stderr, "\r\n"); 61 fprintf(stderr, "\r\n");
63} 62}
diff --git a/log-server.c b/log-server.c
index 42f567af4..34f77b2be 100644
--- a/log-server.c
+++ b/log-server.c
@@ -1,21 +1,21 @@
1/* 1/*
2 2 *
3log-server.c 3 * log-server.c
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Mon Mar 20 21:19:30 1995 ylo 10 * Created: Mon Mar 20 21:19:30 1995 ylo
11 11 *
12Server-side versions of debug(), log(), etc. These normally send the output 12 * Server-side versions of debug(), log(), etc. These normally send the output
13to the system log. 13 * to the system log.
14 14 *
15*/ 15 */
16 16
17#include "includes.h" 17#include "includes.h"
18RCSID("$Id: log-server.c,v 1.4 1999/11/15 06:10:57 damien Exp $"); 18RCSID("$Id: log-server.c,v 1.5 1999/11/24 13:26:22 damien Exp $");
19 19
20#include <syslog.h> 20#include <syslog.h>
21#include "packet.h" 21#include "packet.h"
@@ -33,72 +33,68 @@ static int log_on_stderr = 0;
33static int log_facility = LOG_AUTH; 33static int log_facility = LOG_AUTH;
34 34
35/* Initialize the log. 35/* Initialize the log.
36 av0 program name (should be argv[0]) 36 * av0 program name (should be argv[0])
37 on_stderr print also on stderr 37 * on_stderr print also on stderr
38 level logging level 38 * level logging level
39 */ 39 */
40 40
41void log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr) 41void
42log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr)
42{ 43{
43 44 switch (level) {
44 switch (level) 45 case SYSLOG_LEVEL_QUIET:
45 { 46 case SYSLOG_LEVEL_ERROR:
46 case SYSLOG_LEVEL_QUIET: 47 case SYSLOG_LEVEL_FATAL:
47 case SYSLOG_LEVEL_ERROR: 48 case SYSLOG_LEVEL_INFO:
48 case SYSLOG_LEVEL_FATAL: 49 case SYSLOG_LEVEL_VERBOSE:
49 case SYSLOG_LEVEL_INFO: 50 case SYSLOG_LEVEL_DEBUG:
50 case SYSLOG_LEVEL_CHAT: 51 log_level = level;
51 case SYSLOG_LEVEL_DEBUG: 52 break;
52 log_level = level; 53 default:
53 break; 54 fprintf(stderr, "Unrecognized internal syslog level code %d\n",
54 default: 55 (int) level);
55 fprintf(stderr, "Unrecognized internal syslog level code %d\n", 56 exit(1);
56 (int)level); 57 }
57 exit(1); 58 switch (facility) {
58 } 59 case SYSLOG_FACILITY_DAEMON:
59 60 log_facility = LOG_DAEMON;
60 switch (facility) 61 break;
61 { 62 case SYSLOG_FACILITY_USER:
62 case SYSLOG_FACILITY_DAEMON: 63 log_facility = LOG_USER;
63 log_facility = LOG_DAEMON; 64 break;
64 break; 65 case SYSLOG_FACILITY_AUTH:
65 case SYSLOG_FACILITY_USER: 66 log_facility = LOG_AUTH;
66 log_facility = LOG_USER; 67 break;
67 break; 68 case SYSLOG_FACILITY_LOCAL0:
68 case SYSLOG_FACILITY_AUTH: 69 log_facility = LOG_LOCAL0;
69 log_facility = LOG_AUTH; 70 break;
70 break; 71 case SYSLOG_FACILITY_LOCAL1:
71 case SYSLOG_FACILITY_LOCAL0: 72 log_facility = LOG_LOCAL1;
72 log_facility = LOG_LOCAL0; 73 break;
73 break; 74 case SYSLOG_FACILITY_LOCAL2:
74 case SYSLOG_FACILITY_LOCAL1: 75 log_facility = LOG_LOCAL2;
75 log_facility = LOG_LOCAL1; 76 break;
76 break; 77 case SYSLOG_FACILITY_LOCAL3:
77 case SYSLOG_FACILITY_LOCAL2: 78 log_facility = LOG_LOCAL3;
78 log_facility = LOG_LOCAL2; 79 break;
79 break; 80 case SYSLOG_FACILITY_LOCAL4:
80 case SYSLOG_FACILITY_LOCAL3: 81 log_facility = LOG_LOCAL4;
81 log_facility = LOG_LOCAL3; 82 break;
82 break; 83 case SYSLOG_FACILITY_LOCAL5:
83 case SYSLOG_FACILITY_LOCAL4: 84 log_facility = LOG_LOCAL5;
84 log_facility = LOG_LOCAL4; 85 break;
85 break; 86 case SYSLOG_FACILITY_LOCAL6:
86 case SYSLOG_FACILITY_LOCAL5: 87 log_facility = LOG_LOCAL6;
87 log_facility = LOG_LOCAL5; 88 break;
88 break; 89 case SYSLOG_FACILITY_LOCAL7:
89 case SYSLOG_FACILITY_LOCAL6: 90 log_facility = LOG_LOCAL7;
90 log_facility = LOG_LOCAL6; 91 break;
91 break; 92 default:
92 case SYSLOG_FACILITY_LOCAL7: 93 fprintf(stderr, "Unrecognized internal syslog facility code %d\n",
93 log_facility = LOG_LOCAL7; 94 (int) facility);
94 break; 95 exit(1);
95 default: 96 }
96 fprintf(stderr, "Unrecognized internal syslog facility code %d\n", 97 log_on_stderr = on_stderr;
97 (int)facility);
98 exit(1);
99 }
100
101 log_on_stderr = on_stderr;
102} 98}
103 99
104#define MSGBUFSIZE 1024 100#define MSGBUFSIZE 1024
@@ -106,48 +102,44 @@ void log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr)
106void 102void
107do_log(LogLevel level, const char *fmt, va_list args) 103do_log(LogLevel level, const char *fmt, va_list args)
108{ 104{
109 char msgbuf[MSGBUFSIZE]; 105 char msgbuf[MSGBUFSIZE];
110 char fmtbuf[MSGBUFSIZE]; 106 char fmtbuf[MSGBUFSIZE];
111 char *txt = NULL; 107 char *txt = NULL;
112 int pri = LOG_INFO; 108 int pri = LOG_INFO;
113 109
114 if (level > log_level) 110 if (level > log_level)
115 return; 111 return;
116 switch (level) 112 switch (level) {
117 { 113 case SYSLOG_LEVEL_ERROR:
118 case SYSLOG_LEVEL_ERROR: 114 txt = "error";
119 txt = "error"; 115 pri = LOG_ERR;
120 pri = LOG_ERR; 116 break;
121 break; 117 case SYSLOG_LEVEL_FATAL:
122 case SYSLOG_LEVEL_FATAL: 118 txt = "fatal";
123 txt = "fatal"; 119 pri = LOG_ERR;
124 pri = LOG_ERR; 120 break;
125 break; 121 case SYSLOG_LEVEL_INFO:
126 case SYSLOG_LEVEL_INFO: 122 case SYSLOG_LEVEL_VERBOSE:
127 pri = LOG_INFO; 123 pri = LOG_INFO;
128 break; 124 break;
129 case SYSLOG_LEVEL_CHAT: 125 case SYSLOG_LEVEL_DEBUG:
130 pri = LOG_INFO; 126 txt = "debug";
131 break; 127 pri = LOG_DEBUG;
132 case SYSLOG_LEVEL_DEBUG: 128 break;
133 txt = "debug"; 129 default:
134 pri = LOG_DEBUG; 130 txt = "internal error";
135 break; 131 pri = LOG_ERR;
136 default: 132 break;
137 txt = "internal error"; 133 }
138 pri = LOG_ERR; 134 if (txt != NULL) {
139 break; 135 snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt);
140 } 136 vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args);
141 137 } else {
142 if (txt != NULL) { 138 vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
143 snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt); 139 }
144 vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args); 140 if (log_on_stderr)
145 }else{ 141 fprintf(stderr, "%s\n", msgbuf);
146 vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); 142 openlog(__progname, LOG_PID, log_facility);
147 } 143 syslog(pri, "%.500s", msgbuf);
148 if (log_on_stderr) 144 closelog();
149 fprintf(stderr, "%s\n", msgbuf);
150 openlog(__progname, LOG_PID, log_facility);
151 syslog(pri, "%.500s", msgbuf);
152 closelog();
153} 145}
diff --git a/log.c b/log.c
index 1ce534ea5..e7052115e 100644
--- a/log.c
+++ b/log.c
@@ -1,11 +1,11 @@
1/* 1/*
2 2 *
3Shared versions of debug(), log(), etc. 3 * Shared versions of debug(), log(), etc.
4 4 *
5*/ 5*/
6 6
7#include "includes.h" 7#include "includes.h"
8RCSID("$OpenBSD: log.c,v 1.2 1999/11/19 16:04:17 markus Exp $"); 8RCSID("$OpenBSD: log.c,v 1.5 1999/11/24 00:26:02 deraadt Exp $");
9 9
10#include "ssh.h" 10#include "ssh.h"
11#include "xmalloc.h" 11#include "xmalloc.h"
@@ -13,66 +13,65 @@ RCSID("$OpenBSD: log.c,v 1.2 1999/11/19 16:04:17 markus Exp $");
13/* Fatal messages. This function never returns. */ 13/* Fatal messages. This function never returns. */
14 14
15void 15void
16fatal(const char *fmt, ...) 16fatal(const char *fmt,...)
17{ 17{
18 va_list args; 18 va_list args;
19 va_start(args, fmt); 19 va_start(args, fmt);
20 do_log(SYSLOG_LEVEL_FATAL, fmt, args); 20 do_log(SYSLOG_LEVEL_FATAL, fmt, args);
21 va_end(args); 21 va_end(args);
22 fatal_cleanup(); 22 fatal_cleanup();
23} 23}
24 24
25/* Error messages that should be logged. */ 25/* Error messages that should be logged. */
26 26
27void 27void
28error(const char *fmt, ...) 28error(const char *fmt,...)
29{ 29{
30 va_list args; 30 va_list args;
31 va_start(args, fmt); 31 va_start(args, fmt);
32 do_log(SYSLOG_LEVEL_ERROR, fmt, args); 32 do_log(SYSLOG_LEVEL_ERROR, fmt, args);
33 va_end(args); 33 va_end(args);
34} 34}
35 35
36/* Log this message (information that usually should go to the log). */ 36/* Log this message (information that usually should go to the log). */
37 37
38void 38void
39log(const char *fmt, ...) 39log(const char *fmt,...)
40{ 40{
41 va_list args; 41 va_list args;
42 va_start(args, fmt); 42 va_start(args, fmt);
43 do_log(SYSLOG_LEVEL_INFO, fmt, args); 43 do_log(SYSLOG_LEVEL_INFO, fmt, args);
44 va_end(args); 44 va_end(args);
45} 45}
46 46
47/* More detailed messages (information that does not need to go to the log). */ 47/* More detailed messages (information that does not need to go to the log). */
48 48
49void 49void
50chat(const char *fmt, ...) 50verbose(const char *fmt,...)
51{ 51{
52 va_list args; 52 va_list args;
53 va_start(args, fmt); 53 va_start(args, fmt);
54 do_log(SYSLOG_LEVEL_CHAT, fmt, args); 54 do_log(SYSLOG_LEVEL_VERBOSE, fmt, args);
55 va_end(args); 55 va_end(args);
56} 56}
57 57
58/* Debugging messages that should not be logged during normal operation. */ 58/* Debugging messages that should not be logged during normal operation. */
59 59
60void 60void
61debug(const char *fmt, ...) 61debug(const char *fmt,...)
62{ 62{
63 va_list args; 63 va_list args;
64 va_start(args, fmt); 64 va_start(args, fmt);
65 do_log(SYSLOG_LEVEL_DEBUG, fmt, args); 65 do_log(SYSLOG_LEVEL_DEBUG, fmt, args);
66 va_end(args); 66 va_end(args);
67} 67}
68 68
69/* Fatal cleanup */ 69/* Fatal cleanup */
70 70
71struct fatal_cleanup 71struct fatal_cleanup {
72{ 72 struct fatal_cleanup *next;
73 struct fatal_cleanup *next; 73 void (*proc) (void *);
74 void (*proc)(void *); 74 void *context;
75 void *context;
76}; 75};
77 76
78static struct fatal_cleanup *fatal_cleanups = NULL; 77static struct fatal_cleanup *fatal_cleanups = NULL;
@@ -80,116 +79,108 @@ static struct fatal_cleanup *fatal_cleanups = NULL;
80/* Registers a cleanup function to be called by fatal() before exiting. */ 79/* Registers a cleanup function to be called by fatal() before exiting. */
81 80
82void 81void
83fatal_add_cleanup(void (*proc)(void *), void *context) 82fatal_add_cleanup(void (*proc) (void *), void *context)
84{ 83{
85 struct fatal_cleanup *cu; 84 struct fatal_cleanup *cu;
86 85
87 cu = xmalloc(sizeof(*cu)); 86 cu = xmalloc(sizeof(*cu));
88 cu->proc = proc; 87 cu->proc = proc;
89 cu->context = context; 88 cu->context = context;
90 cu->next = fatal_cleanups; 89 cu->next = fatal_cleanups;
91 fatal_cleanups = cu; 90 fatal_cleanups = cu;
92} 91}
93 92
94/* Removes a cleanup frunction to be called at fatal(). */ 93/* Removes a cleanup frunction to be called at fatal(). */
95 94
96void 95void
97fatal_remove_cleanup(void (*proc)(void *context), void *context) 96fatal_remove_cleanup(void (*proc) (void *context), void *context)
98{ 97{
99 struct fatal_cleanup **cup, *cu; 98 struct fatal_cleanup **cup, *cu;
100 99
101 for (cup = &fatal_cleanups; *cup; cup = &cu->next) 100 for (cup = &fatal_cleanups; *cup; cup = &cu->next) {
102 { 101 cu = *cup;
103 cu = *cup; 102 if (cu->proc == proc && cu->context == context) {
104 if (cu->proc == proc && cu->context == context) 103 *cup = cu->next;
105 { 104 xfree(cu);
106 *cup = cu->next; 105 return;
107 xfree(cu); 106 }
108 return;
109 } 107 }
110 } 108 fatal("fatal_remove_cleanup: no such cleanup function: 0x%lx 0x%lx\n",
111 fatal("fatal_remove_cleanup: no such cleanup function: 0x%lx 0x%lx\n", 109 (unsigned long) proc, (unsigned long) context);
112 (unsigned long)proc, (unsigned long)context);
113} 110}
114 111
115/* Cleanup and exit */ 112/* Cleanup and exit */
116void 113void
117fatal_cleanup(void) 114fatal_cleanup(void)
118{ 115{
119 struct fatal_cleanup *cu, *next_cu; 116 struct fatal_cleanup *cu, *next_cu;
120 static int called = 0; 117 static int called = 0;
121 if (called) 118
122 exit(255); 119 if (called)
123 called = 1; 120 exit(255);
124 121 called = 1;
125 /* Call cleanup functions. */ 122 /* Call cleanup functions. */
126 for (cu = fatal_cleanups; cu; cu = next_cu) 123 for (cu = fatal_cleanups; cu; cu = next_cu) {
127 { 124 next_cu = cu->next;
128 next_cu = cu->next; 125 debug("Calling cleanup 0x%lx(0x%lx)",
129 debug("Calling cleanup 0x%lx(0x%lx)", 126 (unsigned long) cu->proc, (unsigned long) cu->context);
130 (unsigned long)cu->proc, (unsigned long)cu->context); 127 (*cu->proc) (cu->context);
131 (*cu->proc)(cu->context); 128 }
132 } 129 exit(255);
133
134 exit(255);
135} 130}
136 131
137/* textual representation of log-facilities/levels */ 132/* textual representation of log-facilities/levels */
138 133
139 134static struct {
140static struct 135 const char *name;
141{ 136 SyslogFacility val;
142 const char *name; 137} log_facilities[] = {
143 SyslogFacility val; 138 { "DAEMON", SYSLOG_FACILITY_DAEMON },
144} log_facilities[] = 139 { "USER", SYSLOG_FACILITY_USER },
145{ 140 { "AUTH", SYSLOG_FACILITY_AUTH },
146 { "DAEMON", SYSLOG_FACILITY_DAEMON }, 141 { "LOCAL0", SYSLOG_FACILITY_LOCAL0 },
147 { "USER", SYSLOG_FACILITY_USER }, 142 { "LOCAL1", SYSLOG_FACILITY_LOCAL1 },
148 { "AUTH", SYSLOG_FACILITY_AUTH }, 143 { "LOCAL2", SYSLOG_FACILITY_LOCAL2 },
149 { "LOCAL0", SYSLOG_FACILITY_LOCAL0 }, 144 { "LOCAL3", SYSLOG_FACILITY_LOCAL3 },
150 { "LOCAL1", SYSLOG_FACILITY_LOCAL1 }, 145 { "LOCAL4", SYSLOG_FACILITY_LOCAL4 },
151 { "LOCAL2", SYSLOG_FACILITY_LOCAL2 }, 146 { "LOCAL5", SYSLOG_FACILITY_LOCAL5 },
152 { "LOCAL3", SYSLOG_FACILITY_LOCAL3 }, 147 { "LOCAL6", SYSLOG_FACILITY_LOCAL6 },
153 { "LOCAL4", SYSLOG_FACILITY_LOCAL4 }, 148 { "LOCAL7", SYSLOG_FACILITY_LOCAL7 },
154 { "LOCAL5", SYSLOG_FACILITY_LOCAL5 }, 149 { NULL, 0 }
155 { "LOCAL6", SYSLOG_FACILITY_LOCAL6 },
156 { "LOCAL7", SYSLOG_FACILITY_LOCAL7 },
157 { NULL, 0 }
158}; 150};
159 151
160static struct 152static struct {
161{ 153 const char *name;
162 const char *name; 154 LogLevel val;
163 LogLevel val;
164} log_levels[] = 155} log_levels[] =
165{ 156{
166 { "QUIET", SYSLOG_LEVEL_QUIET }, 157 { "QUIET", SYSLOG_LEVEL_QUIET },
167 { "FATAL", SYSLOG_LEVEL_FATAL }, 158 { "FATAL", SYSLOG_LEVEL_FATAL },
168 { "ERROR", SYSLOG_LEVEL_ERROR }, 159 { "ERROR", SYSLOG_LEVEL_ERROR },
169 { "INFO", SYSLOG_LEVEL_INFO }, 160 { "INFO", SYSLOG_LEVEL_INFO },
170 { "CHAT", SYSLOG_LEVEL_CHAT }, 161 { "VERBOSE", SYSLOG_LEVEL_VERBOSE },
171 { "DEBUG", SYSLOG_LEVEL_DEBUG }, 162 { "DEBUG", SYSLOG_LEVEL_DEBUG },
172 { NULL, 0 } 163 { NULL, 0 }
173}; 164};
174 165
175SyslogFacility 166SyslogFacility
176log_facility_number(char *name) 167log_facility_number(char *name)
177{ 168{
178 int i; 169 int i;
179 if (name != NULL) 170 if (name != NULL)
180 for (i = 0; log_facilities[i].name; i++) 171 for (i = 0; log_facilities[i].name; i++)
181 if (strcasecmp(log_facilities[i].name, name) == 0) 172 if (strcasecmp(log_facilities[i].name, name) == 0)
182 return log_facilities[i].val; 173 return log_facilities[i].val;
183 return (SyslogFacility)-1; 174 return (SyslogFacility) - 1;
184} 175}
185 176
186LogLevel 177LogLevel
187log_level_number(char *name) 178log_level_number(char *name)
188{ 179{
189 int i; 180 int i;
190 if (name != NULL) 181 if (name != NULL)
191 for (i = 0; log_levels[i].name; i++) 182 for (i = 0; log_levels[i].name; i++)
192 if (strcasecmp(log_levels[i].name, name) == 0) 183 if (strcasecmp(log_levels[i].name, name) == 0)
193 return log_levels[i].val; 184 return log_levels[i].val;
194 return (LogLevel)-1; 185 return (LogLevel) - 1;
195} 186}
diff --git a/login.c b/login.c
index 8791ec55a..aa01aac45 100644
--- a/login.c
+++ b/login.c
@@ -1,128 +1,129 @@
1/* 1/*
2 2 *
3login.c 3 * login.c
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Fri Mar 24 14:51:08 1995 ylo 10 * Created: Fri Mar 24 14:51:08 1995 ylo
11 11 *
12This file performs some of the things login(1) normally does. We cannot 12 * This file performs some of the things login(1) normally does. We cannot
13easily use something like login -p -h host -f user, because there are 13 * easily use something like login -p -h host -f user, because there are
14several different logins around, and it is hard to determined what kind of 14 * several different logins around, and it is hard to determined what kind of
15login the current system has. Also, we want to be able to execute commands 15 * login the current system has. Also, we want to be able to execute commands
16on a tty. 16 * on a tty.
17 17 *
18*/ 18 */
19 19
20#include "includes.h" 20#include "includes.h"
21RCSID("$Id: login.c,v 1.2 1999/11/10 23:40:23 damien Exp $"); 21RCSID("$Id: login.c,v 1.3 1999/11/24 13:26:22 damien Exp $");
22 22
23#include <utmp.h> 23#include <utmp.h>
24#include "ssh.h"
24 25
26#ifdef HAVE_UTIL_H
27# include <util.h>
28#endif
25#ifdef HAVE_LASTLOG_H 29#ifdef HAVE_LASTLOG_H
26# include <lastlog.h> 30# include <lastlog.h>
27#endif 31#endif
28 32
29#include "ssh.h" 33/* Returns the time when the user last logged in. Returns 0 if the
30 34 information is not available. This must be called before record_login.
31/* Returns the time when the user last logged in. Returns 0 if the
32 information is not available. This must be called before record_login.
33 The host the user logged in from will be returned in buf. */ 35 The host the user logged in from will be returned in buf. */
34 36
35/* Returns the time when the user last logged in (or 0 if no previous login 37/* Returns the time when the user last logged in (or 0 if no previous login
36 is found). The name of the host used last time is returned in buf. */ 38 is found). The name of the host used last time is returned in buf. */
37 39
38unsigned long get_last_login_time(uid_t uid, const char *logname, 40unsigned long
39 char *buf, unsigned int bufsize) 41get_last_login_time(uid_t uid, const char *logname,
42 char *buf, unsigned int bufsize)
40{ 43{
41 struct lastlog ll; 44 struct lastlog ll;
42 char *lastlog; 45 char *lastlog;
43 int fd; 46 int fd;
44 47
45 lastlog = _PATH_LASTLOG; 48 lastlog = _PATH_LASTLOG;
46 49 buf[0] = '\0';
47 buf[0] = '\0'; 50
48 51 fd = open(lastlog, O_RDONLY);
49 fd = open(lastlog, O_RDONLY); 52 if (fd < 0)
50 if (fd < 0) 53 return 0;
51 return 0; 54 lseek(fd, (off_t) ((long) uid * sizeof(ll)), SEEK_SET);
52 lseek(fd, (off_t)((long)uid * sizeof(ll)), SEEK_SET); 55 if (read(fd, &ll, sizeof(ll)) != sizeof(ll)) {
53 if (read(fd, &ll, sizeof(ll)) != sizeof(ll)) 56 close(fd);
54 { 57 return 0;
55 close(fd); 58 }
56 return 0; 59 close(fd);
57 } 60 if (bufsize > sizeof(ll.ll_host) + 1)
58 close(fd); 61 bufsize = sizeof(ll.ll_host) + 1;
59 if (bufsize > sizeof(ll.ll_host) + 1) 62 strncpy(buf, ll.ll_host, bufsize - 1);
60 bufsize = sizeof(ll.ll_host) + 1; 63 buf[bufsize - 1] = 0;
61 strncpy(buf, ll.ll_host, bufsize - 1); 64 return ll.ll_time;
62 buf[bufsize - 1] = 0;
63 return ll.ll_time;
64} 65}
65 66
66/* Records that the user has logged in. I these parts of operating systems 67/* Records that the user has logged in. I these parts of operating systems
67 were more standardized. */ 68 were more standardized. */
68 69
69void record_login(int pid, const char *ttyname, const char *user, uid_t uid, 70void
70 const char *host, struct sockaddr_in *addr) 71record_login(int pid, const char *ttyname, const char *user, uid_t uid,
72 const char *host, struct sockaddr_in * addr)
71{ 73{
72 int fd; 74 int fd;
73 struct lastlog ll; 75 struct lastlog ll;
74 char *lastlog; 76 char *lastlog;
75 77 struct utmp u;
76 struct utmp u; 78 const char *utmp, *wtmp;
77 const char *utmp, *wtmp; 79
78 80 /* Construct an utmp/wtmp entry. */
79 /* Construct an utmp/wtmp entry. */ 81 memset(&u, 0, sizeof(u));
80 memset(&u, 0, sizeof(u)); 82 strncpy(u.ut_line, ttyname + 5, sizeof(u.ut_line));
81 strncpy(u.ut_line, ttyname + 5, sizeof(u.ut_line)); 83 u.ut_time = time(NULL);
82 u.ut_time = time(NULL); 84 strncpy(u.ut_name, user, sizeof(u.ut_name));
83 strncpy(u.ut_name, user, sizeof(u.ut_name));
84#ifdef HAVE_HOST_IN_UTMP 85#ifdef HAVE_HOST_IN_UTMP
85 strncpy(u.ut_host, host, sizeof(u.ut_host)); 86 strncpy(u.ut_host, host, sizeof(u.ut_host));
86#endif 87#endif
87 88
88 /* Figure out the file names. */ 89 /* Figure out the file names. */
89 utmp = _PATH_UTMP; 90 utmp = _PATH_UTMP;
90 wtmp = _PATH_WTMP; 91 wtmp = _PATH_WTMP;
91 92
92 login(&u); 93 login(&u);
93 94 lastlog = _PATH_LASTLOG;
94 lastlog = _PATH_LASTLOG; 95
95 96 /* Update lastlog unless actually recording a logout. */
96 /* Update lastlog unless actually recording a logout. */ 97 if (strcmp(user, "") != 0) {
97 if (strcmp(user, "") != 0) 98 /* It is safer to bzero the lastlog structure first
98 { 99 because some systems might have some extra fields in it
99 /* It is safer to bzero the lastlog structure first because some 100 (e.g. SGI) */
100 systems might have some extra fields in it (e.g. SGI) */ 101 memset(&ll, 0, sizeof(ll));
101 memset(&ll, 0, sizeof(ll)); 102
102 103 /* Update lastlog. */
103 /* Update lastlog. */ 104 ll.ll_time = time(NULL);
104 ll.ll_time = time(NULL); 105 strncpy(ll.ll_line, ttyname + 5, sizeof(ll.ll_line));
105 strncpy(ll.ll_line, ttyname + 5, sizeof(ll.ll_line)); 106 strncpy(ll.ll_host, host, sizeof(ll.ll_host));
106 strncpy(ll.ll_host, host, sizeof(ll.ll_host)); 107 fd = open(lastlog, O_RDWR);
107 fd = open(lastlog, O_RDWR); 108 if (fd >= 0) {
108 if (fd >= 0) 109 lseek(fd, (off_t) ((long) uid * sizeof(ll)), SEEK_SET);
109 { 110 if (write(fd, &ll, sizeof(ll)) != sizeof(ll))
110 lseek(fd, (off_t)((long)uid * sizeof(ll)), SEEK_SET); 111 log("Could not write %.100s: %.100s", lastlog, strerror(errno));
111 if (write(fd, &ll, sizeof(ll)) != sizeof(ll)) 112 close(fd);
112 log("Could not write %.100s: %.100s", lastlog, strerror(errno)); 113 }
113 close(fd);
114 } 114 }
115 }
116} 115}
117 116
118void record_logout(int pid, const char *ttyname) 117/* Records that the user has logged out. */
118
119void
120record_logout(int pid, const char *ttyname)
119{ 121{
120#ifdef HAVE_LIBUTIL_LOGIN 122#ifdef HAVE_LIBUTIL_LOGIN
121 const char *line = ttyname + 5; /* /dev/ttyq8 -> ttyq8 */ 123 const char *line = ttyname + 5; /* /dev/ttyq8 -> ttyq8 */
122 if (logout(line)) 124 if (logout(line))
123 logwtmp(line, "", ""); 125 logwtmp(line, "", "");
124#else /* HAVE_LIBUTIL_LOGIN */ 126#else /* HAVE_LIBUTIL_LOGIN */
125 record_login(pid, ttyname, "", -1, "", NULL); 127 record_login(pid, ttyname, "", -1, "", NULL);
126#endif /* HAVE_LIBUTIL_LOGIN */ 128#endif /* HAVE_LIBUTIL_LOGIN */
127} 129}
128
diff --git a/match.c b/match.c
index b7a7d3389..c0729dd8d 100644
--- a/match.c
+++ b/match.c
@@ -1,78 +1,77 @@
1/* 1/*
2 2 *
3match.c 3 * match.c
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Thu Jun 22 01:17:50 1995 ylo 10 * Created: Thu Jun 22 01:17:50 1995 ylo
11 11 *
12Simple pattern matching, with '*' and '?' as wildcards. 12 * Simple pattern matching, with '*' and '?' as wildcards.
13 13 *
14*/ 14 */
15 15
16#include "includes.h" 16#include "includes.h"
17RCSID("$Id: match.c,v 1.1 1999/10/27 03:42:44 damien Exp $"); 17RCSID("$Id: match.c,v 1.2 1999/11/24 13:26:22 damien Exp $");
18 18
19#include "ssh.h" 19#include "ssh.h"
20 20
21/* Returns true if the given string matches the pattern (which may contain 21/* Returns true if the given string matches the pattern (which may contain
22 ? and * as wildcards), and zero if it does not match. */ 22 ? and * as wildcards), and zero if it does not match. */
23
24int match_pattern(const char *s, const char *pattern)
25{
26 while (1)
27 {
28 /* If at end of pattern, accept if also at end of string. */
29 if (!*pattern)
30 return !*s;
31 23
32 /* Process '*'. */ 24int
33 if (*pattern == '*') 25match_pattern(const char *s, const char *pattern)
34 { 26{
35 /* Skip the asterisk. */ 27 for (;;) {
36 pattern++; 28 /* If at end of pattern, accept if also at end of string. */
29 if (!*pattern)
30 return !*s;
37 31
38 /* If at end of pattern, accept immediately. */ 32 /* Process '*'. */
39 if (!*pattern) 33 if (*pattern == '*') {
40 return 1; 34 /* Skip the asterisk. */
35 pattern++;
41 36
42 /* If next character in pattern is known, optimize. */ 37 /* If at end of pattern, accept immediately. */
43 if (*pattern != '?' && *pattern != '*') 38 if (!*pattern)
44 { 39 return 1;
45 /* Look instances of the next character in pattern, and try
46 to match starting from those. */
47 for (; *s; s++)
48 if (*s == *pattern &&
49 match_pattern(s + 1, pattern + 1))
50 return 1;
51 /* Failed. */
52 return 0;
53 }
54 40
55 /* Move ahead one character at a time and try to match at each 41 /* If next character in pattern is known, optimize. */
56 position. */ 42 if (*pattern != '?' && *pattern != '*') {
57 for (; *s; s++) 43 /* Look instances of the next character in
58 if (match_pattern(s, pattern)) 44 pattern, and try to match starting from
59 return 1; 45 those. */
60 /* Failed. */ 46 for (; *s; s++)
61 return 0; 47 if (*s == *pattern &&
62 } 48 match_pattern(s + 1, pattern + 1))
49 return 1;
50 /* Failed. */
51 return 0;
52 }
53 /* Move ahead one character at a time and try to
54 match at each position. */
55 for (; *s; s++)
56 if (match_pattern(s, pattern))
57 return 1;
58 /* Failed. */
59 return 0;
60 }
61 /* There must be at least one more character in the
62 string. If we are at the end, fail. */
63 if (!*s)
64 return 0;
63 65
64 /* There must be at least one more character in the string. If we are 66 /* Check if the next character of the string is
65 at the end, fail. */ 67 acceptable. */
66 if (!*s) 68 if (*pattern != '?' && *pattern != *s)
67 return 0; 69 return 0;
68 70
69 /* Check if the next character of the string is acceptable. */ 71 /* Move to the next character, both in string and in
70 if (*pattern != '?' && *pattern != *s) 72 pattern. */
71 return 0; 73 s++;
72 74 pattern++;
73 /* Move to the next character, both in string and in pattern. */ 75 }
74 s++; 76 /* NOTREACHED */
75 pattern++;
76 }
77 /*NOTREACHED*/
78} 77}
diff --git a/mpaux.c b/mpaux.c
index 378fd90da..7bc7c13b8 100644
--- a/mpaux.c
+++ b/mpaux.c
@@ -1,21 +1,24 @@
1/* 1/*
2 2 *
3mpaux.c 3 * mpaux.c
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Sun Jul 16 04:29:30 1995 ylo 10 * Created: Sun Jul 16 04:29:30 1995 ylo
11 11 *
12This file contains various auxiliary functions related to multiple 12 * This file contains various auxiliary functions related to multiple
13precision integers. 13 * precision integers.
14 14 *
15*/ 15*/
16 16
17#include "includes.h" 17#include "includes.h"
18RCSID("$Id: mpaux.c,v 1.6 1999/11/16 02:37:16 damien Exp $"); 18RCSID("$Id: mpaux.c,v 1.7 1999/11/24 13:26:22 damien Exp $");
19
20#include "getput.h"
21#include "xmalloc.h"
19 22
20#ifdef HAVE_OPENSSL 23#ifdef HAVE_OPENSSL
21#include <openssl/bn.h> 24#include <openssl/bn.h>
@@ -26,29 +29,24 @@ RCSID("$Id: mpaux.c,v 1.6 1999/11/16 02:37:16 damien Exp $");
26#include <ssl/md5.h> 29#include <ssl/md5.h>
27#endif 30#endif
28 31
29#include "getput.h"
30#include "xmalloc.h"
31
32
33void 32void
34compute_session_id(unsigned char session_id[16], 33compute_session_id(unsigned char session_id[16],
35 unsigned char cookie[8], 34 unsigned char cookie[8],
36 BIGNUM *host_key_n, 35 BIGNUM* host_key_n,
37 BIGNUM *session_key_n) 36 BIGNUM* session_key_n)
38{ 37{
39 unsigned int host_key_bits = BN_num_bits(host_key_n); 38 unsigned int host_key_bits = BN_num_bits(host_key_n);
40 unsigned int session_key_bits = BN_num_bits(session_key_n); 39 unsigned int session_key_bits = BN_num_bits(session_key_n);
41 unsigned int bytes = (host_key_bits + 7) / 8 + (session_key_bits + 7) / 8 + 8; 40 unsigned int bytes = (host_key_bits + 7) / 8 + (session_key_bits + 7) / 8 + 8;
42 unsigned char *buf = xmalloc(bytes); 41 unsigned char *buf = xmalloc(bytes);
43 MD5_CTX md; 42 MD5_CTX md;
44 43
45 BN_bn2bin(host_key_n, buf); 44 BN_bn2bin(host_key_n, buf);
46 BN_bn2bin(session_key_n, buf + (host_key_bits + 7 ) / 8); 45 BN_bn2bin(session_key_n, buf + (host_key_bits + 7) / 8);
47 memcpy(buf + (host_key_bits + 7) / 8 + (session_key_bits + 7) / 8, 46 memcpy(buf + (host_key_bits + 7) / 8 + (session_key_bits + 7) / 8, cookie, 8);
48 cookie, 8); 47 MD5_Init(&md);
49 MD5_Init(&md); 48 MD5_Update(&md, buf, bytes);
50 MD5_Update(&md, buf, bytes); 49 MD5_Final(session_id, &md);
51 MD5_Final(session_id, &md); 50 memset(buf, 0, bytes);
52 memset(buf, 0, bytes); 51 xfree(buf);
53 xfree(buf);
54} 52}
diff --git a/mpaux.h b/mpaux.h
index 85e2fa2bf..b13f07e3a 100644
--- a/mpaux.h
+++ b/mpaux.h
@@ -1,20 +1,19 @@
1/* 1/*
2 2 *
3mpaux.h 3 * mpaux.h
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Sun Jul 16 04:29:30 1995 ylo 10 * Created: Sun Jul 16 04:29:30 1995 ylo
11 11 *
12This file contains various auxiliary functions related to multiple 12 * This file contains various auxiliary functions related to multiple
13precision integers. 13 * precision integers.
14 14 */
15*/ 15
16 16/* RCSID("$Id: mpaux.h,v 1.3 1999/11/24 13:26:22 damien Exp $"); */
17/* RCSID("$Id: mpaux.h,v 1.2 1999/11/16 02:37:16 damien Exp $"); */
18 17
19#ifndef MPAUX_H 18#ifndef MPAUX_H
20#define MPAUX_H 19#define MPAUX_H
@@ -22,9 +21,10 @@ precision integers.
22/* Computes a 16-byte session id in the global variable session_id. 21/* Computes a 16-byte session id in the global variable session_id.
23 The session id is computed by concatenating the linearized, msb 22 The session id is computed by concatenating the linearized, msb
24 first representations of host_key_n, session_key_n, and the cookie. */ 23 first representations of host_key_n, session_key_n, and the cookie. */
25void compute_session_id(unsigned char session_id[16], 24void
26 unsigned char cookie[8], 25compute_session_id(unsigned char session_id[16],
27 BIGNUM *host_key_n, 26 unsigned char cookie[8],
28 BIGNUM *session_key_n); 27 BIGNUM * host_key_n,
28 BIGNUM * session_key_n);
29 29
30#endif /* MPAUX_H */ 30#endif /* MPAUX_H */
diff --git a/nchan.c b/nchan.c
index fcaeae405..b9a8ba49c 100644
--- a/nchan.c
+++ b/nchan.c
@@ -1,5 +1,5 @@
1#include "includes.h" 1#include "includes.h"
2RCSID("$Id: nchan.c,v 1.1 1999/10/27 03:42:44 damien Exp $"); 2RCSID("$Id: nchan.c,v 1.2 1999/11/24 13:26:22 damien Exp $");
3 3
4#include "ssh.h" 4#include "ssh.h"
5 5
@@ -15,122 +15,131 @@ static void chan_shutdown_read(Channel *c);
15static void chan_delele_if_full_closed(Channel *c); 15static void chan_delele_if_full_closed(Channel *c);
16 16
17/* 17/*
18 * EVENTS: update channel input/output states 18 * EVENTS update channel input/output states execute ACTIONS
19 * execute ACTIONS
20 */ 19 */
20
21/* events concerning the INPUT from socket for channel (istate) */ 21/* events concerning the INPUT from socket for channel (istate) */
22void 22void
23chan_rcvd_oclose(Channel *c){ 23chan_rcvd_oclose(Channel *c)
24 switch(c->istate){ 24{
25 switch (c->istate) {
25 case CHAN_INPUT_WAIT_OCLOSE: 26 case CHAN_INPUT_WAIT_OCLOSE:
26 debug("channel %d: INPUT_WAIT_OCLOSE -> INPUT_CLOSED [rcvd OCLOSE]", c->self); 27 debug("channel %d: INPUT_WAIT_OCLOSE -> INPUT_CLOSED [rcvd OCLOSE]", c->self);
27 c->istate=CHAN_INPUT_CLOSED; 28 c->istate = CHAN_INPUT_CLOSED;
28 chan_delele_if_full_closed(c); 29 chan_delele_if_full_closed(c);
29 break; 30 break;
30 case CHAN_INPUT_OPEN: 31 case CHAN_INPUT_OPEN:
31 debug("channel %d: INPUT_OPEN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self); 32 debug("channel %d: INPUT_OPEN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self);
32 chan_shutdown_read(c); 33 chan_shutdown_read(c);
33 chan_send_ieof(c); 34 chan_send_ieof(c);
34 c->istate=CHAN_INPUT_CLOSED; 35 c->istate = CHAN_INPUT_CLOSED;
35 chan_delele_if_full_closed(c); 36 chan_delele_if_full_closed(c);
36 break; 37 break;
37 default: 38 default:
38 debug("protocol error: chan_rcvd_oclose %d for istate %d",c->self,c->istate); 39 debug("protocol error: chan_rcvd_oclose %d for istate %d", c->self, c->istate);
39 break; 40 break;
40 } 41 }
41} 42}
42void 43void
43chan_read_failed(Channel *c){ 44chan_read_failed(Channel *c)
44 switch(c->istate){ 45{
46 switch (c->istate) {
45 case CHAN_INPUT_OPEN: 47 case CHAN_INPUT_OPEN:
46 debug("channel %d: INPUT_OPEN -> INPUT_WAIT_DRAIN [read failed]", c->self); 48 debug("channel %d: INPUT_OPEN -> INPUT_WAIT_DRAIN [read failed]", c->self);
47 chan_shutdown_read(c); 49 chan_shutdown_read(c);
48 c->istate=CHAN_INPUT_WAIT_DRAIN; 50 c->istate = CHAN_INPUT_WAIT_DRAIN;
49 break; 51 break;
50 default: 52 default:
51 debug("internal error: we do not read, but chan_read_failed %d for istate %d", 53 debug("internal error: we do not read, but chan_read_failed %d for istate %d",
52 c->self,c->istate); 54 c->self, c->istate);
53 break; 55 break;
54 } 56 }
55} 57}
56void 58void
57chan_ibuf_empty(Channel *c){ 59chan_ibuf_empty(Channel *c)
58 if(buffer_len(&c->input)){ 60{
59 debug("internal error: chan_ibuf_empty %d for non empty buffer",c->self); 61 if (buffer_len(&c->input)) {
62 debug("internal error: chan_ibuf_empty %d for non empty buffer", c->self);
60 return; 63 return;
61 } 64 }
62 switch(c->istate){ 65 switch (c->istate) {
63 case CHAN_INPUT_WAIT_DRAIN: 66 case CHAN_INPUT_WAIT_DRAIN:
64 debug("channel %d: INPUT_WAIT_DRAIN -> INPUT_WAIT_OCLOSE [inbuf empty, send IEOF]", c->self); 67 debug("channel %d: INPUT_WAIT_DRAIN -> INPUT_WAIT_OCLOSE [inbuf empty, send IEOF]", c->self);
65 chan_send_ieof(c); 68 chan_send_ieof(c);
66 c->istate=CHAN_INPUT_WAIT_OCLOSE; 69 c->istate = CHAN_INPUT_WAIT_OCLOSE;
67 break; 70 break;
68 default: 71 default:
69 debug("internal error: chan_ibuf_empty %d for istate %d",c->self,c->istate); 72 debug("internal error: chan_ibuf_empty %d for istate %d", c->self, c->istate);
70 break; 73 break;
71 } 74 }
72} 75}
76
73/* events concerning the OUTPUT from channel for socket (ostate) */ 77/* events concerning the OUTPUT from channel for socket (ostate) */
74void 78void
75chan_rcvd_ieof(Channel *c){ 79chan_rcvd_ieof(Channel *c)
76 switch(c->ostate){ 80{
81 switch (c->ostate) {
77 case CHAN_OUTPUT_OPEN: 82 case CHAN_OUTPUT_OPEN:
78 debug("channel %d: OUTPUT_OPEN -> OUTPUT_WAIT_DRAIN [rvcd IEOF]", c->self); 83 debug("channel %d: OUTPUT_OPEN -> OUTPUT_WAIT_DRAIN [rvcd IEOF]", c->self);
79 c->ostate=CHAN_OUTPUT_WAIT_DRAIN; 84 c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
80 break; 85 break;
81 case CHAN_OUTPUT_WAIT_IEOF: 86 case CHAN_OUTPUT_WAIT_IEOF:
82 debug("channel %d: OUTPUT_WAIT_IEOF -> OUTPUT_CLOSED [rvcd IEOF]", c->self); 87 debug("channel %d: OUTPUT_WAIT_IEOF -> OUTPUT_CLOSED [rvcd IEOF]", c->self);
83 c->ostate=CHAN_OUTPUT_CLOSED; 88 c->ostate = CHAN_OUTPUT_CLOSED;
84 chan_delele_if_full_closed(c); 89 chan_delele_if_full_closed(c);
85 break; 90 break;
86 default: 91 default:
87 debug("protocol error: chan_rcvd_ieof %d for ostate %d", c->self,c->ostate); 92 debug("protocol error: chan_rcvd_ieof %d for ostate %d", c->self, c->ostate);
88 break; 93 break;
89 } 94 }
90} 95}
91void 96void
92chan_write_failed(Channel *c){ 97chan_write_failed(Channel *c)
93 switch(c->ostate){ 98{
99 switch (c->ostate) {
94 case CHAN_OUTPUT_OPEN: 100 case CHAN_OUTPUT_OPEN:
95 debug("channel %d: OUTPUT_OPEN -> OUTPUT_WAIT_IEOF [write failed]", c->self); 101 debug("channel %d: OUTPUT_OPEN -> OUTPUT_WAIT_IEOF [write failed]", c->self);
96 chan_send_oclose(c); 102 chan_send_oclose(c);
97 c->ostate=CHAN_OUTPUT_WAIT_IEOF; 103 c->ostate = CHAN_OUTPUT_WAIT_IEOF;
98 break; 104 break;
99 case CHAN_OUTPUT_WAIT_DRAIN: 105 case CHAN_OUTPUT_WAIT_DRAIN:
100 debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [write failed]", c->self); 106 debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [write failed]", c->self);
101 chan_send_oclose(c); 107 chan_send_oclose(c);
102 c->ostate=CHAN_OUTPUT_CLOSED; 108 c->ostate = CHAN_OUTPUT_CLOSED;
103 chan_delele_if_full_closed(c); 109 chan_delele_if_full_closed(c);
104 break; 110 break;
105 default: 111 default:
106 debug("internal error: chan_write_failed %d for ostate %d",c->self,c->ostate); 112 debug("internal error: chan_write_failed %d for ostate %d", c->self, c->ostate);
107 break; 113 break;
108 } 114 }
109} 115}
110void 116void
111chan_obuf_empty(Channel *c){ 117chan_obuf_empty(Channel *c)
112 if(buffer_len(&c->output)){ 118{
113 debug("internal error: chan_obuf_empty %d for non empty buffer",c->self); 119 if (buffer_len(&c->output)) {
120 debug("internal error: chan_obuf_empty %d for non empty buffer", c->self);
114 return; 121 return;
115 } 122 }
116 switch(c->ostate){ 123 switch (c->ostate) {
117 case CHAN_OUTPUT_WAIT_DRAIN: 124 case CHAN_OUTPUT_WAIT_DRAIN:
118 debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [obuf empty, send OCLOSE]", c->self); 125 debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [obuf empty, send OCLOSE]", c->self);
119 chan_send_oclose(c); 126 chan_send_oclose(c);
120 c->ostate=CHAN_OUTPUT_CLOSED; 127 c->ostate = CHAN_OUTPUT_CLOSED;
121 chan_delele_if_full_closed(c); 128 chan_delele_if_full_closed(c);
122 break; 129 break;
123 default: 130 default:
124 debug("internal error: chan_obuf_empty %d for ostate %d",c->self,c->ostate); 131 debug("internal error: chan_obuf_empty %d for ostate %d", c->self, c->ostate);
125 break; 132 break;
126 } 133 }
127} 134}
135
128/* 136/*
129 * ACTIONS: should never update c->istate or c->ostate 137 * ACTIONS: should never update the channel states: c->istate or c->ostate
130 */ 138 */
131static void 139static void
132chan_send_ieof(Channel *c){ 140chan_send_ieof(Channel *c)
133 switch(c->istate){ 141{
142 switch (c->istate) {
134 case CHAN_INPUT_OPEN: 143 case CHAN_INPUT_OPEN:
135 case CHAN_INPUT_WAIT_DRAIN: 144 case CHAN_INPUT_WAIT_DRAIN:
136 packet_start(SSH_MSG_CHANNEL_INPUT_EOF); 145 packet_start(SSH_MSG_CHANNEL_INPUT_EOF);
@@ -138,13 +147,14 @@ chan_send_ieof(Channel *c){
138 packet_send(); 147 packet_send();
139 break; 148 break;
140 default: 149 default:
141 debug("internal error: channel %d: cannot send IEOF for istate %d",c->self,c->istate); 150 debug("internal error: channel %d: cannot send IEOF for istate %d", c->self, c->istate);
142 break; 151 break;
143 } 152 }
144} 153}
145static void 154static void
146chan_send_oclose(Channel *c){ 155chan_send_oclose(Channel *c)
147 switch(c->ostate){ 156{
157 switch (c->ostate) {
148 case CHAN_OUTPUT_OPEN: 158 case CHAN_OUTPUT_OPEN:
149 case CHAN_OUTPUT_WAIT_DRAIN: 159 case CHAN_OUTPUT_WAIT_DRAIN:
150 chan_shutdown_write(c); 160 chan_shutdown_write(c);
@@ -154,34 +164,39 @@ chan_send_oclose(Channel *c){
154 packet_send(); 164 packet_send();
155 break; 165 break;
156 default: 166 default:
157 debug("internal error: channel %d: cannot send OCLOSE for ostate %d",c->self,c->istate); 167 debug("internal error: channel %d: cannot send OCLOSE for ostate %d", c->self, c->istate);
158 break; 168 break;
159 } 169 }
160} 170}
171
161/* helper */ 172/* helper */
162static void 173static void
163chan_shutdown_write(Channel *c){ 174chan_shutdown_write(Channel *c)
175{
164 debug("channel %d: shutdown_write", c->self); 176 debug("channel %d: shutdown_write", c->self);
165 if(shutdown(c->sock, SHUT_WR)<0) 177 if (shutdown(c->sock, SHUT_WR) < 0)
166 error("chan_shutdown_write failed for #%d/fd%d: %.100s", 178 error("chan_shutdown_write failed for #%d/fd%d: %.100s",
167 c->self, c->sock, strerror(errno)); 179 c->self, c->sock, strerror(errno));
168} 180}
169static void 181static void
170chan_shutdown_read(Channel *c){ 182chan_shutdown_read(Channel *c)
183{
171 debug("channel %d: shutdown_read", c->self); 184 debug("channel %d: shutdown_read", c->self);
172 if(shutdown(c->sock, SHUT_RD)<0) 185 if (shutdown(c->sock, SHUT_RD) < 0)
173 error("chan_shutdown_read failed for #%d/fd%d: %.100s", 186 error("chan_shutdown_read failed for #%d/fd%d: %.100s",
174 c->self, c->sock, strerror(errno)); 187 c->self, c->sock, strerror(errno));
175} 188}
176static void 189static void
177chan_delele_if_full_closed(Channel *c){ 190chan_delele_if_full_closed(Channel *c)
178 if(c->istate==CHAN_INPUT_CLOSED && c->ostate==CHAN_OUTPUT_CLOSED){ 191{
192 if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) {
179 debug("channel %d: closing", c->self); 193 debug("channel %d: closing", c->self);
180 channel_free(c->self); 194 channel_free(c->self);
181 } 195 }
182} 196}
183void 197void
184chan_init_iostates(Channel *c){ 198chan_init_iostates(Channel *c)
185 c->ostate=CHAN_OUTPUT_OPEN; 199{
186 c->istate=CHAN_INPUT_OPEN; 200 c->ostate = CHAN_OUTPUT_OPEN;
201 c->istate = CHAN_INPUT_OPEN;
187} 202}
diff --git a/nchan.h b/nchan.h
index 16d360d30..323dac349 100644
--- a/nchan.h
+++ b/nchan.h
@@ -1,4 +1,4 @@
1/* RCSID("$Id: nchan.h,v 1.1 1999/10/27 03:42:44 damien Exp $"); */ 1/* RCSID("$Id: nchan.h,v 1.2 1999/11/24 13:26:22 damien Exp $"); */
2 2
3#ifndef NCHAN_H 3#ifndef NCHAN_H
4#define NCHAN_H 4#define NCHAN_H
@@ -7,24 +7,24 @@
7 * SSH Protocol 1.5 aka New Channel Protocol 7 * SSH Protocol 1.5 aka New Channel Protocol
8 * Thanks to Martina, Axel and everyone who left Erlangen, leaving me bored. 8 * Thanks to Martina, Axel and everyone who left Erlangen, leaving me bored.
9 * Written by Markus Friedl in October 1999 9 * Written by Markus Friedl in October 1999
10 * 10 *
11 * Protocol versions 1.3 and 1.5 differ in the handshake protocol used for the 11 * Protocol versions 1.3 and 1.5 differ in the handshake protocol used for the
12 * tear down of channels: 12 * tear down of channels:
13 * 13 *
14 * 1.3: strict request-ack-protocol: 14 * 1.3: strict request-ack-protocol:
15 * CLOSE -> 15 * CLOSE ->
16 * <- CLOSE_CONFIRM 16 * <- CLOSE_CONFIRM
17 * 17 *
18 * 1.5: uses variations of: 18 * 1.5: uses variations of:
19 * IEOF -> 19 * IEOF ->
20 * <- OCLOSE 20 * <- OCLOSE
21 * <- IEOF 21 * <- IEOF
22 * OCLOSE -> 22 * OCLOSE ->
23 * i.e. both sides have to close the channel 23 * i.e. both sides have to close the channel
24 * 24 *
25 * See the debugging output from 'ssh -v' and 'sshd -d' of 25 * See the debugging output from 'ssh -v' and 'sshd -d' of
26 * ssh-1.2.27 as an example. 26 * ssh-1.2.27 as an example.
27 * 27 *
28 */ 28 */
29 29
30/* ssh-proto-1.5 overloads prot-1.3-message-types */ 30/* ssh-proto-1.5 overloads prot-1.3-message-types */
@@ -44,14 +44,14 @@
44#define CHAN_OUTPUT_CLOSED 0x80 44#define CHAN_OUTPUT_CLOSED 0x80
45 45
46/* EVENTS for the input state */ 46/* EVENTS for the input state */
47void chan_rcvd_oclose(Channel *c); 47void chan_rcvd_oclose(Channel * c);
48void chan_read_failed(Channel *c); 48void chan_read_failed(Channel * c);
49void chan_ibuf_empty(Channel *c); 49void chan_ibuf_empty(Channel * c);
50 50
51/* EVENTS for the output state */ 51/* EVENTS for the output state */
52void chan_rcvd_ieof(Channel *c); 52void chan_rcvd_ieof(Channel * c);
53void chan_write_failed(Channel *c); 53void chan_write_failed(Channel * c);
54void chan_obuf_empty(Channel *c); 54void chan_obuf_empty(Channel * c);
55 55
56void chan_init_iostates(Channel *c); 56void chan_init_iostates(Channel * c);
57#endif 57#endif
diff --git a/packet.c b/packet.c
index 74bb38230..0e60dd5ec 100644
--- a/packet.c
+++ b/packet.c
@@ -1,21 +1,21 @@
1/* 1/*
2 2 *
3packet.c 3 * packet.c
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Sat Mar 18 02:40:40 1995 ylo 10 * Created: Sat Mar 18 02:40:40 1995 ylo
11 11 *
12This file contains code implementing the packet protocol and communication 12 * This file contains code implementing the packet protocol and communication
13with the other side. This same code is used both on client and server side. 13 * with the other side. This same code is used both on client and server side.
14 14 *
15*/ 15 */
16 16
17#include "includes.h" 17#include "includes.h"
18RCSID("$Id: packet.c,v 1.4 1999/11/21 02:23:53 damien Exp $"); 18RCSID("$Id: packet.c,v 1.5 1999/11/24 13:26:22 damien Exp $");
19 19
20#include "xmalloc.h" 20#include "xmalloc.h"
21#include "buffer.h" 21#include "buffer.h"
@@ -45,7 +45,8 @@ static unsigned int remote_protocol_flags = 0;
45 45
46/* Encryption context for receiving data. This is only used for decryption. */ 46/* Encryption context for receiving data. This is only used for decryption. */
47static CipherContext receive_context; 47static CipherContext receive_context;
48/* Encryption coontext for sending data. This is only used for encryption. */ 48
49/* Encryption context for sending data. This is only used for encryption. */
49static CipherContext send_context; 50static CipherContext send_context;
50 51
51/* Buffer for raw input data from the socket. */ 52/* Buffer for raw input data from the socket. */
@@ -81,22 +82,20 @@ static int interactive_mode = 0;
81void 82void
82packet_set_connection(int fd_in, int fd_out) 83packet_set_connection(int fd_in, int fd_out)
83{ 84{
84 connection_in = fd_in; 85 connection_in = fd_in;
85 connection_out = fd_out; 86 connection_out = fd_out;
86 cipher_type = SSH_CIPHER_NONE; 87 cipher_type = SSH_CIPHER_NONE;
87 cipher_set_key(&send_context, SSH_CIPHER_NONE, (unsigned char *)"", 0, 1); 88 cipher_set_key(&send_context, SSH_CIPHER_NONE, (unsigned char *) "", 0, 1);
88 cipher_set_key(&receive_context, SSH_CIPHER_NONE, (unsigned char *)"", 0, 0); 89 cipher_set_key(&receive_context, SSH_CIPHER_NONE, (unsigned char *) "", 0, 0);
89 if (!initialized) 90 if (!initialized) {
90 { 91 initialized = 1;
91 initialized = 1; 92 buffer_init(&input);
92 buffer_init(&input); 93 buffer_init(&output);
93 buffer_init(&output); 94 buffer_init(&outgoing_packet);
94 buffer_init(&outgoing_packet); 95 buffer_init(&incoming_packet);
95 buffer_init(&incoming_packet); 96 }
96 } 97 /* Kludge: arrange the close function to be called from fatal(). */
97 98 fatal_add_cleanup((void (*) (void *)) packet_close, NULL);
98 /* Kludge: arrange the close function to be called from fatal(). */
99 fatal_add_cleanup((void (*)(void *))packet_close, NULL);
100} 99}
101 100
102/* Sets the connection into non-blocking mode. */ 101/* Sets the connection into non-blocking mode. */
@@ -104,15 +103,14 @@ packet_set_connection(int fd_in, int fd_out)
104void 103void
105packet_set_nonblocking() 104packet_set_nonblocking()
106{ 105{
107 /* Set the socket into non-blocking mode. */ 106 /* Set the socket into non-blocking mode. */
108 if (fcntl(connection_in, F_SETFL, O_NONBLOCK) < 0) 107 if (fcntl(connection_in, F_SETFL, O_NONBLOCK) < 0)
109 error("fcntl O_NONBLOCK: %.100s", strerror(errno)); 108 error("fcntl O_NONBLOCK: %.100s", strerror(errno));
110 109
111 if (connection_out != connection_in) 110 if (connection_out != connection_in) {
112 { 111 if (fcntl(connection_out, F_SETFL, O_NONBLOCK) < 0)
113 if (fcntl(connection_out, F_SETFL, O_NONBLOCK) < 0) 112 error("fcntl O_NONBLOCK: %.100s", strerror(errno));
114 error("fcntl O_NONBLOCK: %.100s", strerror(errno)); 113 }
115 }
116} 114}
117 115
118/* Returns the socket used for reading. */ 116/* Returns the socket used for reading. */
@@ -120,7 +118,7 @@ packet_set_nonblocking()
120int 118int
121packet_get_connection_in() 119packet_get_connection_in()
122{ 120{
123 return connection_in; 121 return connection_in;
124} 122}
125 123
126/* Returns the descriptor used for writing. */ 124/* Returns the descriptor used for writing. */
@@ -128,7 +126,7 @@ packet_get_connection_in()
128int 126int
129packet_get_connection_out() 127packet_get_connection_out()
130{ 128{
131 return connection_out; 129 return connection_out;
132} 130}
133 131
134/* Closes the connection and clears and frees internal data structures. */ 132/* Closes the connection and clears and frees internal data structures. */
@@ -136,28 +134,24 @@ packet_get_connection_out()
136void 134void
137packet_close() 135packet_close()
138{ 136{
139 if (!initialized) 137 if (!initialized)
140 return; 138 return;
141 initialized = 0; 139 initialized = 0;
142 if (connection_in == connection_out) 140 if (connection_in == connection_out) {
143 { 141 shutdown(connection_out, SHUT_RDWR);
144 shutdown(connection_out, SHUT_RDWR); 142 close(connection_out);
145 close(connection_out); 143 } else {
146 } 144 close(connection_in);
147 else 145 close(connection_out);
148 { 146 }
149 close(connection_in); 147 buffer_free(&input);
150 close(connection_out); 148 buffer_free(&output);
151 } 149 buffer_free(&outgoing_packet);
152 buffer_free(&input); 150 buffer_free(&incoming_packet);
153 buffer_free(&output); 151 if (packet_compression) {
154 buffer_free(&outgoing_packet); 152 buffer_free(&compression_buffer);
155 buffer_free(&incoming_packet); 153 buffer_compress_uninit();
156 if (packet_compression) 154 }
157 {
158 buffer_free(&compression_buffer);
159 buffer_compress_uninit();
160 }
161} 155}
162 156
163/* Sets remote side protocol flags. */ 157/* Sets remote side protocol flags. */
@@ -165,8 +159,8 @@ packet_close()
165void 159void
166packet_set_protocol_flags(unsigned int protocol_flags) 160packet_set_protocol_flags(unsigned int protocol_flags)
167{ 161{
168 remote_protocol_flags = protocol_flags; 162 remote_protocol_flags = protocol_flags;
169 channel_set_options((protocol_flags & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) != 0); 163 channel_set_options((protocol_flags & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) != 0);
170} 164}
171 165
172/* Returns the remote protocol flags set earlier by the above function. */ 166/* Returns the remote protocol flags set earlier by the above function. */
@@ -174,63 +168,60 @@ packet_set_protocol_flags(unsigned int protocol_flags)
174unsigned int 168unsigned int
175packet_get_protocol_flags() 169packet_get_protocol_flags()
176{ 170{
177 return remote_protocol_flags; 171 return remote_protocol_flags;
178} 172}
179 173
180/* Starts packet compression from the next packet on in both directions. 174/* Starts packet compression from the next packet on in both directions.
181 Level is compression level 1 (fastest) - 9 (slow, best) as in gzip. */ 175 Level is compression level 1 (fastest) - 9 (slow, best) as in gzip. */
182 176
183void 177void
184packet_start_compression(int level) 178packet_start_compression(int level)
185{ 179{
186 if (packet_compression) 180 if (packet_compression)
187 fatal("Compression already enabled."); 181 fatal("Compression already enabled.");
188 packet_compression = 1; 182 packet_compression = 1;
189 buffer_init(&compression_buffer); 183 buffer_init(&compression_buffer);
190 buffer_compress_init(level); 184 buffer_compress_init(level);
191} 185}
192 186
193/* Encrypts the given number of bytes, copying from src to dest. 187/* Encrypts the given number of bytes, copying from src to dest.
194 bytes is known to be a multiple of 8. */ 188 bytes is known to be a multiple of 8. */
195 189
196void 190void
197packet_encrypt(CipherContext *cc, void *dest, void *src, 191packet_encrypt(CipherContext * cc, void *dest, void *src,
198 unsigned int bytes) 192 unsigned int bytes)
199{ 193{
200 cipher_encrypt(cc, dest, src, bytes); 194 cipher_encrypt(cc, dest, src, bytes);
201} 195}
202 196
203/* Decrypts the given number of bytes, copying from src to dest. 197/* Decrypts the given number of bytes, copying from src to dest.
204 bytes is known to be a multiple of 8. */ 198 bytes is known to be a multiple of 8. */
205 199
206void 200void
207packet_decrypt(CipherContext *cc, void *dest, void *src, 201packet_decrypt(CipherContext * cc, void *dest, void *src,
208 unsigned int bytes) 202 unsigned int bytes)
209{ 203{
210 int i; 204 int i;
211 205
212 if ((bytes % 8) != 0) 206 if ((bytes % 8) != 0)
213 fatal("packet_decrypt: bad ciphertext length %d", bytes); 207 fatal("packet_decrypt: bad ciphertext length %d", bytes);
214 208
215 /* 209 /* Cryptographic attack detector for ssh - Modifications for packet.c
216 Cryptographic attack detector for ssh - Modifications for packet.c 210 (C)1998 CORE-SDI, Buenos Aires Argentina Ariel Futoransky(futo@core-sdi.com) */
217 (C)1998 CORE-SDI, Buenos Aires Argentina 211
218 Ariel Futoransky(futo@core-sdi.com) 212 switch (cc->type) {
219 */ 213 case SSH_CIPHER_NONE:
220 switch (cc->type) 214 i = DEATTACK_OK;
221 { 215 break;
222 case SSH_CIPHER_NONE: 216 default:
223 i = DEATTACK_OK; 217 i = detect_attack(src, bytes, NULL);
224 break; 218 break;
225 default: 219 }
226 i = detect_attack(src, bytes, NULL); 220
227 break; 221 if (i == DEATTACK_DETECTED)
228 } 222 packet_disconnect("crc32 compensation attack: network attack detected");
229 223
230 if (i == DEATTACK_DETECTED) 224 cipher_decrypt(cc, dest, src, bytes);
231 packet_disconnect("crc32 compensation attack: network attack detected");
232
233 cipher_decrypt(cc, dest, src, bytes);
234} 225}
235 226
236/* Causes any further packets to be encrypted using the given key. The same 227/* Causes any further packets to be encrypted using the given key. The same
@@ -241,9 +232,9 @@ void
241packet_set_encryption_key(const unsigned char *key, unsigned int keylen, 232packet_set_encryption_key(const unsigned char *key, unsigned int keylen,
242 int cipher) 233 int cipher)
243{ 234{
244 /* All other ciphers use the same key in both directions for now. */ 235 /* All other ciphers use the same key in both directions for now. */
245 cipher_set_key(&receive_context, cipher, key, keylen, 0); 236 cipher_set_key(&receive_context, cipher, key, keylen, 0);
246 cipher_set_key(&send_context, cipher, key, keylen, 1); 237 cipher_set_key(&send_context, cipher, key, keylen, 1);
247} 238}
248 239
249/* Starts constructing a packet to send. */ 240/* Starts constructing a packet to send. */
@@ -251,12 +242,12 @@ packet_set_encryption_key(const unsigned char *key, unsigned int keylen,
251void 242void
252packet_start(int type) 243packet_start(int type)
253{ 244{
254 char buf[9]; 245 char buf[9];
255 246
256 buffer_clear(&outgoing_packet); 247 buffer_clear(&outgoing_packet);
257 memset(buf, 0, 8); 248 memset(buf, 0, 8);
258 buf[8] = type; 249 buf[8] = type;
259 buffer_append(&outgoing_packet, buf, 9); 250 buffer_append(&outgoing_packet, buf, 9);
260} 251}
261 252
262/* Appends a character to the packet data. */ 253/* Appends a character to the packet data. */
@@ -264,8 +255,8 @@ packet_start(int type)
264void 255void
265packet_put_char(int value) 256packet_put_char(int value)
266{ 257{
267 char ch = value; 258 char ch = value;
268 buffer_append(&outgoing_packet, &ch, 1); 259 buffer_append(&outgoing_packet, &ch, 1);
269} 260}
270 261
271/* Appends an integer to the packet data. */ 262/* Appends an integer to the packet data. */
@@ -273,7 +264,7 @@ packet_put_char(int value)
273void 264void
274packet_put_int(unsigned int value) 265packet_put_int(unsigned int value)
275{ 266{
276 buffer_put_int(&outgoing_packet, value); 267 buffer_put_int(&outgoing_packet, value);
277} 268}
278 269
279/* Appends a string to packet data. */ 270/* Appends a string to packet data. */
@@ -281,84 +272,85 @@ packet_put_int(unsigned int value)
281void 272void
282packet_put_string(const char *buf, unsigned int len) 273packet_put_string(const char *buf, unsigned int len)
283{ 274{
284 buffer_put_string(&outgoing_packet, buf, len); 275 buffer_put_string(&outgoing_packet, buf, len);
285} 276}
286 277
287/* Appends an arbitrary precision integer to packet data. */ 278/* Appends an arbitrary precision integer to packet data. */
288 279
289void 280void
290packet_put_bignum(BIGNUM *value) 281packet_put_bignum(BIGNUM * value)
291{ 282{
292 buffer_put_bignum(&outgoing_packet, value); 283 buffer_put_bignum(&outgoing_packet, value);
293} 284}
294 285
295/* Finalizes and sends the packet. If the encryption key has been set, 286/* Finalizes and sends the packet. If the encryption key has been set,
296 encrypts the packet before sending. */ 287 encrypts the packet before sending. */
297 288
298void 289void
299packet_send() 290packet_send()
300{ 291{
301 char buf[8], *cp; 292 char buf[8], *cp;
302 int i, padding, len; 293 int i, padding, len;
303 unsigned int checksum; 294 unsigned int checksum;
304 u_int32_t rand = 0; 295 u_int32_t rand = 0;
305 296
306 /* If using packet compression, compress the payload of the outgoing 297 /* If using packet compression, compress the payload of the
307 packet. */ 298 outgoing packet. */
308 if (packet_compression) 299 if (packet_compression) {
309 { 300 buffer_clear(&compression_buffer);
310 buffer_clear(&compression_buffer); 301 /* Skip padding. */
311 buffer_consume(&outgoing_packet, 8); /* Skip padding. */ 302 buffer_consume(&outgoing_packet, 8);
312 buffer_append(&compression_buffer, "\0\0\0\0\0\0\0\0", 8); /* padding */ 303 /* padding */
313 buffer_compress(&outgoing_packet, &compression_buffer); 304 buffer_append(&compression_buffer, "\0\0\0\0\0\0\0\0", 8);
314 buffer_clear(&outgoing_packet); 305 buffer_compress(&outgoing_packet, &compression_buffer);
315 buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer), 306 buffer_clear(&outgoing_packet);
316 buffer_len(&compression_buffer)); 307 buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer),
317 } 308 buffer_len(&compression_buffer));
318 309 }
319 /* Compute packet length without padding (add checksum, remove padding). */ 310 /* Compute packet length without padding (add checksum, remove padding). */
320 len = buffer_len(&outgoing_packet) + 4 - 8; 311 len = buffer_len(&outgoing_packet) + 4 - 8;
321 312
322 /* Insert padding. */ 313 /* Insert padding. */
323 padding = 8 - len % 8; 314 padding = 8 - len % 8;
324 if (cipher_type != SSH_CIPHER_NONE) 315 if (cipher_type != SSH_CIPHER_NONE) {
325 { 316 cp = buffer_ptr(&outgoing_packet);
326 cp = buffer_ptr(&outgoing_packet); 317 for (i = 0; i < padding; i++) {
327 for (i = 0; i < padding; i++) { 318 if (i % 4 == 0)
328 if (i % 4 == 0) 319 rand = arc4random();
329 rand = arc4random(); 320 cp[7 - i] = rand & 0xff;
330 cp[7 - i] = rand & 0xff; 321 rand >>= 8;
331 rand >>= 8; 322 }
332 } 323 }
333 } 324 buffer_consume(&outgoing_packet, 8 - padding);
334 buffer_consume(&outgoing_packet, 8 - padding); 325
335 326 /* Add check bytes. */
336 /* Add check bytes. */ 327 checksum = crc32((unsigned char *) buffer_ptr(&outgoing_packet),
337 checksum = crc32((unsigned char *)buffer_ptr(&outgoing_packet), 328 buffer_len(&outgoing_packet));
338 buffer_len(&outgoing_packet)); 329 PUT_32BIT(buf, checksum);
339 PUT_32BIT(buf, checksum); 330 buffer_append(&outgoing_packet, buf, 4);
340 buffer_append(&outgoing_packet, buf, 4);
341 331
342#ifdef PACKET_DEBUG 332#ifdef PACKET_DEBUG
343 fprintf(stderr, "packet_send plain: "); 333 fprintf(stderr, "packet_send plain: ");
344 buffer_dump(&outgoing_packet); 334 buffer_dump(&outgoing_packet);
345#endif 335#endif
346 336
347 /* Append to output. */ 337 /* Append to output. */
348 PUT_32BIT(buf, len); 338 PUT_32BIT(buf, len);
349 buffer_append(&output, buf, 4); 339 buffer_append(&output, buf, 4);
350 buffer_append_space(&output, &cp, buffer_len(&outgoing_packet)); 340 buffer_append_space(&output, &cp, buffer_len(&outgoing_packet));
351 packet_encrypt(&send_context, cp, buffer_ptr(&outgoing_packet), 341 packet_encrypt(&send_context, cp, buffer_ptr(&outgoing_packet),
352 buffer_len(&outgoing_packet)); 342 buffer_len(&outgoing_packet));
353 343
354#ifdef PACKET_DEBUG 344#ifdef PACKET_DEBUG
355 fprintf(stderr, "encrypted: "); buffer_dump(&output); 345 fprintf(stderr, "encrypted: ");
346 buffer_dump(&output);
356#endif 347#endif
357 348
358 buffer_clear(&outgoing_packet); 349 buffer_clear(&outgoing_packet);
359 350
360 /* Note that the packet is now only buffered in output. It won\'t be 351 /* Note that the packet is now only buffered in output. It won\'t
361 actually sent until packet_write_wait or packet_write_poll is called. */ 352 be actually sent until packet_write_wait or packet_write_poll
353 is called. */
362} 354}
363 355
364/* Waits until a packet has been received, and returns its type. Note that 356/* Waits until a packet has been received, and returns its type. Note that
@@ -368,42 +360,41 @@ packet_send()
368int 360int
369packet_read(int *payload_len_ptr) 361packet_read(int *payload_len_ptr)
370{ 362{
371 int type, len; 363 int type, len;
372 fd_set set; 364 fd_set set;
373 char buf[8192]; 365 char buf[8192];
374 366
375 /* Since we are blocking, ensure that all written packets have been sent. */ 367 /* Since we are blocking, ensure that all written packets have been sent. */
376 packet_write_wait(); 368 packet_write_wait();
377 369
378 /* Stay in the loop until we have received a complete packet. */ 370 /* Stay in the loop until we have received a complete packet. */
379 for (;;) 371 for (;;) {
380 { 372 /* Try to read a packet from the buffer. */
381 /* Try to read a packet from the buffer. */ 373 type = packet_read_poll(payload_len_ptr);
382 type = packet_read_poll(payload_len_ptr); 374 if (type == SSH_SMSG_SUCCESS
383 if (type == SSH_SMSG_SUCCESS 375 || type == SSH_SMSG_FAILURE
384 || type == SSH_SMSG_FAILURE 376 || type == SSH_CMSG_EOF
385 || type == SSH_CMSG_EOF 377 || type == SSH_CMSG_EXIT_CONFIRMATION)
386 || type == SSH_CMSG_EXIT_CONFIRMATION) 378 packet_integrity_check(*payload_len_ptr, 0, type);
387 packet_integrity_check(*payload_len_ptr, 0, type); 379 /* If we got a packet, return it. */
388 /* If we got a packet, return it. */ 380 if (type != SSH_MSG_NONE)
389 if (type != SSH_MSG_NONE) 381 return type;
390 return type; 382 /* Otherwise, wait for some data to arrive, add it to the
391 /* Otherwise, wait for some data to arrive, add it to the buffer, 383 buffer, and try again. */
392 and try again. */ 384 FD_ZERO(&set);
393 FD_ZERO(&set); 385 FD_SET(connection_in, &set);
394 FD_SET(connection_in, &set); 386 /* Wait for some data to arrive. */
395 /* Wait for some data to arrive. */ 387 select(connection_in + 1, &set, NULL, NULL, NULL);
396 select(connection_in + 1, &set, NULL, NULL, NULL); 388 /* Read data from the socket. */
397 /* Read data from the socket. */ 389 len = read(connection_in, buf, sizeof(buf));
398 len = read(connection_in, buf, sizeof(buf)); 390 if (len == 0)
399 if (len == 0) 391 fatal("Connection closed by %.200s", get_remote_ipaddr());
400 fatal("Connection closed by remote host."); 392 if (len < 0)
401 if (len < 0) 393 fatal("Read from socket failed: %.100s", strerror(errno));
402 fatal("Read from socket failed: %.100s", strerror(errno)); 394 /* Append it to the buffer. */
403 /* Append it to the buffer. */ 395 packet_process_incoming(buf, len);
404 packet_process_incoming(buf, len); 396 }
405 } 397 /* NOTREACHED */
406 /*NOTREACHED*/
407} 398}
408 399
409/* Waits until a packet has been received, verifies that its type matches 400/* Waits until a packet has been received, verifies that its type matches
@@ -412,131 +403,126 @@ packet_read(int *payload_len_ptr)
412void 403void
413packet_read_expect(int *payload_len_ptr, int expected_type) 404packet_read_expect(int *payload_len_ptr, int expected_type)
414{ 405{
415 int type; 406 int type;
416 407
417 type = packet_read(payload_len_ptr); 408 type = packet_read(payload_len_ptr);
418 if (type != expected_type) 409 if (type != expected_type)
419 packet_disconnect("Protocol error: expected packet type %d, got %d", 410 packet_disconnect("Protocol error: expected packet type %d, got %d",
420 expected_type, type); 411 expected_type, type);
421} 412}
422 413
423/* Checks if a full packet is available in the data received so far via 414/* Checks if a full packet is available in the data received so far via
424 packet_process_incoming. If so, reads the packet; otherwise returns 415 * packet_process_incoming. If so, reads the packet; otherwise returns
425 SSH_MSG_NONE. This does not wait for data from the connection. 416 * SSH_MSG_NONE. This does not wait for data from the connection.
426 417 *
427 SSH_MSG_DISCONNECT is handled specially here. Also, 418 * SSH_MSG_DISCONNECT is handled specially here. Also,
428 SSH_MSG_IGNORE messages are skipped by this function and are never returned 419 * SSH_MSG_IGNORE messages are skipped by this function and are never returned
429 to higher levels. 420 * to higher levels.
430 421 *
431 The returned payload_len does include space consumed by: 422 * The returned payload_len does include space consumed by:
432 Packet length 423 * Packet length
433 Padding 424 * Padding
434 Packet type 425 * Packet type
435 Check bytes 426 * Check bytes
436 427 */
437
438 */
439 428
440int 429int
441packet_read_poll(int *payload_len_ptr) 430packet_read_poll(int *payload_len_ptr)
442{ 431{
443 unsigned int len, padded_len; 432 unsigned int len, padded_len;
444 unsigned char *ucp; 433 unsigned char *ucp;
445 char buf[8], *cp; 434 char buf[8], *cp;
446 unsigned int checksum, stored_checksum; 435 unsigned int checksum, stored_checksum;
447 436
448 restart: 437restart:
449 438
450 /* Check if input size is less than minimum packet size. */ 439 /* Check if input size is less than minimum packet size. */
451 if (buffer_len(&input) < 4 + 8) 440 if (buffer_len(&input) < 4 + 8)
452 return SSH_MSG_NONE; 441 return SSH_MSG_NONE;
453 /* Get length of incoming packet. */ 442 /* Get length of incoming packet. */
454 ucp = (unsigned char *)buffer_ptr(&input); 443 ucp = (unsigned char *) buffer_ptr(&input);
455 len = GET_32BIT(ucp); 444 len = GET_32BIT(ucp);
456 if (len < 1 + 2 + 2 || len > 256*1024) 445 if (len < 1 + 2 + 2 || len > 256 * 1024)
457 packet_disconnect("Bad packet length %d.", len); 446 packet_disconnect("Bad packet length %d.", len);
458 padded_len = (len + 8) & ~7; 447 padded_len = (len + 8) & ~7;
459 448
460 /* Check if the packet has been entirely received. */ 449 /* Check if the packet has been entirely received. */
461 if (buffer_len(&input) < 4 + padded_len) 450 if (buffer_len(&input) < 4 + padded_len)
462 return SSH_MSG_NONE; 451 return SSH_MSG_NONE;
463 452
464 /* The entire packet is in buffer. */ 453 /* The entire packet is in buffer. */
465 454
466 /* Consume packet length. */ 455 /* Consume packet length. */
467 buffer_consume(&input, 4); 456 buffer_consume(&input, 4);
468 457
469 /* Copy data to incoming_packet. */ 458 /* Copy data to incoming_packet. */
470 buffer_clear(&incoming_packet); 459 buffer_clear(&incoming_packet);
471 buffer_append_space(&incoming_packet, &cp, padded_len); 460 buffer_append_space(&incoming_packet, &cp, padded_len);
472 packet_decrypt(&receive_context, cp, buffer_ptr(&input), padded_len); 461 packet_decrypt(&receive_context, cp, buffer_ptr(&input), padded_len);
473 buffer_consume(&input, padded_len); 462 buffer_consume(&input, padded_len);
474 463
475#ifdef PACKET_DEBUG 464#ifdef PACKET_DEBUG
476 fprintf(stderr, "read_poll plain: "); buffer_dump(&incoming_packet); 465 fprintf(stderr, "read_poll plain: ");
466 buffer_dump(&incoming_packet);
477#endif 467#endif
478 468
479 /* Compute packet checksum. */ 469 /* Compute packet checksum. */
480 checksum = crc32((unsigned char *)buffer_ptr(&incoming_packet), 470 checksum = crc32((unsigned char *) buffer_ptr(&incoming_packet),
481 buffer_len(&incoming_packet) - 4); 471 buffer_len(&incoming_packet) - 4);
482 472
483 /* Skip padding. */ 473 /* Skip padding. */
484 buffer_consume(&incoming_packet, 8 - len % 8); 474 buffer_consume(&incoming_packet, 8 - len % 8);
485 475
486 /* Test check bytes. */ 476 /* Test check bytes. */
487 477
488 if (len != buffer_len(&incoming_packet)) 478 if (len != buffer_len(&incoming_packet))
489 packet_disconnect("packet_read_poll: len %d != buffer_len %d.", 479 packet_disconnect("packet_read_poll: len %d != buffer_len %d.",
490 len, buffer_len(&incoming_packet)); 480 len, buffer_len(&incoming_packet));
491 481
492 ucp = (unsigned char *)buffer_ptr(&incoming_packet) + len - 4; 482 ucp = (unsigned char *) buffer_ptr(&incoming_packet) + len - 4;
493 stored_checksum = GET_32BIT(ucp); 483 stored_checksum = GET_32BIT(ucp);
494 if (checksum != stored_checksum) 484 if (checksum != stored_checksum)
495 packet_disconnect("Corrupted check bytes on input."); 485 packet_disconnect("Corrupted check bytes on input.");
496 buffer_consume_end(&incoming_packet, 4); 486 buffer_consume_end(&incoming_packet, 4);
497 487
498 /* If using packet compression, decompress the packet. */ 488 /* If using packet compression, decompress the packet. */
499 if (packet_compression) 489 if (packet_compression) {
500 { 490 buffer_clear(&compression_buffer);
501 buffer_clear(&compression_buffer); 491 buffer_uncompress(&incoming_packet, &compression_buffer);
502 buffer_uncompress(&incoming_packet, &compression_buffer); 492 buffer_clear(&incoming_packet);
503 buffer_clear(&incoming_packet); 493 buffer_append(&incoming_packet, buffer_ptr(&compression_buffer),
504 buffer_append(&incoming_packet, buffer_ptr(&compression_buffer), 494 buffer_len(&compression_buffer));
505 buffer_len(&compression_buffer)); 495 }
506 } 496 /* Get packet type. */
507 497 buffer_get(&incoming_packet, &buf[0], 1);
508 /* Get packet type. */ 498
509 buffer_get(&incoming_packet, &buf[0], 1); 499 /* Return length of payload (without type field). */
510 500 *payload_len_ptr = buffer_len(&incoming_packet);
511 /* Return length of payload (without type field). */ 501
512 *payload_len_ptr = buffer_len(&incoming_packet); 502 /* Handle disconnect message. */
513 503 if ((unsigned char) buf[0] == SSH_MSG_DISCONNECT)
514 /* Handle disconnect message. */ 504 fatal("Received disconnect: %.900s", packet_get_string(NULL));
515 if ((unsigned char)buf[0] == SSH_MSG_DISCONNECT) 505
516 fatal("%.900s", packet_get_string(NULL)); 506 /* Ignore ignore messages. */
517 507 if ((unsigned char) buf[0] == SSH_MSG_IGNORE)
518 /* Ignore ignore messages. */ 508 goto restart;
519 if ((unsigned char)buf[0] == SSH_MSG_IGNORE) 509
520 goto restart; 510 /* Send debug messages as debugging output. */
521 511 if ((unsigned char) buf[0] == SSH_MSG_DEBUG) {
522 /* Send debug messages as debugging output. */ 512 debug("Remote: %.900s", packet_get_string(NULL));
523 if ((unsigned char)buf[0] == SSH_MSG_DEBUG) 513 goto restart;
524 { 514 }
525 debug("Remote: %.900s", packet_get_string(NULL)); 515 /* Return type. */
526 goto restart; 516 return (unsigned char) buf[0];
527 } 517}
528 518
529 /* Return type. */
530 return (unsigned char)buf[0];
531}
532
533/* Buffers the given amount of input characters. This is intended to be 519/* Buffers the given amount of input characters. This is intended to be
534 used together with packet_read_poll. */ 520 used together with packet_read_poll. */
535 521
536void 522void
537packet_process_incoming(const char *buf, unsigned int len) 523packet_process_incoming(const char *buf, unsigned int len)
538{ 524{
539 buffer_append(&input, buf, len); 525 buffer_append(&input, buf, len);
540} 526}
541 527
542/* Returns a character from the packet. */ 528/* Returns a character from the packet. */
@@ -544,9 +530,9 @@ packet_process_incoming(const char *buf, unsigned int len)
544unsigned int 530unsigned int
545packet_get_char() 531packet_get_char()
546{ 532{
547 char ch; 533 char ch;
548 buffer_get(&incoming_packet, &ch, 1); 534 buffer_get(&incoming_packet, &ch, 1);
549 return (unsigned char)ch; 535 return (unsigned char) ch;
550} 536}
551 537
552/* Returns an integer from the packet data. */ 538/* Returns an integer from the packet data. */
@@ -554,16 +540,16 @@ packet_get_char()
554unsigned int 540unsigned int
555packet_get_int() 541packet_get_int()
556{ 542{
557 return buffer_get_int(&incoming_packet); 543 return buffer_get_int(&incoming_packet);
558} 544}
559 545
560/* Returns an arbitrary precision integer from the packet data. The integer 546/* Returns an arbitrary precision integer from the packet data. The integer
561 must have been initialized before this call. */ 547 must have been initialized before this call. */
562 548
563void 549void
564packet_get_bignum(BIGNUM *value, int *length_ptr) 550packet_get_bignum(BIGNUM * value, int *length_ptr)
565{ 551{
566 *length_ptr = buffer_get_bignum(&incoming_packet, value); 552 *length_ptr = buffer_get_bignum(&incoming_packet, value);
567} 553}
568 554
569/* Returns a string from the packet data. The string is allocated using 555/* Returns a string from the packet data. The string is allocated using
@@ -572,9 +558,10 @@ packet_get_bignum(BIGNUM *value, int *length_ptr)
572 integer into which the length of the string is stored. */ 558 integer into which the length of the string is stored. */
573 559
574char 560char
575*packet_get_string(unsigned int *length_ptr) 561*
562packet_get_string(unsigned int *length_ptr)
576{ 563{
577 return buffer_get_string(&incoming_packet, length_ptr); 564 return buffer_get_string(&incoming_packet, length_ptr);
578} 565}
579 566
580/* Sends a diagnostic message from the server to the client. This message 567/* Sends a diagnostic message from the server to the client. This message
@@ -586,19 +573,19 @@ char
586 packet_write_wait. */ 573 packet_write_wait. */
587 574
588void 575void
589packet_send_debug(const char *fmt, ...) 576packet_send_debug(const char *fmt,...)
590{ 577{
591 char buf[1024]; 578 char buf[1024];
592 va_list args; 579 va_list args;
593 580
594 va_start(args, fmt); 581 va_start(args, fmt);
595 vsnprintf(buf, sizeof(buf), fmt, args); 582 vsnprintf(buf, sizeof(buf), fmt, args);
596 va_end(args); 583 va_end(args);
597 584
598 packet_start(SSH_MSG_DEBUG); 585 packet_start(SSH_MSG_DEBUG);
599 packet_put_string(buf, strlen(buf)); 586 packet_put_string(buf, strlen(buf));
600 packet_send(); 587 packet_send();
601 packet_write_wait(); 588 packet_write_wait();
602} 589}
603 590
604/* Logs the error plus constructs and sends a disconnect 591/* Logs the error plus constructs and sends a disconnect
@@ -607,36 +594,35 @@ packet_send_debug(const char *fmt, ...)
607 formatted message must not exceed 1024 bytes. */ 594 formatted message must not exceed 1024 bytes. */
608 595
609void 596void
610packet_disconnect(const char *fmt, ...) 597packet_disconnect(const char *fmt,...)
611{ 598{
612 char buf[1024]; 599 char buf[1024];
613 va_list args; 600 va_list args;
614 static int disconnecting = 0; 601 static int disconnecting = 0;
615 if (disconnecting) /* Guard against recursive invocations. */ 602 if (disconnecting) /* Guard against recursive invocations. */
616 fatal("packet_disconnect called recursively."); 603 fatal("packet_disconnect called recursively.");
617 disconnecting = 1; 604 disconnecting = 1;
618 605
619 /* Format the message. Note that the caller must make sure the message 606 /* Format the message. Note that the caller must make sure the
620 is of limited size. */ 607 message is of limited size. */
621 va_start(args, fmt); 608 va_start(args, fmt);
622 vsnprintf(buf, sizeof(buf), fmt, args); 609 vsnprintf(buf, sizeof(buf), fmt, args);
623 va_end(args); 610 va_end(args);
624 611
625 /* Send the disconnect message to the other side, and wait for it to get 612 /* Send the disconnect message to the other side, and wait for it to get sent. */
626 sent. */ 613 packet_start(SSH_MSG_DISCONNECT);
627 packet_start(SSH_MSG_DISCONNECT); 614 packet_put_string(buf, strlen(buf));
628 packet_put_string(buf, strlen(buf)); 615 packet_send();
629 packet_send(); 616 packet_write_wait();
630 packet_write_wait(); 617
631 618 /* Stop listening for connections. */
632 /* Stop listening for connections. */ 619 channel_stop_listening();
633 channel_stop_listening(); 620
634 621 /* Close the connection. */
635 /* Close the connection. */ 622 packet_close();
636 packet_close(); 623
637 624 /* Display the error locally and exit. */
638 /* Display the error locally and exit. */ 625 fatal("Disconnecting: %.100s", buf);
639 fatal("Local: %.100s", buf);
640} 626}
641 627
642/* Checks if there is any buffered output, and tries to write some of the 628/* Checks if there is any buffered output, and tries to write some of the
@@ -645,18 +631,17 @@ packet_disconnect(const char *fmt, ...)
645void 631void
646packet_write_poll() 632packet_write_poll()
647{ 633{
648 int len = buffer_len(&output); 634 int len = buffer_len(&output);
649 if (len > 0) 635 if (len > 0) {
650 { 636 len = write(connection_out, buffer_ptr(&output), len);
651 len = write(connection_out, buffer_ptr(&output), len); 637 if (len <= 0) {
652 if (len <= 0) { 638 if (errno == EAGAIN)
653 if (errno == EAGAIN) 639 return;
654 return; 640 else
655 else 641 fatal("Write failed: %.100s", strerror(errno));
656 fatal("Write failed: %.100s", strerror(errno)); 642 }
657 } 643 buffer_consume(&output, len);
658 buffer_consume(&output, len); 644 }
659 }
660} 645}
661 646
662/* Calls packet_write_poll repeatedly until all pending output data has 647/* Calls packet_write_poll repeatedly until all pending output data has
@@ -665,15 +650,14 @@ packet_write_poll()
665void 650void
666packet_write_wait() 651packet_write_wait()
667{ 652{
668 packet_write_poll(); 653 packet_write_poll();
669 while (packet_have_data_to_write()) 654 while (packet_have_data_to_write()) {
670 { 655 fd_set set;
671 fd_set set; 656 FD_ZERO(&set);
672 FD_ZERO(&set); 657 FD_SET(connection_out, &set);
673 FD_SET(connection_out, &set); 658 select(connection_out + 1, NULL, &set, NULL, NULL);
674 select(connection_out + 1, NULL, &set, NULL, NULL); 659 packet_write_poll();
675 packet_write_poll(); 660 }
676 }
677} 661}
678 662
679/* Returns true if there is buffered data to write to the connection. */ 663/* Returns true if there is buffered data to write to the connection. */
@@ -681,7 +665,7 @@ packet_write_wait()
681int 665int
682packet_have_data_to_write() 666packet_have_data_to_write()
683{ 667{
684 return buffer_len(&output) != 0; 668 return buffer_len(&output) != 0;
685} 669}
686 670
687/* Returns true if there is not too much data to write to the connection. */ 671/* Returns true if there is not too much data to write to the connection. */
@@ -689,10 +673,10 @@ packet_have_data_to_write()
689int 673int
690packet_not_very_much_data_to_write() 674packet_not_very_much_data_to_write()
691{ 675{
692 if (interactive_mode) 676 if (interactive_mode)
693 return buffer_len(&output) < 16384; 677 return buffer_len(&output) < 16384;
694 else 678 else
695 return buffer_len(&output) < 128*1024; 679 return buffer_len(&output) < 128 * 1024;
696} 680}
697 681
698/* Informs that the current session is interactive. Sets IP flags for that. */ 682/* Informs that the current session is interactive. Sets IP flags for that. */
@@ -700,45 +684,40 @@ packet_not_very_much_data_to_write()
700void 684void
701packet_set_interactive(int interactive, int keepalives) 685packet_set_interactive(int interactive, int keepalives)
702{ 686{
703 int on = 1; 687 int on = 1;
704 688
705 /* Record that we are in interactive mode. */ 689 /* Record that we are in interactive mode. */
706 interactive_mode = interactive; 690 interactive_mode = interactive;
707 691
708 /* Only set socket options if using a socket (as indicated by the descriptors 692 /* Only set socket options if using a socket (as indicated by the
709 being the same). */ 693 descriptors being the same). */
710 if (connection_in != connection_out) 694 if (connection_in != connection_out)
711 return; 695 return;
712 696
713 if (keepalives) 697 if (keepalives) {
714 { 698 /* Set keepalives if requested. */
715 /* Set keepalives if requested. */ 699 if (setsockopt(connection_in, SOL_SOCKET, SO_KEEPALIVE, (void *) &on,
716 if (setsockopt(connection_in, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, 700 sizeof(on)) < 0)
717 sizeof(on)) < 0) 701 error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
718 error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); 702 }
719 } 703 if (interactive) {
720 704 /* Set IP options for an interactive connection. Use
721 if (interactive) 705 IPTOS_LOWDELAY and TCP_NODELAY. */
722 { 706 int lowdelay = IPTOS_LOWDELAY;
723 /* Set IP options for an interactive connection. Use IPTOS_LOWDELAY 707 if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *) &lowdelay,
724 and TCP_NODELAY. */ 708 sizeof(lowdelay)) < 0)
725 int lowdelay = IPTOS_LOWDELAY; 709 error("setsockopt IPTOS_LOWDELAY: %.100s", strerror(errno));
726 if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *)&lowdelay, 710 if (setsockopt(connection_in, IPPROTO_TCP, TCP_NODELAY, (void *) &on,
727 sizeof(lowdelay)) < 0) 711 sizeof(on)) < 0)
728 error("setsockopt IPTOS_LOWDELAY: %.100s", strerror(errno)); 712 error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
729 if (setsockopt(connection_in, IPPROTO_TCP, TCP_NODELAY, (void *)&on, 713 } else {
730 sizeof(on)) < 0) 714 /* Set IP options for a non-interactive connection. Use
731 error("setsockopt TCP_NODELAY: %.100s", strerror(errno)); 715 IPTOS_THROUGHPUT. */
732 } 716 int throughput = IPTOS_THROUGHPUT;
733 else 717 if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *) &throughput,
734 { 718 sizeof(throughput)) < 0)
735 /* Set IP options for a non-interactive connection. Use 719 error("setsockopt IPTOS_THROUGHPUT: %.100s", strerror(errno));
736 IPTOS_THROUGHPUT. */ 720 }
737 int throughput = IPTOS_THROUGHPUT;
738 if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *)&throughput,
739 sizeof(throughput)) < 0)
740 error("setsockopt IPTOS_THROUGHPUT: %.100s", strerror(errno));
741 }
742} 721}
743 722
744/* Returns true if the current connection is interactive. */ 723/* Returns true if the current connection is interactive. */
@@ -746,22 +725,22 @@ packet_set_interactive(int interactive, int keepalives)
746int 725int
747packet_is_interactive() 726packet_is_interactive()
748{ 727{
749 return interactive_mode; 728 return interactive_mode;
750} 729}
751 730
752int 731int
753packet_set_maxsize(int s) 732packet_set_maxsize(int s)
754{ 733{
755 static int called = 0; 734 static int called = 0;
756 if (called) { 735 if (called) {
757 log("packet_set_maxsize: called twice: old %d new %d", max_packet_size, s); 736 log("packet_set_maxsize: called twice: old %d new %d", max_packet_size, s);
758 return -1; 737 return -1;
759 } 738 }
760 if (s < 4*1024 || s > 1024*1024) { 739 if (s < 4 * 1024 || s > 1024 * 1024) {
761 log("packet_set_maxsize: bad size %d", s); 740 log("packet_set_maxsize: bad size %d", s);
762 return -1; 741 return -1;
763 } 742 }
764 log("packet_set_maxsize: setting to %d", s); 743 log("packet_set_maxsize: setting to %d", s);
765 max_packet_size = s; 744 max_packet_size = s;
766 return s; 745 return s;
767} 746}
diff --git a/packet.h b/packet.h
index 250a6b336..ad1a5b089 100644
--- a/packet.h
+++ b/packet.h
@@ -1,19 +1,19 @@
1/* 1/*
2 2 *
3packet.h 3 * packet.h
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Sat Mar 18 02:02:14 1995 ylo 10 * Created: Sat Mar 18 02:02:14 1995 ylo
11 11 *
12Interface for the packet protocol functions. 12 * Interface for the packet protocol functions.
13 13 *
14*/ 14 */
15 15
16/* RCSID("$Id: packet.h,v 1.5 1999/11/21 02:23:53 damien Exp $"); */ 16/* RCSID("$Id: packet.h,v 1.6 1999/11/24 13:26:22 damien Exp $"); */
17 17
18#ifndef PACKET_H 18#ifndef PACKET_H
19#define PACKET_H 19#define PACKET_H
@@ -31,83 +31,84 @@ Interface for the packet protocol functions.
31 packet_set_encryption_key is called. It is permissible that fd_in 31 packet_set_encryption_key is called. It is permissible that fd_in
32 and fd_out are the same descriptor; in that case it is assumed to 32 and fd_out are the same descriptor; in that case it is assumed to
33 be a socket. */ 33 be a socket. */
34void packet_set_connection(int fd_in, int fd_out); 34void packet_set_connection(int fd_in, int fd_out);
35 35
36/* Puts the connection file descriptors into non-blocking mode. */ 36/* Puts the connection file descriptors into non-blocking mode. */
37void packet_set_nonblocking(void); 37void packet_set_nonblocking(void);
38 38
39/* Returns the file descriptor used for input. */ 39/* Returns the file descriptor used for input. */
40int packet_get_connection_in(void); 40int packet_get_connection_in(void);
41 41
42/* Returns the file descriptor used for output. */ 42/* Returns the file descriptor used for output. */
43int packet_get_connection_out(void); 43int packet_get_connection_out(void);
44 44
45/* Closes the connection (both descriptors) and clears and frees 45/* Closes the connection (both descriptors) and clears and frees
46 internal data structures. */ 46 internal data structures. */
47void packet_close(void); 47void packet_close(void);
48 48
49/* Causes any further packets to be encrypted using the given key. The same 49/* Causes any further packets to be encrypted using the given key. The same
50 key is used for both sending and reception. However, both directions 50 key is used for both sending and reception. However, both directions
51 are encrypted independently of each other. Cipher types are 51 are encrypted independently of each other. Cipher types are
52 defined in ssh.h. */ 52 defined in ssh.h. */
53void packet_set_encryption_key(const unsigned char *key, unsigned int keylen, 53void
54 int cipher_type); 54packet_set_encryption_key(const unsigned char *key, unsigned int keylen,
55 int cipher_type);
55 56
56/* Sets remote side protocol flags for the current connection. This can 57/* Sets remote side protocol flags for the current connection. This can
57 be called at any time. */ 58 be called at any time. */
58void packet_set_protocol_flags(unsigned int flags); 59void packet_set_protocol_flags(unsigned int flags);
59 60
60/* Returns the remote protocol flags set earlier by the above function. */ 61/* Returns the remote protocol flags set earlier by the above function. */
61unsigned int packet_get_protocol_flags(void); 62unsigned int packet_get_protocol_flags(void);
62 63
63/* Enables compression in both directions starting from the next packet. */ 64/* Enables compression in both directions starting from the next packet. */
64void packet_start_compression(int level); 65void packet_start_compression(int level);
65 66
66/* Informs that the current session is interactive. Sets IP flags for optimal 67/* Informs that the current session is interactive. Sets IP flags for optimal
67 performance in interactive use. */ 68 performance in interactive use. */
68void packet_set_interactive(int interactive, int keepalives); 69void packet_set_interactive(int interactive, int keepalives);
69 70
70/* Returns true if the current connection is interactive. */ 71/* Returns true if the current connection is interactive. */
71int packet_is_interactive(void); 72int packet_is_interactive(void);
72 73
73/* Starts constructing a packet to send. */ 74/* Starts constructing a packet to send. */
74void packet_start(int type); 75void packet_start(int type);
75 76
76/* Appends a character to the packet data. */ 77/* Appends a character to the packet data. */
77void packet_put_char(int ch); 78void packet_put_char(int ch);
78 79
79/* Appends an integer to the packet data. */ 80/* Appends an integer to the packet data. */
80void packet_put_int(unsigned int value); 81void packet_put_int(unsigned int value);
81 82
82/* Appends an arbitrary precision integer to packet data. */ 83/* Appends an arbitrary precision integer to packet data. */
83void packet_put_bignum(BIGNUM *value); 84void packet_put_bignum(BIGNUM * value);
84 85
85/* Appends a string to packet data. */ 86/* Appends a string to packet data. */
86void packet_put_string(const char *buf, unsigned int len); 87void packet_put_string(const char *buf, unsigned int len);
87 88
88/* Finalizes and sends the packet. If the encryption key has been set, 89/* Finalizes and sends the packet. If the encryption key has been set,
89 encrypts the packet before sending. */ 90 encrypts the packet before sending. */
90void packet_send(void); 91void packet_send(void);
91 92
92/* Waits until a packet has been received, and returns its type. */ 93/* Waits until a packet has been received, and returns its type. */
93int packet_read(int *payload_len_ptr); 94int packet_read(int *payload_len_ptr);
94 95
95/* Waits until a packet has been received, verifies that its type matches 96/* Waits until a packet has been received, verifies that its type matches
96 that given, and gives a fatal error and exits if there is a mismatch. */ 97 that given, and gives a fatal error and exits if there is a mismatch. */
97void packet_read_expect(int *payload_len_ptr, int type); 98void packet_read_expect(int *payload_len_ptr, int type);
98 99
99/* Checks if a full packet is available in the data received so far via 100/* Checks if a full packet is available in the data received so far via
100 packet_process_incoming. If so, reads the packet; otherwise returns 101 packet_process_incoming. If so, reads the packet; otherwise returns
101 SSH_MSG_NONE. This does not wait for data from the connection. 102 SSH_MSG_NONE. This does not wait for data from the connection.
102 103
103 SSH_MSG_DISCONNECT is handled specially here. Also, 104 SSH_MSG_DISCONNECT is handled specially here. Also,
104 SSH_MSG_IGNORE messages are skipped by this function and are never returned 105 SSH_MSG_IGNORE messages are skipped by this function and are never returned
105 to higher levels. */ 106 to higher levels. */
106int packet_read_poll(int *packet_len_ptr); 107int packet_read_poll(int *packet_len_ptr);
107 108
108/* Buffers the given amount of input characters. This is intended to be 109/* Buffers the given amount of input characters. This is intended to be
109 used together with packet_read_poll. */ 110 used together with packet_read_poll. */
110void packet_process_incoming(const char *buf, unsigned int len); 111void packet_process_incoming(const char *buf, unsigned int len);
111 112
112/* Returns a character (0-255) from the packet data. */ 113/* Returns a character (0-255) from the packet data. */
113unsigned int packet_get_char(void); 114unsigned int packet_get_char(void);
@@ -117,19 +118,19 @@ unsigned int packet_get_int(void);
117 118
118/* Returns an arbitrary precision integer from the packet data. The integer 119/* Returns an arbitrary precision integer from the packet data. The integer
119 must have been initialized before this call. */ 120 must have been initialized before this call. */
120void packet_get_bignum(BIGNUM *value, int *length_ptr); 121void packet_get_bignum(BIGNUM * value, int *length_ptr);
121 122
122/* Returns a string from the packet data. The string is allocated using 123/* Returns a string from the packet data. The string is allocated using
123 xmalloc; it is the responsibility of the calling program to free it when 124 xmalloc; it is the responsibility of the calling program to free it when
124 no longer needed. The length_ptr argument may be NULL, or point to an 125 no longer needed. The length_ptr argument may be NULL, or point to an
125 integer into which the length of the string is stored. */ 126 integer into which the length of the string is stored. */
126char *packet_get_string(unsigned int *length_ptr); 127char *packet_get_string(unsigned int *length_ptr);
127 128
128/* Logs the error in syslog using LOG_INFO, constructs and sends a disconnect 129/* Logs the error in syslog using LOG_INFO, constructs and sends a disconnect
129 packet, closes the connection, and exits. This function never returns. 130 packet, closes the connection, and exits. This function never returns.
130 The error message should not contain a newline. The total length of the 131 The error message should not contain a newline. The total length of the
131 message must not exceed 1024 bytes. */ 132 message must not exceed 1024 bytes. */
132void packet_disconnect(const char *fmt, ...); 133void packet_disconnect(const char *fmt,...);
133 134
134/* Sends a diagnostic message to the other side. This message 135/* Sends a diagnostic message to the other side. This message
135 can be sent at any time (but not while constructing another message). 136 can be sent at any time (but not while constructing another message).
@@ -139,31 +140,31 @@ void packet_disconnect(const char *fmt, ...);
139 must not exceed 1024 bytes. This will automatically call 140 must not exceed 1024 bytes. This will automatically call
140 packet_write_wait. If the remote side protocol flags do not indicate 141 packet_write_wait. If the remote side protocol flags do not indicate
141 that it supports SSH_MSG_DEBUG, this will do nothing. */ 142 that it supports SSH_MSG_DEBUG, this will do nothing. */
142void packet_send_debug(const char *fmt, ...); 143void packet_send_debug(const char *fmt,...);
143 144
144/* Checks if there is any buffered output, and tries to write some of the 145/* Checks if there is any buffered output, and tries to write some of the
145 output. */ 146 output. */
146void packet_write_poll(void); 147void packet_write_poll(void);
147 148
148/* Waits until all pending output data has been written. */ 149/* Waits until all pending output data has been written. */
149void packet_write_wait(void); 150void packet_write_wait(void);
150 151
151/* Returns true if there is buffered data to write to the connection. */ 152/* Returns true if there is buffered data to write to the connection. */
152int packet_have_data_to_write(void); 153int packet_have_data_to_write(void);
153 154
154/* Returns true if there is not too much data to write to the connection. */ 155/* Returns true if there is not too much data to write to the connection. */
155int packet_not_very_much_data_to_write(void); 156int packet_not_very_much_data_to_write(void);
156 157
157/* maximum packet size, requested by client with SSH_CMSG_MAX_PACKET_SIZE */ 158/* maximum packet size, requested by client with SSH_CMSG_MAX_PACKET_SIZE */
158extern int max_packet_size; 159extern int max_packet_size;
159int packet_set_maxsize(int s); 160int packet_set_maxsize(int s);
160#define packet_get_maxsize() max_packet_size 161#define packet_get_maxsize() max_packet_size
161 162
162/* Stores tty modes from the fd into current packet. */ 163/* Stores tty modes from the fd into current packet. */
163void tty_make_modes(int fd); 164void tty_make_modes(int fd);
164 165
165/* Parses tty modes for the fd from the current packet. */ 166/* Parses tty modes for the fd from the current packet. */
166void tty_parse_modes(int fd, int *n_bytes_ptr); 167void tty_parse_modes(int fd, int *n_bytes_ptr);
167 168
168#define packet_integrity_check(payload_len, expected_len, type) \ 169#define packet_integrity_check(payload_len, expected_len, type) \
169do { \ 170do { \
@@ -175,4 +176,4 @@ do { \
175 } \ 176 } \
176} while (0) 177} while (0)
177 178
178#endif /* PACKET_H */ 179#endif /* PACKET_H */
diff --git a/pty.c b/pty.c
index bbe18fd03..34ed48d61 100644
--- a/pty.c
+++ b/pty.c
@@ -1,28 +1,28 @@
1/* 1/*
2 2 *
3pty.c 3 * pty.c
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Fri Mar 17 04:37:25 1995 ylo 10 * Created: Fri Mar 17 04:37:25 1995 ylo
11 11 *
12Allocating a pseudo-terminal, and making it the controlling tty. 12 * Allocating a pseudo-terminal, and making it the controlling tty.
13 13 *
14*/ 14 */
15 15
16#include "includes.h" 16#include "includes.h"
17RCSID("$Id: pty.c,v 1.3 1999/11/15 04:40:55 damien Exp $"); 17RCSID("$Id: pty.c,v 1.4 1999/11/24 13:26:22 damien Exp $");
18
19#include "pty.h"
20#include "ssh.h"
18 21
19#ifdef HAVE_PTY_H 22#ifdef HAVE_PTY_H
20#include <pty.h> 23#include <pty.h>
21#endif /* HAVE_PTY_H */ 24#endif /* HAVE_PTY_H */
22 25
23#include "pty.h"
24#include "ssh.h"
25
26/* Pty allocated with _getpty gets broken if we do I_PUSH:es to it. */ 26/* Pty allocated with _getpty gets broken if we do I_PUSH:es to it. */
27#if defined(HAVE__GETPTY) || defined(HAVE_OPENPTY) 27#if defined(HAVE__GETPTY) || defined(HAVE_OPENPTY)
28#undef HAVE_DEV_PTMX 28#undef HAVE_DEV_PTMX
@@ -34,235 +34,211 @@ RCSID("$Id: pty.c,v 1.3 1999/11/15 04:40:55 damien Exp $");
34 34
35/* Allocates and opens a pty. Returns 0 if no pty could be allocated, 35/* Allocates and opens a pty. Returns 0 if no pty could be allocated,
36 or nonzero if a pty was successfully allocated. On success, open file 36 or nonzero if a pty was successfully allocated. On success, open file
37 descriptors for the pty and tty sides and the name of the tty side are 37 descriptors for the pty and tty sides and the name of the tty side are
38 returned (the buffer must be able to hold at least 64 characters). */ 38 returned (the buffer must be able to hold at least 64 characters). */
39 39
40int pty_allocate(int *ptyfd, int *ttyfd, char *namebuf) 40int
41pty_allocate(int *ptyfd, int *ttyfd, char *namebuf)
41{ 42{
42#ifdef HAVE_OPENPTY 43#ifdef HAVE_OPENPTY
44 /* openpty(3) exists in OSF/1 and some other os'es */
45 int i;
43 46
44 /* openpty(3) exists in OSF/1 and some other os'es */ 47 i = openpty(ptyfd, ttyfd, namebuf, NULL, NULL);
45 48 if (i < 0) {
46 int i; 49 error("openpty: %.100s", strerror(errno));
47 50 return 0;
48 i = openpty(ptyfd, ttyfd, namebuf, NULL, NULL); 51 }
49 52 return 1;
50 if (i < 0)
51 {
52 error("openpty: %.100s", strerror(errno));
53 return 0;
54 }
55
56 return 1;
57
58#else /* HAVE_OPENPTY */ 53#else /* HAVE_OPENPTY */
59#ifdef HAVE__GETPTY 54#ifdef HAVE__GETPTY
60 55 /* _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates
61 /* _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates more 56 more pty's automagically when needed */
62 pty's automagically when needed */ 57 char *slave;
63 58
64 char *slave; 59 slave = _getpty(ptyfd, O_RDWR, 0622, 0);
65 60 if (slave == NULL) {
66 slave = _getpty(ptyfd, O_RDWR, 0622, 0); 61 error("_getpty: %.100s", strerror(errno));
67 if (slave == NULL) 62 return 0;
68 { 63 }
69 error("_getpty: %.100s", strerror(errno)); 64 strcpy(namebuf, slave);
70 return 0; 65 /* Open the slave side. */
71 } 66 *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
72 strcpy(namebuf, slave); 67 if (*ttyfd < 0) {
73 /* Open the slave side. */ 68 error("%.200s: %.100s", namebuf, strerror(errno));
74 *ttyfd = open(namebuf, O_RDWR|O_NOCTTY); 69 close(*ptyfd);
75 if (*ttyfd < 0) 70 return 0;
76 { 71 }
77 error("%.200s: %.100s", namebuf, strerror(errno)); 72 return 1;
78 close(*ptyfd);
79 return 0;
80 }
81 return 1;
82
83#else /* HAVE__GETPTY */ 73#else /* HAVE__GETPTY */
84#ifdef HAVE_DEV_PTMX 74#ifdef HAVE_DEV_PTMX
85 /* This code is used e.g. on Solaris 2.x. (Note that Solaris 2.3 also has 75 /* This code is used e.g. on Solaris 2.x. (Note that Solaris 2.3
86 bsd-style ptys, but they simply do not work.) */ 76 also has bsd-style ptys, but they simply do not work.) */
87 77 int ptm;
88 int ptm; 78 char *pts;
89 char *pts; 79
90 80 ptm = open("/dev/ptmx", O_RDWR | O_NOCTTY);
91 ptm = open("/dev/ptmx", O_RDWR|O_NOCTTY); 81 if (ptm < 0) {
92 if (ptm < 0) 82 error("/dev/ptmx: %.100s", strerror(errno));
93 { 83 return 0;
94 error("/dev/ptmx: %.100s", strerror(errno)); 84 }
95 return 0; 85 if (grantpt(ptm) < 0) {
96 } 86 error("grantpt: %.100s", strerror(errno));
97 if (grantpt(ptm) < 0) 87 return 0;
98 { 88 }
99 error("grantpt: %.100s", strerror(errno)); 89 if (unlockpt(ptm) < 0) {
100 return 0; 90 error("unlockpt: %.100s", strerror(errno));
101 } 91 return 0;
102 if (unlockpt(ptm) < 0) 92 }
103 { 93 pts = ptsname(ptm);
104 error("unlockpt: %.100s", strerror(errno)); 94 if (pts == NULL)
105 return 0; 95 error("Slave pty side name could not be obtained.");
106 } 96 strcpy(namebuf, pts);
107 pts = ptsname(ptm); 97 *ptyfd = ptm;
108 if (pts == NULL) 98
109 error("Slave pty side name could not be obtained."); 99 /* Open the slave side. */
110 strcpy(namebuf, pts); 100 *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
111 *ptyfd = ptm; 101 if (*ttyfd < 0) {
112 102 error("%.100s: %.100s", namebuf, strerror(errno));
113 /* Open the slave side. */ 103 close(*ptyfd);
114 *ttyfd = open(namebuf, O_RDWR|O_NOCTTY); 104 return 0;
115 if (*ttyfd < 0) 105 }
116 { 106 /* Push the appropriate streams modules, as described in Solaris
117 error("%.100s: %.100s", namebuf, strerror(errno)); 107 pts(7). */
118 close(*ptyfd); 108 if (ioctl(*ttyfd, I_PUSH, "ptem") < 0)
119 return 0; 109 error("ioctl I_PUSH ptem: %.100s", strerror(errno));
120 } 110 if (ioctl(*ttyfd, I_PUSH, "ldterm") < 0)
121 /* Push the appropriate streams modules, as described in Solaris pts(7). */ 111 error("ioctl I_PUSH ldterm: %.100s", strerror(errno));
122 if (ioctl(*ttyfd, I_PUSH, "ptem") < 0) 112 if (ioctl(*ttyfd, I_PUSH, "ttcompat") < 0)
123 error("ioctl I_PUSH ptem: %.100s", strerror(errno)); 113 error("ioctl I_PUSH ttcompat: %.100s", strerror(errno));
124 if (ioctl(*ttyfd, I_PUSH, "ldterm") < 0) 114 return 1;
125 error("ioctl I_PUSH ldterm: %.100s", strerror(errno));
126 if (ioctl(*ttyfd, I_PUSH, "ttcompat") < 0)
127 error("ioctl I_PUSH ttcompat: %.100s", strerror(errno));
128 return 1;
129
130#else /* HAVE_DEV_PTMX */ 115#else /* HAVE_DEV_PTMX */
131#ifdef HAVE_DEV_PTS_AND_PTC 116#ifdef HAVE_DEV_PTS_AND_PTC
117 /* AIX-style pty code. */
118 const char *name;
132 119
133 /* AIX-style pty code. */ 120 *ptyfd = open("/dev/ptc", O_RDWR | O_NOCTTY);
134 121 if (*ptyfd < 0) {
135 const char *name; 122 error("Could not open /dev/ptc: %.100s", strerror(errno));
136 123 return 0;
137 *ptyfd = open("/dev/ptc", O_RDWR|O_NOCTTY); 124 }
138 if (*ptyfd < 0) 125 name = ttyname(*ptyfd);
139 { 126 if (!name)
140 error("Could not open /dev/ptc: %.100s", strerror(errno)); 127 fatal("Open of /dev/ptc returns device for which ttyname fails.");
141 return 0; 128 strcpy(namebuf, name);
142 } 129 *ttyfd = open(name, O_RDWR | O_NOCTTY);
143 name = ttyname(*ptyfd); 130 if (*ttyfd < 0) {
144 if (!name) 131 error("Could not open pty slave side %.100s: %.100s",
145 fatal("Open of /dev/ptc returns device for which ttyname fails."); 132 name, strerror(errno));
146 strcpy(namebuf, name); 133 close(*ptyfd);
147 *ttyfd = open(name, O_RDWR|O_NOCTTY); 134 return 0;
148 if (*ttyfd < 0) 135 }
149 { 136 return 1;
150 error("Could not open pty slave side %.100s: %.100s",
151 name, strerror(errno));
152 close(*ptyfd);
153 return 0;
154 }
155 return 1;
156
157#else /* HAVE_DEV_PTS_AND_PTC */ 137#else /* HAVE_DEV_PTS_AND_PTC */
158 /* BSD-style pty code. */ 138 /* BSD-style pty code. */
159 139 char buf[64];
160 char buf[64]; 140 int i;
161 int i; 141 const char *ptymajors =
162 const char *ptymajors = 142 "pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ";
163 "pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ"; 143 const char *ptyminors = "0123456789abcdef";
164 const char *ptyminors = "0123456789abcdef"; 144 int num_minors = strlen(ptyminors);
165 int num_minors = strlen(ptyminors); 145 int num_ptys = strlen(ptymajors) * num_minors;
166 int num_ptys = strlen(ptymajors) * num_minors; 146
167 147 for (i = 0; i < num_ptys; i++) {
168 for (i = 0; i < num_ptys; i++) 148 snprintf(buf, sizeof buf, "/dev/pty%c%c", ptymajors[i / num_minors],
169 { 149 ptyminors[i % num_minors]);
170 snprintf(buf, sizeof buf, "/dev/pty%c%c", ptymajors[i / num_minors], 150 *ptyfd = open(buf, O_RDWR | O_NOCTTY);
171 ptyminors[i % num_minors]); 151 if (*ptyfd < 0)
172 *ptyfd = open(buf, O_RDWR|O_NOCTTY); 152 continue;
173 if (*ptyfd < 0) 153 snprintf(namebuf, sizeof buf, "/dev/tty%c%c", ptymajors[i / num_minors],
174 continue; 154 ptyminors[i % num_minors]);
175 snprintf(namebuf, sizeof buf, "/dev/tty%c%c", ptymajors[i / num_minors], 155
176 ptyminors[i % num_minors]); 156 /* Open the slave side. */
177 157 *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
178 /* Open the slave side. */ 158 if (*ttyfd < 0) {
179 *ttyfd = open(namebuf, O_RDWR|O_NOCTTY); 159 error("%.100s: %.100s", namebuf, strerror(errno));
180 if (*ttyfd < 0) 160 close(*ptyfd);
181 { 161 return 0;
182 error("%.100s: %.100s", namebuf, strerror(errno)); 162 }
183 close(*ptyfd); 163 return 1;
184 return 0;
185 } 164 }
186 return 1; 165 return 0;
187 }
188 return 0;
189#endif /* HAVE_DEV_PTS_AND_PTC */ 166#endif /* HAVE_DEV_PTS_AND_PTC */
190#endif /* HAVE_DEV_PTMX */ 167#endif /* HAVE_DEV_PTMX */
191#endif /* HAVE__GETPTY */ 168#endif /* HAVE__GETPTY */
192#endif /* HAVE_OPENPTY */ 169#endif /* HAVE_OPENPTY */
193} 170}
194 171
195/* Releases the tty. Its ownership is returned to root, and permissions to 172/* Releases the tty. Its ownership is returned to root, and permissions to 0666. */
196 0666. */
197 173
198void pty_release(const char *ttyname) 174void
175pty_release(const char *ttyname)
199{ 176{
200 if (chown(ttyname, (uid_t)0, (gid_t)0) < 0) 177 if (chown(ttyname, (uid_t) 0, (gid_t) 0) < 0)
201 debug("chown %.100s 0 0 failed: %.100s", ttyname, strerror(errno)); 178 debug("chown %.100s 0 0 failed: %.100s", ttyname, strerror(errno));
202 if (chmod(ttyname, (mode_t)0666) < 0) 179 if (chmod(ttyname, (mode_t) 0666) < 0)
203 debug("chmod %.100s 0666 failed: %.100s", ttyname, strerror(errno)); 180 debug("chmod %.100s 0666 failed: %.100s", ttyname, strerror(errno));
204} 181}
205 182
206/* Makes the tty the processes controlling tty and sets it to sane modes. */ 183/* Makes the tty the processes controlling tty and sets it to sane modes. */
207 184
208void pty_make_controlling_tty(int *ttyfd, const char *ttyname) 185void
186pty_make_controlling_tty(int *ttyfd, const char *ttyname)
209{ 187{
210 int fd; 188 int fd;
211 189
212 /* First disconnect from the old controlling tty. */ 190 /* First disconnect from the old controlling tty. */
213#ifdef TIOCNOTTY 191#ifdef TIOCNOTTY
214 fd = open("/dev/tty", O_RDWR|O_NOCTTY); 192 fd = open("/dev/tty", O_RDWR | O_NOCTTY);
215 if (fd >= 0) 193 if (fd >= 0) {
216 { 194 (void) ioctl(fd, TIOCNOTTY, NULL);
217 (void)ioctl(fd, TIOCNOTTY, NULL); 195 close(fd);
218 close(fd); 196 }
219 }
220#endif /* TIOCNOTTY */ 197#endif /* TIOCNOTTY */
221 if (setsid() < 0) 198 if (setsid() < 0)
222 error("setsid: %.100s", strerror(errno)); 199 error("setsid: %.100s", strerror(errno));
223 200
224 /* Verify that we are successfully disconnected from the controlling tty. */ 201 /* Verify that we are successfully disconnected from the
225 fd = open("/dev/tty", O_RDWR|O_NOCTTY); 202 controlling tty. */
226 if (fd >= 0) 203 fd = open("/dev/tty", O_RDWR | O_NOCTTY);
227 { 204 if (fd >= 0) {
228 error("Failed to disconnect from controlling tty."); 205 error("Failed to disconnect from controlling tty.");
229 close(fd); 206 close(fd);
230 } 207 }
231 208 /* Make it our controlling tty. */
232 /* Make it our controlling tty. */
233#ifdef TIOCSCTTY 209#ifdef TIOCSCTTY
234 debug("Setting controlling tty using TIOCSCTTY."); 210 debug("Setting controlling tty using TIOCSCTTY.");
235 /* We ignore errors from this, because HPSUX defines TIOCSCTTY, but returns 211 /* We ignore errors from this, because HPSUX defines TIOCSCTTY,
236 EINVAL with these arguments, and there is absolutely no documentation. */ 212 but returns EINVAL with these arguments, and there is
237 ioctl(*ttyfd, TIOCSCTTY, NULL); 213 absolutely no documentation. */
214 ioctl(*ttyfd, TIOCSCTTY, NULL);
238#endif /* TIOCSCTTY */ 215#endif /* TIOCSCTTY */
239 fd = open(ttyname, O_RDWR); 216 fd = open(ttyname, O_RDWR);
240 if (fd < 0) 217 if (fd < 0)
241 error("%.100s: %.100s", ttyname, strerror(errno)); 218 error("%.100s: %.100s", ttyname, strerror(errno));
242 else 219 else
243 close(fd); 220 close(fd);
244 221
245 /* Verify that we now have a controlling tty. */ 222 /* Verify that we now have a controlling tty. */
246 fd = open("/dev/tty", O_WRONLY); 223 fd = open("/dev/tty", O_WRONLY);
247 if (fd < 0) 224 if (fd < 0)
248 error("open /dev/tty failed - could not set controlling tty: %.100s", 225 error("open /dev/tty failed - could not set controlling tty: %.100s",
249 strerror(errno)); 226 strerror(errno));
250 else 227 else {
251 { 228 close(fd);
252 close(fd); 229 }
253 }
254} 230}
255 231
256/* Changes the window size associated with the pty. */ 232/* Changes the window size associated with the pty. */
257 233
258void pty_change_window_size(int ptyfd, int row, int col, 234void
259 int xpixel, int ypixel) 235pty_change_window_size(int ptyfd, int row, int col,
236 int xpixel, int ypixel)
260{ 237{
261 struct winsize w; 238 struct winsize w;
262 w.ws_row = row; 239 w.ws_row = row;
263 w.ws_col = col; 240 w.ws_col = col;
264 w.ws_xpixel = xpixel; 241 w.ws_xpixel = xpixel;
265 w.ws_ypixel = ypixel; 242 w.ws_ypixel = ypixel;
266 (void)ioctl(ptyfd, TIOCSWINSZ, &w); 243 (void) ioctl(ptyfd, TIOCSWINSZ, &w);
267} 244}
268
diff --git a/pty.h b/pty.h
index 20ee90a1d..215f4343e 100644
--- a/pty.h
+++ b/pty.h
@@ -1,40 +1,40 @@
1/* 1/*
2 2 *
3pty.h 3 * pty.h
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Fri Mar 17 05:03:28 1995 ylo 10 * Created: Fri Mar 17 05:03:28 1995 ylo
11 11 *
12Functions for allocating a pseudo-terminal and making it the controlling 12 * Functions for allocating a pseudo-terminal and making it the controlling
13tty. 13 * tty.
14 14 */
15*/ 15
16 16/* RCSID("$Id: pty.h,v 1.2 1999/11/24 13:26:22 damien Exp $"); */
17/* RCSID("$Id: pty.h,v 1.1 1999/10/27 03:42:44 damien Exp $"); */
18 17
19#ifndef PTY_H 18#ifndef PTY_H
20#define PTY_H 19#define PTY_H
21 20
22/* Allocates and opens a pty. Returns 0 if no pty could be allocated, 21/* Allocates and opens a pty. Returns 0 if no pty could be allocated,
23 or nonzero if a pty was successfully allocated. On success, open file 22 or nonzero if a pty was successfully allocated. On success, open file
24 descriptors for the pty and tty sides and the name of the tty side are 23 descriptors for the pty and tty sides and the name of the tty side are
25 returned (the buffer must be able to hold at least 64 characters). */ 24 returned (the buffer must be able to hold at least 64 characters). */
26int pty_allocate(int *ptyfd, int *ttyfd, char *ttyname); 25int pty_allocate(int *ptyfd, int *ttyfd, char *ttyname);
27 26
28/* Releases the tty. Its ownership is returned to root, and permissions to 27/* Releases the tty. Its ownership is returned to root, and permissions to
29 0666. */ 28 0666. */
30void pty_release(const char *ttyname); 29void pty_release(const char *ttyname);
31 30
32/* Makes the tty the processes controlling tty and sets it to sane modes. 31/* Makes the tty the processes controlling tty and sets it to sane modes.
33 This may need to reopen the tty to get rid of possible eavesdroppers. */ 32 This may need to reopen the tty to get rid of possible eavesdroppers. */
34void pty_make_controlling_tty(int *ttyfd, const char *ttyname); 33void pty_make_controlling_tty(int *ttyfd, const char *ttyname);
35 34
36/* Changes the window size associated with the pty. */ 35/* Changes the window size associated with the pty. */
37void pty_change_window_size(int ptyfd, int row, int col, 36void
38 int xpixel, int ypixel); 37pty_change_window_size(int ptyfd, int row, int col,
38 int xpixel, int ypixel);
39 39
40#endif /* PTY_H */ 40#endif /* PTY_H */
diff --git a/radix.c b/radix.c
index 1c497945e..6637b2fb1 100644
--- a/radix.c
+++ b/radix.c
@@ -1,101 +1,105 @@
1/* 1/*
2 radix.c 2 * radix.c
3 *
4 * base-64 encoding pinched from lynx2-7-2, who pinched it from rpem.
5 * Originally written by Mark Riordan 12 August 1990 and 17 Feb 1991
6 * and placed in the public domain.
7 *
8 * Dug Song <dugsong@UMICH.EDU>
9 */
3 10
4 base-64 encoding pinched from lynx2-7-2, who pinched it from rpem.
5 Originally written by Mark Riordan 12 August 1990 and 17 Feb 1991
6 and placed in the public domain.
7
8 Dug Song <dugsong@UMICH.EDU>
9*/
10
11#include "includes.h" 11#include "includes.h"
12 12
13#ifdef AFS 13#ifdef AFS
14#include <krb.h> 14#include <krb.h>
15 15
16char six2pr[64] = { 16char six2pr[64] = {
17 'A','B','C','D','E','F','G','H','I','J','K','L','M', 17 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
18 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z', 18 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
19 'a','b','c','d','e','f','g','h','i','j','k','l','m', 19 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
20 'n','o','p','q','r','s','t','u','v','w','x','y','z', 20 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
21 '0','1','2','3','4','5','6','7','8','9','+','/' 21 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
22}; 22};
23 23
24unsigned char pr2six[256]; 24unsigned char pr2six[256];
25 25
26int uuencode(unsigned char *bufin, unsigned int nbytes, char *bufcoded) 26int
27uuencode(unsigned char *bufin, unsigned int nbytes, char *bufcoded)
27{ 28{
28 /* ENC is the basic 1 character encoding function to make a char printing */ 29 /* ENC is the basic 1 character encoding function to make a char printing */
29#define ENC(c) six2pr[c] 30#define ENC(c) six2pr[c]
30 31
31 register char *outptr = bufcoded; 32 register char *outptr = bufcoded;
32 unsigned int i; 33 unsigned int i;
33 34
34 for (i=0; i<nbytes; i += 3) { 35 for (i = 0; i < nbytes; i += 3) {
35 *(outptr++) = ENC(*bufin >> 2); /* c1 */ 36 *(outptr++) = ENC(*bufin >> 2); /* c1 */
36 *(outptr++) = ENC(((*bufin << 4) & 060) | ((bufin[1] >> 4) & 017)); /*c2*/ 37 *(outptr++) = ENC(((*bufin << 4) & 060) | ((bufin[1] >> 4) & 017)); /* c2 */
37 *(outptr++) = ENC(((bufin[1] << 2) & 074) | ((bufin[2] >> 6) & 03));/*c3*/ 38 *(outptr++) = ENC(((bufin[1] << 2) & 074) | ((bufin[2] >> 6) & 03)); /* c3 */
38 *(outptr++) = ENC(bufin[2] & 077); /* c4 */ 39 *(outptr++) = ENC(bufin[2] & 077); /* c4 */
39 bufin += 3; 40 bufin += 3;
40 } 41 }
41 if (i == nbytes+1) { 42 if (i == nbytes + 1) {
42 outptr[-1] = '='; 43 outptr[-1] = '=';
43 } else if (i == nbytes+2) { 44 } else if (i == nbytes + 2) {
44 outptr[-1] = '='; 45 outptr[-1] = '=';
45 outptr[-2] = '='; 46 outptr[-2] = '=';
46 } 47 }
47 *outptr = '\0'; 48 *outptr = '\0';
48 return(outptr - bufcoded); 49 return (outptr - bufcoded);
49} 50}
50 51
51int uudecode(const char *bufcoded, unsigned char *bufplain, int outbufsize) 52int
53uudecode(const char *bufcoded, unsigned char *bufplain, int outbufsize)
52{ 54{
53 /* single character decode */ 55 /* single character decode */
54#define DEC(c) pr2six[(unsigned char)c] 56#define DEC(c) pr2six[(unsigned char)c]
55#define MAXVAL 63 57#define MAXVAL 63
56 58
57 static int first = 1; 59 static int first = 1;
58 int nbytesdecoded, j; 60 int nbytesdecoded, j;
59 const char *bufin = bufcoded; 61 const char *bufin = bufcoded;
60 register unsigned char *bufout = bufplain; 62 register unsigned char *bufout = bufplain;
61 register int nprbytes; 63 register int nprbytes;
62 64
63 /* If this is the first call, initialize the mapping table. */ 65 /* If this is the first call, initialize the mapping table. */
64 if (first) { 66 if (first) {
65 first = 0; 67 first = 0;
66 for(j=0; j<256; j++) pr2six[j] = MAXVAL+1; 68 for (j = 0; j < 256; j++)
67 for(j=0; j<64; j++) pr2six[(unsigned char)six2pr[j]] = (unsigned char)j; 69 pr2six[j] = MAXVAL + 1;
68 } 70 for (j = 0; j < 64; j++)
69 71 pr2six[(unsigned char) six2pr[j]] = (unsigned char) j;
70 /* Strip leading whitespace. */ 72 }
71 while (*bufcoded==' ' || *bufcoded == '\t') bufcoded++; 73 /* Strip leading whitespace. */
72 74 while (*bufcoded == ' ' || *bufcoded == '\t')
73 /* Figure out how many characters are in the input buffer. 75 bufcoded++;
74 If this would decode into more bytes than would fit into 76
75 the output buffer, adjust the number of input bytes downwards. */ 77 /* Figure out how many characters are in the input buffer. If this
76 bufin = bufcoded; 78 would decode into more bytes than would fit into the output
77 while (DEC(*(bufin++)) <= MAXVAL); 79 buffer, adjust the number of input bytes downwards. */
78 nprbytes = bufin - bufcoded - 1; 80 bufin = bufcoded;
79 nbytesdecoded = ((nprbytes+3)/4) * 3; 81 while (DEC(*(bufin++)) <= MAXVAL);
80 if (nbytesdecoded > outbufsize) 82 nprbytes = bufin - bufcoded - 1;
81 nprbytes = (outbufsize*4)/3; 83 nbytesdecoded = ((nprbytes + 3) / 4) * 3;
82 84 if (nbytesdecoded > outbufsize)
83 bufin = bufcoded; 85 nprbytes = (outbufsize * 4) / 3;
84 86
85 while (nprbytes > 0) { 87 bufin = bufcoded;
86 *(bufout++) = (unsigned char) (DEC(*bufin) << 2 | DEC(bufin[1]) >> 4); 88
87 *(bufout++) = (unsigned char) (DEC(bufin[1]) << 4 | DEC(bufin[2]) >> 2); 89 while (nprbytes > 0) {
88 *(bufout++) = (unsigned char) (DEC(bufin[2]) << 6 | DEC(bufin[3])); 90 *(bufout++) = (unsigned char) (DEC(*bufin) << 2 | DEC(bufin[1]) >> 4);
89 bufin += 4; 91 *(bufout++) = (unsigned char) (DEC(bufin[1]) << 4 | DEC(bufin[2]) >> 2);
90 nprbytes -= 4; 92 *(bufout++) = (unsigned char) (DEC(bufin[2]) << 6 | DEC(bufin[3]));
91 } 93 bufin += 4;
92 if (nprbytes & 03) { 94 nprbytes -= 4;
93 if (DEC(bufin[-2]) > MAXVAL) 95 }
94 nbytesdecoded -= 2; 96 if (nprbytes & 03) {
95 else 97 if (DEC(bufin[-2]) > MAXVAL)
96 nbytesdecoded -= 1; 98 nbytesdecoded -= 2;
97 } 99 else
98 return(nbytesdecoded); 100 nbytesdecoded -= 1;
101 }
102 return (nbytesdecoded);
99} 103}
100 104
101typedef unsigned char my_u_char; 105typedef unsigned char my_u_char;
@@ -156,103 +160,124 @@ typedef unsigned short my_u_short;
156} 160}
157 161
158 162
159int creds_to_radix(CREDENTIALS *creds, unsigned char *buf) 163int
164creds_to_radix(CREDENTIALS *creds, unsigned char *buf)
160{ 165{
161 char *p, *s; 166 char *p, *s;
162 int len; 167 int len;
163 char temp[2048]; 168 char temp[2048];
164 169
165 p = temp; 170 p = temp;
166 *p++ = 1; /* version */ 171 *p++ = 1; /* version */
167 s = creds->service; while (*s) *p++ = *s++; *p++ = *s; 172 s = creds->service;
168 s = creds->instance; while (*s) *p++ = *s++; *p++ = *s; 173 while (*s)
169 s = creds->realm; while (*s) *p++ = *s++; *p++ = *s; 174 *p++ = *s++;
170 175 *p++ = *s;
171 s = creds->pname; while (*s) *p++ = *s++; *p++ = *s; 176 s = creds->instance;
172 s = creds->pinst; while (*s) *p++ = *s++; *p++ = *s; 177 while (*s)
173 /* Null string to repeat the realm. */ 178 *p++ = *s++;
174 *p++ = '\0'; 179 *p++ = *s;
175 180 s = creds->realm;
176 PUTLONG(creds->issue_date,p); 181 while (*s)
177 { 182 *p++ = *s++;
178 unsigned int endTime ; 183 *p++ = *s;
179 endTime = (unsigned int)krb_life_to_time(creds->issue_date, 184
180 creds->lifetime); 185 s = creds->pname;
181 PUTLONG(endTime,p); 186 while (*s)
182 } 187 *p++ = *s++;
183 188 *p++ = *s;
184 memcpy(p,&creds->session, sizeof(creds->session)); 189 s = creds->pinst;
185 p += sizeof(creds->session); 190 while (*s)
186 191 *p++ = *s++;
187 PUTSHORT(creds->kvno,p); 192 *p++ = *s;
188 PUTLONG(creds->ticket_st.length,p); 193 /* Null string to repeat the realm. */
189 194 *p++ = '\0';
190 memcpy(p,creds->ticket_st.dat, creds->ticket_st.length); 195
191 p += creds->ticket_st.length; 196 PUTLONG(creds->issue_date, p);
192 len = p - temp; 197 {
193 198 unsigned int endTime;
194 return(uuencode(temp, len, buf)); 199 endTime = (unsigned int) krb_life_to_time(creds->issue_date,
200 creds->lifetime);
201 PUTLONG(endTime, p);
202 }
203
204 memcpy(p, &creds->session, sizeof(creds->session));
205 p += sizeof(creds->session);
206
207 PUTSHORT(creds->kvno, p);
208 PUTLONG(creds->ticket_st.length, p);
209
210 memcpy(p, creds->ticket_st.dat, creds->ticket_st.length);
211 p += creds->ticket_st.length;
212 len = p - temp;
213
214 return (uuencode(temp, len, buf));
195} 215}
196 216
197int radix_to_creds(const char *buf, CREDENTIALS *creds) 217int
218radix_to_creds(const char *buf, CREDENTIALS *creds)
198{ 219{
199 220
200 char *p; 221 char *p;
201 int len, tl; 222 int len, tl;
202 char version; 223 char version;
203 char temp[2048]; 224 char temp[2048];
204 225
205 if (!(len = uudecode(buf, temp, sizeof(temp)))) 226 if (!(len = uudecode(buf, temp, sizeof(temp))))
206 return 0; 227 return 0;
207 228
208 p = temp; 229 p = temp;
209 230
210 /* check version and length! */ 231 /* check version and length! */
211 if (len < 1) return 0; 232 if (len < 1)
212 version = *p; p++; len--; 233 return 0;
213 234 version = *p;
214 GETSTRING(creds->service, p, len); 235 p++;
215 GETSTRING(creds->instance, p, len); 236 len--;
216 GETSTRING(creds->realm, p, len); 237
217 238 GETSTRING(creds->service, p, len);
218 GETSTRING(creds->pname, p, len); 239 GETSTRING(creds->instance, p, len);
219 GETSTRING(creds->pinst, p, len); 240 GETSTRING(creds->realm, p, len);
220 /* Ignore possibly different realm. */ 241
221 while (*p && len) p++, len--; 242 GETSTRING(creds->pname, p, len);
222 if (len == 0) return 0; 243 GETSTRING(creds->pinst, p, len);
223 p++, len--; 244 /* Ignore possibly different realm. */
224 245 while (*p && len)
225 /* Enough space for remaining fixed-length parts? */ 246 p++, len--;
226 if (len < (4 + 4 + sizeof(creds->session) + 2 + 4)) 247 if (len == 0)
227 return 0; 248 return 0;
228 249 p++, len--;
229 GETLONG(creds->issue_date,p);
230 len -= 4;
231 {
232 unsigned int endTime;
233 GETLONG(endTime,p);
234 len -= 4;
235 creds->lifetime = krb_time_to_life(creds->issue_date, endTime);
236 }
237
238 memcpy(&creds->session, p, sizeof(creds->session));
239 p += sizeof(creds->session);
240 len -= sizeof(creds->session);
241
242 GETSHORT(creds->kvno,p);
243 len -= 2;
244 GETLONG(creds->ticket_st.length,p);
245 len -= 4;
246
247 tl = creds->ticket_st.length;
248 if (tl < 0 || tl > len || tl > sizeof(creds->ticket_st.dat))
249 return 0;
250
251 memcpy(creds->ticket_st.dat, p, tl);
252 p += tl;
253 len -= tl;
254
255 return 1;
256}
257 250
251 /* Enough space for remaining fixed-length parts? */
252 if (len < (4 + 4 + sizeof(creds->session) + 2 + 4))
253 return 0;
254
255 GETLONG(creds->issue_date, p);
256 len -= 4;
257 {
258 unsigned int endTime;
259 GETLONG(endTime, p);
260 len -= 4;
261 creds->lifetime = krb_time_to_life(creds->issue_date, endTime);
262 }
263
264 memcpy(&creds->session, p, sizeof(creds->session));
265 p += sizeof(creds->session);
266 len -= sizeof(creds->session);
267
268 GETSHORT(creds->kvno, p);
269 len -= 2;
270 GETLONG(creds->ticket_st.length, p);
271 len -= 4;
272
273 tl = creds->ticket_st.length;
274 if (tl < 0 || tl > len || tl > sizeof(creds->ticket_st.dat))
275 return 0;
276
277 memcpy(creds->ticket_st.dat, p, tl);
278 p += tl;
279 len -= tl;
280
281 return 1;
282}
258#endif /* AFS */ 283#endif /* AFS */
diff --git a/readconf.c b/readconf.c
index d8694b82d..063bd467d 100644
--- a/readconf.c
+++ b/readconf.c
@@ -1,20 +1,20 @@
1/* 1/*
2 2 *
3readconf.c 3 * readconf.c
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Sat Apr 22 00:03:10 1995 ylo 10 * Created: Sat Apr 22 00:03:10 1995 ylo
11 11 *
12Functions for reading the configuration files. 12 * Functions for reading the configuration files.
13 13 *
14*/ 14 */
15 15
16#include "includes.h" 16#include "includes.h"
17RCSID("$Id: readconf.c,v 1.4 1999/11/21 02:23:53 damien Exp $"); 17RCSID("$Id: readconf.c,v 1.5 1999/11/24 13:26:22 damien Exp $");
18 18
19#include "ssh.h" 19#include "ssh.h"
20#include "cipher.h" 20#include "cipher.h"
@@ -86,73 +86,72 @@ RCSID("$Id: readconf.c,v 1.4 1999/11/21 02:23:53 damien Exp $");
86 86
87/* Keyword tokens. */ 87/* Keyword tokens. */
88 88
89typedef enum 89typedef enum {
90{ 90 oBadOption,
91 oBadOption, 91 oForwardAgent, oForwardX11, oGatewayPorts, oRhostsAuthentication,
92 oForwardAgent, oForwardX11, oGatewayPorts, oRhostsAuthentication, 92 oPasswordAuthentication, oRSAAuthentication, oFallBackToRsh, oUseRsh,
93 oPasswordAuthentication, oRSAAuthentication, oFallBackToRsh, oUseRsh, 93 oSkeyAuthentication,
94#ifdef KRB4 94#ifdef KRB4
95 oKerberosAuthentication, 95 oKerberosAuthentication,
96#endif /* KRB4 */ 96#endif /* KRB4 */
97#ifdef AFS 97#ifdef AFS
98 oKerberosTgtPassing, oAFSTokenPassing, 98 oKerberosTgtPassing, oAFSTokenPassing,
99#endif 99#endif
100 oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward, 100 oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
101 oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand, 101 oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
102 oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts, 102 oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
103 oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression, 103 oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
104 oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts, oTISAuthentication, 104 oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts, oTISAuthentication,
105 oUsePrivilegedPort, oLogLevel 105 oUsePrivilegedPort, oLogLevel
106} OpCodes; 106} OpCodes;
107 107
108/* Textual representations of the tokens. */ 108/* Textual representations of the tokens. */
109 109
110static struct 110static struct {
111{ 111 const char *name;
112 const char *name; 112 OpCodes opcode;
113 OpCodes opcode; 113} keywords[] = {
114} keywords[] = 114 { "forwardagent", oForwardAgent },
115{ 115 { "forwardx11", oForwardX11 },
116 { "forwardagent", oForwardAgent }, 116 { "gatewayports", oGatewayPorts },
117 { "forwardx11", oForwardX11 }, 117 { "useprivilegedport", oUsePrivilegedPort },
118 { "gatewayports", oGatewayPorts }, 118 { "rhostsauthentication", oRhostsAuthentication },
119 { "useprivilegedport", oUsePrivilegedPort }, 119 { "passwordauthentication", oPasswordAuthentication },
120 { "rhostsauthentication", oRhostsAuthentication }, 120 { "rsaauthentication", oRSAAuthentication },
121 { "passwordauthentication", oPasswordAuthentication }, 121 { "skeyauthentication", oSkeyAuthentication },
122 { "rsaauthentication", oRSAAuthentication },
123#ifdef KRB4 122#ifdef KRB4
124 { "kerberosauthentication", oKerberosAuthentication }, 123 { "kerberosauthentication", oKerberosAuthentication },
125#endif /* KRB4 */ 124#endif /* KRB4 */
126#ifdef AFS 125#ifdef AFS
127 { "kerberostgtpassing", oKerberosTgtPassing }, 126 { "kerberostgtpassing", oKerberosTgtPassing },
128 { "afstokenpassing", oAFSTokenPassing }, 127 { "afstokenpassing", oAFSTokenPassing },
129#endif 128#endif
130 { "fallbacktorsh", oFallBackToRsh }, 129 { "fallbacktorsh", oFallBackToRsh },
131 { "usersh", oUseRsh }, 130 { "usersh", oUseRsh },
132 { "identityfile", oIdentityFile }, 131 { "identityfile", oIdentityFile },
133 { "hostname", oHostName }, 132 { "hostname", oHostName },
134 { "proxycommand", oProxyCommand }, 133 { "proxycommand", oProxyCommand },
135 { "port", oPort }, 134 { "port", oPort },
136 { "cipher", oCipher }, 135 { "cipher", oCipher },
137 { "remoteforward", oRemoteForward }, 136 { "remoteforward", oRemoteForward },
138 { "localforward", oLocalForward }, 137 { "localforward", oLocalForward },
139 { "user", oUser }, 138 { "user", oUser },
140 { "host", oHost }, 139 { "host", oHost },
141 { "escapechar", oEscapeChar }, 140 { "escapechar", oEscapeChar },
142 { "rhostsrsaauthentication", oRhostsRSAAuthentication }, 141 { "rhostsrsaauthentication", oRhostsRSAAuthentication },
143 { "globalknownhostsfile", oGlobalKnownHostsFile }, 142 { "globalknownhostsfile", oGlobalKnownHostsFile },
144 { "userknownhostsfile", oUserKnownHostsFile }, 143 { "userknownhostsfile", oUserKnownHostsFile },
145 { "connectionattempts", oConnectionAttempts }, 144 { "connectionattempts", oConnectionAttempts },
146 { "batchmode", oBatchMode }, 145 { "batchmode", oBatchMode },
147 { "checkhostip", oCheckHostIP }, 146 { "checkhostip", oCheckHostIP },
148 { "stricthostkeychecking", oStrictHostKeyChecking }, 147 { "stricthostkeychecking", oStrictHostKeyChecking },
149 { "compression", oCompression }, 148 { "compression", oCompression },
150 { "compressionlevel", oCompressionLevel }, 149 { "compressionlevel", oCompressionLevel },
151 { "keepalive", oKeepAlives }, 150 { "keepalive", oKeepAlives },
152 { "numberofpasswordprompts", oNumberOfPasswordPrompts }, 151 { "numberofpasswordprompts", oNumberOfPasswordPrompts },
153 { "tisauthentication", oTISAuthentication }, 152 { "tisauthentication", oTISAuthentication },
154 { "loglevel", oLogLevel }, 153 { "loglevel", oLogLevel },
155 { NULL, 0 } 154 { NULL, 0 }
156}; 155};
157 156
158/* Characters considered whitespace in strtok calls. */ 157/* Characters considered whitespace in strtok calls. */
@@ -162,53 +161,56 @@ static struct
162/* Adds a local TCP/IP port forward to options. Never returns if there 161/* Adds a local TCP/IP port forward to options. Never returns if there
163 is an error. */ 162 is an error. */
164 163
165void add_local_forward(Options *options, int port, const char *host, 164void
166 int host_port) 165add_local_forward(Options *options, int port, const char *host,
166 int host_port)
167{ 167{
168 Forward *fwd; 168 Forward *fwd;
169 extern uid_t original_real_uid; 169 extern uid_t original_real_uid;
170 if ((port & 0xffff) != port) 170 if ((port & 0xffff) != port)
171 fatal("Requested forwarding of nonexistent port %d.", port); 171 fatal("Requested forwarding of nonexistent port %d.", port);
172 if (port < IPPORT_RESERVED && original_real_uid != 0) 172 if (port < IPPORT_RESERVED && original_real_uid != 0)
173 fatal("Privileged ports can only be forwarded by root.\n"); 173 fatal("Privileged ports can only be forwarded by root.\n");
174 if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION) 174 if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
175 fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION); 175 fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION);
176 fwd = &options->local_forwards[options->num_local_forwards++]; 176 fwd = &options->local_forwards[options->num_local_forwards++];
177 fwd->port = port; 177 fwd->port = port;
178 fwd->host = xstrdup(host); 178 fwd->host = xstrdup(host);
179 fwd->host_port = host_port; 179 fwd->host_port = host_port;
180} 180}
181 181
182/* Adds a remote TCP/IP port forward to options. Never returns if there 182/* Adds a remote TCP/IP port forward to options. Never returns if there
183 is an error. */ 183 is an error. */
184 184
185void add_remote_forward(Options *options, int port, const char *host, 185void
186 int host_port) 186add_remote_forward(Options *options, int port, const char *host,
187 int host_port)
187{ 188{
188 Forward *fwd; 189 Forward *fwd;
189 if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION) 190 if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
190 fatal("Too many remote forwards (max %d).", 191 fatal("Too many remote forwards (max %d).",
191 SSH_MAX_FORWARDS_PER_DIRECTION); 192 SSH_MAX_FORWARDS_PER_DIRECTION);
192 fwd = &options->remote_forwards[options->num_remote_forwards++]; 193 fwd = &options->remote_forwards[options->num_remote_forwards++];
193 fwd->port = port; 194 fwd->port = port;
194 fwd->host = xstrdup(host); 195 fwd->host = xstrdup(host);
195 fwd->host_port = host_port; 196 fwd->host_port = host_port;
196} 197}
197 198
198/* Returns the number of the token pointed to by cp of length len. 199/* Returns the number of the token pointed to by cp of length len.
199 Never returns if the token is not known. */ 200 Never returns if the token is not known. */
200 201
201static OpCodes parse_token(const char *cp, const char *filename, int linenum) 202static OpCodes
203parse_token(const char *cp, const char *filename, int linenum)
202{ 204{
203 unsigned int i; 205 unsigned int i;
204 206
205 for (i = 0; keywords[i].name; i++) 207 for (i = 0; keywords[i].name; i++)
206 if (strcmp(cp, keywords[i].name) == 0) 208 if (strcmp(cp, keywords[i].name) == 0)
207 return keywords[i].opcode; 209 return keywords[i].opcode;
208 210
209 fprintf(stderr, "%s: line %d: Bad configuration option: %s\n", 211 fprintf(stderr, "%s: line %d: Bad configuration option: %s\n",
210 filename, linenum, cp); 212 filename, linenum, cp);
211 return oBadOption; 213 return oBadOption;
212} 214}
213 215
214/* Processes a single option line as used in the configuration files. 216/* Processes a single option line as used in the configuration files.
@@ -216,336 +218,329 @@ static OpCodes parse_token(const char *cp, const char *filename, int linenum)
216 218
217int 219int
218process_config_line(Options *options, const char *host, 220process_config_line(Options *options, const char *host,
219 char *line, const char *filename, int linenum, 221 char *line, const char *filename, int linenum,
220 int *activep) 222 int *activep)
221{ 223{
222 char buf[256], *cp, *string, **charptr; 224 char buf[256], *cp, *string, **charptr;
223 int opcode, *intptr, value, fwd_port, fwd_host_port; 225 int opcode, *intptr, value, fwd_port, fwd_host_port;
224 226
225 /* Skip leading whitespace. */ 227 /* Skip leading whitespace. */
226 cp = line + strspn(line, WHITESPACE); 228 cp = line + strspn(line, WHITESPACE);
227 if (!*cp || *cp == '\n' || *cp == '#') 229 if (!*cp || *cp == '\n' || *cp == '#')
228 return 0; 230 return 0;
229 231
230 /* Get the keyword. (Each line is supposed to begin with a keyword). */ 232 /* Get the keyword. (Each line is supposed to begin with a
231 cp = strtok(cp, WHITESPACE); 233 keyword). */
232 { 234 cp = strtok(cp, WHITESPACE);
233 char *t = cp; 235 {
234 for (; *t != 0; t++) 236 char *t = cp;
235 if ('A' <= *t && *t <= 'Z') 237 for (; *t != 0; t++)
236 *t = *t - 'A' + 'a'; /* tolower */ 238 if ('A' <= *t && *t <= 'Z')
237 239 *t = *t - 'A' + 'a'; /* tolower */
238 } 240
239 opcode = parse_token(cp, filename, linenum); 241 }
240 242 opcode = parse_token(cp, filename, linenum);
241 switch (opcode) 243
242 { 244 switch (opcode) {
243 case oBadOption: 245 case oBadOption:
244 return -1; /* don't panic, but count bad options */ 246 return -1; /* don't panic, but count bad options */
245 /*NOTREACHED*/ 247 /* NOTREACHED */
246 case oForwardAgent: 248 case oForwardAgent:
247 intptr = &options->forward_agent; 249 intptr = &options->forward_agent;
248 parse_flag: 250parse_flag:
249 cp = strtok(NULL, WHITESPACE); 251 cp = strtok(NULL, WHITESPACE);
250 if (!cp) 252 if (!cp)
251 fatal("%.200s line %d: Missing yes/no argument.", filename, linenum); 253 fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
252 value = 0; /* To avoid compiler warning... */ 254 value = 0; /* To avoid compiler warning... */
253 if (strcmp(cp, "yes") == 0 || strcmp(cp, "true") == 0) 255 if (strcmp(cp, "yes") == 0 || strcmp(cp, "true") == 0)
254 value = 1; 256 value = 1;
255 else if (strcmp(cp, "no") == 0 || strcmp(cp, "false") == 0) 257 else if (strcmp(cp, "no") == 0 || strcmp(cp, "false") == 0)
256 value = 0; 258 value = 0;
257 else 259 else
258 fatal("%.200s line %d: Bad yes/no argument.", filename, linenum); 260 fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
259 if (*activep && *intptr == -1) 261 if (*activep && *intptr == -1)
260 *intptr = value; 262 *intptr = value;
261 break; 263 break;
262 264
263 case oForwardX11: 265 case oForwardX11:
264 intptr = &options->forward_x11; 266 intptr = &options->forward_x11;
265 goto parse_flag; 267 goto parse_flag;
266 268
267 case oGatewayPorts: 269 case oGatewayPorts:
268 intptr = &options->gateway_ports; 270 intptr = &options->gateway_ports;
269 goto parse_flag; 271 goto parse_flag;
270 272
271 case oUsePrivilegedPort: 273 case oUsePrivilegedPort:
272 intptr = &options->use_privileged_port; 274 intptr = &options->use_privileged_port;
273 goto parse_flag; 275 goto parse_flag;
274 276
275 case oRhostsAuthentication: 277 case oRhostsAuthentication:
276 intptr = &options->rhosts_authentication; 278 intptr = &options->rhosts_authentication;
277 goto parse_flag; 279 goto parse_flag;
278 280
279 case oPasswordAuthentication: 281 case oPasswordAuthentication:
280 intptr = &options->password_authentication; 282 intptr = &options->password_authentication;
281 goto parse_flag; 283 goto parse_flag;
282 284
283 case oRSAAuthentication: 285 case oRSAAuthentication:
284 intptr = &options->rsa_authentication; 286 intptr = &options->rsa_authentication;
285 goto parse_flag; 287 goto parse_flag;
286 288
287 case oRhostsRSAAuthentication: 289 case oRhostsRSAAuthentication:
288 intptr = &options->rhosts_rsa_authentication; 290 intptr = &options->rhosts_rsa_authentication;
289 goto parse_flag; 291 goto parse_flag;
292
293 case oTISAuthentication:
294 /* fallthrough, there is no difference on the client side */
295 case oSkeyAuthentication:
296 intptr = &options->skey_authentication;
297 goto parse_flag;
290 298
291#ifdef KRB4 299#ifdef KRB4
292 case oKerberosAuthentication: 300 case oKerberosAuthentication:
293 intptr = &options->kerberos_authentication; 301 intptr = &options->kerberos_authentication;
294 goto parse_flag; 302 goto parse_flag;
295#endif /* KRB4 */ 303#endif /* KRB4 */
296 304
297#ifdef AFS 305#ifdef AFS
298 case oKerberosTgtPassing: 306 case oKerberosTgtPassing:
299 intptr = &options->kerberos_tgt_passing; 307 intptr = &options->kerberos_tgt_passing;
300 goto parse_flag; 308 goto parse_flag;
301 309
302 case oAFSTokenPassing: 310 case oAFSTokenPassing:
303 intptr = &options->afs_token_passing; 311 intptr = &options->afs_token_passing;
304 goto parse_flag; 312 goto parse_flag;
305#endif 313#endif
306 314
307 case oFallBackToRsh: 315 case oFallBackToRsh:
308 intptr = &options->fallback_to_rsh; 316 intptr = &options->fallback_to_rsh;
309 goto parse_flag; 317 goto parse_flag;
310 318
311 case oUseRsh: 319 case oUseRsh:
312 intptr = &options->use_rsh; 320 intptr = &options->use_rsh;
313 goto parse_flag; 321 goto parse_flag;
314 322
315 case oBatchMode: 323 case oBatchMode:
316 intptr = &options->batch_mode; 324 intptr = &options->batch_mode;
317 goto parse_flag; 325 goto parse_flag;
318 326
319 case oCheckHostIP: 327 case oCheckHostIP:
320 intptr = &options->check_host_ip; 328 intptr = &options->check_host_ip;
321 goto parse_flag; 329 goto parse_flag;
322 330
323 case oStrictHostKeyChecking: 331 case oStrictHostKeyChecking:
324 intptr = &options->strict_host_key_checking; 332 intptr = &options->strict_host_key_checking;
325 cp = strtok(NULL, WHITESPACE); 333 cp = strtok(NULL, WHITESPACE);
326 if (!cp) 334 if (!cp)
327 fatal("%.200s line %d: Missing yes/no argument.", 335 fatal("%.200s line %d: Missing yes/no argument.",
328 filename, linenum); 336 filename, linenum);
329 value = 0; /* To avoid compiler warning... */ 337 value = 0; /* To avoid compiler warning... */
330 if (strcmp(cp, "yes") == 0 || strcmp(cp, "true") == 0) 338 if (strcmp(cp, "yes") == 0 || strcmp(cp, "true") == 0)
331 value = 1; 339 value = 1;
332 else if (strcmp(cp, "no") == 0 || strcmp(cp, "false") == 0) 340 else if (strcmp(cp, "no") == 0 || strcmp(cp, "false") == 0)
333 value = 0; 341 value = 0;
334 else if (strcmp(cp, "ask") == 0) 342 else if (strcmp(cp, "ask") == 0)
335 value = 2; 343 value = 2;
336 else 344 else
337 fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum); 345 fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum);
338 if (*activep && *intptr == -1) 346 if (*activep && *intptr == -1)
339 *intptr = value; 347 *intptr = value;
340 break; 348 break;
341 349
342 case oCompression: 350 case oCompression:
343 intptr = &options->compression; 351 intptr = &options->compression;
344 goto parse_flag; 352 goto parse_flag;
345 353
346 case oKeepAlives: 354 case oKeepAlives:
347 intptr = &options->keepalives; 355 intptr = &options->keepalives;
348 goto parse_flag; 356 goto parse_flag;
349 357
350 case oNumberOfPasswordPrompts: 358 case oNumberOfPasswordPrompts:
351 intptr = &options->number_of_password_prompts; 359 intptr = &options->number_of_password_prompts;
352 goto parse_int; 360 goto parse_int;
353 361
354 case oTISAuthentication: 362 case oCompressionLevel:
355 cp = strtok(NULL, WHITESPACE); 363 intptr = &options->compression_level;
356 if (cp != 0 && (strcmp(cp, "yes") == 0 || strcmp(cp, "true") == 0)) 364 goto parse_int;
357 fprintf(stderr, 365
358 "%.99s line %d: Warning, TIS is not supported.\n", 366 case oIdentityFile:
359 filename, 367 cp = strtok(NULL, WHITESPACE);
360 linenum); 368 if (!cp)
361 break; 369 fatal("%.200s line %d: Missing argument.", filename, linenum);
362 370 if (*activep) {
363 case oCompressionLevel: 371 if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
364 intptr = &options->compression_level; 372 fatal("%.200s line %d: Too many identity files specified (max %d).",
365 goto parse_int; 373 filename, linenum, SSH_MAX_IDENTITY_FILES);
366 374 options->identity_files[options->num_identity_files++] = xstrdup(cp);
367 case oIdentityFile: 375 }
368 cp = strtok(NULL, WHITESPACE); 376 break;
369 if (!cp) 377
370 fatal("%.200s line %d: Missing argument.", filename, linenum); 378 case oUser:
371 if (*activep) 379 charptr = &options->user;
372 { 380parse_string:
373 if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES) 381 cp = strtok(NULL, WHITESPACE);
374 fatal("%.200s line %d: Too many identity files specified (max %d).", 382 if (!cp)
375 filename, linenum, SSH_MAX_IDENTITY_FILES); 383 fatal("%.200s line %d: Missing argument.", filename, linenum);
376 options->identity_files[options->num_identity_files++] = xstrdup(cp); 384 if (*activep && *charptr == NULL)
377 } 385 *charptr = xstrdup(cp);
378 break; 386 break;
379 387
380 case oUser: 388 case oGlobalKnownHostsFile:
381 charptr = &options->user; 389 charptr = &options->system_hostfile;
382 parse_string: 390 goto parse_string;
383 cp = strtok(NULL, WHITESPACE); 391
384 if (!cp) 392 case oUserKnownHostsFile:
385 fatal("%.200s line %d: Missing argument.", filename, linenum); 393 charptr = &options->user_hostfile;
386 if (*activep && *charptr == NULL) 394 goto parse_string;
387 *charptr = xstrdup(cp); 395
388 break; 396 case oHostName:
389 397 charptr = &options->hostname;
390 case oGlobalKnownHostsFile: 398 goto parse_string;
391 charptr = &options->system_hostfile; 399
392 goto parse_string; 400 case oProxyCommand:
393 401 charptr = &options->proxy_command;
394 case oUserKnownHostsFile: 402 string = xstrdup("");
395 charptr = &options->user_hostfile; 403 while ((cp = strtok(NULL, WHITESPACE)) != NULL) {
396 goto parse_string; 404 string = xrealloc(string, strlen(string) + strlen(cp) + 2);
397 405 strcat(string, " ");
398 case oHostName: 406 strcat(string, cp);
399 charptr = &options->hostname; 407 }
400 goto parse_string; 408 if (*activep && *charptr == NULL)
401 409 *charptr = string;
402 case oProxyCommand: 410 else
403 charptr = &options->proxy_command; 411 xfree(string);
404 string = xstrdup(""); 412 return 0;
405 while ((cp = strtok(NULL, WHITESPACE)) != NULL) 413
406 { 414 case oPort:
407 string = xrealloc(string, strlen(string) + strlen(cp) + 2); 415 intptr = &options->port;
408 strcat(string, " "); 416parse_int:
409 strcat(string, cp); 417 cp = strtok(NULL, WHITESPACE);
410 } 418 if (!cp)
411 if (*activep && *charptr == NULL) 419 fatal("%.200s line %d: Missing argument.", filename, linenum);
412 *charptr = string; 420 if (cp[0] < '0' || cp[0] > '9')
413 else 421 fatal("%.200s line %d: Bad number.", filename, linenum);
414 xfree(string);
415 return 0;
416
417 case oPort:
418 intptr = &options->port;
419 parse_int:
420 cp = strtok(NULL, WHITESPACE);
421 if (!cp)
422 fatal("%.200s line %d: Missing argument.", filename, linenum);
423 if (cp[0] < '0' || cp[0] > '9')
424 fatal("%.200s line %d: Bad number.", filename, linenum);
425#if 0 422#if 0
426 value = atoi(cp); 423 value = atoi(cp);
427#else 424#else
428 { 425 {
429 char *ptr; 426 char *ptr;
430 value = strtol(cp, &ptr, 0); /* Octal, decimal, or hex format? */ 427 value = strtol(cp, &ptr, 0); /* Octal, decimal, or
431 if (cp == ptr) 428 hex format? */
432 fatal("%.200s line %d: Bad number.", filename, linenum); 429 if (cp == ptr)
433 } 430 fatal("%.200s line %d: Bad number.", filename, linenum);
431 }
434#endif 432#endif
435 if (*activep && *intptr == -1) 433 if (*activep && *intptr == -1)
436 *intptr = value; 434 *intptr = value;
437 break; 435 break;
438 436
439 case oConnectionAttempts: 437 case oConnectionAttempts:
440 intptr = &options->connection_attempts; 438 intptr = &options->connection_attempts;
441 goto parse_int; 439 goto parse_int;
442 440
443 case oCipher: 441 case oCipher:
444 intptr = &options->cipher; 442 intptr = &options->cipher;
445 cp = strtok(NULL, WHITESPACE); 443 cp = strtok(NULL, WHITESPACE);
446 value = cipher_number(cp); 444 value = cipher_number(cp);
447 if (value == -1) 445 if (value == -1)
448 fatal("%.200s line %d: Bad cipher '%s'.", 446 fatal("%.200s line %d: Bad cipher '%s'.",
449 filename, linenum, cp ? cp : "<NONE>"); 447 filename, linenum, cp ? cp : "<NONE>");
450 if (*activep && *intptr == -1) 448 if (*activep && *intptr == -1)
451 *intptr = value; 449 *intptr = value;
452 break; 450 break;
453 451
454 case oLogLevel: 452 case oLogLevel:
455 intptr = (int *)&options->log_level; 453 intptr = (int *) &options->log_level;
456 cp = strtok(NULL, WHITESPACE); 454 cp = strtok(NULL, WHITESPACE);
457 value = log_level_number(cp); 455 value = log_level_number(cp);
458 if (value == (LogLevel)-1) 456 if (value == (LogLevel) - 1)
459 fatal("%.200s line %d: unsupported log level '%s'\n", 457 fatal("%.200s line %d: unsupported log level '%s'\n",
460 filename, linenum, cp ? cp : "<NONE>"); 458 filename, linenum, cp ? cp : "<NONE>");
461 if (*activep && (LogLevel)*intptr == -1) 459 if (*activep && (LogLevel) * intptr == -1)
462 *intptr = (LogLevel)value; 460 *intptr = (LogLevel) value;
463 break; 461 break;
464 462
465 case oRemoteForward: 463 case oRemoteForward:
466 cp = strtok(NULL, WHITESPACE); 464 cp = strtok(NULL, WHITESPACE);
467 if (!cp) 465 if (!cp)
468 fatal("%.200s line %d: Missing argument.", filename, linenum); 466 fatal("%.200s line %d: Missing argument.", filename, linenum);
469 if (cp[0] < '0' || cp[0] > '9') 467 if (cp[0] < '0' || cp[0] > '9')
470 fatal("%.200s line %d: Badly formatted port number.", 468 fatal("%.200s line %d: Badly formatted port number.",
471 filename, linenum); 469 filename, linenum);
472 fwd_port = atoi(cp); 470 fwd_port = atoi(cp);
473 cp = strtok(NULL, WHITESPACE); 471 cp = strtok(NULL, WHITESPACE);
474 if (!cp) 472 if (!cp)
475 fatal("%.200s line %d: Missing second argument.", 473 fatal("%.200s line %d: Missing second argument.",
476 filename, linenum); 474 filename, linenum);
477 if (sscanf(cp, "%255[^:]:%d", buf, &fwd_host_port) != 2) 475 if (sscanf(cp, "%255[^:]:%d", buf, &fwd_host_port) != 2)
478 fatal("%.200s line %d: Badly formatted host:port.", 476 fatal("%.200s line %d: Badly formatted host:port.",
479 filename, linenum); 477 filename, linenum);
480 if (*activep) 478 if (*activep)
481 add_remote_forward(options, fwd_port, buf, fwd_host_port); 479 add_remote_forward(options, fwd_port, buf, fwd_host_port);
482 break; 480 break;
483 481
484 case oLocalForward: 482 case oLocalForward:
485 cp = strtok(NULL, WHITESPACE); 483 cp = strtok(NULL, WHITESPACE);
486 if (!cp) 484 if (!cp)
487 fatal("%.200s line %d: Missing argument.", filename, linenum); 485 fatal("%.200s line %d: Missing argument.", filename, linenum);
488 if (cp[0] < '0' || cp[0] > '9') 486 if (cp[0] < '0' || cp[0] > '9')
489 fatal("%.200s line %d: Badly formatted port number.", 487 fatal("%.200s line %d: Badly formatted port number.",
490 filename, linenum); 488 filename, linenum);
491 fwd_port = atoi(cp); 489 fwd_port = atoi(cp);
492 cp = strtok(NULL, WHITESPACE); 490 cp = strtok(NULL, WHITESPACE);
493 if (!cp) 491 if (!cp)
494 fatal("%.200s line %d: Missing second argument.", 492 fatal("%.200s line %d: Missing second argument.",
495 filename, linenum); 493 filename, linenum);
496 if (sscanf(cp, "%255[^:]:%d", buf, &fwd_host_port) != 2) 494 if (sscanf(cp, "%255[^:]:%d", buf, &fwd_host_port) != 2)
497 fatal("%.200s line %d: Badly formatted host:port.", 495 fatal("%.200s line %d: Badly formatted host:port.",
498 filename, linenum); 496 filename, linenum);
499 if (*activep) 497 if (*activep)
500 add_local_forward(options, fwd_port, buf, fwd_host_port); 498 add_local_forward(options, fwd_port, buf, fwd_host_port);
501 break; 499 break;
502 500
503 case oHost: 501 case oHost:
504 *activep = 0; 502 *activep = 0;
505 while ((cp = strtok(NULL, WHITESPACE)) != NULL) 503 while ((cp = strtok(NULL, WHITESPACE)) != NULL)
506 if (match_pattern(host, cp)) 504 if (match_pattern(host, cp)) {
507 { 505 debug("Applying options for %.100s", cp);
508 debug("Applying options for %.100s", cp); 506 *activep = 1;
509 *activep = 1; 507 break;
510 break; 508 }
511 } 509 /* Avoid garbage check below, as strtok already returned
512 /* Avoid garbage check below, as strtok already returned NULL. */ 510 NULL. */
513 return 0; 511 return 0;
514 512
515 case oEscapeChar: 513 case oEscapeChar:
516 intptr = &options->escape_char; 514 intptr = &options->escape_char;
517 cp = strtok(NULL, WHITESPACE); 515 cp = strtok(NULL, WHITESPACE);
518 if (!cp) 516 if (!cp)
519 fatal("%.200s line %d: Missing argument.", filename, linenum); 517 fatal("%.200s line %d: Missing argument.", filename, linenum);
520 if (cp[0] == '^' && cp[2] == 0 && 518 if (cp[0] == '^' && cp[2] == 0 &&
521 (unsigned char)cp[1] >= 64 && (unsigned char)cp[1] < 128) 519 (unsigned char) cp[1] >= 64 && (unsigned char) cp[1] < 128)
522 value = (unsigned char)cp[1] & 31; 520 value = (unsigned char) cp[1] & 31;
523 else 521 else if (strlen(cp) == 1)
524 if (strlen(cp) == 1) 522 value = (unsigned char) cp[0];
525 value = (unsigned char)cp[0]; 523 else if (strcmp(cp, "none") == 0)
526 else 524 value = -2;
527 if (strcmp(cp, "none") == 0) 525 else {
528 value = -2; 526 fatal("%.200s line %d: Bad escape character.",
529 else 527 filename, linenum);
530 { 528 /* NOTREACHED */
531 fatal("%.200s line %d: Bad escape character.", 529 value = 0; /* Avoid compiler warning. */
532 filename, linenum); 530 }
533 /*NOTREACHED*/ 531 if (*activep && *intptr == -1)
534 value = 0; /* Avoid compiler warning. */ 532 *intptr = value;
535 } 533 break;
536 if (*activep && *intptr == -1) 534
537 *intptr = value; 535 default:
538 break; 536 fatal("process_config_line: Unimplemented opcode %d", opcode);
539 537 }
540 default: 538
541 fatal("process_config_line: Unimplemented opcode %d", opcode); 539 /* Check that there is no garbage at end of line. */
542 } 540 if (strtok(NULL, WHITESPACE) != NULL)
543 541 fatal("%.200s line %d: garbage at end of line.",
544 /* Check that there is no garbage at end of line. */ 542 filename, linenum);
545 if (strtok(NULL, WHITESPACE) != NULL) 543 return 0;
546 fatal("%.200s line %d: garbage at end of line.",
547 filename, linenum);
548 return 0;
549} 544}
550 545
551 546
@@ -553,35 +548,35 @@ process_config_line(Options *options, const char *host,
553 already be initialized before this call. This never returns if there 548 already be initialized before this call. This never returns if there
554 is an error. If the file does not exist, this returns immediately. */ 549 is an error. If the file does not exist, this returns immediately. */
555 550
556void read_config_file(const char *filename, const char *host, Options *options) 551void
552read_config_file(const char *filename, const char *host, Options *options)
557{ 553{
558 FILE *f; 554 FILE *f;
559 char line[1024]; 555 char line[1024];
560 int active, linenum; 556 int active, linenum;
561 int bad_options = 0; 557 int bad_options = 0;
562 558
563 /* Open the file. */ 559 /* Open the file. */
564 f = fopen(filename, "r"); 560 f = fopen(filename, "r");
565 if (!f) 561 if (!f)
566 return; 562 return;
567 563
568 debug("Reading configuration data %.200s", filename); 564 debug("Reading configuration data %.200s", filename);
569 565
570 /* Mark that we are now processing the options. This flag is turned on/off 566 /* Mark that we are now processing the options. This flag is
571 by Host specifications. */ 567 turned on/off by Host specifications. */
572 active = 1; 568 active = 1;
573 linenum = 0; 569 linenum = 0;
574 while (fgets(line, sizeof(line), f)) 570 while (fgets(line, sizeof(line), f)) {
575 { 571 /* Update line number counter. */
576 /* Update line number counter. */ 572 linenum++;
577 linenum++; 573 if (process_config_line(options, host, line, filename, linenum, &active) != 0)
578 if (process_config_line(options, host, line, filename, linenum, &active) != 0) 574 bad_options++;
579 bad_options++; 575 }
580 } 576 fclose(f);
581 fclose(f); 577 if (bad_options > 0)
582 if (bad_options > 0) 578 fatal("%s: terminating, %d bad configuration options\n",
583 fatal("%s: terminating, %d bad configuration options\n", 579 filename, bad_options);
584 filename, bad_options);
585} 580}
586 581
587/* Initializes options to special values that indicate that they have not 582/* Initializes options to special values that indicate that they have not
@@ -589,120 +584,124 @@ void read_config_file(const char *filename, const char *host, Options *options)
589 Options are processed in the following order: command line, user config 584 Options are processed in the following order: command line, user config
590 file, system config file. Last, fill_default_options is called. */ 585 file, system config file. Last, fill_default_options is called. */
591 586
592void initialize_options(Options *options) 587void
588initialize_options(Options * options)
593{ 589{
594 memset(options, 'X', sizeof(*options)); 590 memset(options, 'X', sizeof(*options));
595 options->forward_agent = -1; 591 options->forward_agent = -1;
596 options->forward_x11 = -1; 592 options->forward_x11 = -1;
597 options->gateway_ports = -1; 593 options->gateway_ports = -1;
598 options->use_privileged_port = -1; 594 options->use_privileged_port = -1;
599 options->rhosts_authentication = -1; 595 options->rhosts_authentication = -1;
600 options->rsa_authentication = -1; 596 options->rsa_authentication = -1;
597 options->skey_authentication = -1;
601#ifdef KRB4 598#ifdef KRB4
602 options->kerberos_authentication = -1; 599 options->kerberos_authentication = -1;
603#endif 600#endif
604#ifdef AFS 601#ifdef AFS
605 options->kerberos_tgt_passing = -1; 602 options->kerberos_tgt_passing = -1;
606 options->afs_token_passing = -1; 603 options->afs_token_passing = -1;
607#endif 604#endif
608 options->password_authentication = -1; 605 options->password_authentication = -1;
609 options->rhosts_rsa_authentication = -1; 606 options->rhosts_rsa_authentication = -1;
610 options->fallback_to_rsh = -1; 607 options->fallback_to_rsh = -1;
611 options->use_rsh = -1; 608 options->use_rsh = -1;
612 options->batch_mode = -1; 609 options->batch_mode = -1;
613 options->check_host_ip = -1; 610 options->check_host_ip = -1;
614 options->strict_host_key_checking = -1; 611 options->strict_host_key_checking = -1;
615 options->compression = -1; 612 options->compression = -1;
616 options->keepalives = -1; 613 options->keepalives = -1;
617 options->compression_level = -1; 614 options->compression_level = -1;
618 options->port = -1; 615 options->port = -1;
619 options->connection_attempts = -1; 616 options->connection_attempts = -1;
620 options->number_of_password_prompts = -1; 617 options->number_of_password_prompts = -1;
621 options->cipher = -1; 618 options->cipher = -1;
622 options->num_identity_files = 0; 619 options->num_identity_files = 0;
623 options->hostname = NULL; 620 options->hostname = NULL;
624 options->proxy_command = NULL; 621 options->proxy_command = NULL;
625 options->user = NULL; 622 options->user = NULL;
626 options->escape_char = -1; 623 options->escape_char = -1;
627 options->system_hostfile = NULL; 624 options->system_hostfile = NULL;
628 options->user_hostfile = NULL; 625 options->user_hostfile = NULL;
629 options->num_local_forwards = 0; 626 options->num_local_forwards = 0;
630 options->num_remote_forwards = 0; 627 options->num_remote_forwards = 0;
631 options->log_level = (LogLevel)-1; 628 options->log_level = (LogLevel) - 1;
632} 629}
633 630
634/* Called after processing other sources of option data, this fills those 631/* Called after processing other sources of option data, this fills those
635 options for which no value has been specified with their default values. */ 632 options for which no value has been specified with their default values. */
636 633
637void fill_default_options(Options *options) 634void
635fill_default_options(Options * options)
638{ 636{
639 if (options->forward_agent == -1) 637 if (options->forward_agent == -1)
640 options->forward_agent = 1; 638 options->forward_agent = 1;
641 if (options->forward_x11 == -1) 639 if (options->forward_x11 == -1)
642 options->forward_x11 = 1; 640 options->forward_x11 = 1;
643 if (options->gateway_ports == -1) 641 if (options->gateway_ports == -1)
644 options->gateway_ports = 0; 642 options->gateway_ports = 0;
645 if (options->use_privileged_port == -1) 643 if (options->use_privileged_port == -1)
646 options->use_privileged_port = 1; 644 options->use_privileged_port = 1;
647 if (options->rhosts_authentication == -1) 645 if (options->rhosts_authentication == -1)
648 options->rhosts_authentication = 1; 646 options->rhosts_authentication = 1;
649 if (options->rsa_authentication == -1) 647 if (options->rsa_authentication == -1)
650 options->rsa_authentication = 1; 648 options->rsa_authentication = 1;
649 if (options->skey_authentication == -1)
650 options->skey_authentication = 0;
651#ifdef KRB4 651#ifdef KRB4
652 if (options->kerberos_authentication == -1) 652 if (options->kerberos_authentication == -1)
653 options->kerberos_authentication = 1; 653 options->kerberos_authentication = 1;
654#endif /* KRB4 */ 654#endif /* KRB4 */
655#ifdef AFS 655#ifdef AFS
656 if (options->kerberos_tgt_passing == -1) 656 if (options->kerberos_tgt_passing == -1)
657 options->kerberos_tgt_passing = 1; 657 options->kerberos_tgt_passing = 1;
658 if (options->afs_token_passing == -1) 658 if (options->afs_token_passing == -1)
659 options->afs_token_passing = 1; 659 options->afs_token_passing = 1;
660#endif /* AFS */ 660#endif /* AFS */
661 if (options->password_authentication == -1) 661 if (options->password_authentication == -1)
662 options->password_authentication = 1; 662 options->password_authentication = 1;
663 if (options->rhosts_rsa_authentication == -1) 663 if (options->rhosts_rsa_authentication == -1)
664 options->rhosts_rsa_authentication = 1; 664 options->rhosts_rsa_authentication = 1;
665 if (options->fallback_to_rsh == -1) 665 if (options->fallback_to_rsh == -1)
666 options->fallback_to_rsh = 1; 666 options->fallback_to_rsh = 1;
667 if (options->use_rsh == -1) 667 if (options->use_rsh == -1)
668 options->use_rsh = 0; 668 options->use_rsh = 0;
669 if (options->batch_mode == -1) 669 if (options->batch_mode == -1)
670 options->batch_mode = 0; 670 options->batch_mode = 0;
671 if (options->check_host_ip == -1) 671 if (options->check_host_ip == -1)
672 options->check_host_ip = 1; 672 options->check_host_ip = 1;
673 if (options->strict_host_key_checking == -1) 673 if (options->strict_host_key_checking == -1)
674 options->strict_host_key_checking = 2; /* 2 is default */ 674 options->strict_host_key_checking = 2; /* 2 is default */
675 if (options->compression == -1) 675 if (options->compression == -1)
676 options->compression = 0; 676 options->compression = 0;
677 if (options->keepalives == -1) 677 if (options->keepalives == -1)
678 options->keepalives = 1; 678 options->keepalives = 1;
679 if (options->compression_level == -1) 679 if (options->compression_level == -1)
680 options->compression_level = 6; 680 options->compression_level = 6;
681 if (options->port == -1) 681 if (options->port == -1)
682 options->port = 0; /* Filled in ssh_connect. */ 682 options->port = 0; /* Filled in ssh_connect. */
683 if (options->connection_attempts == -1) 683 if (options->connection_attempts == -1)
684 options->connection_attempts = 4; 684 options->connection_attempts = 4;
685 if (options->number_of_password_prompts == -1) 685 if (options->number_of_password_prompts == -1)
686 options->number_of_password_prompts = 3; 686 options->number_of_password_prompts = 3;
687 if (options->cipher == -1) 687 /* Selected in ssh_login(). */
688 options->cipher = SSH_CIPHER_NOT_SET; /* Selected in ssh_login(). */ 688 if (options->cipher == -1)
689 if (options->num_identity_files == 0) 689 options->cipher = SSH_CIPHER_NOT_SET;
690 { 690 if (options->num_identity_files == 0) {
691 options->identity_files[0] = 691 options->identity_files[0] =
692 xmalloc(2 + strlen(SSH_CLIENT_IDENTITY) + 1); 692 xmalloc(2 + strlen(SSH_CLIENT_IDENTITY) + 1);
693 sprintf(options->identity_files[0], "~/%.100s", SSH_CLIENT_IDENTITY); 693 sprintf(options->identity_files[0], "~/%.100s", SSH_CLIENT_IDENTITY);
694 options->num_identity_files = 1; 694 options->num_identity_files = 1;
695 } 695 }
696 if (options->escape_char == -1) 696 if (options->escape_char == -1)
697 options->escape_char = '~'; 697 options->escape_char = '~';
698 if (options->system_hostfile == NULL) 698 if (options->system_hostfile == NULL)
699 options->system_hostfile = SSH_SYSTEM_HOSTFILE; 699 options->system_hostfile = SSH_SYSTEM_HOSTFILE;
700 if (options->user_hostfile == NULL) 700 if (options->user_hostfile == NULL)
701 options->user_hostfile = SSH_USER_HOSTFILE; 701 options->user_hostfile = SSH_USER_HOSTFILE;
702 if (options->log_level == (LogLevel)-1) 702 if (options->log_level == (LogLevel) - 1)
703 options->log_level = SYSLOG_LEVEL_INFO; 703 options->log_level = SYSLOG_LEVEL_INFO;
704 /* options->proxy_command should not be set by default */ 704 /* options->proxy_command should not be set by default */
705 /* options->user will be set in the main program if appropriate */ 705 /* options->user will be set in the main program if appropriate */
706 /* options->hostname will be set in the main program if appropriate */ 706 /* options->hostname will be set in the main program if appropriate */
707} 707}
708
diff --git a/readconf.h b/readconf.h
index d2d387df1..aeec53a75 100644
--- a/readconf.h
+++ b/readconf.h
@@ -1,118 +1,126 @@
1/* 1/*
2 2 *
3readconf.h 3 * readconf.h
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Sat Apr 22 00:25:29 1995 ylo 10 * Created: Sat Apr 22 00:25:29 1995 ylo
11 11 *
12Functions for reading the configuration file. 12 * Functions for reading the configuration file.
13 13 *
14*/ 14 */
15 15
16/* RCSID("$Id: readconf.h,v 1.3 1999/11/15 04:25:10 damien Exp $"); */ 16/* RCSID("$Id: readconf.h,v 1.4 1999/11/24 13:26:22 damien Exp $"); */
17 17
18#ifndef READCONF_H 18#ifndef READCONF_H
19#define READCONF_H 19#define READCONF_H
20 20
21/* Data structure for representing a forwarding request. */ 21/* Data structure for representing a forwarding request. */
22 22
23typedef struct 23typedef struct {
24{ 24 int port; /* Port to forward. */
25 int port; /* Port to forward. */ 25 char *host; /* Host to connect. */
26 char *host; /* Host to connect. */ 26 int host_port; /* Port to connect on host. */
27 int host_port; /* Port to connect on host. */ 27} Forward;
28} Forward;
29
30/* Data structure for representing option data. */ 28/* Data structure for representing option data. */
31 29
32typedef struct 30typedef struct {
33{ 31 int forward_agent; /* Forward authentication agent. */
34 int forward_agent; /* Forward authentication agent. */ 32 int forward_x11; /* Forward X11 display. */
35 int forward_x11; /* Forward X11 display. */ 33 int gateway_ports; /* Allow remote connects to forwarded ports. */
36 int gateway_ports; /* Allow remote connects to forwarded ports. */ 34 int use_privileged_port; /* Don't use privileged port if false. */
37 int use_privileged_port; /* Don't use privileged port if false. */ 35 int rhosts_authentication; /* Try rhosts authentication. */
38 int rhosts_authentication; /* Try rhosts authentication. */ 36 int rhosts_rsa_authentication; /* Try rhosts with RSA
39 int rhosts_rsa_authentication;/* Try rhosts with RSA authentication. */ 37 * authentication. */
40 int rsa_authentication; /* Try RSA authentication. */ 38 int rsa_authentication; /* Try RSA authentication. */
39 int skey_authentication; /* Try S/Key or TIS authentication. */
41#ifdef KRB4 40#ifdef KRB4
42 int kerberos_authentication; /* Try Kerberos authentication. */ 41 int kerberos_authentication; /* Try Kerberos
42 * authentication. */
43#endif 43#endif
44#ifdef AFS 44#ifdef AFS
45 int kerberos_tgt_passing; /* Try Kerberos tgt passing. */ 45 int kerberos_tgt_passing; /* Try Kerberos tgt passing. */
46 int afs_token_passing; /* Try AFS token passing. */ 46 int afs_token_passing; /* Try AFS token passing. */
47#endif 47#endif
48 int password_authentication; /* Try password authentication. */ 48 int password_authentication; /* Try password
49 int fallback_to_rsh; /* Use rsh if cannot connect with ssh. */ 49 * authentication. */
50 int use_rsh; /* Always use rsh (don\'t try ssh). */ 50 int fallback_to_rsh;/* Use rsh if cannot connect with ssh. */
51 int batch_mode; /* Batch mode: do not ask for passwords. */ 51 int use_rsh; /* Always use rsh (don\'t try ssh). */
52 int check_host_ip; /* Also keep track of keys for IP address */ 52 int batch_mode; /* Batch mode: do not ask for passwords. */
53 int strict_host_key_checking; /* Strict host key checking. */ 53 int check_host_ip; /* Also keep track of keys for IP address */
54 int compression; /* Compress packets in both directions. */ 54 int strict_host_key_checking; /* Strict host key checking. */
55 int compression_level; /* Compression level 1 (fast) to 9 (best). */ 55 int compression; /* Compress packets in both directions. */
56 int keepalives; /* Set SO_KEEPALIVE. */ 56 int compression_level; /* Compression level 1 (fast) to 9
57 LogLevel log_level; /* Level for logging. */ 57 * (best). */
58 58 int keepalives; /* Set SO_KEEPALIVE. */
59 int port; /* Port to connect. */ 59 LogLevel log_level; /* Level for logging. */
60 int connection_attempts; /* Max attempts (seconds) before giving up */ 60
61 int number_of_password_prompts; /* Max number of password prompts. */ 61 int port; /* Port to connect. */
62 int cipher; /* Cipher to use. */ 62 int connection_attempts; /* Max attempts (seconds) before
63 char *hostname; /* Real host to connect. */ 63 * giving up */
64 char *proxy_command; /* Proxy command for connecting the host. */ 64 int number_of_password_prompts; /* Max number of password
65 char *user; /* User to log in as. */ 65 * prompts. */
66 int escape_char; /* Escape character; -2 = none */ 66 int cipher; /* Cipher to use. */
67 67 char *hostname; /* Real host to connect. */
68 char *system_hostfile; /* Path for /etc/ssh_known_hosts. */ 68 char *proxy_command; /* Proxy command for connecting the host. */
69 char *user_hostfile; /* Path for $HOME/.ssh/known_hosts. */ 69 char *user; /* User to log in as. */
70 70 int escape_char; /* Escape character; -2 = none */
71 int num_identity_files; /* Number of files for RSA identities. */ 71
72 char *identity_files[SSH_MAX_IDENTITY_FILES]; 72 char *system_hostfile;/* Path for /etc/ssh_known_hosts. */
73 73 char *user_hostfile; /* Path for $HOME/.ssh/known_hosts. */
74 /* Local TCP/IP forward requests. */ 74
75 int num_local_forwards; 75 int num_identity_files; /* Number of files for RSA identities. */
76 Forward local_forwards[SSH_MAX_FORWARDS_PER_DIRECTION]; 76 char *identity_files[SSH_MAX_IDENTITY_FILES];
77 77
78 /* Remote TCP/IP forward requests. */ 78 /* Local TCP/IP forward requests. */
79 int num_remote_forwards; 79 int num_local_forwards;
80 Forward remote_forwards[SSH_MAX_FORWARDS_PER_DIRECTION]; 80 Forward local_forwards[SSH_MAX_FORWARDS_PER_DIRECTION];
81} Options; 81
82 /* Remote TCP/IP forward requests. */
83 int num_remote_forwards;
84 Forward remote_forwards[SSH_MAX_FORWARDS_PER_DIRECTION];
85} Options;
82 86
83 87
84/* Initializes options to special values that indicate that they have not 88/* Initializes options to special values that indicate that they have not
85 yet been set. Read_config_file will only set options with this value. 89 yet been set. Read_config_file will only set options with this value.
86 Options are processed in the following order: command line, user config 90 Options are processed in the following order: command line, user config
87 file, system config file. Last, fill_default_options is called. */ 91 file, system config file. Last, fill_default_options is called. */
88void initialize_options(Options *options); 92void initialize_options(Options * options);
89 93
90/* Called after processing other sources of option data, this fills those 94/* Called after processing other sources of option data, this fills those
91 options for which no value has been specified with their default values. */ 95 options for which no value has been specified with their default values. */
92void fill_default_options(Options *options); 96void fill_default_options(Options * options);
93 97
94/* Processes a single option line as used in the configuration files. 98/* Processes a single option line as used in the configuration files.
95 This only sets those values that have not already been set. 99 This only sets those values that have not already been set.
96 Returns 0 for legal options */ 100 Returns 0 for legal options */
97int process_config_line(Options *options, const char *host, 101int
98 char *line, const char *filename, int linenum, 102process_config_line(Options * options, const char *host,
99 int *activep); 103 char *line, const char *filename, int linenum,
104 int *activep);
100 105
101/* Reads the config file and modifies the options accordingly. Options should 106/* Reads the config file and modifies the options accordingly. Options should
102 already be initialized before this call. This never returns if there 107 already be initialized before this call. This never returns if there
103 is an error. If the file does not exist, this returns immediately. */ 108 is an error. If the file does not exist, this returns immediately. */
104void read_config_file(const char *filename, const char *host, 109void
105 Options *options); 110read_config_file(const char *filename, const char *host,
111 Options * options);
106 112
107/* Adds a local TCP/IP port forward to options. Never returns if there 113/* Adds a local TCP/IP port forward to options. Never returns if there
108 is an error. */ 114 is an error. */
109void add_local_forward(Options *options, int port, const char *host, 115void
110 int host_port); 116add_local_forward(Options * options, int port, const char *host,
117 int host_port);
111 118
112/* Adds a remote TCP/IP port forward to options. Never returns if there 119/* Adds a remote TCP/IP port forward to options. Never returns if there
113 is an error. */ 120 is an error. */
114void add_remote_forward(Options *options, int port, const char *host, 121void
115 int host_port); 122add_remote_forward(Options * options, int port, const char *host,
123 int host_port);
116 124
117 125
118#endif /* READCONF_H */ 126#endif /* READCONF_H */
diff --git a/readpass.c b/readpass.c
index 3031825e5..66ce33c97 100644
--- a/readpass.c
+++ b/readpass.c
@@ -1,20 +1,20 @@
1/* 1/*
2 2 *
3readpass.c 3 * readpass.c
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Mon Jul 10 22:08:59 1995 ylo 10 * Created: Mon Jul 10 22:08:59 1995 ylo
11 11 *
12Functions for reading passphrases and passwords. 12 * Functions for reading passphrases and passwords.
13 13 *
14*/ 14 */
15 15
16#include "includes.h" 16#include "includes.h"
17RCSID("$Id: readpass.c,v 1.1 1999/10/27 03:42:44 damien Exp $"); 17RCSID("$Id: readpass.c,v 1.2 1999/11/24 13:26:22 damien Exp $");
18 18
19#include "xmalloc.h" 19#include "xmalloc.h"
20#include "ssh.h" 20#include "ssh.h"
@@ -23,92 +23,91 @@ RCSID("$Id: readpass.c,v 1.1 1999/10/27 03:42:44 damien Exp $");
23static struct termios saved_tio; 23static struct termios saved_tio;
24 24
25/* Old interrupt signal handler for read_passphrase. */ 25/* Old interrupt signal handler for read_passphrase. */
26static void (*old_handler)(int sig) = NULL; 26static void (*old_handler) (int sig) = NULL;
27 27
28/* Interrupt signal handler for read_passphrase. */ 28/* Interrupt signal handler for read_passphrase. */
29 29
30void intr_handler(int sig) 30void
31intr_handler(int sig)
31{ 32{
32 /* Restore terminal modes. */ 33 /* Restore terminal modes. */
33 tcsetattr(fileno(stdin), TCSANOW, &saved_tio); 34 tcsetattr(fileno(stdin), TCSANOW, &saved_tio);
34 /* Restore the old signal handler. */ 35 /* Restore the old signal handler. */
35 signal(sig, old_handler); 36 signal(sig, old_handler);
36 /* Resend the signal, with the old handler. */ 37 /* Resend the signal, with the old handler. */
37 kill(getpid(), sig); 38 kill(getpid(), sig);
38} 39}
39 40
40/* Reads a passphrase from /dev/tty with echo turned off. Returns the 41/* Reads a passphrase from /dev/tty with echo turned off. Returns the
41 passphrase (allocated with xmalloc). Exits if EOF is encountered. 42 passphrase (allocated with xmalloc). Exits if EOF is encountered.
42 The passphrase if read from stdin if from_stdin is true (as is the 43 The passphrase if read from stdin if from_stdin is true (as is the
43 case with ssh-keygen). */ 44 case with ssh-keygen). */
44 45
45char *read_passphrase(const char *prompt, int from_stdin) 46char *
47read_passphrase(const char *prompt, int from_stdin)
46{ 48{
47 char buf[1024], *cp; 49 char buf[1024], *cp;
48 struct termios tio; 50 struct termios tio;
49 FILE *f; 51 FILE *f;
50 52
51 if (from_stdin) 53 if (from_stdin)
52 f = stdin; 54 f = stdin;
53 else 55 else {
54 { 56 /* Read the passphrase from /dev/tty to make it possible
55 /* Read the passphrase from /dev/tty to make it possible to ask it even 57 to ask it even when stdin has been redirected. */
56 when stdin has been redirected. */ 58 f = fopen("/dev/tty", "r");
57 f = fopen("/dev/tty", "r"); 59 if (!f) {
58 if (!f) 60 /* No controlling terminal and no DISPLAY. Nowhere to read. */
59 { 61 fprintf(stderr, "You have no controlling tty and no DISPLAY. Cannot read passphrase.\n");
60 /* No controlling terminal and no DISPLAY. Nowhere to read. */ 62 exit(1);
61 fprintf(stderr, "You have no controlling tty and no DISPLAY. Cannot read passphrase.\n"); 63 }
62 exit(1);
63 } 64 }
64 }
65
66 /* Display the prompt (on stderr because stdout might be redirected). */
67 fflush(stdout);
68 fprintf(stderr, "%s", prompt);
69 fflush(stderr);
70
71 /* Get terminal modes. */
72 tcgetattr(fileno(f), &tio);
73 saved_tio = tio;
74 /* Save signal handler and set the new handler. */
75 old_handler = signal(SIGINT, intr_handler);
76 65
77 /* Set new terminal modes disabling all echo. */ 66 /* Display the prompt (on stderr because stdout might be redirected). */
78 tio.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); 67 fflush(stdout);
79 tcsetattr(fileno(f), TCSANOW, &tio); 68 fprintf(stderr, "%s", prompt);
80 69 fflush(stderr);
81 /* Read the passphrase from the terminal. */ 70
82 if (fgets(buf, sizeof(buf), f) == NULL) 71 /* Get terminal modes. */
83 { 72 tcgetattr(fileno(f), &tio);
84 /* Got EOF. Just exit. */ 73 saved_tio = tio;
85 /* Restore terminal modes. */ 74 /* Save signal handler and set the new handler. */
86 tcsetattr(fileno(f), TCSANOW, &saved_tio); 75 old_handler = signal(SIGINT, intr_handler);
87 /* Restore the signal handler. */ 76
88 signal(SIGINT, old_handler); 77 /* Set new terminal modes disabling all echo. */
89 /* Print a newline (the prompt probably didn\'t have one). */ 78 tio.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
90 fprintf(stderr, "\n"); 79 tcsetattr(fileno(f), TCSANOW, &tio);
91 /* Close the file. */ 80
92 if (f != stdin) 81 /* Read the passphrase from the terminal. */
93 fclose(f); 82 if (fgets(buf, sizeof(buf), f) == NULL) {
94 exit(1); 83 /* Got EOF. Just exit. */
95 } 84 /* Restore terminal modes. */
96 /* Restore terminal modes. */ 85 tcsetattr(fileno(f), TCSANOW, &saved_tio);
97 tcsetattr(fileno(f), TCSANOW, &saved_tio); 86 /* Restore the signal handler. */
98 /* Restore the signal handler. */ 87 signal(SIGINT, old_handler);
99 (void)signal(SIGINT, old_handler); 88 /* Print a newline (the prompt probably didn\'t have one). */
100 /* Remove newline from the passphrase. */ 89 fprintf(stderr, "\n");
101 if (strchr(buf, '\n')) 90 /* Close the file. */
102 *strchr(buf, '\n') = 0; 91 if (f != stdin)
103 /* Allocate a copy of the passphrase. */ 92 fclose(f);
104 cp = xstrdup(buf); 93 exit(1);
105 /* Clear the buffer so we don\'t leave copies of the passphrase laying 94 }
106 around. */ 95 /* Restore terminal modes. */
107 memset(buf, 0, sizeof(buf)); 96 tcsetattr(fileno(f), TCSANOW, &saved_tio);
108 /* Print a newline since the prompt probably didn\'t have one. */ 97 /* Restore the signal handler. */
109 fprintf(stderr, "\n"); 98 (void) signal(SIGINT, old_handler);
110 /* Close the file. */ 99 /* Remove newline from the passphrase. */
111 if (f != stdin) 100 if (strchr(buf, '\n'))
112 fclose(f); 101 *strchr(buf, '\n') = 0;
113 return cp; 102 /* Allocate a copy of the passphrase. */
103 cp = xstrdup(buf);
104 /* Clear the buffer so we don\'t leave copies of the passphrase
105 laying around. */
106 memset(buf, 0, sizeof(buf));
107 /* Print a newline since the prompt probably didn\'t have one. */
108 fprintf(stderr, "\n");
109 /* Close the file. */
110 if (f != stdin)
111 fclose(f);
112 return cp;
114} 113}
diff --git a/rsa.c b/rsa.c
index 61e53759d..5228fd398 100644
--- a/rsa.c
+++ b/rsa.c
@@ -1,41 +1,41 @@
1/* 1/*
2 2 *
3rsa.c 3 * rsa.c
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Fri Mar 3 22:07:06 1995 ylo 10 * Created: Fri Mar 3 22:07:06 1995 ylo
11 11 *
12Description of the RSA algorithm can be found e.g. from the following sources: 12 * Description of the RSA algorithm can be found e.g. from the following sources:
13 13 *
14 Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1994. 14 * Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1994.
15 15 *
16 Jennifer Seberry and Josed Pieprzyk: Cryptography: An Introduction to 16 * Jennifer Seberry and Josed Pieprzyk: Cryptography: An Introduction to
17 Computer Security. Prentice-Hall, 1989. 17 * Computer Security. Prentice-Hall, 1989.
18 18 *
19 Man Young Rhee: Cryptography and Secure Data Communications. McGraw-Hill, 19 * Man Young Rhee: Cryptography and Secure Data Communications. McGraw-Hill,
20 1994. 20 * 1994.
21 21 *
22 R. Rivest, A. Shamir, and L. M. Adleman: Cryptographic Communications 22 * R. Rivest, A. Shamir, and L. M. Adleman: Cryptographic Communications
23 System and Method. US Patent 4,405,829, 1983. 23 * System and Method. US Patent 4,405,829, 1983.
24 24 *
25 Hans Riesel: Prime Numbers and Computer Methods for Factorization. 25 * Hans Riesel: Prime Numbers and Computer Methods for Factorization.
26 Birkhauser, 1994. 26 * Birkhauser, 1994.
27 27 *
28 The RSA Frequently Asked Questions document by RSA Data Security, Inc., 1995. 28 * The RSA Frequently Asked Questions document by RSA Data Security, Inc., 1995.
29 29 *
30 RSA in 3 lines of perl by Adam Back <aba@atlax.ex.ac.uk>, 1995, as included 30 * RSA in 3 lines of perl by Adam Back <aba@atlax.ex.ac.uk>, 1995, as included
31 below: 31 * below:
32 32 *
33 gone - had to be deleted - what a pity 33 * [gone - had to be deleted - what a pity]
34 34 *
35*/ 35*/
36 36
37#include "includes.h" 37#include "includes.h"
38RCSID("$Id: rsa.c,v 1.3 1999/11/08 23:35:52 damien Exp $"); 38RCSID("$Id: rsa.c,v 1.4 1999/11/24 13:26:22 damien Exp $");
39 39
40#include "rsa.h" 40#include "rsa.h"
41#include "ssh.h" 41#include "ssh.h"
@@ -46,13 +46,13 @@ int rsa_verbose = 1;
46int 46int
47rsa_alive() 47rsa_alive()
48{ 48{
49 RSA *key; 49 RSA *key;
50 50
51 key = RSA_generate_key(32, 3, NULL, NULL); 51 key = RSA_generate_key(32, 3, NULL, NULL);
52 if (key == NULL) 52 if (key == NULL)
53 return (0); 53 return (0);
54 RSA_free(key); 54 RSA_free(key);
55 return (1); 55 return (1);
56} 56}
57 57
58/* Generates RSA public and private keys. This initializes the data 58/* Generates RSA public and private keys. This initializes the data
@@ -62,101 +62,100 @@ rsa_alive()
62void 62void
63rsa_generate_key(RSA *prv, RSA *pub, unsigned int bits) 63rsa_generate_key(RSA *prv, RSA *pub, unsigned int bits)
64{ 64{
65 RSA *key; 65 RSA *key;
66 66
67 if (rsa_verbose) { 67 if (rsa_verbose) {
68 printf("Generating RSA keys: "); 68 printf("Generating RSA keys: ");
69 fflush(stdout); 69 fflush(stdout);
70 } 70 }
71 71 key = RSA_generate_key(bits, 35, NULL, NULL);
72 key = RSA_generate_key(bits, 35, NULL, NULL); 72 if (key == NULL)
73 if (key == NULL) 73 fatal("rsa_generate_key: key generation failed.");
74 fatal("rsa_generate_key: key generation failed."); 74
75 75 /* Copy public key parameters */
76 /* Copy public key parameters */ 76 pub->n = BN_new();
77 pub->n = BN_new(); 77 BN_copy(pub->n, key->n);
78 BN_copy(pub->n, key->n); 78 pub->e = BN_new();
79 pub->e = BN_new(); 79 BN_copy(pub->e, key->e);
80 BN_copy(pub->e, key->e); 80
81 81 /* Copy private key parameters */
82 /* Copy private key parameters */ 82 prv->n = BN_new();
83 prv->n = BN_new(); 83 BN_copy(prv->n, key->n);
84 BN_copy(prv->n, key->n); 84 prv->e = BN_new();
85 prv->e = BN_new(); 85 BN_copy(prv->e, key->e);
86 BN_copy(prv->e, key->e); 86 prv->d = BN_new();
87 prv->d = BN_new(); 87 BN_copy(prv->d, key->d);
88 BN_copy(prv->d, key->d); 88 prv->p = BN_new();
89 prv->p = BN_new(); 89 BN_copy(prv->p, key->p);
90 BN_copy(prv->p, key->p); 90 prv->q = BN_new();
91 prv->q = BN_new(); 91 BN_copy(prv->q, key->q);
92 BN_copy(prv->q, key->q); 92
93 93 prv->dmp1 = BN_new();
94 prv->dmp1 = BN_new(); 94 BN_copy(prv->dmp1, key->dmp1);
95 BN_copy(prv->dmp1, key->dmp1); 95
96 96 prv->dmq1 = BN_new();
97 prv->dmq1 = BN_new(); 97 BN_copy(prv->dmq1, key->dmq1);
98 BN_copy(prv->dmq1, key->dmq1); 98
99 99 prv->iqmp = BN_new();
100 prv->iqmp = BN_new(); 100 BN_copy(prv->iqmp, key->iqmp);
101 BN_copy(prv->iqmp, key->iqmp); 101
102 102 RSA_free(key);
103 RSA_free(key); 103
104 104 if (rsa_verbose)
105 if (rsa_verbose) 105 printf("Key generation complete.\n");
106 printf("Key generation complete.\n");
107} 106}
108 107
109void 108void
110rsa_public_encrypt(BIGNUM *out, BIGNUM *in, RSA* key) 109rsa_public_encrypt(BIGNUM *out, BIGNUM *in, RSA *key)
111{ 110{
112 char *inbuf, *outbuf; 111 char *inbuf, *outbuf;
113 int len, ilen, olen; 112 int len, ilen, olen;
114 113
115 if (BN_num_bits(key->e) < 2 || !BN_is_odd(key->e)) 114 if (BN_num_bits(key->e) < 2 || !BN_is_odd(key->e))
116 fatal("rsa_public_encrypt() exponent too small or not odd"); 115 fatal("rsa_public_encrypt() exponent too small or not odd");
117 116
118 olen = BN_num_bytes(key->n); 117 olen = BN_num_bytes(key->n);
119 outbuf = xmalloc(olen); 118 outbuf = xmalloc(olen);
120 119
121 ilen = BN_num_bytes(in); 120 ilen = BN_num_bytes(in);
122 inbuf = xmalloc(ilen); 121 inbuf = xmalloc(ilen);
123 BN_bn2bin(in, inbuf); 122 BN_bn2bin(in, inbuf);
124 123
125 if ((len = RSA_public_encrypt(ilen, inbuf, outbuf, key, 124 if ((len = RSA_public_encrypt(ilen, inbuf, outbuf, key,
126 RSA_PKCS1_PADDING)) <= 0) 125 RSA_PKCS1_PADDING)) <= 0)
127 fatal("rsa_public_encrypt() failed"); 126 fatal("rsa_public_encrypt() failed");
128 127
129 BN_bin2bn(outbuf, len, out); 128 BN_bin2bn(outbuf, len, out);
130 129
131 memset(outbuf, 0, olen); 130 memset(outbuf, 0, olen);
132 memset(inbuf, 0, ilen); 131 memset(inbuf, 0, ilen);
133 xfree(outbuf); 132 xfree(outbuf);
134 xfree(inbuf); 133 xfree(inbuf);
135} 134}
136 135
137void 136void
138rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *key) 137rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *key)
139{ 138{
140 char *inbuf, *outbuf; 139 char *inbuf, *outbuf;
141 int len, ilen, olen; 140 int len, ilen, olen;
142 141
143 olen = BN_num_bytes(key->n); 142 olen = BN_num_bytes(key->n);
144 outbuf = xmalloc(olen); 143 outbuf = xmalloc(olen);
145 144
146 ilen = BN_num_bytes(in); 145 ilen = BN_num_bytes(in);
147 inbuf = xmalloc(ilen); 146 inbuf = xmalloc(ilen);
148 BN_bn2bin(in, inbuf); 147 BN_bn2bin(in, inbuf);
149 148
150 if ((len = RSA_private_decrypt(ilen, inbuf, outbuf, key, 149 if ((len = RSA_private_decrypt(ilen, inbuf, outbuf, key,
151 RSA_SSLV23_PADDING)) <= 0) 150 RSA_SSLV23_PADDING)) <= 0)
152 fatal("rsa_private_decrypt() failed"); 151 fatal("rsa_private_decrypt() failed");
153 152
154 BN_bin2bn(outbuf, len, out); 153 BN_bin2bn(outbuf, len, out);
155 154
156 memset(outbuf, 0, olen); 155 memset(outbuf, 0, olen);
157 memset(inbuf, 0, ilen); 156 memset(inbuf, 0, ilen);
158 xfree(outbuf); 157 xfree(outbuf);
159 xfree(inbuf); 158 xfree(inbuf);
160} 159}
161 160
162/* Set whether to output verbose messages during key generation. */ 161/* Set whether to output verbose messages during key generation. */
@@ -164,5 +163,5 @@ rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *key)
164void 163void
165rsa_set_verbose(int verbose) 164rsa_set_verbose(int verbose)
166{ 165{
167 rsa_verbose = verbose; 166 rsa_verbose = verbose;
168} 167}
diff --git a/rsa.h b/rsa.h
index c19b5a965..31acb2dac 100644
--- a/rsa.h
+++ b/rsa.h
@@ -1,24 +1,25 @@
1/* 1/*
2 2 *
3rsa.h 3 * rsa.h
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Fri Mar 3 22:01:06 1995 ylo 10 * Created: Fri Mar 3 22:01:06 1995 ylo
11 11 *
12RSA key generation, encryption and decryption. 12 * RSA key generation, encryption and decryption.
13 13 *
14*/ 14*/
15 15
16/* RCSID("$Id: rsa.h,v 1.3 1999/11/10 23:40:23 damien Exp $"); */ 16/* RCSID("$Id: rsa.h,v 1.4 1999/11/24 13:26:22 damien Exp $"); */
17#include "config.h"
18 17
19#ifndef RSA_H 18#ifndef RSA_H
20#define RSA_H 19#define RSA_H
21 20
21#include "config.h"
22
22#ifdef HAVE_OPENSSL 23#ifdef HAVE_OPENSSL
23#include <openssl/bn.h> 24#include <openssl/bn.h>
24#include <openssl/rsa.h> 25#include <openssl/rsa.h>
@@ -30,15 +31,15 @@ RSA key generation, encryption and decryption.
30#endif 31#endif
31 32
32/* Calls SSL RSA_generate_key, only copies to prv and pub */ 33/* Calls SSL RSA_generate_key, only copies to prv and pub */
33void rsa_generate_key(RSA *prv, RSA *pub, unsigned int bits); 34void rsa_generate_key(RSA * prv, RSA * pub, unsigned int bits);
34 35
35/* Indicates whether the rsa module is permitted to show messages on 36/* Indicates whether the rsa module is permitted to show messages on
36 the terminal. */ 37 the terminal. */
37void rsa_set_verbose(int verbose); 38void rsa_set_verbose __P((int verbose));
38 39
39int rsa_alive(void); 40int rsa_alive __P((void));
40 41
41void rsa_public_encrypt(BIGNUM *out, BIGNUM *in, RSA *prv); 42void rsa_public_encrypt __P((BIGNUM * out, BIGNUM * in, RSA * prv));
42void rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *prv); 43void rsa_private_decrypt __P((BIGNUM * out, BIGNUM * in, RSA * prv));
43 44
44#endif /* RSA_H */ 45#endif /* RSA_H */
diff --git a/scp.c b/scp.c
index 9cc9528b8..977c38984 100644
--- a/scp.c
+++ b/scp.c
@@ -1,13 +1,13 @@
1/* 1/*
2 2 *
3scp - secure remote copy. This is basically patched BSD rcp which uses ssh 3 * scp - secure remote copy. This is basically patched BSD rcp which uses ssh
4to do the data transfer (instead of using rcmd). 4 * to do the data transfer (instead of using rcmd).
5 5 *
6NOTE: This version should NOT be suid root. (This uses ssh to do the transfer 6 * NOTE: This version should NOT be suid root. (This uses ssh to do the transfer
7and ssh has the necessary privileges.) 7 * and ssh has the necessary privileges.)
8 8 *
91995 Timo Rinne <tri@iki.fi>, Tatu Ylonen <ylo@cs.hut.fi> 9 * 1995 Timo Rinne <tri@iki.fi>, Tatu Ylonen <ylo@cs.hut.fi>
10 10 *
11*/ 11*/
12 12
13/* 13/*
@@ -42,11 +42,10 @@ and ssh has the necessary privileges.)
42 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 42 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43 * SUCH DAMAGE. 43 * SUCH DAMAGE.
44 * 44 *
45 * $Id: scp.c,v 1.8 1999/11/19 01:34:14 damien Exp $
46 */ 45 */
47 46
48#include "includes.h" 47#include "includes.h"
49RCSID("$Id: scp.c,v 1.8 1999/11/19 01:34:14 damien Exp $"); 48RCSID("$Id: scp.c,v 1.9 1999/11/24 13:26:22 damien Exp $");
50 49
51#include "ssh.h" 50#include "ssh.h"
52#include "xmalloc.h" 51#include "xmalloc.h"
@@ -76,7 +75,7 @@ off_t totalbytes = 0;
76char *curfile; 75char *curfile;
77 76
78/* This is set to non-zero to enable verbose mode. */ 77/* This is set to non-zero to enable verbose mode. */
79int verbose = 0; 78int verbose_mode = 0;
80 79
81/* This is set to non-zero if compression is desired. */ 80/* This is set to non-zero if compression is desired. */
82int compress = 0; 81int compress = 0;
@@ -91,7 +90,7 @@ int batchmode = 0;
91/* This is set to the cipher type string if given on the command line. */ 90/* This is set to the cipher type string if given on the command line. */
92char *cipher = NULL; 91char *cipher = NULL;
93 92
94/* This is set to the RSA authentication identity file name if given on 93/* This is set to the RSA authentication identity file name if given on
95 the command line. */ 94 the command line. */
96char *identity = NULL; 95char *identity = NULL;
97 96
@@ -102,98 +101,95 @@ char *port = NULL;
102 host. This returns < 0 if execution fails, and >= 0 otherwise. 101 host. This returns < 0 if execution fails, and >= 0 otherwise.
103 This assigns the input and output file descriptors on success. */ 102 This assigns the input and output file descriptors on success. */
104 103
105int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout) 104int
105do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
106{ 106{
107 int pin[2], pout[2], reserved[2]; 107 int pin[2], pout[2], reserved[2];
108 108
109 if (verbose) 109 if (verbose_mode)
110 fprintf(stderr, "Executing: host %s, user %s, command %s\n", 110 fprintf(stderr, "Executing: host %s, user %s, command %s\n",
111 host, remuser ? remuser : "(unspecified)", cmd); 111 host, remuser ? remuser : "(unspecified)", cmd);
112 112
113 /* Reserve two descriptors so that the real pipes won't get descriptors 113 /* Reserve two descriptors so that the real pipes won't get
114 0 and 1 because that will screw up dup2 below. */ 114 descriptors 0 and 1 because that will screw up dup2 below. */
115 pipe(reserved); 115 pipe(reserved);
116 116
117 /* Create a socket pair for communicating with ssh. */ 117 /* Create a socket pair for communicating with ssh. */
118 if (pipe(pin) < 0) 118 if (pipe(pin) < 0)
119 fatal("pipe: %s", strerror(errno)); 119 fatal("pipe: %s", strerror(errno));
120 if (pipe(pout) < 0) 120 if (pipe(pout) < 0)
121 fatal("pipe: %s", strerror(errno)); 121 fatal("pipe: %s", strerror(errno));
122 122
123 /* Free the reserved descriptors. */ 123 /* Free the reserved descriptors. */
124 close(reserved[0]); 124 close(reserved[0]);
125 close(reserved[1]); 125 close(reserved[1]);
126 126
127 /* For a child to execute the command on the remote host using ssh. */ 127 /* For a child to execute the command on the remote host using ssh. */
128 if (fork() == 0) 128 if (fork() == 0) {
129 { 129 char *args[100];
130 char *args[100]; 130 unsigned int i;
131 unsigned int i; 131
132 132 /* Child. */
133 /* Child. */ 133 close(pin[1]);
134 close(pin[1]); 134 close(pout[0]);
135 close(pout[0]); 135 dup2(pin[0], 0);
136 dup2(pin[0], 0); 136 dup2(pout[1], 1);
137 dup2(pout[1], 1); 137 close(pin[0]);
138 close(pin[0]); 138 close(pout[1]);
139 close(pout[1]); 139
140 140 i = 0;
141 i = 0; 141 args[i++] = SSH_PROGRAM;
142 args[i++] = SSH_PROGRAM; 142 args[i++] = "-x";
143 args[i++] = "-x"; 143 args[i++] = "-oFallBackToRsh no";
144 args[i++] = "-oFallBackToRsh no"; 144 if (verbose_mode)
145 if (verbose) 145 args[i++] = "-v";
146 args[i++] = "-v"; 146 if (compress)
147 if (compress) 147 args[i++] = "-C";
148 args[i++] = "-C"; 148 if (batchmode)
149 if (batchmode) 149 args[i++] = "-oBatchMode yes";
150 args[i++] = "-oBatchMode yes"; 150 if (cipher != NULL) {
151 if (cipher != NULL) 151 args[i++] = "-c";
152 { 152 args[i++] = cipher;
153 args[i++] = "-c"; 153 }
154 args[i++] = cipher; 154 if (identity != NULL) {
155 } 155 args[i++] = "-i";
156 if (identity != NULL) 156 args[i++] = identity;
157 { 157 }
158 args[i++] = "-i"; 158 if (port != NULL) {
159 args[i++] = identity; 159 args[i++] = "-p";
160 } 160 args[i++] = port;
161 if (port != NULL) 161 }
162 { 162 if (remuser != NULL) {
163 args[i++] = "-p"; 163 args[i++] = "-l";
164 args[i++] = port; 164 args[i++] = remuser;
165 } 165 }
166 if (remuser != NULL) 166 args[i++] = host;
167 { 167 args[i++] = cmd;
168 args[i++] = "-l"; 168 args[i++] = NULL;
169 args[i++] = remuser; 169
170 execvp(SSH_PROGRAM, args);
171 perror(SSH_PROGRAM);
172 exit(1);
170 } 173 }
171 args[i++] = host; 174 /* Parent. Close the other side, and return the local side. */
172 args[i++] = cmd; 175 close(pin[0]);
173 args[i++] = NULL; 176 *fdout = pin[1];
174 177 close(pout[1]);
175 execvp(SSH_PROGRAM, args); 178 *fdin = pout[0];
176 perror(SSH_PROGRAM); 179 return 0;
177 exit(1);
178 }
179 /* Parent. Close the other side, and return the local side. */
180 close(pin[0]);
181 *fdout = pin[1];
182 close(pout[1]);
183 *fdin = pout[0];
184 return 0;
185} 180}
186 181
187void fatal(const char *fmt, ...) 182void
183fatal(const char *fmt,...)
188{ 184{
189 va_list ap; 185 va_list ap;
190 char buf[1024]; 186 char buf[1024];
191 187
192 va_start(ap, fmt); 188 va_start(ap, fmt);
193 vsnprintf(buf, sizeof(buf), fmt, ap); 189 vsnprintf(buf, sizeof(buf), fmt, ap);
194 va_end(ap); 190 va_end(ap);
195 fprintf(stderr, "%s\n", buf); 191 fprintf(stderr, "%s\n", buf);
196 exit(255); 192 exit(255);
197} 193}
198 194
199/* This stuff used to be in BSD rcp extern.h. */ 195/* This stuff used to be in BSD rcp extern.h. */
@@ -205,31 +201,31 @@ typedef struct {
205 201
206extern int iamremote; 202extern int iamremote;
207 203
208BUF *allocbuf(BUF *, int, int); 204BUF *allocbuf(BUF *, int, int);
209char *colon(char *); 205char *colon(char *);
210void lostconn(int); 206void lostconn(int);
211void nospace(void); 207void nospace(void);
212int okname(char *); 208int okname(char *);
213void run_err(const char *, ...); 209void run_err(const char *,...);
214void verifydir(char *); 210void verifydir(char *);
215 211
216/* Stuff from BSD rcp.c continues. */ 212/* Stuff from BSD rcp.c continues. */
217 213
218struct passwd *pwd; 214struct passwd *pwd;
219uid_t userid; 215uid_t userid;
220int errs, remin, remout; 216int errs, remin, remout;
221int pflag, iamremote, iamrecursive, targetshouldbedirectory; 217int pflag, iamremote, iamrecursive, targetshouldbedirectory;
222 218
223#define CMDNEEDS 64 219#define CMDNEEDS 64
224char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */ 220char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */
225 221
226int response(void); 222int response(void);
227void rsource(char *, struct stat *); 223void rsource(char *, struct stat *);
228void sink(int, char *[]); 224void sink(int, char *[]);
229void source(int, char *[]); 225void source(int, char *[]);
230void tolocal(int, char *[]); 226void tolocal(int, char *[]);
231void toremote(char *, int, char *[]); 227void toremote(char *, int, char *[]);
232void usage(void); 228void usage(void);
233 229
234int 230int
235main(argc, argv) 231main(argc, argv)
@@ -242,47 +238,48 @@ main(argc, argv)
242 extern int optind; 238 extern int optind;
243 239
244 fflag = tflag = 0; 240 fflag = tflag = 0;
245 while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q")) != EOF) 241 while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q")) != EOF)
246 switch(ch) { /* User-visible flags. */ 242 switch (ch) {
243 /* User-visible flags. */
247 case 'p': 244 case 'p':
248 pflag = 1; 245 pflag = 1;
249 break; 246 break;
250 case 'P': 247 case 'P':
251 port = optarg; 248 port = optarg;
252 break; 249 break;
253 case 'r': 250 case 'r':
254 iamrecursive = 1; 251 iamrecursive = 1;
255 break; 252 break;
256 /* Server options. */ 253 /* Server options. */
257 case 'd': 254 case 'd':
258 targetshouldbedirectory = 1; 255 targetshouldbedirectory = 1;
259 break; 256 break;
260 case 'f': /* "from" */ 257 case 'f': /* "from" */
261 iamremote = 1; 258 iamremote = 1;
262 fflag = 1; 259 fflag = 1;
263 break; 260 break;
264 case 't': /* "to" */ 261 case 't': /* "to" */
265 iamremote = 1; 262 iamremote = 1;
266 tflag = 1; 263 tflag = 1;
267 break; 264 break;
268 case 'c': 265 case 'c':
269 cipher = optarg; 266 cipher = optarg;
270 break; 267 break;
271 case 'i': 268 case 'i':
272 identity = optarg; 269 identity = optarg;
273 break; 270 break;
274 case 'v': 271 case 'v':
275 verbose = 1; 272 verbose_mode = 1;
276 break; 273 break;
277 case 'B': 274 case 'B':
278 batchmode = 1; 275 batchmode = 1;
279 break; 276 break;
280 case 'C': 277 case 'C':
281 compress = 1; 278 compress = 1;
282 break; 279 break;
283 case 'q': 280 case 'q':
284 showprogress = 0; 281 showprogress = 0;
285 break; 282 break;
286 case '?': 283 case '?':
287 default: 284 default:
288 usage(); 285 usage();
@@ -291,25 +288,25 @@ main(argc, argv)
291 argv += optind; 288 argv += optind;
292 289
293 if ((pwd = getpwuid(userid = getuid())) == NULL) 290 if ((pwd = getpwuid(userid = getuid())) == NULL)
294 fatal("unknown user %d", (int)userid); 291 fatal("unknown user %d", (int) userid);
295 292
296 if (! isatty(STDERR_FILENO)) 293 if (!isatty(STDERR_FILENO))
297 showprogress = 0; 294 showprogress = 0;
298 295
299 remin = STDIN_FILENO; 296 remin = STDIN_FILENO;
300 remout = STDOUT_FILENO; 297 remout = STDOUT_FILENO;
301 298
302 if (fflag) { /* Follow "protocol", send data. */ 299 if (fflag) {
303 (void)response(); 300 /* Follow "protocol", send data. */
301 (void) response();
304 source(argc, argv); 302 source(argc, argv);
305 exit(errs != 0); 303 exit(errs != 0);
306 } 304 }
307 305 if (tflag) {
308 if (tflag) { /* Receive data. */ 306 /* Receive data. */
309 sink(argc, argv); 307 sink(argc, argv);
310 exit(errs != 0); 308 exit(errs != 0);
311 } 309 }
312
313 if (argc < 2) 310 if (argc < 2)
314 usage(); 311 usage();
315 if (argc > 2) 312 if (argc > 2)
@@ -317,16 +314,16 @@ main(argc, argv)
317 314
318 remin = remout = -1; 315 remin = remout = -1;
319 /* Command to be executed on remote system using "ssh". */ 316 /* Command to be executed on remote system using "ssh". */
320 (void)sprintf(cmd, "scp%s%s%s%s", verbose ? " -v" : "", 317 (void) sprintf(cmd, "scp%s%s%s%s", verbose_mode ? " -v" : "",
321 iamrecursive ? " -r" : "", pflag ? " -p" : "", 318 iamrecursive ? " -r" : "", pflag ? " -p" : "",
322 targetshouldbedirectory ? " -d" : ""); 319 targetshouldbedirectory ? " -d" : "");
323 320
324 (void)signal(SIGPIPE, lostconn); 321 (void) signal(SIGPIPE, lostconn);
325 322
326 if ((targ = colon(argv[argc - 1]))) /* Dest is remote host. */ 323 if ((targ = colon(argv[argc - 1]))) /* Dest is remote host. */
327 toremote(targ, argc, argv); 324 toremote(targ, argc, argv);
328 else { 325 else {
329 tolocal(argc, argv); /* Dest is local host. */ 326 tolocal(argc, argv); /* Dest is local host. */
330 if (targetshouldbedirectory) 327 if (targetshouldbedirectory)
331 verifydir(argv[argc - 1]); 328 verifydir(argv[argc - 1]);
332 } 329 }
@@ -360,15 +357,15 @@ toremote(targ, argc, argv)
360 357
361 for (i = 0; i < argc - 1; i++) { 358 for (i = 0; i < argc - 1; i++) {
362 src = colon(argv[i]); 359 src = colon(argv[i]);
363 if (src) { /* remote to remote */ 360 if (src) { /* remote to remote */
364 *src++ = 0; 361 *src++ = 0;
365 if (*src == 0) 362 if (*src == 0)
366 src = "."; 363 src = ".";
367 host = strchr(argv[i], '@'); 364 host = strchr(argv[i], '@');
368 len = strlen(SSH_PROGRAM) + strlen(argv[i]) + 365 len = strlen(SSH_PROGRAM) + strlen(argv[i]) +
369 strlen(src) + (tuser ? strlen(tuser) : 0) + 366 strlen(src) + (tuser ? strlen(tuser) : 0) +
370 strlen(thost) + strlen(targ) + CMDNEEDS + 32; 367 strlen(thost) + strlen(targ) + CMDNEEDS + 32;
371 bp = xmalloc(len); 368 bp = xmalloc(len);
372 if (host) { 369 if (host) {
373 *host++ = 0; 370 *host++ = 0;
374 suser = argv[i]; 371 suser = argv[i];
@@ -376,37 +373,37 @@ toremote(targ, argc, argv)
376 suser = pwd->pw_name; 373 suser = pwd->pw_name;
377 else if (!okname(suser)) 374 else if (!okname(suser))
378 continue; 375 continue;
379 (void)sprintf(bp, 376 (void) sprintf(bp,
380 "%s%s -x -o'FallBackToRsh no' -n -l %s %s %s %s '%s%s%s:%s'", 377 "%s%s -x -o'FallBackToRsh no' -n -l %s %s %s %s '%s%s%s:%s'",
381 SSH_PROGRAM, verbose ? " -v" : "", 378 SSH_PROGRAM, verbose_mode ? " -v" : "",
382 suser, host, cmd, src, 379 suser, host, cmd, src,
383 tuser ? tuser : "", tuser ? "@" : "", 380 tuser ? tuser : "", tuser ? "@" : "",
384 thost, targ); 381 thost, targ);
385 } else 382 } else
386 (void)sprintf(bp, 383 (void) sprintf(bp,
387 "exec %s%s -x -o'FallBackToRsh no' -n %s %s %s '%s%s%s:%s'", 384 "exec %s%s -x -o'FallBackToRsh no' -n %s %s %s '%s%s%s:%s'",
388 SSH_PROGRAM, verbose ? " -v" : "", 385 SSH_PROGRAM, verbose_mode ? " -v" : "",
389 argv[i], cmd, src, 386 argv[i], cmd, src,
390 tuser ? tuser : "", tuser ? "@" : "", 387 tuser ? tuser : "", tuser ? "@" : "",
391 thost, targ); 388 thost, targ);
392 if (verbose) 389 if (verbose_mode)
393 fprintf(stderr, "Executing: %s\n", bp); 390 fprintf(stderr, "Executing: %s\n", bp);
394 (void)system(bp); 391 (void) system(bp);
395 (void)xfree(bp); 392 (void) xfree(bp);
396 } else { /* local to remote */ 393 } else { /* local to remote */
397 if (remin == -1) { 394 if (remin == -1) {
398 len = strlen(targ) + CMDNEEDS + 20; 395 len = strlen(targ) + CMDNEEDS + 20;
399 bp = xmalloc(len); 396 bp = xmalloc(len);
400 (void)sprintf(bp, "%s -t %s", cmd, targ); 397 (void) sprintf(bp, "%s -t %s", cmd, targ);
401 host = thost; 398 host = thost;
402 if (do_cmd(host, tuser, 399 if (do_cmd(host, tuser,
403 bp, &remin, &remout) < 0) 400 bp, &remin, &remout) < 0)
404 exit(1); 401 exit(1);
405 if (response() < 0) 402 if (response() < 0)
406 exit(1); 403 exit(1);
407 (void)xfree(bp); 404 (void) xfree(bp);
408 } 405 }
409 source(1, argv+i); 406 source(1, argv + i);
410 } 407 }
411 } 408 }
412} 409}
@@ -420,18 +417,18 @@ tolocal(argc, argv)
420 char *bp, *host, *src, *suser; 417 char *bp, *host, *src, *suser;
421 418
422 for (i = 0; i < argc - 1; i++) { 419 for (i = 0; i < argc - 1; i++) {
423 if (!(src = colon(argv[i]))) { /* Local to local. */ 420 if (!(src = colon(argv[i]))) { /* Local to local. */
424 len = strlen(_PATH_CP) + strlen(argv[i]) + 421 len = strlen(_PATH_CP) + strlen(argv[i]) +
425 strlen(argv[argc - 1]) + 20; 422 strlen(argv[argc - 1]) + 20;
426 bp = xmalloc(len); 423 bp = xmalloc(len);
427 (void)sprintf(bp, "exec %s%s%s %s %s", _PATH_CP, 424 (void) sprintf(bp, "exec %s%s%s %s %s", _PATH_CP,
428 iamrecursive ? " -r" : "", pflag ? " -p" : "", 425 iamrecursive ? " -r" : "", pflag ? " -p" : "",
429 argv[i], argv[argc - 1]); 426 argv[i], argv[argc - 1]);
430 if (verbose) 427 if (verbose_mode)
431 fprintf(stderr, "Executing: %s\n", bp); 428 fprintf(stderr, "Executing: %s\n", bp);
432 if (system(bp)) 429 if (system(bp))
433 ++errs; 430 ++errs;
434 (void)xfree(bp); 431 (void) xfree(bp);
435 continue; 432 continue;
436 } 433 }
437 *src++ = 0; 434 *src++ = 0;
@@ -449,16 +446,16 @@ tolocal(argc, argv)
449 continue; 446 continue;
450 } 447 }
451 len = strlen(src) + CMDNEEDS + 20; 448 len = strlen(src) + CMDNEEDS + 20;
452 bp = xmalloc(len); 449 bp = xmalloc(len);
453 (void)sprintf(bp, "%s -f %s", cmd, src); 450 (void) sprintf(bp, "%s -f %s", cmd, src);
454 if (do_cmd(host, suser, bp, &remin, &remout) < 0) { 451 if (do_cmd(host, suser, bp, &remin, &remout) < 0) {
455 (void)xfree(bp); 452 (void) xfree(bp);
456 ++errs; 453 ++errs;
457 continue; 454 continue;
458 } 455 }
459 xfree(bp); 456 xfree(bp);
460 sink(1, argv + argc - 1); 457 sink(1, argv + argc - 1);
461 (void)close(remin); 458 (void) close(remin);
462 remin = remout = -1; 459 remin = remout = -1;
463 } 460 }
464} 461}
@@ -476,7 +473,7 @@ source(argc, argv)
476 char *last, *name, buf[2048]; 473 char *last, *name, buf[2048];
477 474
478 for (indx = 0; indx < argc; ++indx) { 475 for (indx = 0; indx < argc; ++indx) {
479 name = argv[indx]; 476 name = argv[indx];
480 statbytes = 0; 477 statbytes = 0;
481 if ((fd = open(name, O_RDONLY, 0)) < 0) 478 if ((fd = open(name, O_RDONLY, 0)) < 0)
482 goto syserr; 479 goto syserr;
@@ -507,36 +504,33 @@ syserr: run_err("%s: %s", name, strerror(errno));
507 * Make it compatible with possible future 504 * Make it compatible with possible future
508 * versions expecting microseconds. 505 * versions expecting microseconds.
509 */ 506 */
510 (void)sprintf(buf, "T%lu 0 %lu 0\n", 507 (void) sprintf(buf, "T%lu 0 %lu 0\n",
511 (unsigned long)stb.st_mtime, 508 (unsigned long) stb.st_mtime,
512 (unsigned long)stb.st_atime); 509 (unsigned long) stb.st_atime);
513 (void)write(remout, buf, strlen(buf)); 510 (void) write(remout, buf, strlen(buf));
514 if (response() < 0) 511 if (response() < 0)
515 goto next; 512 goto next;
516 } 513 }
517#define FILEMODEMASK (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) 514#define FILEMODEMASK (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
518 (void)sprintf(buf, "C%04o %lu %s\n", 515 (void) sprintf(buf, "C%04o %lu %s\n",
519 (unsigned int)(stb.st_mode & FILEMODEMASK), 516 (unsigned int) (stb.st_mode & FILEMODEMASK),
520 (unsigned long)stb.st_size, 517 (unsigned long) stb.st_size,
521 last); 518 last);
522 if (verbose) 519 if (verbose_mode) {
523 { 520 fprintf(stderr, "Sending file modes: %s", buf);
524 fprintf(stderr, "Sending file modes: %s", buf); 521 fflush(stderr);
525 fflush(stderr); 522 }
526 } 523 (void) write(remout, buf, strlen(buf));
527 (void)write(remout, buf, strlen(buf));
528 if (response() < 0) 524 if (response() < 0)
529 goto next; 525 goto next;
530 if ((bp = allocbuf(&buffer, fd, 2048)) == NULL) { 526 if ((bp = allocbuf(&buffer, fd, 2048)) == NULL) {
531next: (void)close(fd); 527next: (void) close(fd);
532 continue; 528 continue;
533 } 529 }
534
535 if (showprogress) { 530 if (showprogress) {
536 totalbytes = stb.st_size; 531 totalbytes = stb.st_size;
537 progressmeter(-1); 532 progressmeter(-1);
538 } 533 }
539
540 /* Keep writing after an error so that we stay sync'd up. */ 534 /* Keep writing after an error so that we stay sync'd up. */
541 for (haderr = i = 0; i < stb.st_size; i += bp->cnt) { 535 for (haderr = i = 0; i < stb.st_size; i += bp->cnt) {
542 amt = bp->cnt; 536 amt = bp->cnt;
@@ -548,7 +542,7 @@ next: (void)close(fd);
548 haderr = result >= 0 ? EIO : errno; 542 haderr = result >= 0 ? EIO : errno;
549 } 543 }
550 if (haderr) 544 if (haderr)
551 (void)write(remout, bp->buf, amt); 545 (void) write(remout, bp->buf, amt);
552 else { 546 else {
553 result = write(remout, bp->buf, amt); 547 result = write(remout, bp->buf, amt);
554 if (result != amt) 548 if (result != amt)
@@ -556,16 +550,16 @@ next: (void)close(fd);
556 statbytes += result; 550 statbytes += result;
557 } 551 }
558 } 552 }
559 if(showprogress) 553 if (showprogress)
560 progressmeter(1); 554 progressmeter(1);
561 555
562 if (close(fd) < 0 && !haderr) 556 if (close(fd) < 0 && !haderr)
563 haderr = errno; 557 haderr = errno;
564 if (!haderr) 558 if (!haderr)
565 (void)write(remout, "", 1); 559 (void) write(remout, "", 1);
566 else 560 else
567 run_err("%s: %s", name, strerror(haderr)); 561 run_err("%s: %s", name, strerror(haderr));
568 (void)response(); 562 (void) response();
569 } 563 }
570} 564}
571 565
@@ -588,21 +582,21 @@ rsource(name, statp)
588 else 582 else
589 last++; 583 last++;
590 if (pflag) { 584 if (pflag) {
591 (void)sprintf(path, "T%lu 0 %lu 0\n", 585 (void) sprintf(path, "T%lu 0 %lu 0\n",
592 (unsigned long)statp->st_mtime, 586 (unsigned long) statp->st_mtime,
593 (unsigned long)statp->st_atime); 587 (unsigned long) statp->st_atime);
594 (void)write(remout, path, strlen(path)); 588 (void) write(remout, path, strlen(path));
595 if (response() < 0) { 589 if (response() < 0) {
596 closedir(dirp); 590 closedir(dirp);
597 return; 591 return;
598 } 592 }
599 } 593 }
600 (void)sprintf(path, 594 (void) sprintf(path, "D%04o %d %.1024s\n",
601 "D%04o %d %.1024s\n", (unsigned int)(statp->st_mode & FILEMODEMASK), 595 (unsigned int) (statp->st_mode & FILEMODEMASK),
602 0, last); 596 0, last);
603 if (verbose) 597 if (verbose_mode)
604 fprintf(stderr, "Entering directory: %s", path); 598 fprintf(stderr, "Entering directory: %s", path);
605 (void)write(remout, path, strlen(path)); 599 (void) write(remout, path, strlen(path));
606 if (response() < 0) { 600 if (response() < 0) {
607 closedir(dirp); 601 closedir(dirp);
608 return; 602 return;
@@ -616,13 +610,13 @@ rsource(name, statp)
616 run_err("%s/%s: name too long", name, dp->d_name); 610 run_err("%s/%s: name too long", name, dp->d_name);
617 continue; 611 continue;
618 } 612 }
619 (void)sprintf(path, "%s/%s", name, dp->d_name); 613 (void) sprintf(path, "%s/%s", name, dp->d_name);
620 vect[0] = path; 614 vect[0] = path;
621 source(1, vect); 615 source(1, vect);
622 } 616 }
623 (void)closedir(dirp); 617 (void) closedir(dirp);
624 (void)write(remout, "E\n", 2); 618 (void) write(remout, "E\n", 2);
625 (void)response(); 619 (void) response();
626} 620}
627 621
628void 622void
@@ -632,21 +626,23 @@ sink(argc, argv)
632{ 626{
633 static BUF buffer; 627 static BUF buffer;
634 struct stat stb; 628 struct stat stb;
635 enum { YES, NO, DISPLAYED } wrerr; 629 enum {
630 YES, NO, DISPLAYED
631 } wrerr;
636 BUF *bp; 632 BUF *bp;
637 off_t i, j; 633 off_t i, j;
638 int amt, count, exists, first, mask, mode, ofd, omode; 634 int amt, count, exists, first, mask, mode, ofd, omode;
639 int setimes, size, targisdir, wrerrno = 0; 635 int setimes, size, targisdir, wrerrno = 0;
640 char ch, *cp, *np, *targ, *why, *vect[1], buf[2048]; 636 char ch, *cp, *np, *targ, *why, *vect[1], buf[2048];
641 struct utimbuf ut; 637 struct utimbuf ut;
642 int dummy_usec; 638 int dummy_usec;
643 639
644#define SCREWUP(str) { why = str; goto screwup; } 640#define SCREWUP(str) { why = str; goto screwup; }
645 641
646 setimes = targisdir = 0; 642 setimes = targisdir = 0;
647 mask = umask(0); 643 mask = umask(0);
648 if (!pflag) 644 if (!pflag)
649 (void)umask(mask); 645 (void) umask(mask);
650 if (argc != 1) { 646 if (argc != 1) {
651 run_err("ambiguous target"); 647 run_err("ambiguous target");
652 exit(1); 648 exit(1);
@@ -654,8 +650,8 @@ sink(argc, argv)
654 targ = *argv; 650 targ = *argv;
655 if (targetshouldbedirectory) 651 if (targetshouldbedirectory)
656 verifydir(targ); 652 verifydir(targ);
657 653
658 (void)write(remout, "", 1); 654 (void) write(remout, "", 1);
659 if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode)) 655 if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode))
660 targisdir = 1; 656 targisdir = 1;
661 for (first = 1;; first = 0) { 657 for (first = 1;; first = 0) {
@@ -673,18 +669,17 @@ sink(argc, argv)
673 669
674 if (buf[0] == '\01' || buf[0] == '\02') { 670 if (buf[0] == '\01' || buf[0] == '\02') {
675 if (iamremote == 0) 671 if (iamremote == 0)
676 (void)write(STDERR_FILENO, 672 (void) write(STDERR_FILENO,
677 buf + 1, strlen(buf + 1)); 673 buf + 1, strlen(buf + 1));
678 if (buf[0] == '\02') 674 if (buf[0] == '\02')
679 exit(1); 675 exit(1);
680 ++errs; 676 ++errs;
681 continue; 677 continue;
682 } 678 }
683 if (buf[0] == 'E') { 679 if (buf[0] == 'E') {
684 (void)write(remout, "", 1); 680 (void) write(remout, "", 1);
685 return; 681 return;
686 } 682 }
687
688 if (ch == '\n') 683 if (ch == '\n')
689 *--cp = 0; 684 *--cp = 0;
690 685
@@ -706,7 +701,7 @@ sink(argc, argv)
706 getnum(dummy_usec); 701 getnum(dummy_usec);
707 if (*cp++ != '\0') 702 if (*cp++ != '\0')
708 SCREWUP("atime.usec not delimited"); 703 SCREWUP("atime.usec not delimited");
709 (void)write(remout, "", 1); 704 (void) write(remout, "", 1);
710 continue; 705 continue;
711 } 706 }
712 if (*cp != 'C' && *cp != 'D') { 707 if (*cp != 'C' && *cp != 'D') {
@@ -732,7 +727,7 @@ sink(argc, argv)
732 if (*cp++ != ' ') 727 if (*cp++ != ' ')
733 SCREWUP("mode not delimited"); 728 SCREWUP("mode not delimited");
734 729
735 for (size = 0; *cp >= '0' && *cp <= '9';) 730 for (size = 0; *cp >= '0' && *cp <= '9';)
736 size = size * 10 + (*cp++ - '0'); 731 size = size * 10 + (*cp++ - '0');
737 if (*cp++ != ' ') 732 if (*cp++ != ' ')
738 SCREWUP("size not delimited"); 733 SCREWUP("size not delimited");
@@ -743,9 +738,9 @@ sink(argc, argv)
743 738
744 need = strlen(targ) + strlen(cp) + 250; 739 need = strlen(targ) + strlen(cp) + 250;
745 if (need > cursize) 740 if (need > cursize)
746 namebuf = xmalloc(need); 741 namebuf = xmalloc(need);
747 (void)sprintf(namebuf, "%s%s%s", targ, 742 (void) sprintf(namebuf, "%s%s%s", targ,
748 *targ ? "/" : "", cp); 743 *targ ? "/" : "", cp);
749 np = namebuf; 744 np = namebuf;
750 } else 745 } else
751 np = targ; 746 np = targ;
@@ -759,9 +754,10 @@ sink(argc, argv)
759 goto bad; 754 goto bad;
760 } 755 }
761 if (pflag) 756 if (pflag)
762 (void)chmod(np, mode); 757 (void) chmod(np, mode);
763 } else { 758 } else {
764 /* Handle copying from a read-only directory */ 759 /* Handle copying from a read-only
760 directory */
765 mod_flag = 1; 761 mod_flag = 1;
766 if (mkdir(np, mode | S_IRWXU) < 0) 762 if (mkdir(np, mode | S_IRWXU) < 0)
767 goto bad; 763 goto bad;
@@ -771,22 +767,22 @@ sink(argc, argv)
771 if (setimes) { 767 if (setimes) {
772 setimes = 0; 768 setimes = 0;
773 if (utime(np, &ut) < 0) 769 if (utime(np, &ut) < 0)
774 run_err("%s: set times: %s", 770 run_err("%s: set times: %s",
775 np, strerror(errno)); 771 np, strerror(errno));
776 } 772 }
777 if (mod_flag) 773 if (mod_flag)
778 (void)chmod(np, mode); 774 (void) chmod(np, mode);
779 continue; 775 continue;
780 } 776 }
781 omode = mode; 777 omode = mode;
782 mode |= S_IWRITE; 778 mode |= S_IWRITE;
783 if ((ofd = open(np, O_WRONLY|O_CREAT|O_TRUNC, mode)) < 0) { 779 if ((ofd = open(np, O_WRONLY | O_CREAT | O_TRUNC, mode)) < 0) {
784bad: run_err("%s: %s", np, strerror(errno)); 780bad: run_err("%s: %s", np, strerror(errno));
785 continue; 781 continue;
786 } 782 }
787 (void)write(remout, "", 1); 783 (void) write(remout, "", 1);
788 if ((bp = allocbuf(&buffer, ofd, 4096)) == NULL) { 784 if ((bp = allocbuf(&buffer, ofd, 4096)) == NULL) {
789 (void)close(ofd); 785 (void) close(ofd);
790 continue; 786 continue;
791 } 787 }
792 cp = bp->buf; 788 cp = bp->buf;
@@ -806,12 +802,12 @@ bad: run_err("%s: %s", np, strerror(errno));
806 j = read(remin, cp, amt); 802 j = read(remin, cp, amt);
807 if (j <= 0) { 803 if (j <= 0) {
808 run_err("%s", j ? strerror(errno) : 804 run_err("%s", j ? strerror(errno) :
809 "dropped connection"); 805 "dropped connection");
810 exit(1); 806 exit(1);
811 } 807 }
812 amt -= j; 808 amt -= j;
813 cp += j; 809 cp += j;
814 statbytes += j; 810 statbytes += j;
815 } while (amt > 0); 811 } while (amt > 0);
816 if (count == bp->cnt) { 812 if (count == bp->cnt) {
817 /* Keep reading so we stay sync'd up. */ 813 /* Keep reading so we stay sync'd up. */
@@ -819,7 +815,7 @@ bad: run_err("%s: %s", np, strerror(errno));
819 j = write(ofd, bp->buf, count); 815 j = write(ofd, bp->buf, count);
820 if (j != count) { 816 if (j != count) {
821 wrerr = YES; 817 wrerr = YES;
822 wrerrno = j >= 0 ? EIO : errno; 818 wrerrno = j >= 0 ? EIO : errno;
823 } 819 }
824 } 820 }
825 count = 0; 821 count = 0;
@@ -831,7 +827,7 @@ bad: run_err("%s: %s", np, strerror(errno));
831 if (count != 0 && wrerr == NO && 827 if (count != 0 && wrerr == NO &&
832 (j = write(ofd, bp->buf, count)) != count) { 828 (j = write(ofd, bp->buf, count)) != count) {
833 wrerr = YES; 829 wrerr = YES;
834 wrerrno = j >= 0 ? EIO : errno; 830 wrerrno = j >= 0 ? EIO : errno;
835 } 831 }
836#if 0 832#if 0
837 if (ftruncate(ofd, size)) { 833 if (ftruncate(ofd, size)) {
@@ -843,29 +839,29 @@ bad: run_err("%s: %s", np, strerror(errno));
843 if (exists || omode != mode) 839 if (exists || omode != mode)
844 if (fchmod(ofd, omode)) 840 if (fchmod(ofd, omode))
845 run_err("%s: set mode: %s", 841 run_err("%s: set mode: %s",
846 np, strerror(errno)); 842 np, strerror(errno));
847 } else { 843 } else {
848 if (!exists && omode != mode) 844 if (!exists && omode != mode)
849 if (fchmod(ofd, omode & ~mask)) 845 if (fchmod(ofd, omode & ~mask))
850 run_err("%s: set mode: %s", 846 run_err("%s: set mode: %s",
851 np, strerror(errno)); 847 np, strerror(errno));
852 } 848 }
853 (void)close(ofd); 849 (void) close(ofd);
854 (void)response(); 850 (void) response();
855 if (setimes && wrerr == NO) { 851 if (setimes && wrerr == NO) {
856 setimes = 0; 852 setimes = 0;
857 if (utime(np, &ut) < 0) { 853 if (utime(np, &ut) < 0) {
858 run_err("%s: set times: %s", 854 run_err("%s: set times: %s",
859 np, strerror(errno)); 855 np, strerror(errno));
860 wrerr = DISPLAYED; 856 wrerr = DISPLAYED;
861 } 857 }
862 } 858 }
863 switch(wrerr) { 859 switch (wrerr) {
864 case YES: 860 case YES:
865 run_err("%s: %s", np, strerror(wrerrno)); 861 run_err("%s: %s", np, strerror(wrerrno));
866 break; 862 break;
867 case NO: 863 case NO:
868 (void)write(remout, "", 1); 864 (void) write(remout, "", 1);
869 break; 865 break;
870 case DISPLAYED: 866 case DISPLAYED:
871 break; 867 break;
@@ -885,14 +881,14 @@ response()
885 lostconn(0); 881 lostconn(0);
886 882
887 cp = rbuf; 883 cp = rbuf;
888 switch(resp) { 884 switch (resp) {
889 case 0: /* ok */ 885 case 0: /* ok */
890 return (0); 886 return (0);
891 default: 887 default:
892 *cp++ = resp; 888 *cp++ = resp;
893 /* FALLTHROUGH */ 889 /* FALLTHROUGH */
894 case 1: /* error, followed by error msg */ 890 case 1: /* error, followed by error msg */
895 case 2: /* fatal error, "" */ 891 case 2: /* fatal error, "" */
896 do { 892 do {
897 if (read(remin, &ch, sizeof(ch)) != sizeof(ch)) 893 if (read(remin, &ch, sizeof(ch)) != sizeof(ch))
898 lostconn(0); 894 lostconn(0);
@@ -900,7 +896,7 @@ response()
900 } while (cp < &rbuf[sizeof(rbuf) - 1] && ch != '\n'); 896 } while (cp < &rbuf[sizeof(rbuf) - 1] && ch != '\n');
901 897
902 if (!iamremote) 898 if (!iamremote)
903 (void)write(STDERR_FILENO, rbuf, cp - rbuf); 899 (void) write(STDERR_FILENO, rbuf, cp - rbuf);
904 ++errs; 900 ++errs;
905 if (resp == 1) 901 if (resp == 1)
906 return (-1); 902 return (-1);
@@ -912,13 +908,13 @@ response()
912void 908void
913usage() 909usage()
914{ 910{
915 (void)fprintf(stderr, 911 (void) fprintf(stderr,
916 "usage: scp [-pqrvC] [-P port] [-c cipher] [-i identity] f1 f2; or:\n scp [options] f1 ... fn directory\n"); 912 "usage: scp [-pqrvC] [-P port] [-c cipher] [-i identity] f1 f2; or:\n scp [options] f1 ... fn directory\n");
917 exit(1); 913 exit(1);
918} 914}
919 915
920void 916void
921run_err(const char *fmt, ...) 917run_err(const char *fmt,...)
922{ 918{
923 static FILE *fp; 919 static FILE *fp;
924 va_list ap; 920 va_list ap;
@@ -927,18 +923,16 @@ run_err(const char *fmt, ...)
927 ++errs; 923 ++errs;
928 if (fp == NULL && !(fp = fdopen(remout, "w"))) 924 if (fp == NULL && !(fp = fdopen(remout, "w")))
929 return; 925 return;
930 (void)fprintf(fp, "%c", 0x01); 926 (void) fprintf(fp, "%c", 0x01);
931 (void)fprintf(fp, "scp: "); 927 (void) fprintf(fp, "scp: ");
932 (void)vfprintf(fp, fmt, ap); 928 (void) vfprintf(fp, fmt, ap);
933 (void)fprintf(fp, "\n"); 929 (void) fprintf(fp, "\n");
934 (void)fflush(fp); 930 (void) fflush(fp);
935 931
936 if (!iamremote) 932 if (!iamremote) {
937 { 933 vfprintf(stderr, fmt, ap);
938 vfprintf(stderr, fmt, ap); 934 fprintf(stderr, "\n");
939 fprintf(stderr, "\n"); 935 }
940 }
941
942 va_end(ap); 936 va_end(ap);
943} 937}
944 938
@@ -976,7 +970,7 @@ run_err(const char *fmt, ...)
976 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 970 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
977 * SUCH DAMAGE. 971 * SUCH DAMAGE.
978 * 972 *
979 * $Id: scp.c,v 1.8 1999/11/19 01:34:14 damien Exp $ 973 * $Id: scp.c,v 1.9 1999/11/24 13:26:22 damien Exp $
980 */ 974 */
981 975
982char * 976char *
@@ -1043,17 +1037,17 @@ allocbuf(bp, fd, blksize)
1043 run_err("fstat: %s", strerror(errno)); 1037 run_err("fstat: %s", strerror(errno));
1044 return (0); 1038 return (0);
1045 } 1039 }
1046 if (stb.st_blksize == 0) 1040 if (stb.st_blksize == 0)
1047 size = blksize; 1041 size = blksize;
1048 else 1042 else
1049 size = blksize + (stb.st_blksize - blksize % stb.st_blksize) % 1043 size = blksize + (stb.st_blksize - blksize % stb.st_blksize) %
1050 stb.st_blksize; 1044 stb.st_blksize;
1051 if (bp->cnt >= size) 1045 if (bp->cnt >= size)
1052 return (bp); 1046 return (bp);
1053 if (bp->buf == NULL) 1047 if (bp->buf == NULL)
1054 bp->buf = xmalloc(size); 1048 bp->buf = xmalloc(size);
1055 else 1049 else
1056 bp->buf = xrealloc(bp->buf, size); 1050 bp->buf = xrealloc(bp->buf, size);
1057 bp->cnt = size; 1051 bp->cnt = size;
1058 return (bp); 1052 return (bp);
1059} 1053}
@@ -1072,16 +1066,16 @@ lostconn(signo)
1072 */ 1066 */
1073int 1067int
1074atomicio(f, fd, s, n) 1068atomicio(f, fd, s, n)
1075int (*f)(); 1069 int (*f) ();
1076char *s; 1070 char *s;
1077{ 1071{
1078 int res, pos = 0; 1072 int res, pos = 0;
1079 1073
1080 while (n>pos) { 1074 while (n > pos) {
1081 res = (f)(fd, s+pos, n-pos); 1075 res = (f) (fd, s + pos, n - pos);
1082 switch (res) { 1076 switch (res) {
1083 case -1: 1077 case -1:
1084 if (errno==EINTR || errno==EAGAIN) 1078 if (errno == EINTR || errno == EAGAIN)
1085 continue; 1079 continue;
1086 case 0: 1080 case 0:
1087 return (res); 1081 return (res);
@@ -1095,12 +1089,12 @@ char *s;
1095void 1089void
1096alarmtimer(int wait) 1090alarmtimer(int wait)
1097{ 1091{
1098 struct itimerval itv; 1092 struct itimerval itv;
1099 1093
1100 itv.it_value.tv_sec = wait; 1094 itv.it_value.tv_sec = wait;
1101 itv.it_value.tv_usec = 0; 1095 itv.it_value.tv_usec = 0;
1102 itv.it_interval = itv.it_value; 1096 itv.it_interval = itv.it_value;
1103 setitimer(ITIMER_REAL, &itv, NULL); 1097 setitimer(ITIMER_REAL, &itv, NULL);
1104} 1098}
1105 1099
1106void 1100void
@@ -1121,8 +1115,8 @@ foregroundproc()
1121 if (pgrp == -1) 1115 if (pgrp == -1)
1122 pgrp = getpgrp(); 1116 pgrp = getpgrp();
1123 1117
1124 return((ioctl(STDOUT_FILENO, TIOCGPGRP, &ctty_pgrp) != -1 && 1118 return ((ioctl(STDOUT_FILENO, TIOCGPGRP, &ctty_pgrp) != -1 &&
1125 ctty_pgrp == pgrp)); 1119 ctty_pgrp == pgrp));
1126} 1120}
1127 1121
1128void 1122void
@@ -1138,35 +1132,33 @@ progressmeter(int flag)
1138 char buf[256]; 1132 char buf[256];
1139 1133
1140 if (flag == -1) { 1134 if (flag == -1) {
1141 (void)gettimeofday(&start, (struct timezone *)0); 1135 (void) gettimeofday(&start, (struct timezone *) 0);
1142 lastupdate = start; 1136 lastupdate = start;
1143 lastsize = 0; 1137 lastsize = 0;
1144 } 1138 }
1145 if (foregroundproc() == 0) 1139 if (foregroundproc() == 0)
1146 return; 1140 return;
1147 1141
1148 (void)gettimeofday(&now, (struct timezone *)0); 1142 (void) gettimeofday(&now, (struct timezone *) 0);
1149 cursize = statbytes; 1143 cursize = statbytes;
1150 if (totalbytes != 0) { 1144 if (totalbytes != 0) {
1151 ratio = cursize * 100.0 / totalbytes; 1145 ratio = cursize * 100.0 / totalbytes;
1152 ratio = MAX(ratio, 0); 1146 ratio = MAX(ratio, 0);
1153 ratio = MIN(ratio, 100); 1147 ratio = MIN(ratio, 100);
1154 } 1148 } else
1155 else
1156 ratio = 100; 1149 ratio = 100;
1157 1150
1158 snprintf(buf, sizeof(buf), "\r%-20.20s %3d%% ", curfile, ratio); 1151 snprintf(buf, sizeof(buf), "\r%-20.20s %3d%% ", curfile, ratio);
1159 1152
1160 barlength = getttywidth() - 51; 1153 barlength = getttywidth() - 51;
1161 if (barlength > 0) { 1154 if (barlength > 0) {
1162 i = barlength * ratio / 100; 1155 i = barlength * ratio / 100;
1163 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), 1156 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
1164 "|%.*s%*s|", i, 1157 "|%.*s%*s|", i,
1165"*****************************************************************************" 1158 "*****************************************************************************"
1166"*****************************************************************************", 1159 "*****************************************************************************",
1167 barlength - i, ""); 1160 barlength - i, "");
1168 } 1161 }
1169
1170 i = 0; 1162 i = 0;
1171 abbrevsize = cursize; 1163 abbrevsize = cursize;
1172 while (abbrevsize >= 100000 && i < sizeof(prefixes)) { 1164 while (abbrevsize >= 100000 && i < sizeof(prefixes)) {
@@ -1174,8 +1166,8 @@ progressmeter(int flag)
1174 abbrevsize >>= 10; 1166 abbrevsize >>= 10;
1175 } 1167 }
1176 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %5qd %c%c ", 1168 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %5qd %c%c ",
1177 (quad_t)abbrevsize, prefixes[i], prefixes[i] == ' ' ? ' ' : 1169 (quad_t) abbrevsize, prefixes[i], prefixes[i] == ' ' ? ' ' :
1178 'B'); 1170 'B');
1179 1171
1180 timersub(&now, &lastupdate, &wait); 1172 timersub(&now, &lastupdate, &wait);
1181 if (cursize > lastsize) { 1173 if (cursize > lastsize) {
@@ -1187,33 +1179,32 @@ progressmeter(int flag)
1187 } 1179 }
1188 wait.tv_sec = 0; 1180 wait.tv_sec = 0;
1189 } 1181 }
1190
1191 timersub(&now, &start, &td); 1182 timersub(&now, &start, &td);
1192 elapsed = td.tv_sec + (td.tv_usec / 1000000.0); 1183 elapsed = td.tv_sec + (td.tv_usec / 1000000.0);
1193 1184
1194 if (statbytes <= 0 || elapsed <= 0.0 || cursize > totalbytes) { 1185 if (statbytes <= 0 || elapsed <= 0.0 || cursize > totalbytes) {
1195 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), 1186 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
1196 " --:-- ETA"); 1187 " --:-- ETA");
1197 } else if (wait.tv_sec >= STALLTIME) { 1188 } else if (wait.tv_sec >= STALLTIME) {
1198 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), 1189 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
1199 " - stalled -"); 1190 " - stalled -");
1200 } else { 1191 } else {
1201 remaining = (int)(totalbytes / (statbytes / elapsed) - elapsed); 1192 remaining = (int) (totalbytes / (statbytes / elapsed) - elapsed);
1202 i = remaining / 3600; 1193 i = remaining / 3600;
1203 if (i) 1194 if (i)
1204 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), 1195 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
1205 "%2d:", i); 1196 "%2d:", i);
1206 else 1197 else
1207 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), 1198 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
1208 " "); 1199 " ");
1209 i = remaining % 3600; 1200 i = remaining % 3600;
1210 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), 1201 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
1211 "%02d:%02d ETA", i / 60, i % 60); 1202 "%02d:%02d ETA", i / 60, i % 60);
1212 } 1203 }
1213 atomicio(write, fileno(stdout), buf, strlen(buf)); 1204 atomicio(write, fileno(stdout), buf, strlen(buf));
1214 1205
1215 if (flag == -1) { 1206 if (flag == -1) {
1216 signal(SIGALRM, (void *)updateprogressmeter); 1207 signal(SIGALRM, (void *) updateprogressmeter);
1217 alarmtimer(1); 1208 alarmtimer(1);
1218 } else if (flag == 1) { 1209 } else if (flag == 1) {
1219 alarmtimer(0); 1210 alarmtimer(0);
@@ -1228,9 +1219,7 @@ getttywidth(void)
1228 struct winsize winsize; 1219 struct winsize winsize;
1229 1220
1230 if (ioctl(fileno(stdout), TIOCGWINSZ, &winsize) != -1) 1221 if (ioctl(fileno(stdout), TIOCGWINSZ, &winsize) != -1)
1231 return(winsize.ws_col ? winsize.ws_col : 80); 1222 return (winsize.ws_col ? winsize.ws_col : 80);
1232 else 1223 else
1233 return(80); 1224 return (80);
1234} 1225}
1235
1236
diff --git a/servconf.c b/servconf.c
index 086bc0364..aa7d5b781 100644
--- a/servconf.c
+++ b/servconf.c
@@ -1,18 +1,18 @@
1/* 1/*
2 2 *
3servconf.c 3 * servconf.c
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Mon Aug 21 15:48:58 1995 ylo 10 * Created: Mon Aug 21 15:48:58 1995 ylo
11 11 *
12*/ 12 */
13 13
14#include "includes.h" 14#include "includes.h"
15RCSID("$Id: servconf.c,v 1.5 1999/11/21 02:23:53 damien Exp $"); 15RCSID("$Id: servconf.c,v 1.6 1999/11/24 13:26:22 damien Exp $");
16 16
17#include "ssh.h" 17#include "ssh.h"
18#include "servconf.h" 18#include "servconf.h"
@@ -20,535 +20,514 @@ RCSID("$Id: servconf.c,v 1.5 1999/11/21 02:23:53 damien Exp $");
20 20
21/* Initializes the server options to their default values. */ 21/* Initializes the server options to their default values. */
22 22
23void initialize_server_options(ServerOptions *options) 23void
24initialize_server_options(ServerOptions *options)
24{ 25{
25 memset(options, 0, sizeof(*options)); 26 memset(options, 0, sizeof(*options));
26 options->port = -1; 27 options->port = -1;
27 options->listen_addr.s_addr = htonl(INADDR_ANY); 28 options->listen_addr.s_addr = htonl(INADDR_ANY);
28 options->host_key_file = NULL; 29 options->host_key_file = NULL;
29 options->server_key_bits = -1; 30 options->server_key_bits = -1;
30 options->login_grace_time = -1; 31 options->login_grace_time = -1;
31 options->key_regeneration_time = -1; 32 options->key_regeneration_time = -1;
32 options->permit_root_login = -1; 33 options->permit_root_login = -1;
33 options->ignore_rhosts = -1; 34 options->ignore_rhosts = -1;
34 options->ignore_user_known_hosts = -1; 35 options->ignore_user_known_hosts = -1;
35 options->print_motd = -1; 36 options->print_motd = -1;
36 options->check_mail = -1; 37 options->check_mail = -1;
37 options->x11_forwarding = -1; 38 options->x11_forwarding = -1;
38 options->x11_display_offset = -1; 39 options->x11_display_offset = -1;
39 options->strict_modes = -1; 40 options->strict_modes = -1;
40 options->keepalives = -1; 41 options->keepalives = -1;
41 options->log_facility = (SyslogFacility)-1; 42 options->log_facility = (SyslogFacility) - 1;
42 options->log_level = (LogLevel)-1; 43 options->log_level = (LogLevel) - 1;
43 options->rhosts_authentication = -1; 44 options->rhosts_authentication = -1;
44 options->rhosts_rsa_authentication = -1; 45 options->rhosts_rsa_authentication = -1;
45 options->rsa_authentication = -1; 46 options->rsa_authentication = -1;
46#ifdef KRB4 47#ifdef KRB4
47 options->kerberos_authentication = -1; 48 options->kerberos_authentication = -1;
48 options->kerberos_or_local_passwd = -1; 49 options->kerberos_or_local_passwd = -1;
49 options->kerberos_ticket_cleanup = -1; 50 options->kerberos_ticket_cleanup = -1;
50#endif 51#endif
51#ifdef AFS 52#ifdef AFS
52 options->kerberos_tgt_passing = -1; 53 options->kerberos_tgt_passing = -1;
53 options->afs_token_passing = -1; 54 options->afs_token_passing = -1;
54#endif 55#endif
55 options->password_authentication = -1; 56 options->password_authentication = -1;
56#ifdef SKEY 57#ifdef SKEY
57 options->skey_authentication = -1; 58 options->skey_authentication = -1;
58#endif 59#endif
59 options->permit_empty_passwd = -1; 60 options->permit_empty_passwd = -1;
60 options->use_login = -1; 61 options->use_login = -1;
61 options->num_allow_users = 0; 62 options->num_allow_users = 0;
62 options->num_deny_users = 0; 63 options->num_deny_users = 0;
63 options->num_allow_groups = 0; 64 options->num_allow_groups = 0;
64 options->num_deny_groups = 0; 65 options->num_deny_groups = 0;
65} 66}
66 67
67void fill_default_server_options(ServerOptions *options) 68void
69fill_default_server_options(ServerOptions *options)
68{ 70{
69 if (options->port == -1) 71 if (options->port == -1) {
70 { 72 struct servent *sp;
71 struct servent *sp; 73
72 74 sp = getservbyname(SSH_SERVICE_NAME, "tcp");
73 sp = getservbyname(SSH_SERVICE_NAME, "tcp"); 75 if (sp)
74 if (sp) 76 options->port = ntohs(sp->s_port);
75 options->port = ntohs(sp->s_port); 77 else
76 else 78 options->port = SSH_DEFAULT_PORT;
77 options->port = SSH_DEFAULT_PORT; 79 endservent();
78 endservent(); 80 }
79 } 81 if (options->host_key_file == NULL)
80 if (options->host_key_file == NULL) 82 options->host_key_file = HOST_KEY_FILE;
81 options->host_key_file = HOST_KEY_FILE; 83 if (options->server_key_bits == -1)
82 if (options->server_key_bits == -1) 84 options->server_key_bits = 768;
83 options->server_key_bits = 768; 85 if (options->login_grace_time == -1)
84 if (options->login_grace_time == -1) 86 options->login_grace_time = 600;
85 options->login_grace_time = 600; 87 if (options->key_regeneration_time == -1)
86 if (options->key_regeneration_time == -1) 88 options->key_regeneration_time = 3600;
87 options->key_regeneration_time = 3600; 89 if (options->permit_root_login == -1)
88 if (options->permit_root_login == -1) 90 options->permit_root_login = 1; /* yes */
89 options->permit_root_login = 1; /* yes */ 91 if (options->ignore_rhosts == -1)
90 if (options->ignore_rhosts == -1) 92 options->ignore_rhosts = 0;
91 options->ignore_rhosts = 0; 93 if (options->ignore_user_known_hosts == -1)
92 if (options->ignore_user_known_hosts == -1) 94 options->ignore_user_known_hosts = 0;
93 options->ignore_user_known_hosts = 0; 95 if (options->check_mail == -1)
94 if (options->check_mail == -1) 96 options->check_mail = 0;
95 options->check_mail = 0; 97 if (options->print_motd == -1)
96 if (options->print_motd == -1) 98 options->print_motd = 1;
97 options->print_motd = 1; 99 if (options->x11_forwarding == -1)
98 if (options->x11_forwarding == -1) 100 options->x11_forwarding = 1;
99 options->x11_forwarding = 1; 101 if (options->x11_display_offset == -1)
100 if (options->x11_display_offset == -1) 102 options->x11_display_offset = 1;
101 options->x11_display_offset = 1; 103 if (options->strict_modes == -1)
102 if (options->strict_modes == -1) 104 options->strict_modes = 1;
103 options->strict_modes = 1; 105 if (options->keepalives == -1)
104 if (options->keepalives == -1) 106 options->keepalives = 1;
105 options->keepalives = 1; 107 if (options->log_facility == (SyslogFacility) (-1))
106 if (options->log_facility == (SyslogFacility)(-1)) 108 options->log_facility = SYSLOG_FACILITY_AUTH;
107 options->log_facility = SYSLOG_FACILITY_AUTH; 109 if (options->log_level == (LogLevel) (-1))
108 if (options->log_level == (LogLevel)(-1)) 110 options->log_level = SYSLOG_LEVEL_INFO;
109 options->log_level = SYSLOG_LEVEL_INFO; 111 if (options->rhosts_authentication == -1)
110 if (options->rhosts_authentication == -1) 112 options->rhosts_authentication = 0;
111 options->rhosts_authentication = 0; 113 if (options->rhosts_rsa_authentication == -1)
112 if (options->rhosts_rsa_authentication == -1) 114 options->rhosts_rsa_authentication = 1;
113 options->rhosts_rsa_authentication = 1; 115 if (options->rsa_authentication == -1)
114 if (options->rsa_authentication == -1) 116 options->rsa_authentication = 1;
115 options->rsa_authentication = 1;
116#ifdef KRB4 117#ifdef KRB4
117 if (options->kerberos_authentication == -1) 118 if (options->kerberos_authentication == -1)
118 options->kerberos_authentication = (access(KEYFILE, R_OK) == 0); 119 options->kerberos_authentication = (access(KEYFILE, R_OK) == 0);
119 if (options->kerberos_or_local_passwd == -1) 120 if (options->kerberos_or_local_passwd == -1)
120 options->kerberos_or_local_passwd = 1; 121 options->kerberos_or_local_passwd = 1;
121 if (options->kerberos_ticket_cleanup == -1) 122 if (options->kerberos_ticket_cleanup == -1)
122 options->kerberos_ticket_cleanup = 1; 123 options->kerberos_ticket_cleanup = 1;
123#endif /* KRB4 */ 124#endif /* KRB4 */
124#ifdef AFS 125#ifdef AFS
125 if (options->kerberos_tgt_passing == -1) 126 if (options->kerberos_tgt_passing == -1)
126 options->kerberos_tgt_passing = 0; 127 options->kerberos_tgt_passing = 0;
127 if (options->afs_token_passing == -1) 128 if (options->afs_token_passing == -1)
128 options->afs_token_passing = k_hasafs(); 129 options->afs_token_passing = k_hasafs();
129#endif /* AFS */ 130#endif /* AFS */
130 if (options->password_authentication == -1) 131 if (options->password_authentication == -1)
131 options->password_authentication = 1; 132 options->password_authentication = 1;
132#ifdef SKEY 133#ifdef SKEY
133 if (options->skey_authentication == -1) 134 if (options->skey_authentication == -1)
134 options->skey_authentication = 1; 135 options->skey_authentication = 1;
135#endif 136#endif
136 if (options->permit_empty_passwd == -1) 137 if (options->permit_empty_passwd == -1)
137 options->permit_empty_passwd = 1; 138 options->permit_empty_passwd = 1;
138 if (options->use_login == -1) 139 if (options->use_login == -1)
139 options->use_login = 0; 140 options->use_login = 0;
140} 141}
141 142
142#define WHITESPACE " \t\r\n" 143#define WHITESPACE " \t\r\n"
143 144
144/* Keyword tokens. */ 145/* Keyword tokens. */
145typedef enum 146typedef enum {
146{ 147 sBadOption, /* == unknown option */
147 sBadOption, /* == unknown option */ 148 sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime,
148 sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime, 149 sPermitRootLogin, sLogFacility, sLogLevel,
149 sPermitRootLogin, sLogFacility, sLogLevel, 150 sRhostsAuthentication, sRhostsRSAAuthentication, sRSAAuthentication,
150 sRhostsAuthentication, sRhostsRSAAuthentication, sRSAAuthentication,
151#ifdef KRB4 151#ifdef KRB4
152 sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, 152 sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
153#endif 153#endif
154#ifdef AFS 154#ifdef AFS
155 sKerberosTgtPassing, sAFSTokenPassing, 155 sKerberosTgtPassing, sAFSTokenPassing,
156#endif 156#endif
157#ifdef SKEY 157#ifdef SKEY
158 sSkeyAuthentication, 158 sSkeyAuthentication,
159#endif 159#endif
160 sPasswordAuthentication, sListenAddress, 160 sPasswordAuthentication, sListenAddress,
161 sPrintMotd, sIgnoreRhosts, sX11Forwarding, sX11DisplayOffset, 161 sPrintMotd, sIgnoreRhosts, sX11Forwarding, sX11DisplayOffset,
162 sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail, 162 sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail,
163 sUseLogin, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups, 163 sUseLogin, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
164 sIgnoreUserKnownHosts 164 sIgnoreUserKnownHosts
165} ServerOpCodes; 165} ServerOpCodes;
166 166
167/* Textual representation of the tokens. */ 167/* Textual representation of the tokens. */
168static struct 168static struct {
169{ 169 const char *name;
170 const char *name; 170 ServerOpCodes opcode;
171 ServerOpCodes opcode; 171} keywords[] = {
172} keywords[] = 172 { "port", sPort },
173{ 173 { "hostkey", sHostKeyFile },
174 { "port", sPort }, 174 { "serverkeybits", sServerKeyBits },
175 { "hostkey", sHostKeyFile }, 175 { "logingracetime", sLoginGraceTime },
176 { "serverkeybits", sServerKeyBits }, 176 { "keyregenerationinterval", sKeyRegenerationTime },
177 { "logingracetime", sLoginGraceTime }, 177 { "permitrootlogin", sPermitRootLogin },
178 { "keyregenerationinterval", sKeyRegenerationTime }, 178 { "syslogfacility", sLogFacility },
179 { "permitrootlogin", sPermitRootLogin }, 179 { "loglevel", sLogLevel },
180 { "syslogfacility", sLogFacility }, 180 { "rhostsauthentication", sRhostsAuthentication },
181 { "loglevel", sLogLevel }, 181 { "rhostsrsaauthentication", sRhostsRSAAuthentication },
182 { "rhostsauthentication", sRhostsAuthentication }, 182 { "rsaauthentication", sRSAAuthentication },
183 { "rhostsrsaauthentication", sRhostsRSAAuthentication },
184 { "rsaauthentication", sRSAAuthentication },
185#ifdef KRB4 183#ifdef KRB4
186 { "kerberosauthentication", sKerberosAuthentication }, 184 { "kerberosauthentication", sKerberosAuthentication },
187 { "kerberosorlocalpasswd", sKerberosOrLocalPasswd }, 185 { "kerberosorlocalpasswd", sKerberosOrLocalPasswd },
188 { "kerberosticketcleanup", sKerberosTicketCleanup }, 186 { "kerberosticketcleanup", sKerberosTicketCleanup },
189#endif 187#endif
190#ifdef AFS 188#ifdef AFS
191 { "kerberostgtpassing", sKerberosTgtPassing }, 189 { "kerberostgtpassing", sKerberosTgtPassing },
192 { "afstokenpassing", sAFSTokenPassing }, 190 { "afstokenpassing", sAFSTokenPassing },
193#endif 191#endif
194 { "passwordauthentication", sPasswordAuthentication }, 192 { "passwordauthentication", sPasswordAuthentication },
195#ifdef SKEY 193#ifdef SKEY
196 { "skeyauthentication", sSkeyAuthentication }, 194 { "skeyauthentication", sSkeyAuthentication },
197#endif 195#endif
198 { "checkmail", sCheckMail }, 196 { "checkmail", sCheckMail },
199 { "listenaddress", sListenAddress }, 197 { "listenaddress", sListenAddress },
200 { "printmotd", sPrintMotd }, 198 { "printmotd", sPrintMotd },
201 { "ignorerhosts", sIgnoreRhosts }, 199 { "ignorerhosts", sIgnoreRhosts },
202 { "ignoreuserknownhosts", sIgnoreUserKnownHosts }, 200 { "ignoreuserknownhosts", sIgnoreUserKnownHosts },
203 { "x11forwarding", sX11Forwarding }, 201 { "x11forwarding", sX11Forwarding },
204 { "x11displayoffset", sX11DisplayOffset }, 202 { "x11displayoffset", sX11DisplayOffset },
205 { "strictmodes", sStrictModes }, 203 { "strictmodes", sStrictModes },
206 { "permitemptypasswords", sEmptyPasswd }, 204 { "permitemptypasswords", sEmptyPasswd },
207 { "uselogin", sUseLogin }, 205 { "uselogin", sUseLogin },
208 { "randomseed", sRandomSeedFile }, 206 { "randomseed", sRandomSeedFile },
209 { "keepalive", sKeepAlives }, 207 { "keepalive", sKeepAlives },
210 { "allowusers", sAllowUsers }, 208 { "allowusers", sAllowUsers },
211 { "denyusers", sDenyUsers }, 209 { "denyusers", sDenyUsers },
212 { "allowgroups", sAllowGroups }, 210 { "allowgroups", sAllowGroups },
213 { "denygroups", sDenyGroups }, 211 { "denygroups", sDenyGroups },
214 { NULL, 0 } 212 { NULL, 0 }
215}; 213};
216 214
217/* Returns the number of the token pointed to by cp of length len. 215/* Returns the number of the token pointed to by cp of length len.
218 Never returns if the token is not known. */ 216 Never returns if the token is not known. */
219 217
220static ServerOpCodes parse_token(const char *cp, const char *filename, 218static ServerOpCodes
221 int linenum) 219parse_token(const char *cp, const char *filename,
220 int linenum)
222{ 221{
223 unsigned int i; 222 unsigned int i;
224 223
225 for (i = 0; keywords[i].name; i++) 224 for (i = 0; keywords[i].name; i++)
226 if (strcmp(cp, keywords[i].name) == 0) 225 if (strcmp(cp, keywords[i].name) == 0)
227 return keywords[i].opcode; 226 return keywords[i].opcode;
228 227
229 fprintf(stderr, "%s: line %d: Bad configuration option: %s\n", 228 fprintf(stderr, "%s: line %d: Bad configuration option: %s\n",
230 filename, linenum, cp); 229 filename, linenum, cp);
231 return sBadOption; 230 return sBadOption;
232} 231}
233 232
234/* Reads the server configuration file. */ 233/* Reads the server configuration file. */
235 234
236void read_server_config(ServerOptions *options, const char *filename) 235void
236read_server_config(ServerOptions *options, const char *filename)
237{ 237{
238 FILE *f; 238 FILE *f;
239 char line[1024]; 239 char line[1024];
240 char *cp, **charptr; 240 char *cp, **charptr;
241 int linenum, *intptr, value; 241 int linenum, *intptr, value;
242 int bad_options = 0; 242 int bad_options = 0;
243 ServerOpCodes opcode; 243 ServerOpCodes opcode;
244 244
245 f = fopen(filename, "r"); 245 f = fopen(filename, "r");
246 if (!f) 246 if (!f) {
247 { 247 perror(filename);
248 perror(filename);
249 exit(1);
250 }
251
252 linenum = 0;
253 while (fgets(line, sizeof(line), f))
254 {
255 linenum++;
256 cp = line + strspn(line, WHITESPACE);
257 if (!*cp || *cp == '#')
258 continue;
259 cp = strtok(cp, WHITESPACE);
260 {
261 char *t = cp;
262 for (; *t != 0; t++)
263 if ('A' <= *t && *t <= 'Z')
264 *t = *t - 'A' + 'a'; /* tolower */
265
266 }
267 opcode = parse_token(cp, filename, linenum);
268 switch (opcode)
269 {
270 case sBadOption:
271 bad_options++;
272 continue;
273 case sPort:
274 intptr = &options->port;
275 parse_int:
276 cp = strtok(NULL, WHITESPACE);
277 if (!cp)
278 {
279 fprintf(stderr, "%s line %d: missing integer value.\n",
280 filename, linenum);
281 exit(1);
282 }
283 value = atoi(cp);
284 if (*intptr == -1)
285 *intptr = value;
286 break;
287
288 case sServerKeyBits:
289 intptr = &options->server_key_bits;
290 goto parse_int;
291
292 case sLoginGraceTime:
293 intptr = &options->login_grace_time;
294 goto parse_int;
295
296 case sKeyRegenerationTime:
297 intptr = &options->key_regeneration_time;
298 goto parse_int;
299
300 case sListenAddress:
301 cp = strtok(NULL, WHITESPACE);
302 if (!cp)
303 {
304 fprintf(stderr, "%s line %d: missing inet addr.\n",
305 filename, linenum);
306 exit(1);
307 }
308 options->listen_addr.s_addr = inet_addr(cp);
309 break;
310
311 case sHostKeyFile:
312 charptr = &options->host_key_file;
313 cp = strtok(NULL, WHITESPACE);
314 if (!cp)
315 {
316 fprintf(stderr, "%s line %d: missing file name.\n",
317 filename, linenum);
318 exit(1);
319 }
320 if (*charptr == NULL)
321 *charptr = tilde_expand_filename(cp, getuid());
322 break;
323
324 case sRandomSeedFile:
325 fprintf(stderr, "%s line %d: \"randomseed\" option is obsolete.\n",
326 filename, linenum);
327 cp = strtok(NULL, WHITESPACE);
328 break;
329
330 case sPermitRootLogin:
331 intptr = &options->permit_root_login;
332 cp = strtok(NULL, WHITESPACE);
333 if (!cp)
334 {
335 fprintf(stderr, "%s line %d: missing yes/without-password/no argument.\n",
336 filename, linenum);
337 exit(1);
338 }
339 if (strcmp(cp, "without-password") == 0)
340 value = 2;
341 else if (strcmp(cp, "yes") == 0)
342 value = 1;
343 else if (strcmp(cp, "no") == 0)
344 value = 0;
345 else
346 {
347 fprintf(stderr, "%s line %d: Bad yes/without-password/no argument: %s\n",
348 filename, linenum, cp);
349 exit(1);
350 }
351 if (*intptr == -1)
352 *intptr = value;
353 break;
354
355 case sIgnoreRhosts:
356 intptr = &options->ignore_rhosts;
357 parse_flag:
358 cp = strtok(NULL, WHITESPACE);
359 if (!cp)
360 {
361 fprintf(stderr, "%s line %d: missing yes/no argument.\n",
362 filename, linenum);
363 exit(1);
364 }
365 if (strcmp(cp, "yes") == 0)
366 value = 1;
367 else
368 if (strcmp(cp, "no") == 0)
369 value = 0;
370 else
371 {
372 fprintf(stderr, "%s line %d: Bad yes/no argument: %s\n",
373 filename, linenum, cp);
374 exit(1); 248 exit(1);
375 } 249 }
376 if (*intptr == -1) 250 linenum = 0;
377 *intptr = value; 251 while (fgets(line, sizeof(line), f)) {
378 break; 252 linenum++;
379 253 cp = line + strspn(line, WHITESPACE);
380 case sIgnoreUserKnownHosts: 254 if (!*cp || *cp == '#')
381 intptr = &options->ignore_user_known_hosts; 255 continue;
382 goto parse_int; 256 cp = strtok(cp, WHITESPACE);
383 257 {
384 case sRhostsAuthentication: 258 char *t = cp;
385 intptr = &options->rhosts_authentication; 259 for (; *t != 0; t++)
386 goto parse_flag; 260 if ('A' <= *t && *t <= 'Z')
387 261 *t = *t - 'A' + 'a'; /* tolower */
388 case sRhostsRSAAuthentication: 262
389 intptr = &options->rhosts_rsa_authentication; 263 }
390 goto parse_flag; 264 opcode = parse_token(cp, filename, linenum);
391 265 switch (opcode) {
392 case sRSAAuthentication: 266 case sBadOption:
393 intptr = &options->rsa_authentication; 267 bad_options++;
394 goto parse_flag; 268 continue;
395 269 case sPort:
270 intptr = &options->port;
271parse_int:
272 cp = strtok(NULL, WHITESPACE);
273 if (!cp) {
274 fprintf(stderr, "%s line %d: missing integer value.\n",
275 filename, linenum);
276 exit(1);
277 }
278 value = atoi(cp);
279 if (*intptr == -1)
280 *intptr = value;
281 break;
282
283 case sServerKeyBits:
284 intptr = &options->server_key_bits;
285 goto parse_int;
286
287 case sLoginGraceTime:
288 intptr = &options->login_grace_time;
289 goto parse_int;
290
291 case sKeyRegenerationTime:
292 intptr = &options->key_regeneration_time;
293 goto parse_int;
294
295 case sListenAddress:
296 cp = strtok(NULL, WHITESPACE);
297 if (!cp) {
298 fprintf(stderr, "%s line %d: missing inet addr.\n",
299 filename, linenum);
300 exit(1);
301 }
302 options->listen_addr.s_addr = inet_addr(cp);
303 break;
304
305 case sHostKeyFile:
306 charptr = &options->host_key_file;
307 cp = strtok(NULL, WHITESPACE);
308 if (!cp) {
309 fprintf(stderr, "%s line %d: missing file name.\n",
310 filename, linenum);
311 exit(1);
312 }
313 if (*charptr == NULL)
314 *charptr = tilde_expand_filename(cp, getuid());
315 break;
316
317 case sRandomSeedFile:
318 fprintf(stderr, "%s line %d: \"randomseed\" option is obsolete.\n",
319 filename, linenum);
320 cp = strtok(NULL, WHITESPACE);
321 break;
322
323 case sPermitRootLogin:
324 intptr = &options->permit_root_login;
325 cp = strtok(NULL, WHITESPACE);
326 if (!cp) {
327 fprintf(stderr, "%s line %d: missing yes/without-password/no argument.\n",
328 filename, linenum);
329 exit(1);
330 }
331 if (strcmp(cp, "without-password") == 0)
332 value = 2;
333 else if (strcmp(cp, "yes") == 0)
334 value = 1;
335 else if (strcmp(cp, "no") == 0)
336 value = 0;
337 else {
338 fprintf(stderr, "%s line %d: Bad yes/without-password/no argument: %s\n",
339 filename, linenum, cp);
340 exit(1);
341 }
342 if (*intptr == -1)
343 *intptr = value;
344 break;
345
346 case sIgnoreRhosts:
347 intptr = &options->ignore_rhosts;
348parse_flag:
349 cp = strtok(NULL, WHITESPACE);
350 if (!cp) {
351 fprintf(stderr, "%s line %d: missing yes/no argument.\n",
352 filename, linenum);
353 exit(1);
354 }
355 if (strcmp(cp, "yes") == 0)
356 value = 1;
357 else if (strcmp(cp, "no") == 0)
358 value = 0;
359 else {
360 fprintf(stderr, "%s line %d: Bad yes/no argument: %s\n",
361 filename, linenum, cp);
362 exit(1);
363 }
364 if (*intptr == -1)
365 *intptr = value;
366 break;
367
368 case sIgnoreUserKnownHosts:
369 intptr = &options->ignore_user_known_hosts;
370 goto parse_int;
371
372 case sRhostsAuthentication:
373 intptr = &options->rhosts_authentication;
374 goto parse_flag;
375
376 case sRhostsRSAAuthentication:
377 intptr = &options->rhosts_rsa_authentication;
378 goto parse_flag;
379
380 case sRSAAuthentication:
381 intptr = &options->rsa_authentication;
382 goto parse_flag;
383
396#ifdef KRB4 384#ifdef KRB4
397 case sKerberosAuthentication: 385 case sKerberosAuthentication:
398 intptr = &options->kerberos_authentication; 386 intptr = &options->kerberos_authentication;
399 goto parse_flag; 387 goto parse_flag;
400 388
401 case sKerberosOrLocalPasswd: 389 case sKerberosOrLocalPasswd:
402 intptr = &options->kerberos_or_local_passwd; 390 intptr = &options->kerberos_or_local_passwd;
403 goto parse_flag; 391 goto parse_flag;
404 392
405 case sKerberosTicketCleanup: 393 case sKerberosTicketCleanup:
406 intptr = &options->kerberos_ticket_cleanup; 394 intptr = &options->kerberos_ticket_cleanup;
407 goto parse_flag; 395 goto parse_flag;
408#endif 396#endif
409 397
410#ifdef AFS 398#ifdef AFS
411 case sKerberosTgtPassing: 399 case sKerberosTgtPassing:
412 intptr = &options->kerberos_tgt_passing; 400 intptr = &options->kerberos_tgt_passing;
413 goto parse_flag; 401 goto parse_flag;
414 402
415 case sAFSTokenPassing: 403 case sAFSTokenPassing:
416 intptr = &options->afs_token_passing; 404 intptr = &options->afs_token_passing;
417 goto parse_flag; 405 goto parse_flag;
418#endif 406#endif
419 407
420 case sPasswordAuthentication: 408 case sPasswordAuthentication:
421 intptr = &options->password_authentication; 409 intptr = &options->password_authentication;
422 goto parse_flag; 410 goto parse_flag;
423 411
424 case sCheckMail: 412 case sCheckMail:
425 intptr = &options->check_mail; 413 intptr = &options->check_mail;
426 goto parse_flag; 414 goto parse_flag;
427 415
428#ifdef SKEY 416#ifdef SKEY
429 case sSkeyAuthentication: 417 case sSkeyAuthentication:
430 intptr = &options->skey_authentication; 418 intptr = &options->skey_authentication;
431 goto parse_flag; 419 goto parse_flag;
432#endif 420#endif
433 421
434 case sPrintMotd: 422 case sPrintMotd:
435 intptr = &options->print_motd; 423 intptr = &options->print_motd;
436 goto parse_flag; 424 goto parse_flag;
437 425
438 case sX11Forwarding: 426 case sX11Forwarding:
439 intptr = &options->x11_forwarding; 427 intptr = &options->x11_forwarding;
440 goto parse_flag; 428 goto parse_flag;
441 429
442 case sX11DisplayOffset: 430 case sX11DisplayOffset:
443 intptr = &options->x11_display_offset; 431 intptr = &options->x11_display_offset;
444 goto parse_int; 432 goto parse_int;
445 433
446 case sStrictModes: 434 case sStrictModes:
447 intptr = &options->strict_modes; 435 intptr = &options->strict_modes;
448 goto parse_flag; 436 goto parse_flag;
449 437
450 case sKeepAlives: 438 case sKeepAlives:
451 intptr = &options->keepalives; 439 intptr = &options->keepalives;
452 goto parse_flag; 440 goto parse_flag;
453 441
454 case sEmptyPasswd: 442 case sEmptyPasswd:
455 intptr = &options->permit_empty_passwd; 443 intptr = &options->permit_empty_passwd;
456 goto parse_flag; 444 goto parse_flag;
457 445
458 case sUseLogin: 446 case sUseLogin:
459 intptr = &options->use_login; 447 intptr = &options->use_login;
460 goto parse_flag; 448 goto parse_flag;
461 449
462 case sLogFacility: 450 case sLogFacility:
463 intptr = (int *)&options->log_facility; 451 intptr = (int *) &options->log_facility;
464 cp = strtok(NULL, WHITESPACE); 452 cp = strtok(NULL, WHITESPACE);
465 value = log_facility_number(cp); 453 value = log_facility_number(cp);
466 if (value == (SyslogFacility)-1) 454 if (value == (SyslogFacility) - 1)
467 fatal("%.200s line %d: unsupported log facility '%s'\n", 455 fatal("%.200s line %d: unsupported log facility '%s'\n",
468 filename, linenum, cp ? cp : "<NONE>"); 456 filename, linenum, cp ? cp : "<NONE>");
469 if (*intptr == -1) 457 if (*intptr == -1)
470 *intptr = (SyslogFacility)value; 458 *intptr = (SyslogFacility) value;
471 break; 459 break;
472 460
473 case sLogLevel: 461 case sLogLevel:
474 intptr = (int *)&options->log_level; 462 intptr = (int *) &options->log_level;
475 cp = strtok(NULL, WHITESPACE); 463 cp = strtok(NULL, WHITESPACE);
476 value = log_level_number(cp); 464 value = log_level_number(cp);
477 if (value == (LogLevel)-1) 465 if (value == (LogLevel) - 1)
478 fatal("%.200s line %d: unsupported log level '%s'\n", 466 fatal("%.200s line %d: unsupported log level '%s'\n",
479 filename, linenum, cp ? cp : "<NONE>"); 467 filename, linenum, cp ? cp : "<NONE>");
480 if (*intptr == -1) 468 if (*intptr == -1)
481 *intptr = (LogLevel)value; 469 *intptr = (LogLevel) value;
482 break; 470 break;
483 471
484 case sAllowUsers: 472 case sAllowUsers:
485 while ((cp = strtok(NULL, WHITESPACE))) 473 while ((cp = strtok(NULL, WHITESPACE))) {
486 { 474 if (options->num_allow_users >= MAX_ALLOW_USERS) {
487 if (options->num_allow_users >= MAX_ALLOW_USERS) 475 fprintf(stderr, "%s line %d: too many allow users.\n",
488 { 476 filename, linenum);
489 fprintf(stderr, "%s line %d: too many allow users.\n", 477 exit(1);
490 filename, linenum); 478 }
491 exit(1); 479 options->allow_users[options->num_allow_users++] = xstrdup(cp);
480 }
481 break;
482
483 case sDenyUsers:
484 while ((cp = strtok(NULL, WHITESPACE))) {
485 if (options->num_deny_users >= MAX_DENY_USERS) {
486 fprintf(stderr, "%s line %d: too many deny users.\n",
487 filename, linenum);
488 exit(1);
489 }
490 options->deny_users[options->num_deny_users++] = xstrdup(cp);
491 }
492 break;
493
494 case sAllowGroups:
495 while ((cp = strtok(NULL, WHITESPACE))) {
496 if (options->num_allow_groups >= MAX_ALLOW_GROUPS) {
497 fprintf(stderr, "%s line %d: too many allow groups.\n",
498 filename, linenum);
499 exit(1);
500 }
501 options->allow_groups[options->num_allow_groups++] = xstrdup(cp);
502 }
503 break;
504
505 case sDenyGroups:
506 while ((cp = strtok(NULL, WHITESPACE))) {
507 if (options->num_deny_groups >= MAX_DENY_GROUPS) {
508 fprintf(stderr, "%s line %d: too many deny groups.\n",
509 filename, linenum);
510 exit(1);
511 }
512 options->deny_groups[options->num_deny_groups++] = xstrdup(cp);
513 }
514 break;
515
516 default:
517 fprintf(stderr, "%s line %d: Missing handler for opcode %s (%d)\n",
518 filename, linenum, cp, opcode);
519 exit(1);
492 } 520 }
493 options->allow_users[options->num_allow_users++] = xstrdup(cp); 521 if (strtok(NULL, WHITESPACE) != NULL) {
494 } 522 fprintf(stderr, "%s line %d: garbage at end of line.\n",
495 break; 523 filename, linenum);
496 524 exit(1);
497 case sDenyUsers:
498 while ((cp = strtok(NULL, WHITESPACE)))
499 {
500 if (options->num_deny_users >= MAX_DENY_USERS)
501 {
502 fprintf(stderr, "%s line %d: too many deny users.\n",
503 filename, linenum);
504 exit(1);
505 }
506 options->deny_users[options->num_deny_users++] = xstrdup(cp);
507 }
508 break;
509
510 case sAllowGroups:
511 while ((cp = strtok(NULL, WHITESPACE)))
512 {
513 if (options->num_allow_groups >= MAX_ALLOW_GROUPS)
514 {
515 fprintf(stderr, "%s line %d: too many allow groups.\n",
516 filename, linenum);
517 exit(1);
518 } 525 }
519 options->allow_groups[options->num_allow_groups++] = xstrdup(cp);
520 }
521 break;
522
523 case sDenyGroups:
524 while ((cp = strtok(NULL, WHITESPACE)))
525 {
526 if (options->num_deny_groups >= MAX_DENY_GROUPS)
527 {
528 fprintf(stderr, "%s line %d: too many deny groups.\n",
529 filename, linenum);
530 exit(1);
531 }
532 options->deny_groups[options->num_deny_groups++] = xstrdup(cp);
533 }
534 break;
535
536 default:
537 fprintf(stderr, "%s line %d: Missing handler for opcode %s (%d)\n",
538 filename, linenum, cp, opcode);
539 exit(1);
540 } 526 }
541 if (strtok(NULL, WHITESPACE) != NULL) 527 fclose(f);
542 { 528 if (bad_options > 0) {
543 fprintf(stderr, "%s line %d: garbage at end of line.\n", 529 fprintf(stderr, "%s: terminating, %d bad configuration options\n",
544 filename, linenum); 530 filename, bad_options);
545 exit(1); 531 exit(1);
546 } 532 }
547 }
548 fclose(f);
549 if (bad_options > 0) {
550 fprintf(stderr, "%s: terminating, %d bad configuration options\n",
551 filename, bad_options);
552 exit(1);
553 }
554} 533}
diff --git a/servconf.h b/servconf.h
index e16f3d044..4f3238e0c 100644
--- a/servconf.h
+++ b/servconf.h
@@ -1,86 +1,98 @@
1/* 1/*
2 *
3 * servconf.h
4 *
5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 *
7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 * All rights reserved
9 *
10 * Created: Mon Aug 21 15:35:03 1995 ylo
11 *
12 * Definitions for server configuration data and for the functions reading it.
13 *
14 */
2 15
3servconf.h 16/* RCSID("$Id: servconf.h,v 1.4 1999/11/24 13:26:22 damien Exp $"); */
4
5Author: Tatu Ylonen <ylo@cs.hut.fi>
6
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved
9
10Created: Mon Aug 21 15:35:03 1995 ylo
11
12Definitions for server configuration data and for the functions reading it.
13
14*/
15
16/* RCSID("$Id: servconf.h,v 1.3 1999/11/12 00:33:04 damien Exp $"); */
17 17
18#ifndef SERVCONF_H 18#ifndef SERVCONF_H
19#define SERVCONF_H 19#define SERVCONF_H
20 20
21#define MAX_ALLOW_USERS 256 /* Max # users on allow list. */ 21#define MAX_ALLOW_USERS 256 /* Max # users on allow list. */
22#define MAX_DENY_USERS 256 /* Max # users on deny list. */ 22#define MAX_DENY_USERS 256 /* Max # users on deny list. */
23#define MAX_ALLOW_GROUPS 256 /* Max # groups on allow list. */ 23#define MAX_ALLOW_GROUPS 256 /* Max # groups on allow list. */
24#define MAX_DENY_GROUPS 256 /* Max # groups on deny list. */ 24#define MAX_DENY_GROUPS 256 /* Max # groups on deny list. */
25 25
26typedef struct 26typedef struct {
27{ 27 int port; /* Port number to listen on. */
28 int port; /* Port number to listen on. */ 28 struct in_addr listen_addr; /* Address on which the server
29 struct in_addr listen_addr; /* Address on which the server listens. */ 29 * listens. */
30 char *host_key_file; /* File containing host key. */ 30 char *host_key_file; /* File containing host key. */
31 int server_key_bits; /* Size of the server key. */ 31 int server_key_bits;/* Size of the server key. */
32 int login_grace_time; /* Disconnect if no auth in this time (sec). */ 32 int login_grace_time; /* Disconnect if no auth in this time
33 int key_regeneration_time; /* Server key lifetime (seconds). */ 33 * (sec). */
34 int permit_root_login; /* If true, permit root login. */ 34 int key_regeneration_time; /* Server key lifetime (seconds). */
35 int ignore_rhosts; /* Ignore .rhosts and .shosts. */ 35 int permit_root_login; /* If true, permit root login. */
36 int ignore_user_known_hosts; /* Ignore ~/.ssh/known_hosts for RhostsRsaAuth */ 36 int ignore_rhosts; /* Ignore .rhosts and .shosts. */
37 int print_motd; /* If true, print /etc/motd. */ 37 int ignore_user_known_hosts; /* Ignore ~/.ssh/known_hosts
38 int check_mail; /* If true, check for new mail. */ 38 * for RhostsRsaAuth */
39 int x11_forwarding; /* If true, permit inet (spoofing) X11 fwd. */ 39 int print_motd; /* If true, print /etc/motd. */
40 int x11_display_offset; /* What DISPLAY number to start searching at */ 40 int check_mail; /* If true, check for new mail. */
41 int strict_modes; /* If true, require string home dir modes. */ 41 int x11_forwarding; /* If true, permit inet (spoofing) X11 fwd. */
42 int keepalives; /* If true, set SO_KEEPALIVE. */ 42 int x11_display_offset; /* What DISPLAY number to start
43 SyslogFacility log_facility; /* Facility for system logging. */ 43 * searching at */
44 LogLevel log_level; /* Level for system logging. */ 44 int strict_modes; /* If true, require string home dir modes. */
45 int rhosts_authentication; /* If true, permit rhosts authentication. */ 45 int keepalives; /* If true, set SO_KEEPALIVE. */
46 int rhosts_rsa_authentication;/* If true, permit rhosts RSA authentication.*/ 46 SyslogFacility log_facility; /* Facility for system logging. */
47 int rsa_authentication; /* If true, permit RSA authentication. */ 47 LogLevel log_level; /* Level for system logging. */
48 int rhosts_authentication; /* If true, permit rhosts
49 * authentication. */
50 int rhosts_rsa_authentication; /* If true, permit rhosts RSA
51 * authentication. */
52 int rsa_authentication; /* If true, permit RSA authentication. */
48#ifdef KRB4 53#ifdef KRB4
49 int kerberos_authentication; /* If true, permit Kerberos authentication. */ 54 int kerberos_authentication; /* If true, permit Kerberos
50 int kerberos_or_local_passwd; /* If true, permit kerberos and any other 55 * authentication. */
51 password authentication mechanism, such 56 int kerberos_or_local_passwd; /* If true, permit kerberos
52 as SecurID or /etc/passwd */ 57 * and any other password
53 int kerberos_ticket_cleanup; /* If true, destroy ticket file on logout. */ 58 * authentication mechanism,
59 * such as SecurID or
60 * /etc/passwd */
61 int kerberos_ticket_cleanup; /* If true, destroy ticket
62 * file on logout. */
54#endif 63#endif
55#ifdef AFS 64#ifdef AFS
56 int kerberos_tgt_passing; /* If true, permit Kerberos tgt passing. */ 65 int kerberos_tgt_passing; /* If true, permit Kerberos tgt
57 int afs_token_passing; /* If true, permit AFS token passing. */ 66 * passing. */
67 int afs_token_passing; /* If true, permit AFS token passing. */
58#endif 68#endif
59 int password_authentication; /* If true, permit password authentication. */ 69 int password_authentication; /* If true, permit password
70 * authentication. */
60#ifdef SKEY 71#ifdef SKEY
61 int skey_authentication; /* If true, permit s/key authentication. */ 72 int skey_authentication; /* If true, permit s/key
73 * authentication. */
62#endif 74#endif
63 int permit_empty_passwd; /* If false, do not permit empty passwords. */ 75 int permit_empty_passwd; /* If false, do not permit empty
64 int use_login; /* If true, login(1) is used */ 76 * passwords. */
65 unsigned int num_allow_users; 77 int use_login; /* If true, login(1) is used */
66 char *allow_users[MAX_ALLOW_USERS]; 78 unsigned int num_allow_users;
67 unsigned int num_deny_users; 79 char *allow_users[MAX_ALLOW_USERS];
68 char *deny_users[MAX_DENY_USERS]; 80 unsigned int num_deny_users;
69 unsigned int num_allow_groups; 81 char *deny_users[MAX_DENY_USERS];
70 char *allow_groups[MAX_ALLOW_GROUPS]; 82 unsigned int num_allow_groups;
71 unsigned int num_deny_groups; 83 char *allow_groups[MAX_ALLOW_GROUPS];
72 char *deny_groups[MAX_DENY_GROUPS]; 84 unsigned int num_deny_groups;
73} ServerOptions; 85 char *deny_groups[MAX_DENY_GROUPS];
74 86} ServerOptions;
75/* Initializes the server options to special values that indicate that they 87/* Initializes the server options to special values that indicate that they
76 have not yet been set. */ 88 have not yet been set. */
77void initialize_server_options(ServerOptions *options); 89void initialize_server_options(ServerOptions * options);
78 90
79/* Reads the server configuration file. This only sets the values for those 91/* Reads the server configuration file. This only sets the values for those
80 options that have the special value indicating they have not been set. */ 92 options that have the special value indicating they have not been set. */
81void read_server_config(ServerOptions *options, const char *filename); 93void read_server_config(ServerOptions * options, const char *filename);
82 94
83/* Sets values for those values that have not yet been set. */ 95/* Sets values for those values that have not yet been set. */
84void fill_default_server_options(ServerOptions *options); 96void fill_default_server_options(ServerOptions * options);
85 97
86#endif /* SERVCONF_H */ 98#endif /* SERVCONF_H */
diff --git a/serverloop.c b/serverloop.c
index 9961170a5..fc959baef 100644
--- a/serverloop.c
+++ b/serverloop.c
@@ -1,17 +1,10 @@
1/* 1/*
2 2 * Author: Tatu Ylonen <ylo@cs.hut.fi>
3serverloop.c 3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 4 * All rights reserved
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Created: Sun Sep 10 00:30:37 1995 ylo
6 6 * Server main loop for handling the interactive session.
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 */
8 All rights reserved
9
10Created: Sun Sep 10 00:30:37 1995 ylo
11
12Server main loop for handling the interactive session.
13
14*/
15 8
16#include "includes.h" 9#include "includes.h"
17#include "xmalloc.h" 10#include "xmalloc.h"
@@ -43,603 +36,594 @@ static int max_fd; /* Max file descriptor number for select(). */
43/* This SIGCHLD kludge is used to detect when the child exits. The server 36/* This SIGCHLD kludge is used to detect when the child exits. The server
44 will exit after that, as soon as forwarded connections have terminated. */ 37 will exit after that, as soon as forwarded connections have terminated. */
45 38
46static int child_pid; /* Pid of the child. */ 39static int child_pid; /* Pid of the child. */
47static volatile int child_terminated; /* The child has terminated. */ 40static volatile int child_terminated; /* The child has terminated. */
48static volatile int child_wait_status; /* Status from wait(). */ 41static volatile int child_wait_status; /* Status from wait(). */
49 42
50void sigchld_handler(int sig) 43void
44sigchld_handler(int sig)
51{ 45{
52 int save_errno = errno; 46 int save_errno = errno;
53 int wait_pid; 47 int wait_pid;
54 debug("Received SIGCHLD."); 48 debug("Received SIGCHLD.");
55 wait_pid = wait((int *)&child_wait_status); 49 wait_pid = wait((int *) &child_wait_status);
56 if (wait_pid != -1) 50 if (wait_pid != -1) {
57 { 51 if (wait_pid != child_pid)
58 if (wait_pid != child_pid) 52 error("Strange, got SIGCHLD and wait returned pid %d but child is %d",
59 error("Strange, got SIGCHLD and wait returned pid %d but child is %d", 53 wait_pid, child_pid);
60 wait_pid, child_pid); 54 if (WIFEXITED(child_wait_status) ||
61 if (WIFEXITED(child_wait_status) || 55 WIFSIGNALED(child_wait_status))
62 WIFSIGNALED(child_wait_status)) 56 child_terminated = 1;
63 child_terminated = 1; 57 }
64 } 58 signal(SIGCHLD, sigchld_handler);
65 signal(SIGCHLD, sigchld_handler); 59 errno = save_errno;
66 errno = save_errno;
67} 60}
68 61
69/* Process any buffered packets that have been received from the client. */ 62/*
70 63 * Process any buffered packets that have been received from the client.
71void process_buffered_input_packets() 64 */
65void
66process_buffered_input_packets()
72{ 67{
73 int type; 68 int type;
74 char *data; 69 char *data;
75 unsigned int data_len; 70 unsigned int data_len;
76 int row, col, xpixel, ypixel; 71 int row, col, xpixel, ypixel;
77 int payload_len; 72 int payload_len;
78 73
79 /* Process buffered packets from the client. */ 74 /* Process buffered packets from the client. */
80 while ((type = packet_read_poll(&payload_len)) != SSH_MSG_NONE) 75 while ((type = packet_read_poll(&payload_len)) != SSH_MSG_NONE) {
81 { 76 switch (type) {
82 switch (type) 77 case SSH_CMSG_STDIN_DATA:
83 { 78 /* Stdin data from the client. Append it to the buffer. */
84 case SSH_CMSG_STDIN_DATA: 79 /* Ignore any data if the client has closed stdin. */
85 /* Stdin data from the client. Append it to the buffer. */ 80 if (fdin == -1)
86 if (fdin == -1) 81 break;
87 break; /* Ignore any data if the client has closed stdin. */ 82 data = packet_get_string(&data_len);
88 data = packet_get_string(&data_len); 83 packet_integrity_check(payload_len, (4 + data_len), type);
89 packet_integrity_check(payload_len, (4 + data_len), type); 84 buffer_append(&stdin_buffer, data, data_len);
90 buffer_append(&stdin_buffer, data, data_len); 85 memset(data, 0, data_len);
91 memset(data, 0, data_len); 86 xfree(data);
92 xfree(data); 87 break;
93 break; 88
94 89 case SSH_CMSG_EOF:
95 case SSH_CMSG_EOF: 90 /* Eof from the client. The stdin descriptor to
96 /* Eof from the client. The stdin descriptor to the program 91 the program will be closed when all buffered
97 will be closed when all buffered data has drained. */ 92 data has drained. */
98 debug("EOF received for stdin."); 93 debug("EOF received for stdin.");
99 packet_integrity_check(payload_len, 0, type); 94 packet_integrity_check(payload_len, 0, type);
100 stdin_eof = 1; 95 stdin_eof = 1;
101 break; 96 break;
102 97
103 case SSH_CMSG_WINDOW_SIZE: 98 case SSH_CMSG_WINDOW_SIZE:
104 debug("Window change received."); 99 debug("Window change received.");
105 packet_integrity_check(payload_len, 4*4, type); 100 packet_integrity_check(payload_len, 4 * 4, type);
106 row = packet_get_int(); 101 row = packet_get_int();
107 col = packet_get_int(); 102 col = packet_get_int();
108 xpixel = packet_get_int(); 103 xpixel = packet_get_int();
109 ypixel = packet_get_int(); 104 ypixel = packet_get_int();
110 if (fdin != -1) 105 if (fdin != -1)
111 pty_change_window_size(fdin, row, col, xpixel, ypixel); 106 pty_change_window_size(fdin, row, col, xpixel, ypixel);
112 break; 107 break;
113 108
114 case SSH_MSG_PORT_OPEN: 109 case SSH_MSG_PORT_OPEN:
115 debug("Received port open request."); 110 debug("Received port open request.");
116 channel_input_port_open(payload_len); 111 channel_input_port_open(payload_len);
117 break; 112 break;
118 113
119 case SSH_MSG_CHANNEL_OPEN_CONFIRMATION: 114 case SSH_MSG_CHANNEL_OPEN_CONFIRMATION:
120 debug("Received channel open confirmation."); 115 debug("Received channel open confirmation.");
121 packet_integrity_check(payload_len, 4 + 4, type); 116 packet_integrity_check(payload_len, 4 + 4, type);
122 channel_input_open_confirmation(); 117 channel_input_open_confirmation();
123 break; 118 break;
124 119
125 case SSH_MSG_CHANNEL_OPEN_FAILURE: 120 case SSH_MSG_CHANNEL_OPEN_FAILURE:
126 debug("Received channel open failure."); 121 debug("Received channel open failure.");
127 packet_integrity_check(payload_len, 4, type); 122 packet_integrity_check(payload_len, 4, type);
128 channel_input_open_failure(); 123 channel_input_open_failure();
129 break; 124 break;
130 125
131 case SSH_MSG_CHANNEL_DATA: 126 case SSH_MSG_CHANNEL_DATA:
132 channel_input_data(payload_len); 127 channel_input_data(payload_len);
133 break; 128 break;
134 129
135 case SSH_MSG_CHANNEL_CLOSE: 130 case SSH_MSG_CHANNEL_CLOSE:
136 debug("Received channel close."); 131 debug("Received channel close.");
137 packet_integrity_check(payload_len, 4, type); 132 packet_integrity_check(payload_len, 4, type);
138 channel_input_close(); 133 channel_input_close();
139 break; 134 break;
140 135
141 case SSH_MSG_CHANNEL_CLOSE_CONFIRMATION: 136 case SSH_MSG_CHANNEL_CLOSE_CONFIRMATION:
142 debug("Received channel close confirmation."); 137 debug("Received channel close confirmation.");
143 packet_integrity_check(payload_len, 4, type); 138 packet_integrity_check(payload_len, 4, type);
144 channel_input_close_confirmation(); 139 channel_input_close_confirmation();
145 break; 140 break;
146 141
147 default: 142 default:
148 /* In this phase, any unexpected messages cause a protocol 143 /* In this phase, any unexpected messages cause a
149 error. This is to ease debugging; also, since no 144 protocol error. This is to ease debugging;
150 confirmations are sent messages, unprocessed unknown 145 also, since no confirmations are sent messages,
151 messages could cause strange problems. Any compatible 146 unprocessed unknown messages could cause
152 protocol extensions must be negotiated before entering the 147 strange problems. Any compatible protocol
153 interactive session. */ 148 extensions must be negotiated before entering
154 packet_disconnect("Protocol error during session: type %d", 149 the interactive session. */
155 type); 150 packet_disconnect("Protocol error during session: type %d",
151 type);
152 }
156 } 153 }
157 }
158} 154}
159 155
160/* Make packets from buffered stderr data, and buffer it for sending 156/*
161 to the client. */ 157 * Make packets from buffered stderr data, and buffer it for sending
162 158 * to the client.
163void make_packets_from_stderr_data() 159 */
160void
161make_packets_from_stderr_data()
164{ 162{
165 int len; 163 int len;
166 164
167 /* Send buffered stderr data to the client. */ 165 /* Send buffered stderr data to the client. */
168 while (buffer_len(&stderr_buffer) > 0 && 166 while (buffer_len(&stderr_buffer) > 0 &&
169 packet_not_very_much_data_to_write()) 167 packet_not_very_much_data_to_write()) {
170 { 168 len = buffer_len(&stderr_buffer);
171 len = buffer_len(&stderr_buffer); 169 if (packet_is_interactive()) {
172 if (packet_is_interactive()) 170 if (len > 512)
173 { 171 len = 512;
174 if (len > 512) 172 } else {
175 len = 512; 173 /* Keep the packets at reasonable size. */
176 } 174 if (len > packet_get_maxsize())
177 else 175 len = packet_get_maxsize();
178 { 176 }
179 if (len > packet_get_maxsize()) 177 packet_start(SSH_SMSG_STDERR_DATA);
180 len = packet_get_maxsize(); /* Keep the packets at reasonable size. */ 178 packet_put_string(buffer_ptr(&stderr_buffer), len);
179 packet_send();
180 buffer_consume(&stderr_buffer, len);
181 stderr_bytes += len;
181 } 182 }
182 packet_start(SSH_SMSG_STDERR_DATA);
183 packet_put_string(buffer_ptr(&stderr_buffer), len);
184 packet_send();
185 buffer_consume(&stderr_buffer, len);
186 stderr_bytes += len;
187 }
188} 183}
189 184
190/* Make packets from buffered stdout data, and buffer it for sending to the 185/*
191 client. */ 186 * Make packets from buffered stdout data, and buffer it for sending to the
192 187 * client.
193void make_packets_from_stdout_data() 188 */
189void
190make_packets_from_stdout_data()
194{ 191{
195 int len; 192 int len;
196 193
197 /* Send buffered stdout data to the client. */ 194 /* Send buffered stdout data to the client. */
198 while (buffer_len(&stdout_buffer) > 0 && 195 while (buffer_len(&stdout_buffer) > 0 &&
199 packet_not_very_much_data_to_write()) 196 packet_not_very_much_data_to_write()) {
200 { 197 len = buffer_len(&stdout_buffer);
201 len = buffer_len(&stdout_buffer); 198 if (packet_is_interactive()) {
202 if (packet_is_interactive()) 199 if (len > 512)
203 { 200 len = 512;
204 if (len > 512) 201 } else {
205 len = 512; 202 /* Keep the packets at reasonable size. */
206 } 203 if (len > packet_get_maxsize())
207 else 204 len = packet_get_maxsize();
208 { 205 }
209 if (len > packet_get_maxsize()) 206 packet_start(SSH_SMSG_STDOUT_DATA);
210 len = packet_get_maxsize(); /* Keep the packets at reasonable size. */ 207 packet_put_string(buffer_ptr(&stdout_buffer), len);
208 packet_send();
209 buffer_consume(&stdout_buffer, len);
210 stdout_bytes += len;
211 } 211 }
212 packet_start(SSH_SMSG_STDOUT_DATA);
213 packet_put_string(buffer_ptr(&stdout_buffer), len);
214 packet_send();
215 buffer_consume(&stdout_buffer, len);
216 stdout_bytes += len;
217 }
218} 212}
219 213
220/* Sleep in select() until we can do something. This will initialize the 214/*
221 select masks. Upon return, the masks will indicate which descriptors 215 * Sleep in select() until we can do something. This will initialize the
222 have data or can accept data. Optionally, a maximum time can be specified 216 * select masks. Upon return, the masks will indicate which descriptors
223 for the duration of the wait (0 = infinite). */ 217 * have data or can accept data. Optionally, a maximum time can be specified
224 218 * for the duration of the wait (0 = infinite).
225void wait_until_can_do_something(fd_set *readset, fd_set *writeset, 219 */
226 unsigned int max_time_milliseconds) 220void
221wait_until_can_do_something(fd_set * readset, fd_set * writeset,
222 unsigned int max_time_milliseconds)
227{ 223{
228 struct timeval tv, *tvp; 224 struct timeval tv, *tvp;
229 int ret; 225 int ret;
230 226
231 /* When select fails we restart from here. */ 227 /* When select fails we restart from here. */
232retry_select: 228retry_select:
233 229
234 /* Initialize select() masks. */ 230 /* Initialize select() masks. */
235 FD_ZERO(readset); 231 FD_ZERO(readset);
236 232
237 /* Read packets from the client unless we have too much buffered stdin 233 /* Read packets from the client unless we have too much buffered
238 or channel data. */ 234 stdin or channel data. */
239 if (buffer_len(&stdin_buffer) < 4096 && 235 if (buffer_len(&stdin_buffer) < 4096 &&
240 channel_not_very_much_buffered_data()) 236 channel_not_very_much_buffered_data())
241 FD_SET(connection_in, readset); 237 FD_SET(connection_in, readset);
242 238
243 /* If there is not too much data already buffered going to the client, 239 /* If there is not too much data already buffered going to the
244 try to get some more data from the program. */ 240 client, try to get some more data from the program. */
245 if (packet_not_very_much_data_to_write()) 241 if (packet_not_very_much_data_to_write()) {
246 { 242 if (!fdout_eof)
247 if (!fdout_eof) 243 FD_SET(fdout, readset);
248 FD_SET(fdout, readset); 244 if (!fderr_eof)
249 if (!fderr_eof) 245 FD_SET(fderr, readset);
250 FD_SET(fderr, readset); 246 }
251 } 247 FD_ZERO(writeset);
252 248
253 FD_ZERO(writeset); 249 /* Set masks for channel descriptors. */
254 250 channel_prepare_select(readset, writeset);
255 /* Set masks for channel descriptors. */ 251
256 channel_prepare_select(readset, writeset); 252 /* If we have buffered packet data going to the client, mark that
257 253 descriptor. */
258 /* If we have buffered packet data going to the client, mark that 254 if (packet_have_data_to_write())
259 descriptor. */ 255 FD_SET(connection_out, writeset);
260 if (packet_have_data_to_write()) 256
261 FD_SET(connection_out, writeset); 257 /* If we have buffered data, try to write some of that data to the
262 258 program. */
263 /* If we have buffered data, try to write some of that data to the 259 if (fdin != -1 && buffer_len(&stdin_buffer) > 0)
264 program. */ 260 FD_SET(fdin, writeset);
265 if (fdin != -1 && buffer_len(&stdin_buffer) > 0) 261
266 FD_SET(fdin, writeset); 262 /* Update the maximum descriptor number if appropriate. */
267 263 if (channel_max_fd() > max_fd)
268 /* Update the maximum descriptor number if appropriate. */ 264 max_fd = channel_max_fd();
269 if (channel_max_fd() > max_fd) 265
270 max_fd = channel_max_fd(); 266 /* If child has terminated and there is enough buffer space to
271 267 read from it, then read as much as is available and exit. */
272 /* If child has terminated and there is enough buffer space to read from 268 if (child_terminated && packet_not_very_much_data_to_write())
273 it, then read as much as is available and exit. */ 269 if (max_time_milliseconds == 0)
274 if (child_terminated && packet_not_very_much_data_to_write()) 270 max_time_milliseconds = 100;
275 if (max_time_milliseconds == 0) 271
276 max_time_milliseconds = 100; 272 if (max_time_milliseconds == 0)
277 273 tvp = NULL;
278 if (max_time_milliseconds == 0) 274 else {
279 tvp = NULL; 275 tv.tv_sec = max_time_milliseconds / 1000;
280 else 276 tv.tv_usec = 1000 * (max_time_milliseconds % 1000);
281 { 277 tvp = &tv;
282 tv.tv_sec = max_time_milliseconds / 1000; 278 }
283 tv.tv_usec = 1000 * (max_time_milliseconds % 1000);
284 tvp = &tv;
285 }
286
287 /* Wait for something to happen, or the timeout to expire. */
288 ret = select(max_fd + 1, readset, writeset, NULL, tvp);
289
290 if (ret < 0)
291 {
292 if (errno != EINTR)
293 error("select: %.100s", strerror(errno));
294 else
295 goto retry_select;
296 }
297}
298 279
299/* Processes input from the client and the program. Input data is stored 280 /* Wait for something to happen, or the timeout to expire. */
300 in buffers and processed later. */ 281 ret = select(max_fd + 1, readset, writeset, NULL, tvp);
301 282
302void process_input(fd_set *readset) 283 if (ret < 0) {
303{ 284 if (errno != EINTR)
304 int len; 285 error("select: %.100s", strerror(errno));
305 char buf[16384]; 286 else
306 287 goto retry_select;
307 /* Read and buffer any input data from the client. */
308 if (FD_ISSET(connection_in, readset))
309 {
310 len = read(connection_in, buf, sizeof(buf));
311 if (len == 0)
312 fatal("Connection closed by remote host.");
313
314 /* There is a kernel bug on Solaris that causes select to sometimes
315 wake up even though there is no data available. */
316 if (len < 0 && errno == EAGAIN)
317 len = 0;
318
319 if (len < 0)
320 fatal("Read error from remote host: %.100s", strerror(errno));
321
322 /* Buffer any received data. */
323 packet_process_incoming(buf, len);
324 }
325
326 /* Read and buffer any available stdout data from the program. */
327 if (!fdout_eof && FD_ISSET(fdout, readset))
328 {
329 len = read(fdout, buf, sizeof(buf));
330 if (len <= 0)
331 fdout_eof = 1;
332 else
333 {
334 buffer_append(&stdout_buffer, buf, len);
335 fdout_bytes += len;
336 } 288 }
337 }
338
339 /* Read and buffer any available stderr data from the program. */
340 if (!fderr_eof && FD_ISSET(fderr, readset))
341 {
342 len = read(fderr, buf, sizeof(buf));
343 if (len <= 0)
344 fderr_eof = 1;
345 else
346 buffer_append(&stderr_buffer, buf, len);
347 }
348} 289}
349 290
350/* Sends data from internal buffers to client program stdin. */ 291/*
292 * Processes input from the client and the program. Input data is stored
293 * in buffers and processed later.
294 */
295void
296process_input(fd_set * readset)
297{
298 int len;
299 char buf[16384];
300
301 /* Read and buffer any input data from the client. */
302 if (FD_ISSET(connection_in, readset)) {
303 len = read(connection_in, buf, sizeof(buf));
304 if (len == 0) {
305 verbose("Connection closed by remote host.");
306 fatal_cleanup();
307 }
308 /* There is a kernel bug on Solaris that causes select to
309 sometimes wake up even though there is no data
310 available. */
311 if (len < 0 && errno == EAGAIN)
312 len = 0;
313
314 if (len < 0) {
315 verbose("Read error from remote host: %.100s", strerror(errno));
316 fatal_cleanup();
317 }
318 /* Buffer any received data. */
319 packet_process_incoming(buf, len);
320 }
321 /* Read and buffer any available stdout data from the program. */
322 if (!fdout_eof && FD_ISSET(fdout, readset)) {
323 len = read(fdout, buf, sizeof(buf));
324 if (len <= 0)
325 fdout_eof = 1;
326 else {
327 buffer_append(&stdout_buffer, buf, len);
328 fdout_bytes += len;
329 }
330 }
331 /* Read and buffer any available stderr data from the program. */
332 if (!fderr_eof && FD_ISSET(fderr, readset)) {
333 len = read(fderr, buf, sizeof(buf));
334 if (len <= 0)
335 fderr_eof = 1;
336 else
337 buffer_append(&stderr_buffer, buf, len);
338 }
339}
351 340
352void process_output(fd_set *writeset) 341/*
342 * Sends data from internal buffers to client program stdin.
343 */
344void
345process_output(fd_set * writeset)
353{ 346{
354 int len; 347 int len;
355 348
356 /* Write buffered data to program stdin. */ 349 /* Write buffered data to program stdin. */
357 if (fdin != -1 && FD_ISSET(fdin, writeset)) 350 if (fdin != -1 && FD_ISSET(fdin, writeset)) {
358 { 351 len = write(fdin, buffer_ptr(&stdin_buffer),
359 len = write(fdin, buffer_ptr(&stdin_buffer), 352 buffer_len(&stdin_buffer));
360 buffer_len(&stdin_buffer)); 353 if (len <= 0) {
361 if (len <= 0)
362 {
363#ifdef USE_PIPES 354#ifdef USE_PIPES
364 close(fdin); 355 close(fdin);
365#else 356#else
366 if (fdout == -1) 357 if (fdout == -1)
367 close(fdin); 358 close(fdin);
368 else 359 else
369 shutdown(fdin, SHUT_WR); /* We will no longer send. */ 360 shutdown(fdin, SHUT_WR); /* We will no longer send. */
370#endif 361#endif
371 fdin = -1; 362 fdin = -1;
372 } 363 } else {
373 else 364 /* Successful write. Consume the data from the buffer. */
374 { 365 buffer_consume(&stdin_buffer, len);
375 /* Successful write. Consume the data from the buffer. */ 366 /* Update the count of bytes written to the program. */
376 buffer_consume(&stdin_buffer, len); 367 stdin_bytes += len;
377 /* Update the count of bytes written to the program. */ 368 }
378 stdin_bytes += len;
379 } 369 }
380 } 370 /* Send any buffered packet data to the client. */
381 371 if (FD_ISSET(connection_out, writeset))
382 /* Send any buffered packet data to the client. */ 372 packet_write_poll();
383 if (FD_ISSET(connection_out, writeset))
384 packet_write_poll();
385} 373}
386 374
387/* Wait until all buffered output has been sent to the client. 375/*
388 This is used when the program terminates. */ 376 * Wait until all buffered output has been sent to the client.
389 377 * This is used when the program terminates.
390void drain_output() 378 */
379void
380drain_output()
391{ 381{
392 /* Send any buffered stdout data to the client. */ 382 /* Send any buffered stdout data to the client. */
393 if (buffer_len(&stdout_buffer) > 0) 383 if (buffer_len(&stdout_buffer) > 0) {
394 { 384 packet_start(SSH_SMSG_STDOUT_DATA);
395 packet_start(SSH_SMSG_STDOUT_DATA); 385 packet_put_string(buffer_ptr(&stdout_buffer),
396 packet_put_string(buffer_ptr(&stdout_buffer), 386 buffer_len(&stdout_buffer));
397 buffer_len(&stdout_buffer)); 387 packet_send();
398 packet_send(); 388 /* Update the count of sent bytes. */
399 /* Update the count of sent bytes. */ 389 stdout_bytes += buffer_len(&stdout_buffer);
400 stdout_bytes += buffer_len(&stdout_buffer); 390 }
401 } 391 /* Send any buffered stderr data to the client. */
402 392 if (buffer_len(&stderr_buffer) > 0) {
403 /* Send any buffered stderr data to the client. */ 393 packet_start(SSH_SMSG_STDERR_DATA);
404 if (buffer_len(&stderr_buffer) > 0) 394 packet_put_string(buffer_ptr(&stderr_buffer),
405 { 395 buffer_len(&stderr_buffer));
406 packet_start(SSH_SMSG_STDERR_DATA); 396 packet_send();
407 packet_put_string(buffer_ptr(&stderr_buffer), 397 /* Update the count of sent bytes. */
408 buffer_len(&stderr_buffer)); 398 stderr_bytes += buffer_len(&stderr_buffer);
409 packet_send(); 399 }
410 /* Update the count of sent bytes. */ 400 /* Wait until all buffered data has been written to the client. */
411 stderr_bytes += buffer_len(&stderr_buffer); 401 packet_write_wait();
412 }
413
414 /* Wait until all buffered data has been written to the client. */
415 packet_write_wait();
416} 402}
417 403
418/* Performs the interactive session. This handles data transmission between 404/*
419 the client and the program. Note that the notion of stdin, stdout, and 405 * Performs the interactive session. This handles data transmission between
420 stderr in this function is sort of reversed: this function writes to 406 * the client and the program. Note that the notion of stdin, stdout, and
421 stdin (of the child program), and reads from stdout and stderr (of the 407 * stderr in this function is sort of reversed: this function writes to
422 child program). */ 408 * stdin (of the child program), and reads from stdout and stderr (of the
423 409 * child program).
424void server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg) 410 */
411void
412server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg)
425{ 413{
426 int wait_status, wait_pid; /* Status and pid returned by wait(). */ 414 int wait_status, wait_pid; /* Status and pid returned by wait(). */
427 int waiting_termination = 0; /* Have displayed waiting close message. */ 415 int waiting_termination = 0; /* Have displayed waiting close message. */
428 unsigned int max_time_milliseconds; 416 unsigned int max_time_milliseconds;
429 unsigned int previous_stdout_buffer_bytes; 417 unsigned int previous_stdout_buffer_bytes;
430 unsigned int stdout_buffer_bytes; 418 unsigned int stdout_buffer_bytes;
431 int type; 419 int type;
432 420
433 debug("Entering interactive session."); 421 debug("Entering interactive session.");
434 422
435 /* Initialize the SIGCHLD kludge. */ 423 /* Initialize the SIGCHLD kludge. */
436 child_pid = pid; 424 child_pid = pid;
437 child_terminated = 0; 425 child_terminated = 0;
438 signal(SIGCHLD, sigchld_handler); 426 signal(SIGCHLD, sigchld_handler);
439 427
440 /* Initialize our global variables. */ 428 /* Initialize our global variables. */
441 fdin = fdin_arg; 429 fdin = fdin_arg;
442 fdout = fdout_arg; 430 fdout = fdout_arg;
443 fderr = fderr_arg; 431 fderr = fderr_arg;
444 connection_in = packet_get_connection_in(); 432 connection_in = packet_get_connection_in();
445 connection_out = packet_get_connection_out(); 433 connection_out = packet_get_connection_out();
446 434
447 previous_stdout_buffer_bytes = 0; 435 previous_stdout_buffer_bytes = 0;
448 436
449 /* Set approximate I/O buffer size. */ 437 /* Set approximate I/O buffer size. */
450 if (packet_is_interactive()) 438 if (packet_is_interactive())
451 buffer_high = 4096; 439 buffer_high = 4096;
452 else 440 else
453 buffer_high = 64 * 1024; 441 buffer_high = 64 * 1024;
454 442
455 /* Initialize max_fd to the maximum of the known file descriptors. */ 443 /* Initialize max_fd to the maximum of the known file descriptors. */
456 max_fd = fdin; 444 max_fd = fdin;
457 if (fdout > max_fd) 445 if (fdout > max_fd)
458 max_fd = fdout; 446 max_fd = fdout;
459 if (fderr != -1 && fderr > max_fd) 447 if (fderr != -1 && fderr > max_fd)
460 max_fd = fderr; 448 max_fd = fderr;
461 if (connection_in > max_fd) 449 if (connection_in > max_fd)
462 max_fd = connection_in; 450 max_fd = connection_in;
463 if (connection_out > max_fd) 451 if (connection_out > max_fd)
464 max_fd = connection_out; 452 max_fd = connection_out;
465 453
466 /* Initialize Initialize buffers. */ 454 /* Initialize Initialize buffers. */
467 buffer_init(&stdin_buffer); 455 buffer_init(&stdin_buffer);
468 buffer_init(&stdout_buffer); 456 buffer_init(&stdout_buffer);
469 buffer_init(&stderr_buffer); 457 buffer_init(&stderr_buffer);
470 458
471 /* If we have no separate fderr (which is the case when we have a pty - there 459 /* If we have no separate fderr (which is the case when we have a
472 we cannot make difference between data sent to stdout and stderr), 460 pty - there we cannot make difference between data sent to
473 indicate that we have seen an EOF from stderr. This way we don\'t 461 stdout and stderr), indicate that we have seen an EOF from
474 need to check the descriptor everywhere. */ 462 stderr. This way we don\'t need to check the descriptor
475 if (fderr == -1) 463 everywhere. */
476 fderr_eof = 1; 464 if (fderr == -1)
477 465 fderr_eof = 1;
478 /* Main loop of the server for the interactive session mode. */ 466
479 for (;;) 467 /* Main loop of the server for the interactive session mode. */
480 { 468 for (;;) {
481 fd_set readset, writeset; 469 fd_set readset, writeset;
482 470
483 /* Process buffered packets from the client. */ 471 /* Process buffered packets from the client. */
484 process_buffered_input_packets(); 472 process_buffered_input_packets();
485 473
486 /* If we have received eof, and there is no more pending input data, 474 /* If we have received eof, and there is no more pending
487 cause a real eof by closing fdin. */ 475 input data, cause a real eof by closing fdin. */
488 if (stdin_eof && fdin != -1 && buffer_len(&stdin_buffer) == 0) 476 if (stdin_eof && fdin != -1 && buffer_len(&stdin_buffer) == 0) {
489 {
490#ifdef USE_PIPES 477#ifdef USE_PIPES
491 close(fdin); 478 close(fdin);
492#else 479#else
493 if (fdout == -1) 480 if (fdout == -1)
494 close(fdin); 481 close(fdin);
495 else 482 else
496 shutdown(fdin, SHUT_WR); /* We will no longer send. */ 483 shutdown(fdin, SHUT_WR); /* We will no longer send. */
497#endif 484#endif
498 fdin = -1; 485 fdin = -1;
486 }
487 /* Make packets from buffered stderr data to send to the
488 client. */
489 make_packets_from_stderr_data();
490
491 /* Make packets from buffered stdout data to send to the
492 client. If there is very little to send, this arranges
493 to not send them now, but to wait a short while to see
494 if we are getting more data. This is necessary, as some
495 systems wake up readers from a pty after each separate
496 character. */
497 max_time_milliseconds = 0;
498 stdout_buffer_bytes = buffer_len(&stdout_buffer);
499 if (stdout_buffer_bytes != 0 && stdout_buffer_bytes < 256 &&
500 stdout_buffer_bytes != previous_stdout_buffer_bytes) {
501 /* try again after a while */
502 max_time_milliseconds = 10;
503 } else {
504 /* Send it now. */
505 make_packets_from_stdout_data();
506 }
507 previous_stdout_buffer_bytes = buffer_len(&stdout_buffer);
508
509 /* Send channel data to the client. */
510 if (packet_not_very_much_data_to_write())
511 channel_output_poll();
512
513 /* Bail out of the loop if the program has closed its
514 output descriptors, and we have no more data to send to
515 the client, and there is no pending buffered data. */
516 if (fdout_eof && fderr_eof && !packet_have_data_to_write() &&
517 buffer_len(&stdout_buffer) == 0 && buffer_len(&stderr_buffer) == 0) {
518 if (!channel_still_open())
519 goto quit;
520 if (!waiting_termination) {
521 const char *s = "Waiting for forwarded connections to terminate...\r\n";
522 char *cp;
523 waiting_termination = 1;
524 buffer_append(&stderr_buffer, s, strlen(s));
525
526 /* Display list of open channels. */
527 cp = channel_open_message();
528 buffer_append(&stderr_buffer, cp, strlen(cp));
529 xfree(cp);
530 }
531 }
532 /* Sleep in select() until we can do something. */
533 wait_until_can_do_something(&readset, &writeset,
534 max_time_milliseconds);
535
536 /* Process any channel events. */
537 channel_after_select(&readset, &writeset);
538
539 /* Process input from the client and from program stdout/stderr. */
540 process_input(&readset);
541
542 /* Process output to the client and to program stdin. */
543 process_output(&writeset);
499 } 544 }
500 545
501 /* Make packets from buffered stderr data to send to the client. */ 546quit:
502 make_packets_from_stderr_data(); 547 /* Cleanup and termination code. */
503
504 /* Make packets from buffered stdout data to send to the client.
505 If there is very little to send, this arranges to not send them
506 now, but to wait a short while to see if we are getting more data.
507 This is necessary, as some systems wake up readers from a pty after
508 each separate character. */
509 max_time_milliseconds = 0;
510 stdout_buffer_bytes = buffer_len(&stdout_buffer);
511 if (stdout_buffer_bytes != 0 && stdout_buffer_bytes < 256 &&
512 stdout_buffer_bytes != previous_stdout_buffer_bytes)
513 max_time_milliseconds = 10; /* try again after a while */
514 else
515 make_packets_from_stdout_data(); /* Send it now. */
516 previous_stdout_buffer_bytes = buffer_len(&stdout_buffer);
517
518 /* Send channel data to the client. */
519 if (packet_not_very_much_data_to_write())
520 channel_output_poll();
521
522 /* Bail out of the loop if the program has closed its output descriptors,
523 and we have no more data to send to the client, and there is no
524 pending buffered data. */
525 if (fdout_eof && fderr_eof && !packet_have_data_to_write() &&
526 buffer_len(&stdout_buffer) == 0 && buffer_len(&stderr_buffer) == 0)
527 {
528 if (!channel_still_open())
529 goto quit;
530 if (!waiting_termination)
531 {
532 const char *s =
533 "Waiting for forwarded connections to terminate...\r\n";
534 char *cp;
535 waiting_termination = 1;
536 buffer_append(&stderr_buffer, s, strlen(s));
537
538 /* Display list of open channels. */
539 cp = channel_open_message();
540 buffer_append(&stderr_buffer, cp, strlen(cp));
541 xfree(cp);
542 }
543 }
544 548
545 /* Sleep in select() until we can do something. */ 549 /* Wait until all output has been sent to the client. */
546 wait_until_can_do_something(&readset, &writeset, 550 drain_output();
547 max_time_milliseconds);
548
549 /* Process any channel events. */
550 channel_after_select(&readset, &writeset);
551
552 /* Process input from the client and from program stdout/stderr. */
553 process_input(&readset);
554
555 /* Process output to the client and to program stdin. */
556 process_output(&writeset);
557 }
558
559 quit:
560 /* Cleanup and termination code. */
561
562 /* Wait until all output has been sent to the client. */
563 drain_output();
564
565 debug("End of interactive session; stdin %ld, stdout (read %ld, sent %ld), stderr %ld bytes.",
566 stdin_bytes, fdout_bytes, stdout_bytes, stderr_bytes);
567
568 /* Free and clear the buffers. */
569 buffer_free(&stdin_buffer);
570 buffer_free(&stdout_buffer);
571 buffer_free(&stderr_buffer);
572
573 /* Close the file descriptors. */
574 if (fdout != -1)
575 close(fdout);
576 fdout = -1;
577 fdout_eof = 1;
578 if (fderr != -1)
579 close(fderr);
580 fderr = -1;
581 fderr_eof = 1;
582 if (fdin != -1)
583 close(fdin);
584 fdin = -1;
585
586 /* Stop listening for channels; this removes unix domain sockets. */
587 channel_stop_listening();
588
589 /* Wait for the child to exit. Get its exit status. */
590 wait_pid = wait(&wait_status);
591 if (wait_pid < 0)
592 {
593 /* It is possible that the wait was handled by SIGCHLD handler. This
594 may result in either: this call returning with EINTR, or: this
595 call returning ECHILD. */
596 if (child_terminated)
597 wait_status = child_wait_status;
598 else
599 packet_disconnect("wait: %.100s", strerror(errno));
600 }
601 else
602 {
603 /* Check if it matches the process we forked. */
604 if (wait_pid != pid)
605 error("Strange, wait returned pid %d, expected %d", wait_pid, pid);
606 }
607
608 /* We no longer want our SIGCHLD handler to be called. */
609 signal(SIGCHLD, SIG_DFL);
610
611 /* Check if it exited normally. */
612 if (WIFEXITED(wait_status))
613 {
614 /* Yes, normal exit. Get exit status and send it to the client. */
615 debug("Command exited with status %d.", WEXITSTATUS(wait_status));
616 packet_start(SSH_SMSG_EXITSTATUS);
617 packet_put_int(WEXITSTATUS(wait_status));
618 packet_send();
619 packet_write_wait();
620
621 /* Wait for exit confirmation. Note that there might be other
622 packets coming before it; however, the program has already died
623 so we just ignore them. The client is supposed to respond with
624 the confirmation when it receives the exit status. */
625 do
626 {
627 int plen;
628 type = packet_read(&plen);
629 }
630 while (type != SSH_CMSG_EXIT_CONFIRMATION);
631 551
632 debug("Received exit confirmation."); 552 debug("End of interactive session; stdin %ld, stdout (read %ld, sent %ld), stderr %ld bytes.",
633 return; 553 stdin_bytes, fdout_bytes, stdout_bytes, stderr_bytes);
634 }
635 554
636 /* Check if the program terminated due to a signal. */ 555 /* Free and clear the buffers. */
637 if (WIFSIGNALED(wait_status)) 556 buffer_free(&stdin_buffer);
638 packet_disconnect("Command terminated on signal %d.", 557 buffer_free(&stdout_buffer);
639 WTERMSIG(wait_status)); 558 buffer_free(&stderr_buffer);
640 559
641 /* Some weird exit cause. Just exit. */ 560 /* Close the file descriptors. */
642 packet_disconnect("wait returned status %04x.", wait_status); 561 if (fdout != -1)
643 /*NOTREACHED*/ 562 close(fdout);
644} 563 fdout = -1;
564 fdout_eof = 1;
565 if (fderr != -1)
566 close(fderr);
567 fderr = -1;
568 fderr_eof = 1;
569 if (fdin != -1)
570 close(fdin);
571 fdin = -1;
572
573 /* Stop listening for channels; this removes unix domain sockets. */
574 channel_stop_listening();
575
576 /* Wait for the child to exit. Get its exit status. */
577 wait_pid = wait(&wait_status);
578 if (wait_pid < 0) {
579 /*
580 * It is possible that the wait was handled by SIGCHLD
581 * handler. This may result in either: this call
582 * returning with EINTR, or: this call returning ECHILD.
583 */
584 if (child_terminated)
585 wait_status = child_wait_status;
586 else
587 packet_disconnect("wait: %.100s", strerror(errno));
588 } else {
589 /* Check if it matches the process we forked. */
590 if (wait_pid != pid)
591 error("Strange, wait returned pid %d, expected %d",
592 wait_pid, pid);
593 }
645 594
595 /* We no longer want our SIGCHLD handler to be called. */
596 signal(SIGCHLD, SIG_DFL);
597
598 /* Check if it exited normally. */
599 if (WIFEXITED(wait_status)) {
600 /* Yes, normal exit. Get exit status and send it to the client. */
601 debug("Command exited with status %d.", WEXITSTATUS(wait_status));
602 packet_start(SSH_SMSG_EXITSTATUS);
603 packet_put_int(WEXITSTATUS(wait_status));
604 packet_send();
605 packet_write_wait();
606
607 /* Wait for exit confirmation. Note that there might be
608 other packets coming before it; however, the program
609 has already died so we just ignore them. The client is
610 supposed to respond with the confirmation when it
611 receives the exit status. */
612 do {
613 int plen;
614 type = packet_read(&plen);
615 }
616 while (type != SSH_CMSG_EXIT_CONFIRMATION);
617
618 debug("Received exit confirmation.");
619 return;
620 }
621 /* Check if the program terminated due to a signal. */
622 if (WIFSIGNALED(wait_status))
623 packet_disconnect("Command terminated on signal %d.",
624 WTERMSIG(wait_status));
625
626 /* Some weird exit cause. Just exit. */
627 packet_disconnect("wait returned status %04x.", wait_status);
628 /* NOTREACHED */
629}
diff --git a/ssh-add.c b/ssh-add.c
index a95914417..f94dcdabb 100644
--- a/ssh-add.c
+++ b/ssh-add.c
@@ -1,20 +1,13 @@
1/* 1/*
2 2 * Author: Tatu Ylonen <ylo@cs.hut.fi>
3ssh-add.c 3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 4 * All rights reserved
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Created: Thu Apr 6 00:52:24 1995 ylo
6 6 * Adds an identity to the authentication server, or removes an identity.
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 */
8 All rights reserved
9
10Created: Thu Apr 6 00:52:24 1995 ylo
11
12Adds an identity to the authentication server, or removes an identity.
13
14*/
15 8
16#include "includes.h" 9#include "includes.h"
17RCSID("$Id: ssh-add.c,v 1.12 1999/11/23 00:24:32 damien Exp $"); 10RCSID("$Id: ssh-add.c,v 1.13 1999/11/24 13:26:22 damien Exp $");
18 11
19#include "rsa.h" 12#include "rsa.h"
20#include "ssh.h" 13#include "ssh.h"
@@ -35,291 +28,279 @@ const char *__progname = "ssh-add";
35void 28void
36delete_file(AuthenticationConnection *ac, const char *filename) 29delete_file(AuthenticationConnection *ac, const char *filename)
37{ 30{
38 RSA *key; 31 RSA *key;
39 char *comment; 32 char *comment;
40 33
41 key = RSA_new(); 34 key = RSA_new();
42 if (!load_public_key(filename, key, &comment)) 35 if (!load_public_key(filename, key, &comment)) {
43 { 36 printf("Bad key file %s: %s\n", filename, strerror(errno));
44 printf("Bad key file %s: %s\n", filename, strerror(errno)); 37 return;
45 return; 38 }
46 } 39 if (ssh_remove_identity(ac, key))
47 40 fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment);
48 if (ssh_remove_identity(ac, key)) 41 else
49 fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment); 42 fprintf(stderr, "Could not remove identity: %s\n", filename);
50 else 43 RSA_free(key);
51 fprintf(stderr, "Could not remove identity: %s\n", filename); 44 xfree(comment);
52 RSA_free(key);
53 xfree(comment);
54} 45}
55 46
56void 47void
57delete_all(AuthenticationConnection *ac) 48delete_all(AuthenticationConnection *ac)
58{ 49{
59 /* Send a request to remove all identities. */ 50 /* Send a request to remove all identities. */
60 if (ssh_remove_all_identities(ac)) 51 if (ssh_remove_all_identities(ac))
61 fprintf(stderr, "All identities removed.\n"); 52 fprintf(stderr, "All identities removed.\n");
62 else 53 else
63 fprintf(stderr, "Failed to remove all identitities.\n"); 54 fprintf(stderr, "Failed to remove all identitities.\n");
64} 55}
65 56
66void 57void
67add_file(AuthenticationConnection *ac, const char *filename) 58add_file(AuthenticationConnection *ac, const char *filename)
68{ 59{
69 RSA *key; 60 RSA *key;
70 RSA *public_key; 61 RSA *public_key;
71 char *saved_comment, *comment; 62 char *saved_comment, *comment;
72 int success; 63 int success;
73 64
74 key = RSA_new(); 65 key = RSA_new();
75 public_key = RSA_new(); 66 public_key = RSA_new();
76 if (!load_public_key(filename, public_key, &saved_comment)) 67 if (!load_public_key(filename, public_key, &saved_comment)) {
77 { 68 printf("Bad key file %s: %s\n", filename, strerror(errno));
78 printf("Bad key file %s: %s\n", filename, strerror(errno)); 69 return;
79 return; 70 }
80 } 71 RSA_free(public_key);
81 RSA_free(public_key);
82
83 /* At first, try empty passphrase */
84 success = load_private_key(filename, "", key, &comment);
85 if (!success) {
86 printf("Need passphrase for %s (%s).\n", filename, saved_comment);
87 if (!isatty(STDIN_FILENO)) {
88#ifdef USE_EXTERNAL_ASKPASS
89 int prompts = 3;
90 72
91 while (prompts && !success) 73 /* At first, try empty passphrase */
92 { 74 success = load_private_key(filename, "", key, &comment);
93 success = askpass(filename, key, saved_comment, &comment); 75 if (!success) {
94 prompts--; 76 printf("Need passphrase for %s (%s).\n", filename, saved_comment);
95 } 77 if (!isatty(STDIN_FILENO)) {
96 if (!success) 78#ifdef USE_EXTERNAL_ASKPASS
97 { 79 int prompts = 3;
98 xfree(saved_comment); 80 while (prompts && !success) {
99 return; 81 success = askpass(filename, key, saved_comment, &comment);
100 } 82 prompts--;
83 }
84 if (!success) {
85 xfree(saved_comment);
86 return;
87 }
101#else /* !USE_EXTERNAL_ASKPASS */ 88#else /* !USE_EXTERNAL_ASKPASS */
102 xfree(saved_comment); 89 xfree(saved_comment);
103 return; 90 return;
104#endif /* USE_EXTERNAL_ASKPASS */ 91#endif /* USE_EXTERNAL_ASKPASS */
105 } 92 }
106 93
107 while (!success) { 94 while (!success) {
108 char *pass = read_passphrase("Enter passphrase: ", 1); 95 char *pass = read_passphrase("Enter passphrase: ", 1);
109 if (strcmp(pass, "") == 0){ 96 if (strcmp(pass, "") == 0) {
110 xfree(pass); 97 xfree(pass);
111 xfree(saved_comment); 98 xfree(saved_comment);
112 return; 99 return;
113 } 100 }
114 success = load_private_key(filename, pass, key, &comment); 101 success = load_private_key(filename, pass, key, &comment);
115 memset(pass, 0, strlen(pass)); 102 memset(pass, 0, strlen(pass));
116 xfree(pass); 103 xfree(pass);
117 if (success) 104 if (success)
118 break; 105 break;
119 printf("Bad passphrase.\n"); 106 printf("Bad passphrase.\n");
120 } 107 }
121 } 108 }
122 xfree(saved_comment); 109 xfree(saved_comment);
123 110
124 if (ssh_add_identity(ac, key, comment)) 111 if (ssh_add_identity(ac, key, comment))
125 fprintf(stderr, "Identity added: %s (%s)\n", filename, comment); 112 fprintf(stderr, "Identity added: %s (%s)\n", filename, comment);
126 else 113 else
127 fprintf(stderr, "Could not add identity: %s\n", filename); 114 fprintf(stderr, "Could not add identity: %s\n", filename);
128 RSA_free(key); 115 RSA_free(key);
129 xfree(comment); 116 xfree(comment);
130} 117}
131 118
132void 119void
133list_identities(AuthenticationConnection *ac, int fp) 120list_identities(AuthenticationConnection *ac, int fp)
134{ 121{
135 BIGNUM *e, *n; 122 BIGNUM *e, *n;
136 int status; 123 int status;
137 char *comment; 124 char *comment;
138 int had_identities; 125 int had_identities;
139 126
140 e = BN_new(); 127 e = BN_new();
141 n = BN_new(); 128 n = BN_new();
142 had_identities = 0; 129 had_identities = 0;
143 for (status = ssh_get_first_identity(ac, e, n, &comment); 130 for (status = ssh_get_first_identity(ac, e, n, &comment);
144 status; 131 status;
145 status = ssh_get_next_identity(ac, e, n, &comment)) 132 status = ssh_get_next_identity(ac, e, n, &comment)) {
146 { 133 unsigned int bits = BN_num_bits(n);
147 unsigned int bits = BN_num_bits(n); 134 had_identities = 1;
148 had_identities = 1; 135 if (fp) {
149 if (fp) { 136 printf("%d %s %s\n", bits, fingerprint(e, n), comment);
150 printf("%d %s %s\n", bits, fingerprint(e, n), comment); 137 } else {
151 } else { 138 char *ebuf, *nbuf;
152 char *ebuf, *nbuf; 139 ebuf = BN_bn2dec(e);
153 ebuf = BN_bn2dec(e); 140 if (ebuf == NULL) {
154 if (ebuf == NULL) { 141 error("list_identities: BN_bn2dec(e) failed.");
155 error("list_identities: BN_bn2dec(e) failed."); 142 } else {
156 }else{ 143 nbuf = BN_bn2dec(n);
157 nbuf = BN_bn2dec(n); 144 if (nbuf == NULL) {
158 if (nbuf == NULL) { 145 error("list_identities: BN_bn2dec(n) failed.");
159 error("list_identities: BN_bn2dec(n) failed."); 146 } else {
160 }else{ 147 printf("%d %s %s %s\n", bits, ebuf, nbuf, comment);
161 printf("%d %s %s %s\n", bits, ebuf, nbuf, comment); 148 free(nbuf);
162 free(nbuf); 149 }
163 } 150 free(ebuf);
164 free(ebuf); 151 }
152 }
153 xfree(comment);
165 } 154 }
166 } 155 BN_clear_free(e);
167 xfree(comment); 156 BN_clear_free(n);
168 } 157 if (!had_identities)
169 BN_clear_free(e); 158 printf("The agent has no identities.\n");
170 BN_clear_free(n);
171 if (!had_identities)
172 printf("The agent has no identities.\n");
173} 159}
174 160
175int 161int
176main(int argc, char **argv) 162main(int argc, char **argv)
177{ 163{
178 AuthenticationConnection *ac = NULL; 164 AuthenticationConnection *ac = NULL;
179 struct passwd *pw; 165 struct passwd *pw;
180 char buf[1024]; 166 char buf[1024];
181 int no_files = 1; 167 int no_files = 1;
182 int i; 168 int i;
183 int deleting = 0; 169 int deleting = 0;
184 170
185 /* check if RSA support exists */ 171 /* check if RSA support exists */
186 if (rsa_alive() == 0) { 172 if (rsa_alive() == 0) {
187 fprintf(stderr, 173 extern char *__progname;
188 "%s: no RSA support in libssl and libcrypto. See ssl(8).\n", 174
189 __progname); 175 fprintf(stderr,
190 exit(1); 176 "%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
191 } 177 __progname);
192 178 exit(1);
193 /* At first, get a connection to the authentication agent. */
194 ac = ssh_get_authentication_connection();
195 if (ac == NULL) {
196 fprintf(stderr, "Could not open a connection to your authentication agent.\n");
197 exit(1);
198 }
199
200 for (i = 1; i < argc; i++)
201 {
202 if ((strcmp(argv[i], "-l") == 0) ||
203 (strcmp(argv[i], "-L") == 0))
204 {
205 list_identities(ac, argv[i][1] == 'l' ? 1 : 0);
206 no_files = 0; /* Don't default-add/delete if -l. */
207 continue;
208 } 179 }
209 if (strcmp(argv[i], "-d") == 0) 180 /* At first, get a connection to the authentication agent. */
210 { 181 ac = ssh_get_authentication_connection();
211 deleting = 1; 182 if (ac == NULL) {
212 continue; 183 fprintf(stderr, "Could not open a connection to your authentication agent.\n");
184 exit(1);
213 } 185 }
214 if (strcmp(argv[i], "-D") == 0) 186 for (i = 1; i < argc; i++) {
215 { 187 if ((strcmp(argv[i], "-l") == 0) ||
216 delete_all(ac); 188 (strcmp(argv[i], "-L") == 0)) {
217 no_files = 0; 189 list_identities(ac, argv[i][1] == 'l' ? 1 : 0);
218 continue; 190 /* Don't default-add/delete if -l. */
191 no_files = 0;
192 continue;
193 }
194 if (strcmp(argv[i], "-d") == 0) {
195 deleting = 1;
196 continue;
197 }
198 if (strcmp(argv[i], "-D") == 0) {
199 delete_all(ac);
200 no_files = 0;
201 continue;
202 }
203 no_files = 0;
204 if (deleting)
205 delete_file(ac, argv[i]);
206 else
207 add_file(ac, argv[i]);
219 } 208 }
220 no_files = 0; 209 if (no_files) {
221 if (deleting) 210 pw = getpwuid(getuid());
222 delete_file(ac, argv[i]); 211 if (!pw) {
223 else 212 fprintf(stderr, "No user found with uid %d\n", (int) getuid());
224 add_file(ac, argv[i]); 213 ssh_close_authentication_connection(ac);
225 } 214 exit(1);
226 if (no_files) 215 }
227 { 216 snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, SSH_CLIENT_IDENTITY);
228 pw = getpwuid(getuid()); 217 if (deleting)
229 if (!pw) 218 delete_file(ac, buf);
230 { 219 else
231 fprintf(stderr, "No user found with uid %d\n", (int)getuid()); 220 add_file(ac, buf);
232 ssh_close_authentication_connection(ac);
233 exit(1);
234 } 221 }
235 snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, SSH_CLIENT_IDENTITY); 222 ssh_close_authentication_connection(ac);
236 if (deleting) 223 exit(0);
237 delete_file(ac, buf);
238 else
239 add_file(ac, buf);
240 }
241 ssh_close_authentication_connection(ac);
242 exit(0);
243} 224}
244 225
245#ifdef USE_EXTERNAL_ASKPASS 226#ifdef USE_EXTERNAL_ASKPASS
246int askpass(const char *filename, RSA *key, const char *saved_comment, char **comment) 227int askpass(const char *filename, RSA *key, const char *saved_comment, char **comment)
247{ 228{
248 int pipes[2]; 229 int pipes[2];
249 char buf[1024]; 230 char buf[1024];
250 int tmp; 231 int tmp;
251 pid_t child; 232 pid_t child;
252 FILE *pipef; 233 FILE *pipef;
253 234
254 /* Check that we are X11-capable */ 235 /* Check that we are X11-capable */
255 if (getenv("DISPLAY") == NULL) 236 if (getenv("DISPLAY") == NULL)
256 exit(1); 237 exit(1);
257 238
258 if (pipe(pipes) == -1) { 239 if (pipe(pipes) == -1) {
259 fprintf(stderr, "Creating pipes failed: %s\n", strerror(errno)); 240 fprintf(stderr, "Creating pipes failed: %s\n", strerror(errno));
260 exit(1); 241 exit(1);
261 } 242 }
262 243
263 if (fflush(NULL) == EOF) { 244 if (fflush(NULL) == EOF) {
264 fprintf(stderr, "Cannot flush buffers: %s\n", strerror(errno)); 245 fprintf(stderr, "Cannot flush buffers: %s\n", strerror(errno));
265 exit(1); 246 exit(1);
266 } 247 }
267 248
268 child = fork(); 249 child = fork();
269 if (child == -1) { 250 if (child == -1) {
270 fprintf(stderr, "Cannot fork: %s\n", strerror(errno)); 251 fprintf(stderr, "Cannot fork: %s\n", strerror(errno));
271 exit(1); 252 exit(1);
272 } 253 }
273 254
274 if (child == 0) { 255 if (child == 0) {
275 /* In child */ 256 /* In child */
276 257
277 close(pipes[0]); 258 close(pipes[0]);
278 if (dup2(pipes[1], 1) ==-1) { 259 if (dup2(pipes[1], 1) ==-1) {
279 fprintf(stderr, "dup2 failed: %s\n", strerror(errno)); 260 fprintf(stderr, "dup2 failed: %s\n", strerror(errno));
280 exit(1); 261 exit(1);
281 } 262 }
282 263
283 tmp = snprintf(buf, sizeof(buf), "Need passphrase for %s", saved_comment); 264 tmp = snprintf(buf, sizeof(buf), "Need passphrase for %s", saved_comment);
284 /* skip the prompt if it won't fit */ 265 /* skip the prompt if it won't fit */
285 if ((tmp < 0) || (tmp >= sizeof(buf))) 266 if ((tmp < 0) || (tmp >= sizeof(buf)))
286 tmp = execlp(ASKPASS_PROGRAM, "ssh-askpass", 0); 267 tmp = execlp(ASKPASS_PROGRAM, "ssh-askpass", 0);
287 else 268 else
288 tmp = execlp(ASKPASS_PROGRAM, "ssh-askpass", buf, 0); 269 tmp = execlp(ASKPASS_PROGRAM, "ssh-askpass", buf, 0);
289 270
290 /* Shouldn't get this far */ 271 /* Shouldn't get this far */
291 fprintf(stderr, "Executing ssh-askpass failed: %s\n", strerror(errno)); 272 fprintf(stderr, "Executing ssh-askpass failed: %s\n", strerror(errno));
292 exit(1); 273 exit(1);
293 } 274 }
294 275
295 /* In parent */ 276 /* In parent */
296 close(pipes[1]); 277 close(pipes[1]);
297 278
298 if ((pipef = fdopen(pipes[0], "r")) == NULL) { 279 if ((pipef = fdopen(pipes[0], "r")) == NULL) {
299 fprintf(stderr, "fdopen failed: %s\n", strerror(errno)); 280 fprintf(stderr, "fdopen failed: %s\n", strerror(errno));
300 exit(1); 281 exit(1);
301 } 282 }
302 283
303 /* Read passphrase back from child, abort if none presented */ 284 /* Read passphrase back from child, abort if none presented */
304 if(fgets(buf, sizeof(buf), pipef) == NULL) 285 if(fgets(buf, sizeof(buf), pipef) == NULL)
305 exit(1); 286 exit(1);
306 287
307 fclose(pipef); 288 fclose(pipef);
308 289
309 if (strchr(buf, '\n')) 290 if (strchr(buf, '\n'))
310 *strchr(buf, '\n') = 0; 291 *strchr(buf, '\n') = 0;
311 292
312 if (waitpid(child, NULL, 0) == -1) { 293 if (waitpid(child, NULL, 0) == -1) {
313 fprintf(stderr, "Waiting for child failed: %s\n", 294 fprintf(stderr, "Waiting for child failed: %s\n",
314 strerror(errno)); 295 strerror(errno));
315 exit(1); 296 exit(1);
316 } 297 }
317 298
318 /* Try password as it was presented */ 299 /* Try password as it was presented */
319 tmp = load_private_key(filename, buf, key, comment); 300 tmp = load_private_key(filename, buf, key, comment);
320 301
321 memset(buf, 0, sizeof(buf)); 302 memset(buf, 0, sizeof(buf));
322 303
323 return(tmp); 304 return(tmp);
324} 305}
325#endif /* USE_EXTERNAL_ASKPASS */ 306#endif /* USE_EXTERNAL_ASKPASS */
diff --git a/ssh-agent.c b/ssh-agent.c
index f1ceb5692..70c2a7f65 100644
--- a/ssh-agent.c
+++ b/ssh-agent.c
@@ -1,22 +1,15 @@
1/* $OpenBSD: ssh-agent.c,v 1.20 1999/11/19 10:20:51 markus Exp $ */ 1/* $OpenBSD: ssh-agent.c,v 1.22 1999/11/24 00:26:03 deraadt Exp $ */
2 2
3/* 3/*
4 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
5ssh-agent.c 5 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
6 6 * All rights reserved
7Author: Tatu Ylonen <ylo@cs.hut.fi> 7 * Created: Wed Mar 29 03:46:59 1995 ylo
8 8 * The authentication agent program.
9Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 9 */
10 All rights reserved
11
12Created: Wed Mar 29 03:46:59 1995 ylo
13
14The authentication agent program.
15
16*/
17 10
18#include "includes.h" 11#include "includes.h"
19RCSID("$OpenBSD: ssh-agent.c,v 1.20 1999/11/19 10:20:51 markus Exp $"); 12RCSID("$OpenBSD: ssh-agent.c,v 1.22 1999/11/24 00:26:03 deraadt Exp $");
20 13
21#include "ssh.h" 14#include "ssh.h"
22#include "rsa.h" 15#include "rsa.h"
@@ -35,27 +28,21 @@ RCSID("$OpenBSD: ssh-agent.c,v 1.20 1999/11/19 10:20:51 markus Exp $");
35#include <ssl/md5.h> 28#include <ssl/md5.h>
36#endif 29#endif
37 30
38#ifdef HAVE___PROGNAME 31typedef struct {
39extern char *__progname; 32 int fd;
40#else /* HAVE___PROGNAME */ 33 enum {
41const char *__progname = "ssh-agent"; 34 AUTH_UNUSED, AUTH_SOCKET, AUTH_CONNECTION
42#endif /* HAVE___PROGNAME */ 35 } type;
43 36 Buffer input;
44typedef struct 37 Buffer output;
45{
46 int fd;
47 enum { AUTH_UNUSED, AUTH_SOCKET, AUTH_CONNECTION } type;
48 Buffer input;
49 Buffer output;
50} SocketEntry; 38} SocketEntry;
51 39
52unsigned int sockets_alloc = 0; 40unsigned int sockets_alloc = 0;
53SocketEntry *sockets = NULL; 41SocketEntry *sockets = NULL;
54 42
55typedef struct 43typedef struct {
56{ 44 RSA *key;
57 RSA *key; 45 char *comment;
58 char *comment;
59} Identity; 46} Identity;
60 47
61unsigned int num_identities = 0; 48unsigned int num_identities = 0;
@@ -70,640 +57,601 @@ int parent_pid = -1;
70char socket_name[1024]; 57char socket_name[1024];
71char socket_dir[1024]; 58char socket_dir[1024];
72 59
60#ifdef HAVE___PROGNAME
61extern char *__progname;
62#else /* HAVE___PROGNAME */
63const char *__progname = "ssh-agent";
64#endif /* HAVE___PROGNAME */
65
73void 66void
74process_request_identity(SocketEntry *e) 67process_request_identity(SocketEntry *e)
75{ 68{
76 Buffer msg; 69 Buffer msg;
77 int i; 70 int i;
78 71
79 buffer_init(&msg); 72 buffer_init(&msg);
80 buffer_put_char(&msg, SSH_AGENT_RSA_IDENTITIES_ANSWER); 73 buffer_put_char(&msg, SSH_AGENT_RSA_IDENTITIES_ANSWER);
81 buffer_put_int(&msg, num_identities); 74 buffer_put_int(&msg, num_identities);
82 for (i = 0; i < num_identities; i++) 75 for (i = 0; i < num_identities; i++) {
83 { 76 buffer_put_int(&msg, BN_num_bits(identities[i].key->n));
84 buffer_put_int(&msg, BN_num_bits(identities[i].key->n)); 77 buffer_put_bignum(&msg, identities[i].key->e);
85 buffer_put_bignum(&msg, identities[i].key->e); 78 buffer_put_bignum(&msg, identities[i].key->n);
86 buffer_put_bignum(&msg, identities[i].key->n); 79 buffer_put_string(&msg, identities[i].comment,
87 buffer_put_string(&msg, identities[i].comment, 80 strlen(identities[i].comment));
88 strlen(identities[i].comment)); 81 }
89 } 82 buffer_put_int(&e->output, buffer_len(&msg));
90 buffer_put_int(&e->output, buffer_len(&msg)); 83 buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
91 buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg)); 84 buffer_free(&msg);
92 buffer_free(&msg);
93} 85}
94 86
95void 87void
96process_authentication_challenge(SocketEntry *e) 88process_authentication_challenge(SocketEntry *e)
97{ 89{
98 int i, pub_bits, len; 90 int i, pub_bits, len;
99 BIGNUM *pub_e, *pub_n, *challenge; 91 BIGNUM *pub_e, *pub_n, *challenge;
100 Buffer msg; 92 Buffer msg;
101 MD5_CTX md; 93 MD5_CTX md;
102 unsigned char buf[32], mdbuf[16], session_id[16]; 94 unsigned char buf[32], mdbuf[16], session_id[16];
103 unsigned int response_type; 95 unsigned int response_type;
104 96
105 buffer_init(&msg); 97 buffer_init(&msg);
106 pub_e = BN_new(); 98 pub_e = BN_new();
107 pub_n = BN_new(); 99 pub_n = BN_new();
108 challenge = BN_new(); 100 challenge = BN_new();
109 pub_bits = buffer_get_int(&e->input); 101 pub_bits = buffer_get_int(&e->input);
110 buffer_get_bignum(&e->input, pub_e); 102 buffer_get_bignum(&e->input, pub_e);
111 buffer_get_bignum(&e->input, pub_n); 103 buffer_get_bignum(&e->input, pub_n);
112 buffer_get_bignum(&e->input, challenge); 104 buffer_get_bignum(&e->input, challenge);
113 if (buffer_len(&e->input) == 0) 105 if (buffer_len(&e->input) == 0) {
114 { 106 /* Compatibility code for old servers. */
115 /* Compatibility code for old servers. */ 107 memset(session_id, 0, 16);
116 memset(session_id, 0, 16); 108 response_type = 0;
117 response_type = 0; 109 } else {
118 } 110 /* New code. */
119 else 111 buffer_get(&e->input, (char *) session_id, 16);
120 { 112 response_type = buffer_get_int(&e->input);
121 /* New code. */ 113 }
122 buffer_get(&e->input, (char *)session_id, 16); 114 for (i = 0; i < num_identities; i++)
123 response_type = buffer_get_int(&e->input); 115 if (pub_bits == BN_num_bits(identities[i].key->n) &&
124 } 116 BN_cmp(pub_e, identities[i].key->e) == 0 &&
125 for (i = 0; i < num_identities; i++) 117 BN_cmp(pub_n, identities[i].key->n) == 0) {
126 if (pub_bits == BN_num_bits(identities[i].key->n) && 118 /* Decrypt the challenge using the private key. */
127 BN_cmp(pub_e, identities[i].key->e) == 0 && 119 rsa_private_decrypt(challenge, challenge, identities[i].key);
128 BN_cmp(pub_n, identities[i].key->n) == 0) 120
129 { 121 /* Compute the desired response. */
130 /* Decrypt the challenge using the private key. */ 122 switch (response_type) {
131 rsa_private_decrypt(challenge, challenge, identities[i].key); 123 case 0:/* As of protocol 1.0 */
132 124 /* This response type is no longer supported. */
133 /* Compute the desired response. */ 125 log("Compatibility with ssh protocol 1.0 no longer supported.");
134 switch (response_type) 126 buffer_put_char(&msg, SSH_AGENT_FAILURE);
135 { 127 goto send;
136 case 0: /* As of protocol 1.0 */ 128
137 /* This response type is no longer supported. */ 129 case 1:/* As of protocol 1.1 */
138 log("Compatibility with ssh protocol 1.0 no longer supported."); 130 /* The response is MD5 of decrypted challenge plus session id. */
139 buffer_put_char(&msg, SSH_AGENT_FAILURE); 131 len = BN_num_bytes(challenge);
140 goto send; 132
141 133 if (len <= 0 || len > 32) {
142 case 1: /* As of protocol 1.1 */ 134 fatal("process_authentication_challenge: "
143 /* The response is MD5 of decrypted challenge plus session id. */ 135 "bad challenge length %d", len);
144 len = BN_num_bytes(challenge); 136 }
145 137 memset(buf, 0, 32);
146 if (len <= 0 || len > 32) { 138 BN_bn2bin(challenge, buf + 32 - len);
147 fatal("process_authentication_challenge: " 139 MD5_Init(&md);
148 "bad challenge length %d", len); 140 MD5_Update(&md, buf, 32);
149 } 141 MD5_Update(&md, session_id, 16);
150 142 MD5_Final(mdbuf, &md);
151 memset(buf, 0, 32); 143 break;
152 BN_bn2bin(challenge, buf + 32 - len); 144
153 MD5_Init(&md); 145 default:
154 MD5_Update(&md, buf, 32); 146 fatal("process_authentication_challenge: bad response_type %d",
155 MD5_Update(&md, session_id, 16); 147 response_type);
156 MD5_Final(mdbuf, &md); 148 break;
157 break; 149 }
158 150
159 default: 151 /* Send the response. */
160 fatal("process_authentication_challenge: bad response_type %d", 152 buffer_put_char(&msg, SSH_AGENT_RSA_RESPONSE);
161 response_type); 153 for (i = 0; i < 16; i++)
162 break; 154 buffer_put_char(&msg, mdbuf[i]);
163 } 155
164 156 goto send;
165 /* Send the response. */ 157 }
166 buffer_put_char(&msg, SSH_AGENT_RSA_RESPONSE); 158 /* Unknown identity. Send failure. */
167 for (i = 0; i < 16; i++) 159 buffer_put_char(&msg, SSH_AGENT_FAILURE);
168 buffer_put_char(&msg, mdbuf[i]); 160send:
169 161 buffer_put_int(&e->output, buffer_len(&msg));
170 goto send; 162 buffer_append(&e->output, buffer_ptr(&msg),
171 } 163 buffer_len(&msg));
172 /* Unknown identity. Send failure. */ 164 buffer_free(&msg);
173 buffer_put_char(&msg, SSH_AGENT_FAILURE); 165 BN_clear_free(pub_e);
174 send: 166 BN_clear_free(pub_n);
175 buffer_put_int(&e->output, buffer_len(&msg)); 167 BN_clear_free(challenge);
176 buffer_append(&e->output, buffer_ptr(&msg),
177 buffer_len(&msg));
178 buffer_free(&msg);
179 BN_clear_free(pub_e);
180 BN_clear_free(pub_n);
181 BN_clear_free(challenge);
182} 168}
183 169
184void 170void
185process_remove_identity(SocketEntry *e) 171process_remove_identity(SocketEntry *e)
186{ 172{
187 unsigned int bits; 173 unsigned int bits;
188 unsigned int i; 174 unsigned int i;
189 BIGNUM *dummy, *n; 175 BIGNUM *dummy, *n;
190 176
191 dummy = BN_new(); 177 dummy = BN_new();
192 n = BN_new(); 178 n = BN_new();
193 179
194 /* Get the key from the packet. */ 180 /* Get the key from the packet. */
195 bits = buffer_get_int(&e->input); 181 bits = buffer_get_int(&e->input);
196 buffer_get_bignum(&e->input, dummy); 182 buffer_get_bignum(&e->input, dummy);
197 buffer_get_bignum(&e->input, n); 183 buffer_get_bignum(&e->input, n);
198 184
199 if (bits != BN_num_bits(n)) 185 if (bits != BN_num_bits(n))
200 error("Warning: keysize mismatch: actual %d, announced %d", 186 error("Warning: keysize mismatch: actual %d, announced %d",
201 BN_num_bits(n), bits); 187 BN_num_bits(n), bits);
202 188
203 /* Check if we have the key. */ 189 /* Check if we have the key. */
204 for (i = 0; i < num_identities; i++) 190 for (i = 0; i < num_identities; i++)
205 if (BN_cmp(identities[i].key->n, n) == 0) 191 if (BN_cmp(identities[i].key->n, n) == 0) {
206 { 192 /* We have this key. Free the old key. Since we
207 /* We have this key. Free the old key. Since we don\'t want to leave 193 don\'t want to leave empty slots in the middle
208 empty slots in the middle of the array, we actually free the 194 of the array, we actually free the key there
209 key there and copy data from the last entry. */ 195 and copy data from the last entry. */
210 RSA_free(identities[i].key); 196 RSA_free(identities[i].key);
211 xfree(identities[i].comment); 197 xfree(identities[i].comment);
212 if (i < num_identities - 1) 198 if (i < num_identities - 1)
213 identities[i] = identities[num_identities - 1]; 199 identities[i] = identities[num_identities - 1];
214 num_identities--; 200 num_identities--;
215 BN_clear_free(dummy); 201 BN_clear_free(dummy);
216 BN_clear_free(n); 202 BN_clear_free(n);
217 203
218 /* Send success. */ 204 /* Send success. */
205 buffer_put_int(&e->output, 1);
206 buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
207 return;
208 }
209 /* We did not have the key. */
210 BN_clear(dummy);
211 BN_clear(n);
212
213 /* Send failure. */
219 buffer_put_int(&e->output, 1); 214 buffer_put_int(&e->output, 1);
220 buffer_put_char(&e->output, SSH_AGENT_SUCCESS); 215 buffer_put_char(&e->output, SSH_AGENT_FAILURE);
221 return;
222 }
223 /* We did not have the key. */
224 BN_clear(dummy);
225 BN_clear(n);
226
227 /* Send failure. */
228 buffer_put_int(&e->output, 1);
229 buffer_put_char(&e->output, SSH_AGENT_FAILURE);
230} 216}
231 217
232/* Removes all identities from the agent. */ 218/*
233 219 * Removes all identities from the agent.
220 */
234void 221void
235process_remove_all_identities(SocketEntry *e) 222process_remove_all_identities(SocketEntry *e)
236{ 223{
237 unsigned int i; 224 unsigned int i;
238
239 /* Loop over all identities and clear the keys. */
240 for (i = 0; i < num_identities; i++)
241 {
242 RSA_free(identities[i].key);
243 xfree(identities[i].comment);
244 }
245
246 /* Mark that there are no identities. */
247 num_identities = 0;
248
249 /* Send success. */
250 buffer_put_int(&e->output, 1);
251 buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
252 return;
253}
254 225
255/* Adds an identity to the agent. */ 226 /* Loop over all identities and clear the keys. */
227 for (i = 0; i < num_identities; i++) {
228 RSA_free(identities[i].key);
229 xfree(identities[i].comment);
230 }
256 231
257void 232 /* Mark that there are no identities. */
258process_add_identity(SocketEntry *e) 233 num_identities = 0;
259{
260 RSA *k;
261 int i;
262 BIGNUM *aux;
263 BN_CTX *ctx;
264
265 if (num_identities == 0)
266 identities = xmalloc(sizeof(Identity));
267 else
268 identities = xrealloc(identities, (num_identities + 1) * sizeof(Identity));
269
270 identities[num_identities].key = RSA_new();
271 k = identities[num_identities].key;
272 buffer_get_int(&e->input); /* bits */
273 k->n = BN_new();
274 buffer_get_bignum(&e->input, k->n);
275 k->e = BN_new();
276 buffer_get_bignum(&e->input, k->e);
277 k->d = BN_new();
278 buffer_get_bignum(&e->input, k->d);
279 k->iqmp = BN_new();
280 buffer_get_bignum(&e->input, k->iqmp);
281 /* SSH and SSL have p and q swapped */
282 k->q = BN_new();
283 buffer_get_bignum(&e->input, k->q); /* p */
284 k->p = BN_new();
285 buffer_get_bignum(&e->input, k->p); /* q */
286
287 /* Generate additional parameters */
288 aux = BN_new();
289 ctx = BN_CTX_new();
290
291 BN_sub(aux, k->q, BN_value_one());
292 k->dmq1 = BN_new();
293 BN_mod(k->dmq1, k->d, aux, ctx);
294
295 BN_sub(aux, k->p, BN_value_one());
296 k->dmp1 = BN_new();
297 BN_mod(k->dmp1, k->d, aux, ctx);
298
299 BN_clear_free(aux);
300 BN_CTX_free(ctx);
301
302 identities[num_identities].comment = buffer_get_string(&e->input, NULL);
303
304 /* Check if we already have the key. */
305 for (i = 0; i < num_identities; i++)
306 if (BN_cmp(identities[i].key->n, k->n) == 0)
307 {
308 /* We already have this key. Clear and free the new data and
309 return success. */
310 RSA_free(k);
311 xfree(identities[num_identities].comment);
312 234
313 /* Send success. */ 235 /* Send success. */
314 buffer_put_int(&e->output, 1); 236 buffer_put_int(&e->output, 1);
315 buffer_put_char(&e->output, SSH_AGENT_SUCCESS); 237 buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
316 return; 238 return;
317 } 239}
318 240
319 /* Increment the number of identities. */ 241/*
320 num_identities++; 242 * Adds an identity to the agent.
321 243 */
322 /* Send a success message. */ 244void
323 buffer_put_int(&e->output, 1); 245process_add_identity(SocketEntry *e)
324 buffer_put_char(&e->output, SSH_AGENT_SUCCESS); 246{
247 RSA *k;
248 int i;
249 BIGNUM *aux;
250 BN_CTX *ctx;
251
252 if (num_identities == 0)
253 identities = xmalloc(sizeof(Identity));
254 else
255 identities = xrealloc(identities, (num_identities + 1) * sizeof(Identity));
256
257 identities[num_identities].key = RSA_new();
258 k = identities[num_identities].key;
259 buffer_get_int(&e->input); /* bits */
260 k->n = BN_new();
261 buffer_get_bignum(&e->input, k->n);
262 k->e = BN_new();
263 buffer_get_bignum(&e->input, k->e);
264 k->d = BN_new();
265 buffer_get_bignum(&e->input, k->d);
266 k->iqmp = BN_new();
267 buffer_get_bignum(&e->input, k->iqmp);
268 /* SSH and SSL have p and q swapped */
269 k->q = BN_new();
270 buffer_get_bignum(&e->input, k->q); /* p */
271 k->p = BN_new();
272 buffer_get_bignum(&e->input, k->p); /* q */
273
274 /* Generate additional parameters */
275 aux = BN_new();
276 ctx = BN_CTX_new();
277
278 BN_sub(aux, k->q, BN_value_one());
279 k->dmq1 = BN_new();
280 BN_mod(k->dmq1, k->d, aux, ctx);
281
282 BN_sub(aux, k->p, BN_value_one());
283 k->dmp1 = BN_new();
284 BN_mod(k->dmp1, k->d, aux, ctx);
285
286 BN_clear_free(aux);
287 BN_CTX_free(ctx);
288
289 identities[num_identities].comment = buffer_get_string(&e->input, NULL);
290
291 /* Check if we already have the key. */
292 for (i = 0; i < num_identities; i++)
293 if (BN_cmp(identities[i].key->n, k->n) == 0) {
294 /* We already have this key. Clear and free the
295 new data and return success. */
296 RSA_free(k);
297 xfree(identities[num_identities].comment);
298
299 /* Send success. */
300 buffer_put_int(&e->output, 1);
301 buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
302 return;
303 }
304 /* Increment the number of identities. */
305 num_identities++;
306
307 /* Send a success message. */
308 buffer_put_int(&e->output, 1);
309 buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
325} 310}
326 311
327void 312void
328process_message(SocketEntry *e) 313process_message(SocketEntry *e)
329{ 314{
330 unsigned int msg_len; 315 unsigned int msg_len;
331 unsigned int type; 316 unsigned int type;
332 unsigned char *cp; 317 unsigned char *cp;
333 if (buffer_len(&e->input) < 5) 318 if (buffer_len(&e->input) < 5)
334 return; /* Incomplete message. */ 319 return; /* Incomplete message. */
335 cp = (unsigned char *)buffer_ptr(&e->input); 320 cp = (unsigned char *) buffer_ptr(&e->input);
336 msg_len = GET_32BIT(cp); 321 msg_len = GET_32BIT(cp);
337 if (msg_len > 256 * 1024) 322 if (msg_len > 256 * 1024) {
338 { 323 shutdown(e->fd, SHUT_RDWR);
339 shutdown(e->fd, SHUT_RDWR); 324 close(e->fd);
340 close(e->fd); 325 e->type = AUTH_UNUSED;
341 e->type = AUTH_UNUSED; 326 return;
342 return; 327 }
343 } 328 if (buffer_len(&e->input) < msg_len + 4)
344 if (buffer_len(&e->input) < msg_len + 4) 329 return;
345 return; 330 buffer_consume(&e->input, 4);
346 buffer_consume(&e->input, 4); 331 type = buffer_get_char(&e->input);
347 type = buffer_get_char(&e->input); 332
348 333 switch (type) {
349 switch (type) 334 case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
350 { 335 process_request_identity(e);
351 case SSH_AGENTC_REQUEST_RSA_IDENTITIES: 336 break;
352 process_request_identity(e); 337 case SSH_AGENTC_RSA_CHALLENGE:
353 break; 338 process_authentication_challenge(e);
354 case SSH_AGENTC_RSA_CHALLENGE: 339 break;
355 process_authentication_challenge(e); 340 case SSH_AGENTC_ADD_RSA_IDENTITY:
356 break; 341 process_add_identity(e);
357 case SSH_AGENTC_ADD_RSA_IDENTITY: 342 break;
358 process_add_identity(e); 343 case SSH_AGENTC_REMOVE_RSA_IDENTITY:
359 break; 344 process_remove_identity(e);
360 case SSH_AGENTC_REMOVE_RSA_IDENTITY: 345 break;
361 process_remove_identity(e); 346 case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
362 break; 347 process_remove_all_identities(e);
363 case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES: 348 break;
364 process_remove_all_identities(e); 349 default:
365 break; 350 /* Unknown message. Respond with failure. */
366 default: 351 error("Unknown message %d", type);
367 /* Unknown message. Respond with failure. */ 352 buffer_clear(&e->input);
368 error("Unknown message %d", type); 353 buffer_put_int(&e->output, 1);
369 buffer_clear(&e->input); 354 buffer_put_char(&e->output, SSH_AGENT_FAILURE);
370 buffer_put_int(&e->output, 1); 355 break;
371 buffer_put_char(&e->output, SSH_AGENT_FAILURE); 356 }
372 break;
373 }
374} 357}
375 358
376void 359void
377new_socket(int type, int fd) 360new_socket(int type, int fd)
378{ 361{
379 unsigned int i, old_alloc; 362 unsigned int i, old_alloc;
380 if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) 363 if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
381 error("fcntl O_NONBLOCK: %s", strerror(errno)); 364 error("fcntl O_NONBLOCK: %s", strerror(errno));
382 365
383 if (fd > max_fd) 366 if (fd > max_fd)
384 max_fd = fd; 367 max_fd = fd;
385 368
386 for (i = 0; i < sockets_alloc; i++) 369 for (i = 0; i < sockets_alloc; i++)
387 if (sockets[i].type == AUTH_UNUSED) 370 if (sockets[i].type == AUTH_UNUSED) {
388 { 371 sockets[i].fd = fd;
389 sockets[i].fd = fd; 372 sockets[i].type = type;
390 sockets[i].type = type; 373 buffer_init(&sockets[i].input);
391 buffer_init(&sockets[i].input); 374 buffer_init(&sockets[i].output);
392 buffer_init(&sockets[i].output); 375 return;
393 return; 376 }
394 } 377 old_alloc = sockets_alloc;
395 old_alloc = sockets_alloc; 378 sockets_alloc += 10;
396 sockets_alloc += 10; 379 if (sockets)
397 if (sockets) 380 sockets = xrealloc(sockets, sockets_alloc * sizeof(sockets[0]));
398 sockets = xrealloc(sockets, sockets_alloc * sizeof(sockets[0])); 381 else
399 else 382 sockets = xmalloc(sockets_alloc * sizeof(sockets[0]));
400 sockets = xmalloc(sockets_alloc * sizeof(sockets[0])); 383 for (i = old_alloc; i < sockets_alloc; i++)
401 for (i = old_alloc; i < sockets_alloc; i++) 384 sockets[i].type = AUTH_UNUSED;
402 sockets[i].type = AUTH_UNUSED; 385 sockets[old_alloc].type = type;
403 sockets[old_alloc].type = type; 386 sockets[old_alloc].fd = fd;
404 sockets[old_alloc].fd = fd; 387 buffer_init(&sockets[old_alloc].input);
405 buffer_init(&sockets[old_alloc].input); 388 buffer_init(&sockets[old_alloc].output);
406 buffer_init(&sockets[old_alloc].output);
407} 389}
408 390
409void 391void
410prepare_select(fd_set *readset, fd_set *writeset) 392prepare_select(fd_set *readset, fd_set *writeset)
411{ 393{
412 unsigned int i; 394 unsigned int i;
413 for (i = 0; i < sockets_alloc; i++) 395 for (i = 0; i < sockets_alloc; i++)
414 switch (sockets[i].type) 396 switch (sockets[i].type) {
415 { 397 case AUTH_SOCKET:
416 case AUTH_SOCKET: 398 case AUTH_CONNECTION:
417 case AUTH_CONNECTION: 399 FD_SET(sockets[i].fd, readset);
418 FD_SET(sockets[i].fd, readset); 400 if (buffer_len(&sockets[i].output) > 0)
419 if (buffer_len(&sockets[i].output) > 0) 401 FD_SET(sockets[i].fd, writeset);
420 FD_SET(sockets[i].fd, writeset); 402 break;
421 break; 403 case AUTH_UNUSED:
422 case AUTH_UNUSED: 404 break;
423 break; 405 default:
424 default: 406 fatal("Unknown socket type %d", sockets[i].type);
425 fatal("Unknown socket type %d", sockets[i].type); 407 break;
426 break; 408 }
427 }
428} 409}
429 410
430void after_select(fd_set *readset, fd_set *writeset) 411void
412after_select(fd_set *readset, fd_set *writeset)
431{ 413{
432 unsigned int i; 414 unsigned int i;
433 int len, sock; 415 int len, sock;
434 char buf[1024]; 416 char buf[1024];
435 struct sockaddr_un sunaddr; 417 struct sockaddr_un sunaddr;
436 418
437 for (i = 0; i < sockets_alloc; i++) 419 for (i = 0; i < sockets_alloc; i++)
438 switch (sockets[i].type) 420 switch (sockets[i].type) {
439 { 421 case AUTH_UNUSED:
440 case AUTH_UNUSED: 422 break;
441 break; 423 case AUTH_SOCKET:
442 case AUTH_SOCKET: 424 if (FD_ISSET(sockets[i].fd, readset)) {
443 if (FD_ISSET(sockets[i].fd, readset)) 425 len = sizeof(sunaddr);
444 { 426 sock = accept(sockets[i].fd, (struct sockaddr *) & sunaddr, &len);
445 len = sizeof(sunaddr); 427 if (sock < 0) {
446 sock = accept(sockets[i].fd, (struct sockaddr *)&sunaddr, &len); 428 perror("accept from AUTH_SOCKET");
447 if (sock < 0) 429 break;
448 { 430 }
449 perror("accept from AUTH_SOCKET"); 431 new_socket(AUTH_CONNECTION, sock);
450 break; 432 }
451 } 433 break;
452 new_socket(AUTH_CONNECTION, sock); 434 case AUTH_CONNECTION:
453 } 435 if (buffer_len(&sockets[i].output) > 0 &&
454 break; 436 FD_ISSET(sockets[i].fd, writeset)) {
455 case AUTH_CONNECTION: 437 len = write(sockets[i].fd, buffer_ptr(&sockets[i].output),
456 if (buffer_len(&sockets[i].output) > 0 && 438 buffer_len(&sockets[i].output));
457 FD_ISSET(sockets[i].fd, writeset)) 439 if (len <= 0) {
458 { 440 shutdown(sockets[i].fd, SHUT_RDWR);
459 len = write(sockets[i].fd, buffer_ptr(&sockets[i].output), 441 close(sockets[i].fd);
460 buffer_len(&sockets[i].output)); 442 sockets[i].type = AUTH_UNUSED;
461 if (len <= 0) 443 break;
462 { 444 }
463 shutdown(sockets[i].fd, SHUT_RDWR); 445 buffer_consume(&sockets[i].output, len);
464 close(sockets[i].fd); 446 }
465 sockets[i].type = AUTH_UNUSED; 447 if (FD_ISSET(sockets[i].fd, readset)) {
466 break; 448 len = read(sockets[i].fd, buf, sizeof(buf));
467 } 449 if (len <= 0) {
468 buffer_consume(&sockets[i].output, len); 450 shutdown(sockets[i].fd, SHUT_RDWR);
469 } 451 close(sockets[i].fd);
470 if (FD_ISSET(sockets[i].fd, readset)) 452 sockets[i].type = AUTH_UNUSED;
471 { 453 break;
472 len = read(sockets[i].fd, buf, sizeof(buf)); 454 }
473 if (len <= 0) 455 buffer_append(&sockets[i].input, buf, len);
474 { 456 process_message(&sockets[i]);
475 shutdown(sockets[i].fd, SHUT_RDWR); 457 }
476 close(sockets[i].fd); 458 break;
477 sockets[i].type = AUTH_UNUSED; 459 default:
478 break; 460 fatal("Unknown type %d", sockets[i].type);
479 } 461 }
480 buffer_append(&sockets[i].input, buf, len);
481 process_message(&sockets[i]);
482 }
483 break;
484 default:
485 fatal("Unknown type %d", sockets[i].type);
486 }
487} 462}
488 463
489void 464void
490check_parent_exists(int sig) 465check_parent_exists(int sig)
491{ 466{
492 if (kill(parent_pid, 0) < 0) 467 if (kill(parent_pid, 0) < 0) {
493 { 468 /* printf("Parent has died - Authentication agent exiting.\n"); */
494 /* printf("Parent has died - Authentication agent exiting.\n"); */ 469 exit(1);
495 exit(1); 470 }
496 } 471 signal(SIGALRM, check_parent_exists);
497 signal(SIGALRM, check_parent_exists); 472 alarm(10);
498 alarm(10);
499} 473}
500 474
501void 475void
502cleanup_socket(void) 476cleanup_socket(void)
503{ 477{
504 remove(socket_name); 478 remove(socket_name);
505 rmdir(socket_dir); 479 rmdir(socket_dir);
506} 480}
507 481
508void 482void
509cleanup_exit(int i) 483cleanup_exit(int i)
510{ 484{
511 cleanup_socket(); 485 cleanup_socket();
512 exit(i); 486 exit(i);
513} 487}
514 488
515void 489void
516usage() 490usage()
517{ 491{
518 fprintf(stderr, "ssh-agent version %s\n", SSH_VERSION); 492 fprintf(stderr, "ssh-agent version %s\n", SSH_VERSION);
519 fprintf(stderr, "Usage: %s [-c | -s] [-k] [command {args...]]\n", 493 fprintf(stderr, "Usage: %s [-c | -s] [-k] [command {args...]]\n",
520 __progname); 494 __progname);
521 exit(1); 495 exit(1);
522} 496}
523 497
524int 498int
525main(int ac, char **av) 499main(int ac, char **av)
526{ 500{
527 fd_set readset, writeset; 501 fd_set readset, writeset;
528 int sock, c_flag = 0, k_flag = 0, s_flag = 0, ch; 502 int sock, c_flag = 0, k_flag = 0, s_flag = 0, ch;
529 struct sockaddr_un sunaddr; 503 struct sockaddr_un sunaddr;
530 pid_t pid; 504 pid_t pid;
531 char *shell, *format, *pidstr, pidstrbuf[1 + 3 * sizeof pid]; 505 char *shell, *format, *pidstr, pidstrbuf[1 + 3 * sizeof pid];
532 506
533 /* check if RSA support exists */ 507 /* check if RSA support exists */
534 if (rsa_alive() == 0) { 508 if (rsa_alive() == 0) {
535 fprintf(stderr, 509 fprintf(stderr,
536 "%s: no RSA support in libssl and libcrypto. See ssl(8).\n", 510 "%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
537 __progname); 511 __progname);
538 exit(1); 512 exit(1);
539 } 513 }
540
541#if defined(__GNU_LIBRARY__) 514#if defined(__GNU_LIBRARY__)
542 while ((ch = getopt(ac, av, "+cks")) != -1) 515 while ((ch = getopt(ac, av, "+cks")) != -1) {
543#else 516#else
544 while ((ch = getopt(ac, av, "cks")) != -1) 517 while ((ch = getopt(ac, av, "cks")) != -1) {
545#endif /* defined(__GNU_LIBRARY__) */ 518#endif /* defined(__GNU_LIBRARY__) */
546 { 519 switch (ch) {
547 switch (ch) 520 case 'c':
548 { 521 if (s_flag)
549 case 'c': 522 usage();
550 if (s_flag) 523 c_flag++;
551 usage(); 524 break;
552 c_flag++; 525 case 'k':
553 break; 526 k_flag++;
554 case 'k': 527 break;
555 k_flag++; 528 case 's':
556 break; 529 if (c_flag)
557 case 's': 530 usage();
558 if (c_flag) 531 s_flag++;
559 usage(); 532 break;
560 s_flag++; 533 default:
561 break; 534 usage();
562 default: 535 }
563 usage();
564 } 536 }
565 } 537 ac -= optind;
566 ac -= optind; 538 av += optind;
567 av += optind; 539
568 540 if (ac > 0 && (c_flag || k_flag || s_flag))
569 if (ac > 0 && (c_flag || k_flag || s_flag)) 541 usage();
570 usage(); 542
571 543 if (ac == 0 && !c_flag && !k_flag && !s_flag) {
572 if (ac == 0 && !c_flag && !k_flag && !s_flag) 544 shell = getenv("SHELL");
573 { 545 if (shell != NULL && strncmp(shell + strlen(shell) - 3, "csh", 3) == 0)
574 shell = getenv("SHELL"); 546 c_flag = 1;
575 if (shell != NULL && strncmp(shell + strlen(shell) - 3, "csh", 3) == 0)
576 c_flag = 1;
577 }
578
579 if (k_flag)
580 {
581 pidstr = getenv(SSH_AGENTPID_ENV_NAME);
582 if (pidstr == NULL)
583 {
584 fprintf(stderr, "%s not set, cannot kill agent\n",
585 SSH_AGENTPID_ENV_NAME);
586 exit(1);
587 } 547 }
588 pid = atoi(pidstr); 548 if (k_flag) {
589 if (pid < 1) /* XXX PID_MAX check too */ 549 pidstr = getenv(SSH_AGENTPID_ENV_NAME);
590 { 550 if (pidstr == NULL) {
591 fprintf(stderr, "%s=\"%s\", which is not a good PID\n", 551 fprintf(stderr, "%s not set, cannot kill agent\n",
592 SSH_AGENTPID_ENV_NAME, pidstr); 552 SSH_AGENTPID_ENV_NAME);
593 exit(1); 553 exit(1);
554 }
555 pid = atoi(pidstr);
556 if (pid < 1) { /* XXX PID_MAX check too */
557 fprintf(stderr, "%s=\"%s\", which is not a good PID\n",
558 SSH_AGENTPID_ENV_NAME, pidstr);
559 exit(1);
560 }
561 if (kill(pid, SIGTERM) == -1) {
562 perror("kill");
563 exit(1);
564 }
565 format = c_flag ? "unsetenv %s;\n" : "unset %s;\n";
566 printf(format, SSH_AUTHSOCKET_ENV_NAME);
567 printf(format, SSH_AGENTPID_ENV_NAME);
568 printf("echo Agent pid %d killed;\n", pid);
569 exit(0);
594 } 570 }
595 if (kill(pid, SIGTERM) == -1) 571 parent_pid = getpid();
596 { 572
597 perror("kill"); 573 /* Create private directory for agent socket */
598 exit(1); 574 strlcpy(socket_dir, "/tmp/ssh-XXXXXXXX", sizeof socket_dir);
575 if (mkdtemp(socket_dir) == NULL) {
576 perror("mkdtemp: private socket dir");
577 exit(1);
578 }
579 snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir,
580 parent_pid);
581
582 /* Create socket early so it will exist before command gets run
583 from the parent. */
584 sock = socket(AF_UNIX, SOCK_STREAM, 0);
585 if (sock < 0) {
586 perror("socket");
587 cleanup_exit(1);
588 }
589 memset(&sunaddr, 0, sizeof(sunaddr));
590 sunaddr.sun_family = AF_UNIX;
591 strlcpy(sunaddr.sun_path, socket_name, sizeof(sunaddr.sun_path));
592 if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) {
593 perror("bind");
594 cleanup_exit(1);
595 }
596 if (listen(sock, 5) < 0) {
597 perror("listen");
598 cleanup_exit(1);
599 } 599 }
600 format = c_flag ? "unsetenv %s;\n" : "unset %s;\n"; 600 /* Fork, and have the parent execute the command, if any, or
601 printf(format, SSH_AUTHSOCKET_ENV_NAME); 601 present the socket data. The child continues as the
602 printf(format, SSH_AGENTPID_ENV_NAME); 602 authentication agent. */
603 printf("echo Agent pid %d killed;\n", pid); 603 pid = fork();
604 exit(0); 604 if (pid == -1) {
605 } 605 perror("fork");
606 606 exit(1);
607 parent_pid = getpid();
608
609 /* Create private directory for agent socket */
610 strlcpy(socket_dir, "/tmp/ssh-XXXXXXXX", sizeof socket_dir);
611 if (mkdtemp(socket_dir) == NULL) {
612 perror("mkdtemp: private socket dir");
613 exit(1);
614 }
615 snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir,
616 parent_pid);
617
618 /* Create socket early so it will exist before command gets run from
619 the parent. */
620 sock = socket(AF_UNIX, SOCK_STREAM, 0);
621 if (sock < 0)
622 {
623 perror("socket");
624 cleanup_exit(1);
625 }
626 memset(&sunaddr, 0, sizeof(sunaddr));
627 sunaddr.sun_family = AF_UNIX;
628 strlcpy(sunaddr.sun_path, socket_name, sizeof(sunaddr.sun_path));
629 if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0)
630 {
631 perror("bind");
632 cleanup_exit(1);
633 }
634 if (listen(sock, 5) < 0)
635 {
636 perror("listen");
637 cleanup_exit(1);
638 }
639
640 /* Fork, and have the parent execute the command, if any, or present the
641 socket data. The child continues as the authentication agent. */
642 pid = fork();
643 if (pid == -1)
644 {
645 perror("fork");
646 exit(1);
647 }
648 if (pid != 0)
649 { /* Parent - execute the given command. */
650 close(sock);
651 snprintf(pidstrbuf, sizeof pidstrbuf, "%d", pid);
652 if (ac == 0)
653 {
654 format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
655 printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
656 SSH_AUTHSOCKET_ENV_NAME);
657 printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf,
658 SSH_AGENTPID_ENV_NAME);
659 printf("echo Agent pid %d;\n", pid);
660 exit(0);
661 } 607 }
608 if (pid != 0) { /* Parent - execute the given command. */
609 close(sock);
610 snprintf(pidstrbuf, sizeof pidstrbuf, "%d", pid);
611 if (ac == 0) {
612 format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
613 printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
614 SSH_AUTHSOCKET_ENV_NAME);
615 printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf,
616 SSH_AGENTPID_ENV_NAME);
617 printf("echo Agent pid %d;\n", pid);
618 exit(0);
619 }
620 setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1);
621 setenv(SSH_AGENTPID_ENV_NAME, pidstrbuf, 1);
622 execvp(av[0], av);
623 perror(av[0]);
624 exit(1);
625 }
626 close(0);
627 close(1);
628 close(2);
662 629
663 setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1); 630 if (setsid() == -1) {
664 setenv(SSH_AGENTPID_ENV_NAME, pidstrbuf, 1); 631 perror("setsid");
665 execvp(av[0], av); 632 cleanup_exit(1);
666 perror(av[0]); 633 }
667 exit(1); 634 if (atexit(cleanup_socket) < 0) {
668 } 635 perror("atexit");
669 636 cleanup_exit(1);
670 close(0); 637 }
671 close(1); 638 new_socket(AUTH_SOCKET, sock);
672 close(2); 639 if (ac > 0) {
673 640 signal(SIGALRM, check_parent_exists);
674 if (setsid() == -1) 641 alarm(10);
675 { 642 }
676 perror("setsid"); 643 signal(SIGINT, SIG_IGN);
677 cleanup_exit(1); 644 signal(SIGPIPE, SIG_IGN);
678 } 645 while (1) {
679 646 FD_ZERO(&readset);
680 if (atexit(cleanup_socket) < 0) 647 FD_ZERO(&writeset);
681 { 648 prepare_select(&readset, &writeset);
682 perror("atexit"); 649 if (select(max_fd + 1, &readset, &writeset, NULL, NULL) < 0) {
683 cleanup_exit(1); 650 if (errno == EINTR)
684 } 651 continue;
685 652 exit(1);
686 new_socket(AUTH_SOCKET, sock); 653 }
687 if (ac > 0) 654 after_select(&readset, &writeset);
688 {
689 signal(SIGALRM, check_parent_exists);
690 alarm(10);
691 }
692
693 signal(SIGINT, SIG_IGN);
694 signal(SIGPIPE, SIG_IGN);
695 while (1)
696 {
697 FD_ZERO(&readset);
698 FD_ZERO(&writeset);
699 prepare_select(&readset, &writeset);
700 if (select(max_fd + 1, &readset, &writeset, NULL, NULL) < 0)
701 {
702 if (errno == EINTR)
703 continue;
704 exit(1);
705 } 655 }
706 after_select(&readset, &writeset); 656 /* NOTREACHED */
707 }
708 /*NOTREACHED*/
709} 657}
diff --git a/ssh-keygen.c b/ssh-keygen.c
index 47e1cca07..6f2d426b8 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -1,32 +1,19 @@
1/* 1/*
2 2 * Author: Tatu Ylonen <ylo@cs.hut.fi>
3ssh-keygen.c 3 * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 4 * All rights reserved
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Created: Mon Mar 27 02:26:40 1995 ylo
6 6 * Identity and host key generation and maintenance.
7Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 */
8 All rights reserved
9
10Created: Mon Mar 27 02:26:40 1995 ylo
11
12Identity and host key generation and maintenance.
13
14*/
15 8
16#include "includes.h" 9#include "includes.h"
17RCSID("$Id: ssh-keygen.c,v 1.8 1999/11/22 02:22:29 damien Exp $"); 10RCSID("$Id: ssh-keygen.c,v 1.9 1999/11/24 13:26:23 damien Exp $");
18 11
19#include "rsa.h" 12#include "rsa.h"
20#include "ssh.h" 13#include "ssh.h"
21#include "xmalloc.h" 14#include "xmalloc.h"
22#include "fingerprint.h" 15#include "fingerprint.h"
23 16
24#ifdef HAVE___PROGNAME
25extern char *__progname;
26#else /* HAVE___PROGNAME */
27const char *__progname = "ssh-keygen";
28#endif /* HAVE___PROGNAME */
29
30/* Generated private key. */ 17/* Generated private key. */
31RSA *private_key; 18RSA *private_key;
32 19
@@ -64,533 +51,493 @@ char *identity_new_passphrase = NULL;
64char *identity_comment = NULL; 51char *identity_comment = NULL;
65 52
66/* argv0 */ 53/* argv0 */
54#ifdef HAVE___PROGNAME
67extern char *__progname; 55extern char *__progname;
56#else /* HAVE___PROGNAME */
57const char *__progname = "ssh-keygen";
58#endif /* HAVE___PROGNAME */
68 59
69void 60void
70ask_filename(struct passwd *pw, const char *prompt) 61ask_filename(struct passwd *pw, const char *prompt)
71{ 62{
72 char buf[1024]; 63 char buf[1024];
73 snprintf(identity_file, sizeof(identity_file), "%s/%s", 64 snprintf(identity_file, sizeof(identity_file), "%s/%s",
74 pw->pw_dir, SSH_CLIENT_IDENTITY); 65 pw->pw_dir, SSH_CLIENT_IDENTITY);
75 printf("%s (%s): ", prompt, identity_file); 66 printf("%s (%s): ", prompt, identity_file);
76 fflush(stdout); 67 fflush(stdout);
77 if (fgets(buf, sizeof(buf), stdin) == NULL) 68 if (fgets(buf, sizeof(buf), stdin) == NULL)
78 exit(1); 69 exit(1);
79 if (strchr(buf, '\n')) 70 if (strchr(buf, '\n'))
80 *strchr(buf, '\n') = 0; 71 *strchr(buf, '\n') = 0;
81 if (strcmp(buf, "") != 0) 72 if (strcmp(buf, "") != 0)
82 strlcpy(identity_file, buf, sizeof(identity_file)); 73 strlcpy(identity_file, buf, sizeof(identity_file));
83 have_identity = 1; 74 have_identity = 1;
84} 75}
85 76
86void 77void
87do_fingerprint(struct passwd *pw) 78do_fingerprint(struct passwd *pw)
88{ 79{
89 char *comment; 80 char *comment;
90 RSA *public_key; 81 RSA *public_key;
91 struct stat st; 82 struct stat st;
92 83
93 if (!have_identity) 84 if (!have_identity)
94 ask_filename(pw, "Enter file in which the key is"); 85 ask_filename(pw, "Enter file in which the key is");
95 if (stat(identity_file, &st) < 0) 86 if (stat(identity_file, &st) < 0) {
96 { 87 perror(identity_file);
97 perror(identity_file); 88 exit(1);
98 exit(1); 89 }
99 } 90 public_key = RSA_new();
100 public_key = RSA_new(); 91 if (!load_public_key(identity_file, public_key, &comment)) {
101 if (!load_public_key(identity_file, public_key, &comment)) { 92 char *cp, line[1024];
102 char *cp, line[1024]; 93 BIGNUM *e, *n;
103 BIGNUM *e, *n; 94 int dummy, invalid = 0;
104 int dummy, invalid = 0; 95 FILE *f = fopen(identity_file, "r");
105 FILE *f = fopen(identity_file, "r"); 96 n = BN_new();
106 n = BN_new(); 97 e = BN_new();
107 e = BN_new(); 98 if (f && fgets(line, sizeof(line), f)) {
108 if (f && fgets(line, sizeof(line), f)) { 99 cp = line;
109 cp = line; 100 line[strlen(line) - 1] = '\0';
110 line[strlen(line)-1] = '\0'; 101 if (auth_rsa_read_key(&cp, &dummy, e, n)) {
111 if (auth_rsa_read_key(&cp, &dummy, e, n)) { 102 public_key->e = e;
112 public_key->e = e; 103 public_key->n = n;
113 public_key->n = n; 104 comment = xstrdup(cp ? cp : "no comment");
114 comment = xstrdup(cp ? cp : "no comment"); 105 } else {
115 } else { 106 invalid = 1;
116 invalid = 1; 107 }
117 } 108 } else {
118 } else { 109 invalid = 1;
119 invalid = 1; 110 }
120 } 111 if (invalid) {
121 if (invalid) { 112 printf("%s is not a valid key file.\n", identity_file);
122 printf("%s is not a valid key file.\n", identity_file); 113 BN_free(e);
123 BN_free(e); 114 BN_free(n);
124 BN_free(n); 115 exit(1);
125 exit(1); 116 }
126 } 117 }
127 } 118 printf("%d %s %s\n", BN_num_bits(public_key->n),
128 119 fingerprint(public_key->e, public_key->n),
129 printf("%d %s %s\n", BN_num_bits(public_key->n), 120 comment);
130 fingerprint(public_key->e, public_key->n), 121 RSA_free(public_key);
131 comment); 122 exit(0);
132 RSA_free(public_key);
133 exit(0);
134} 123}
135 124
136/* Perform changing a passphrase. The argument is the passwd structure 125/*
137 for the current user. */ 126 * Perform changing a passphrase. The argument is the passwd structure
138 127 * for the current user.
128 */
139void 129void
140do_change_passphrase(struct passwd *pw) 130do_change_passphrase(struct passwd *pw)
141{ 131{
142 char *comment; 132 char *comment;
143 char *old_passphrase, *passphrase1, *passphrase2; 133 char *old_passphrase, *passphrase1, *passphrase2;
144 struct stat st; 134 struct stat st;
145 RSA *private_key; 135 RSA *private_key;
146 136
147 if (!have_identity) 137 if (!have_identity)
148 ask_filename(pw, "Enter file in which the key is"); 138 ask_filename(pw, "Enter file in which the key is");
149 /* Check if the file exists. */ 139 /* Check if the file exists. */
150 if (stat(identity_file, &st) < 0) 140 if (stat(identity_file, &st) < 0) {
151 { 141 perror(identity_file);
152 perror(identity_file); 142 exit(1);
153 exit(1); 143 }
154 } 144 /* Try to load the public key from the file the verify that it is
155 145 readable and of the proper format. */
156 /* Try to load the public key from the file the verify that it is 146 public_key = RSA_new();
157 readable and of the proper format. */ 147 if (!load_public_key(identity_file, public_key, NULL)) {
158 public_key = RSA_new(); 148 printf("%s is not a valid key file.\n", identity_file);
159 if (!load_public_key(identity_file, public_key, NULL)) 149 exit(1);
160 { 150 }
161 printf("%s is not a valid key file.\n", identity_file); 151 /* Clear the public key since we are just about to load the whole file. */
162 exit(1); 152 RSA_free(public_key);
163 } 153
164 /* Clear the public key since we are just about to load the whole file. */ 154 /* Try to load the file with empty passphrase. */
165 RSA_free(public_key); 155 private_key = RSA_new();
166 156 if (!load_private_key(identity_file, "", private_key, &comment)) {
167 /* Try to load the file with empty passphrase. */ 157 /* Read passphrase from the user. */
168 private_key = RSA_new(); 158 if (identity_passphrase)
169 if (!load_private_key(identity_file, "", private_key, &comment)) { 159 old_passphrase = xstrdup(identity_passphrase);
170 /* Read passphrase from the user. */ 160 else
171 if (identity_passphrase) 161 old_passphrase = read_passphrase("Enter old passphrase: ", 1);
172 old_passphrase = xstrdup(identity_passphrase); 162 /* Try to load using the passphrase. */
173 else 163 if (!load_private_key(identity_file, old_passphrase, private_key, &comment)) {
174 old_passphrase = read_passphrase("Enter old passphrase: ", 1); 164 memset(old_passphrase, 0, strlen(old_passphrase));
175 /* Try to load using the passphrase. */ 165 xfree(old_passphrase);
176 if (!load_private_key(identity_file, old_passphrase, private_key, &comment)) 166 printf("Bad passphrase.\n");
177 { 167 exit(1);
178 memset(old_passphrase, 0, strlen(old_passphrase)); 168 }
179 xfree(old_passphrase); 169 /* Destroy the passphrase. */
180 printf("Bad passphrase.\n"); 170 memset(old_passphrase, 0, strlen(old_passphrase));
181 exit(1); 171 xfree(old_passphrase);
182 } 172 }
183 /* Destroy the passphrase. */ 173 printf("Key has comment '%s'\n", comment);
184 memset(old_passphrase, 0, strlen(old_passphrase)); 174
185 xfree(old_passphrase); 175 /* Ask the new passphrase (twice). */
186 } 176 if (identity_new_passphrase) {
187 printf("Key has comment '%s'\n", comment); 177 passphrase1 = xstrdup(identity_new_passphrase);
188 178 passphrase2 = NULL;
189 /* Ask the new passphrase (twice). */ 179 } else {
190 if (identity_new_passphrase) 180 passphrase1 =
191 { 181 read_passphrase("Enter new passphrase (empty for no passphrase): ", 1);
192 passphrase1 = xstrdup(identity_new_passphrase); 182 passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
193 passphrase2 = NULL; 183
194 } 184 /* Verify that they are the same. */
195 else 185 if (strcmp(passphrase1, passphrase2) != 0) {
196 { 186 memset(passphrase1, 0, strlen(passphrase1));
197 passphrase1 = 187 memset(passphrase2, 0, strlen(passphrase2));
198 read_passphrase("Enter new passphrase (empty for no passphrase): ", 1); 188 xfree(passphrase1);
199 passphrase2 = read_passphrase("Enter same passphrase again: ", 1); 189 xfree(passphrase2);
200 190 printf("Pass phrases do not match. Try again.\n");
201 /* Verify that they are the same. */ 191 exit(1);
202 if (strcmp(passphrase1, passphrase2) != 0) 192 }
203 { 193 /* Destroy the other copy. */
204 memset(passphrase1, 0, strlen(passphrase1)); 194 memset(passphrase2, 0, strlen(passphrase2));
205 memset(passphrase2, 0, strlen(passphrase2)); 195 xfree(passphrase2);
206 xfree(passphrase1);
207 xfree(passphrase2);
208 printf("Pass phrases do not match. Try again.\n");
209 exit(1);
210 } 196 }
211 /* Destroy the other copy. */
212 memset(passphrase2, 0, strlen(passphrase2));
213 xfree(passphrase2);
214 }
215
216 /* Save the file using the new passphrase. */
217 if (!save_private_key(identity_file, passphrase1, private_key, comment))
218 {
219 printf("Saving the key failed: %s: %s.\n",
220 identity_file, strerror(errno));
221 memset(passphrase1, 0, strlen(passphrase1));
222 xfree(passphrase1);
223 RSA_free(private_key);
224 xfree(comment);
225 exit(1);
226 }
227 /* Destroy the passphrase and the copy of the key in memory. */
228 memset(passphrase1, 0, strlen(passphrase1));
229 xfree(passphrase1);
230 RSA_free(private_key); /* Destroys contents */
231 xfree(comment);
232
233 printf("Your identification has been saved with the new passphrase.\n");
234 exit(0);
235}
236 197
237/* Change the comment of a private key file. */ 198 /* Save the file using the new passphrase. */
199 if (!save_private_key(identity_file, passphrase1, private_key, comment)) {
200 printf("Saving the key failed: %s: %s.\n",
201 identity_file, strerror(errno));
202 memset(passphrase1, 0, strlen(passphrase1));
203 xfree(passphrase1);
204 RSA_free(private_key);
205 xfree(comment);
206 exit(1);
207 }
208 /* Destroy the passphrase and the copy of the key in memory. */
209 memset(passphrase1, 0, strlen(passphrase1));
210 xfree(passphrase1);
211 RSA_free(private_key); /* Destroys contents */
212 xfree(comment);
213
214 printf("Your identification has been saved with the new passphrase.\n");
215 exit(0);
216}
238 217
218/*
219 * Change the comment of a private key file.
220 */
239void 221void
240do_change_comment(struct passwd *pw) 222do_change_comment(struct passwd *pw)
241{ 223{
242 char new_comment[1024], *comment; 224 char new_comment[1024], *comment;
243 RSA *private_key; 225 RSA *private_key;
244 char *passphrase; 226 char *passphrase;
245 struct stat st; 227 struct stat st;
246 FILE *f; 228 FILE *f;
247 char *tmpbuf; 229 char *tmpbuf;
248 230
249 if (!have_identity) 231 if (!have_identity)
250 ask_filename(pw, "Enter file in which the key is"); 232 ask_filename(pw, "Enter file in which the key is");
251 /* Check if the file exists. */ 233 /* Check if the file exists. */
252 if (stat(identity_file, &st) < 0) 234 if (stat(identity_file, &st) < 0) {
253 { 235 perror(identity_file);
254 perror(identity_file); 236 exit(1);
255 exit(1); 237 }
256 } 238 /* Try to load the public key from the file the verify that it is
257 239 readable and of the proper format. */
258 /* Try to load the public key from the file the verify that it is 240 public_key = RSA_new();
259 readable and of the proper format. */ 241 if (!load_public_key(identity_file, public_key, NULL)) {
260 public_key = RSA_new(); 242 printf("%s is not a valid key file.\n", identity_file);
261 if (!load_public_key(identity_file, public_key, NULL)) 243 exit(1);
262 {
263 printf("%s is not a valid key file.\n", identity_file);
264 exit(1);
265 }
266
267 private_key = RSA_new();
268 /* Try to load the file with empty passphrase. */
269 if (load_private_key(identity_file, "", private_key, &comment))
270 passphrase = xstrdup("");
271 else
272 {
273 /* Read passphrase from the user. */
274 if (identity_passphrase)
275 passphrase = xstrdup(identity_passphrase);
276 else
277 if (identity_new_passphrase)
278 passphrase = xstrdup(identity_new_passphrase);
279 else
280 passphrase = read_passphrase("Enter passphrase: ", 1);
281 /* Try to load using the passphrase. */
282 if (!load_private_key(identity_file, passphrase, private_key, &comment))
283 {
284 memset(passphrase, 0, strlen(passphrase));
285 xfree(passphrase);
286 printf("Bad passphrase.\n");
287 exit(1);
288 } 244 }
289 } 245 private_key = RSA_new();
290 printf("Key now has comment '%s'\n", comment); 246 /* Try to load the file with empty passphrase. */
291 247 if (load_private_key(identity_file, "", private_key, &comment))
292 if (identity_comment) 248 passphrase = xstrdup("");
293 { 249 else {
294 strlcpy(new_comment, identity_comment, sizeof(new_comment)); 250 /* Read passphrase from the user. */
295 } 251 if (identity_passphrase)
296 else 252 passphrase = xstrdup(identity_passphrase);
297 { 253 else if (identity_new_passphrase)
298 printf("Enter new comment: "); 254 passphrase = xstrdup(identity_new_passphrase);
299 fflush(stdout); 255 else
300 if (!fgets(new_comment, sizeof(new_comment), stdin)) 256 passphrase = read_passphrase("Enter passphrase: ", 1);
301 { 257 /* Try to load using the passphrase. */
302 memset(passphrase, 0, strlen(passphrase)); 258 if (!load_private_key(identity_file, passphrase, private_key, &comment)) {
303 RSA_free(private_key); 259 memset(passphrase, 0, strlen(passphrase));
304 exit(1); 260 xfree(passphrase);
261 printf("Bad passphrase.\n");
262 exit(1);
263 }
264 }
265 printf("Key now has comment '%s'\n", comment);
266
267 if (identity_comment) {
268 strlcpy(new_comment, identity_comment, sizeof(new_comment));
269 } else {
270 printf("Enter new comment: ");
271 fflush(stdout);
272 if (!fgets(new_comment, sizeof(new_comment), stdin)) {
273 memset(passphrase, 0, strlen(passphrase));
274 RSA_free(private_key);
275 exit(1);
276 }
277 /* Remove terminating newline from comment. */
278 if (strchr(new_comment, '\n'))
279 *strchr(new_comment, '\n') = 0;
280 }
281
282 /* Save the file using the new passphrase. */
283 if (!save_private_key(identity_file, passphrase, private_key, new_comment)) {
284 printf("Saving the key failed: %s: %s.\n",
285 identity_file, strerror(errno));
286 memset(passphrase, 0, strlen(passphrase));
287 xfree(passphrase);
288 RSA_free(private_key);
289 xfree(comment);
290 exit(1);
305 } 291 }
306 292 /* Destroy the passphrase and the private key in memory. */
307 /* Remove terminating newline from comment. */ 293 memset(passphrase, 0, strlen(passphrase));
308 if (strchr(new_comment, '\n')) 294 xfree(passphrase);
309 *strchr(new_comment, '\n') = 0; 295 RSA_free(private_key);
310 } 296
311 297 /* Save the public key in text format in a file with the same name
312 /* Save the file using the new passphrase. */ 298 but .pub appended. */
313 if (!save_private_key(identity_file, passphrase, private_key, new_comment)) 299 strlcat(identity_file, ".pub", sizeof(identity_file));
314 { 300 f = fopen(identity_file, "w");
315 printf("Saving the key failed: %s: %s.\n", 301 if (!f) {
316 identity_file, strerror(errno)); 302 printf("Could not save your public key in %s\n", identity_file);
317 memset(passphrase, 0, strlen(passphrase)); 303 exit(1);
318 xfree(passphrase); 304 }
319 RSA_free(private_key); 305 fprintf(f, "%d ", BN_num_bits(public_key->n));
320 xfree(comment); 306 tmpbuf = BN_bn2dec(public_key->e);
321 exit(1); 307 fprintf(f, "%s ", tmpbuf);
322 } 308 free(tmpbuf);
323 309 tmpbuf = BN_bn2dec(public_key->n);
324 /* Destroy the passphrase and the private key in memory. */ 310 fprintf(f, "%s %s\n", tmpbuf, new_comment);
325 memset(passphrase, 0, strlen(passphrase)); 311 free(tmpbuf);
326 xfree(passphrase); 312 fclose(f);
327 RSA_free(private_key); 313
328 314 xfree(comment);
329 /* Save the public key in text format in a file with the same name but 315
330 .pub appended. */ 316 printf("The comment in your key file has been changed.\n");
331 strlcat(identity_file, ".pub", sizeof(identity_file)); 317 exit(0);
332 f = fopen(identity_file, "w");
333 if (!f)
334 {
335 printf("Could not save your public key in %s\n", identity_file);
336 exit(1);
337 }
338 fprintf(f, "%d ", BN_num_bits(public_key->n));
339 tmpbuf = BN_bn2dec(public_key->e);
340 fprintf(f, "%s ", tmpbuf);
341 free (tmpbuf);
342 tmpbuf = BN_bn2dec(public_key->n);
343 fprintf(f, "%s %s\n", tmpbuf, new_comment);
344 free (tmpbuf);
345 fclose(f);
346
347 xfree(comment);
348
349 printf("The comment in your key file has been changed.\n");
350 exit(0);
351} 318}
352 319
353void 320void
354usage(void) 321usage(void)
355{ 322{
356 printf("ssh-keygen version %s\n", SSH_VERSION); 323 printf("ssh-keygen version %s\n", SSH_VERSION);
357 printf("Usage: %s [-b bits] [-p] [-c] [-f file] [-P pass] [-N new-pass] [-C comment]\n", __progname); 324 printf("Usage: %s [-b bits] [-p] [-c] [-f file] [-P pass] [-N new-pass] [-C comment]\n", __progname);
358 exit(1); 325 exit(1);
359} 326}
360 327
361/* Main program for key management. */ 328/*
362 329 * Main program for key management.
330 */
363int 331int
364main(int ac, char **av) 332main(int ac, char **av)
365{ 333{
366 char dotsshdir[16*1024], comment[1024], *passphrase1, *passphrase2; 334 char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2;
367 struct passwd *pw; 335 struct passwd *pw;
368 char *tmpbuf; 336 char *tmpbuf;
369 int opt; 337 int opt;
370 struct stat st; 338 struct stat st;
371 FILE *f; 339 FILE *f;
372 char hostname[MAXHOSTNAMELEN]; 340 char hostname[MAXHOSTNAMELEN];
373 extern int optind; 341 extern int optind;
374 extern char *optarg; 342 extern char *optarg;
375 343
376 /* check if RSA support exists */ 344 /* check if RSA support exists */
377 if (rsa_alive() == 0) { 345 if (rsa_alive() == 0) {
378 extern char *__progname; 346 extern char *__progname;
379 347
380 fprintf(stderr, 348 fprintf(stderr,
381 "%s: no RSA support in libssl and libcrypto. See ssl(8).\n", 349 "%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
382 __progname); 350 __progname);
383 exit(1); 351 exit(1);
384 }
385
386 /* Get user\'s passwd structure. We need this for the home directory. */
387 pw = getpwuid(getuid());
388 if (!pw)
389 {
390 printf("You don't exist, go away!\n");
391 exit(1);
392 }
393
394 /* Parse command line arguments. */
395 while ((opt = getopt(ac, av, "qpclb:f:P:N:C:")) != EOF)
396 {
397 switch (opt)
398 {
399 case 'b':
400 bits = atoi(optarg);
401 if (bits < 512 || bits > 32768)
402 {
403 printf("Bits has bad value.\n");
404 exit(1);
405 }
406 break;
407
408 case 'l':
409 print_fingerprint = 1;
410 break;
411
412 case 'p':
413 change_passphrase = 1;
414 break;
415
416 case 'c':
417 change_comment = 1;
418 break;
419
420 case 'f':
421 strlcpy(identity_file, optarg, sizeof(identity_file));
422 have_identity = 1;
423 break;
424
425 case 'P':
426 identity_passphrase = optarg;
427 break;
428
429 case 'N':
430 identity_new_passphrase = optarg;
431 break;
432
433 case 'C':
434 identity_comment = optarg;
435 break;
436
437 case 'q':
438 quiet = 1;
439 break;
440
441 case '?':
442 default:
443 usage();
444 } 352 }
445 } 353 /* Get user\'s passwd structure. We need this for the home
446 if (optind < ac) 354 directory. */
447 { 355 pw = getpwuid(getuid());
448 printf("Too many arguments.\n"); 356 if (!pw) {
449 usage(); 357 printf("You don't exist, go away!\n");
450 } 358 exit(1);
451 if (change_passphrase && change_comment) 359 }
452 { 360 /* Parse command line arguments. */
453 printf("Can only have one of -p and -c.\n"); 361 while ((opt = getopt(ac, av, "qpclb:f:P:N:C:")) != EOF) {
454 usage(); 362 switch (opt) {
455 } 363 case 'b':
456 364 bits = atoi(optarg);
457 if (print_fingerprint) 365 if (bits < 512 || bits > 32768) {
458 do_fingerprint(pw); 366 printf("Bits has bad value.\n");
459 367 exit(1);
460 /* If the user requested to change the passphrase, do it now. This 368 }
461 function never returns. */ 369 break;
462 if (change_passphrase) 370
463 do_change_passphrase(pw); 371 case 'l':
464 372 print_fingerprint = 1;
465 /* If the user requested to change the comment, do it now. This function 373 break;
466 never returns. */ 374
467 if (change_comment) 375 case 'p':
468 do_change_comment(pw); 376 change_passphrase = 1;
469 377 break;
470 arc4random_stir(); 378
471 379 case 'c':
472 if (quiet) 380 change_comment = 1;
473 rsa_set_verbose(0); 381 break;
474 382
475 /* Generate the rsa key pair. */ 383 case 'f':
476 private_key = RSA_new(); 384 strlcpy(identity_file, optarg, sizeof(identity_file));
477 public_key = RSA_new(); 385 have_identity = 1;
478 rsa_generate_key(private_key, public_key, bits); 386 break;
479 387
480 if (!have_identity) 388 case 'P':
481 ask_filename(pw, "Enter file in which to save the key"); 389 identity_passphrase = optarg;
482 390 break;
483 /* Create ~/.ssh directory if it doesn\'t already exist. */ 391
484 snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, SSH_USER_DIR); 392 case 'N':
485 if (strstr(identity_file, dotsshdir) != NULL && 393 identity_new_passphrase = optarg;
486 stat(dotsshdir, &st) < 0) { 394 break;
487 if (mkdir(dotsshdir, 0755) < 0) 395
488 error("Could not create directory '%s'.", dotsshdir); 396 case 'C':
489 else if(!quiet) 397 identity_comment = optarg;
490 printf("Created directory '%s'.\n", dotsshdir); 398 break;
491 } 399
492 400 case 'q':
493 /* If the file already exists, ask the user to confirm. */ 401 quiet = 1;
494 if (stat(identity_file, &st) >= 0) 402 break;
495 { 403
496 char yesno[3]; 404 case '?':
497 printf("%s already exists.\n", identity_file); 405 default:
498 printf("Overwrite (y/n)? "); 406 usage();
499 fflush(stdout); 407 }
500 if (fgets(yesno, sizeof(yesno), stdin) == NULL) 408 }
501 exit(1); 409 if (optind < ac) {
502 if (yesno[0] != 'y' && yesno[0] != 'Y') 410 printf("Too many arguments.\n");
503 exit(1); 411 usage();
504 } 412 }
505 413 if (change_passphrase && change_comment) {
506 /* Ask for a passphrase (twice). */ 414 printf("Can only have one of -p and -c.\n");
507 if (identity_passphrase) 415 usage();
508 passphrase1 = xstrdup(identity_passphrase); 416 }
509 else 417 if (print_fingerprint)
510 if (identity_new_passphrase) 418 do_fingerprint(pw);
511 passphrase1 = xstrdup(identity_new_passphrase); 419
512 else 420 /* If the user requested to change the passphrase, do it now.
513 { 421 This function never returns. */
514 passphrase_again: 422 if (change_passphrase)
515 passphrase1 = 423 do_change_passphrase(pw);
516 read_passphrase("Enter passphrase (empty for no passphrase): ", 1); 424
517 passphrase2 = read_passphrase("Enter same passphrase again: ", 1); 425 /* If the user requested to change the comment, do it now. This
518 if (strcmp(passphrase1, passphrase2) != 0) 426 function never returns. */
519 { 427 if (change_comment)
520 /* The passphrases do not match. Clear them and retry. */ 428 do_change_comment(pw);
521 memset(passphrase1, 0, strlen(passphrase1)); 429
522 memset(passphrase2, 0, strlen(passphrase2)); 430 arc4random_stir();
523 xfree(passphrase1); 431
524 xfree(passphrase2); 432 if (quiet)
525 printf("Passphrases do not match. Try again.\n"); 433 rsa_set_verbose(0);
526 goto passphrase_again; 434
527 } 435 /* Generate the rsa key pair. */
528 /* Clear the other copy of the passphrase. */ 436 private_key = RSA_new();
529 memset(passphrase2, 0, strlen(passphrase2)); 437 public_key = RSA_new();
530 xfree(passphrase2); 438 rsa_generate_key(private_key, public_key, bits);
531 } 439
532 440 if (!have_identity)
533 /* Create default commend field for the passphrase. The user can later 441 ask_filename(pw, "Enter file in which to save the key");
534 edit this field. */ 442
535 if (identity_comment) 443 /* Create ~/.ssh directory if it doesn\'t already exist. */
536 { 444 snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, SSH_USER_DIR);
537 strlcpy(comment, identity_comment, sizeof(comment)); 445 if (strstr(identity_file, dotsshdir) != NULL &&
538 } 446 stat(dotsshdir, &st) < 0) {
539 else 447 if (mkdir(dotsshdir, 0755) < 0)
540 { 448 error("Could not create directory '%s'.", dotsshdir);
541 if (gethostname(hostname, sizeof(hostname)) < 0) 449 else if (!quiet)
542 { 450 printf("Created directory '%s'.\n", dotsshdir);
543 perror("gethostname"); 451 }
544 exit(1); 452 /* If the file already exists, ask the user to confirm. */
453 if (stat(identity_file, &st) >= 0) {
454 char yesno[3];
455 printf("%s already exists.\n", identity_file);
456 printf("Overwrite (y/n)? ");
457 fflush(stdout);
458 if (fgets(yesno, sizeof(yesno), stdin) == NULL)
459 exit(1);
460 if (yesno[0] != 'y' && yesno[0] != 'Y')
461 exit(1);
462 }
463 /* Ask for a passphrase (twice). */
464 if (identity_passphrase)
465 passphrase1 = xstrdup(identity_passphrase);
466 else if (identity_new_passphrase)
467 passphrase1 = xstrdup(identity_new_passphrase);
468 else {
469passphrase_again:
470 passphrase1 =
471 read_passphrase("Enter passphrase (empty for no passphrase): ", 1);
472 passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
473 if (strcmp(passphrase1, passphrase2) != 0) {
474 /* The passphrases do not match. Clear them and retry. */
475 memset(passphrase1, 0, strlen(passphrase1));
476 memset(passphrase2, 0, strlen(passphrase2));
477 xfree(passphrase1);
478 xfree(passphrase2);
479 printf("Passphrases do not match. Try again.\n");
480 goto passphrase_again;
481 }
482 /* Clear the other copy of the passphrase. */
483 memset(passphrase2, 0, strlen(passphrase2));
484 xfree(passphrase2);
485 }
486
487 /* Create default commend field for the passphrase. The user can
488 later edit this field. */
489 if (identity_comment) {
490 strlcpy(comment, identity_comment, sizeof(comment));
491 } else {
492 if (gethostname(hostname, sizeof(hostname)) < 0) {
493 perror("gethostname");
494 exit(1);
495 }
496 snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
497 }
498
499 /* Save the key with the given passphrase and comment. */
500 if (!save_private_key(identity_file, passphrase1, private_key, comment)) {
501 printf("Saving the key failed: %s: %s.\n",
502 identity_file, strerror(errno));
503 memset(passphrase1, 0, strlen(passphrase1));
504 xfree(passphrase1);
505 exit(1);
506 }
507 /* Clear the passphrase. */
508 memset(passphrase1, 0, strlen(passphrase1));
509 xfree(passphrase1);
510
511 /* Clear the private key and the random number generator. */
512 RSA_free(private_key);
513 arc4random_stir();
514
515 if (!quiet)
516 printf("Your identification has been saved in %s.\n", identity_file);
517
518 /* Save the public key in text format in a file with the same name
519 but .pub appended. */
520 strlcat(identity_file, ".pub", sizeof(identity_file));
521 f = fopen(identity_file, "w");
522 if (!f) {
523 printf("Could not save your public key in %s\n", identity_file);
524 exit(1);
525 }
526 fprintf(f, "%d ", BN_num_bits(public_key->n));
527 tmpbuf = BN_bn2dec(public_key->e);
528 fprintf(f, "%s ", tmpbuf);
529 free(tmpbuf);
530 tmpbuf = BN_bn2dec(public_key->n);
531 fprintf(f, "%s %s\n", tmpbuf, comment);
532 free(tmpbuf);
533 fclose(f);
534
535 if (!quiet) {
536 printf("Your public key has been saved in %s.\n", identity_file);
537 printf("The key fingerprint is:\n");
538 printf("%d %s %s\n", BN_num_bits(public_key->n),
539 fingerprint(public_key->e, public_key->n),
540 comment);
545 } 541 }
546 snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname); 542 exit(0);
547 }
548
549 /* Save the key with the given passphrase and comment. */
550 if (!save_private_key(identity_file, passphrase1, private_key, comment))
551 {
552 printf("Saving the key failed: %s: %s.\n",
553 identity_file, strerror(errno));
554 memset(passphrase1, 0, strlen(passphrase1));
555 xfree(passphrase1);
556 exit(1);
557 }
558 /* Clear the passphrase. */
559 memset(passphrase1, 0, strlen(passphrase1));
560 xfree(passphrase1);
561
562 /* Clear the private key and the random number generator. */
563 RSA_free(private_key);
564 arc4random_stir();
565
566 if (!quiet)
567 printf("Your identification has been saved in %s.\n", identity_file);
568
569 /* Save the public key in text format in a file with the same name but
570 .pub appended. */
571 strlcat(identity_file, ".pub", sizeof(identity_file));
572 f = fopen(identity_file, "w");
573 if (!f)
574 {
575 printf("Could not save your public key in %s\n", identity_file);
576 exit(1);
577 }
578 fprintf(f, "%d ", BN_num_bits(public_key->n));
579 tmpbuf = BN_bn2dec(public_key->e);
580 fprintf(f, "%s ", tmpbuf);
581 free(tmpbuf);
582 tmpbuf = BN_bn2dec(public_key->n);
583 fprintf(f, "%s %s\n", tmpbuf, comment);
584 free(tmpbuf);
585 fclose(f);
586
587 if (!quiet) {
588 printf("Your public key has been saved in %s.\n", identity_file);
589 printf("The key fingerprint is:\n");
590 printf("%d %s %s\n", BN_num_bits(public_key->n),
591 fingerprint(public_key->e, public_key->n),
592 comment);
593 }
594
595 exit(0);
596} 543}
diff --git a/ssh.1 b/ssh.1
index 939db85cc..df7c0b455 100644
--- a/ssh.1
+++ b/ssh.1
@@ -9,7 +9,7 @@
9.\" 9.\"
10.\" Created: Sat Apr 22 21:55:14 1995 ylo 10.\" Created: Sat Apr 22 21:55:14 1995 ylo
11.\" 11.\"
12.\" $Id: ssh.1,v 1.8 1999/11/18 00:35:13 damien Exp $ 12.\" $Id: ssh.1,v 1.9 1999/11/24 13:26:23 damien Exp $
13.\" 13.\"
14.Dd September 25, 1999 14.Dd September 25, 1999
15.Dt SSH 1 15.Dt SSH 1
@@ -662,6 +662,16 @@ or
662RSA authentication will only be 662RSA authentication will only be
663attempted if the identity file exists, or an authentication agent is 663attempted if the identity file exists, or an authentication agent is
664running. 664running.
665.It Cm SkeyAuthentication
666Specifies whether to use
667.Xr skey 1
668authentication. The argument to
669this keyword must be
670.Dq yes
671or
672.Dq no .
673The default is
674.Dq no .
665.It Cm CheckHostIP 675.It Cm CheckHostIP
666If this flag is set to 676If this flag is set to
667.Dq yes , 677.Dq yes ,
diff --git a/ssh.c b/ssh.c
index 08a32cc19..8d73e61e3 100644
--- a/ssh.c
+++ b/ssh.c
@@ -1,24 +1,17 @@
1/* 1/*
2 2 * Author: Tatu Ylonen <ylo@cs.hut.fi>
3ssh.c 3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 4 * All rights reserved
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Created: Sat Mar 18 16:36:11 1995 ylo
6 6 * Ssh client program. This program can be used to log into a remote machine.
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * The software supports strong authentication, encryption, and forwarding
8 All rights reserved 8 * of X11, TCP/IP, and authentication connections.
9 9 *
10Created: Sat Mar 18 16:36:11 1995 ylo 10 * Modified to work with SSL by Niels Provos <provos@citi.umich.edu> in Canada.
11 11 */
12Ssh client program. This program can be used to log into a remote machine.
13The software supports strong authentication, encryption, and forwarding
14of X11, TCP/IP, and authentication connections.
15
16Modified to work with SSL by Niels Provos <provos@citi.umich.edu> in Canada.
17
18*/
19 12
20#include "includes.h" 13#include "includes.h"
21RCSID("$Id: ssh.c,v 1.10 1999/11/16 02:37:16 damien Exp $"); 14RCSID("$Id: ssh.c,v 1.11 1999/11/24 13:26:23 damien Exp $");
22 15
23#include "xmalloc.h" 16#include "xmalloc.h"
24#include "ssh.h" 17#include "ssh.h"
@@ -34,13 +27,11 @@ extern char *__progname;
34const char *__progname = "ssh"; 27const char *__progname = "ssh";
35#endif /* HAVE___PROGNAME */ 28#endif /* HAVE___PROGNAME */
36 29
37/* Flag indicating whether debug mode is on. This can be set on the 30/* Flag indicating whether debug mode is on. This can be set on the command line. */
38 command line. */
39int debug_flag = 0; 31int debug_flag = 0;
40 32
41/* Flag indicating whether to allocate a pseudo tty. This can be set on the 33/* Flag indicating whether to allocate a pseudo tty. This can be set on the command
42 command line, and is automatically set if no command is given on the command 34 line, and is automatically set if no command is given on the command line. */
43 line. */
44int tty_flag = 0; 35int tty_flag = 0;
45 36
46/* Flag indicating that nothing should be read from stdin. This can be set 37/* Flag indicating that nothing should be read from stdin. This can be set
@@ -87,730 +78,680 @@ uid_t original_real_uid;
87void 78void
88usage() 79usage()
89{ 80{
90 fprintf(stderr, "Usage: %s [options] host [command]\n", av0); 81 fprintf(stderr, "Usage: %s [options] host [command]\n", av0);
91 fprintf(stderr, "Options:\n"); 82 fprintf(stderr, "Options:\n");
92 fprintf(stderr, " -l user Log in using this user name.\n"); 83 fprintf(stderr, " -l user Log in using this user name.\n");
93 fprintf(stderr, " -n Redirect input from /dev/null.\n"); 84 fprintf(stderr, " -n Redirect input from /dev/null.\n");
94 fprintf(stderr, " -a Disable authentication agent forwarding.\n"); 85 fprintf(stderr, " -a Disable authentication agent forwarding.\n");
95#ifdef AFS 86#ifdef AFS
96 fprintf(stderr, " -k Disable Kerberos ticket and AFS token forwarding.\n"); 87 fprintf(stderr, " -k Disable Kerberos ticket and AFS token forwarding.\n");
97#endif /* AFS */ 88#endif /* AFS */
98 fprintf(stderr, " -x Disable X11 connection forwarding.\n"); 89 fprintf(stderr, " -x Disable X11 connection forwarding.\n");
99 fprintf(stderr, " -i file Identity for RSA authentication (default: ~/.ssh/identity).\n"); 90 fprintf(stderr, " -i file Identity for RSA authentication (default: ~/.ssh/identity).\n");
100 fprintf(stderr, " -t Tty; allocate a tty even if command is given.\n"); 91 fprintf(stderr, " -t Tty; allocate a tty even if command is given.\n");
101 fprintf(stderr, " -v Verbose; display verbose debugging messages.\n"); 92 fprintf(stderr, " -v Verbose; display verbose debugging messages.\n");
102 fprintf(stderr, " -V Display version number only.\n"); 93 fprintf(stderr, " -V Display version number only.\n");
103 fprintf(stderr, " -P Don't allocate a privileged port.\n"); 94 fprintf(stderr, " -P Don't allocate a privileged port.\n");
104 fprintf(stderr, " -q Quiet; don't display any warning messages.\n"); 95 fprintf(stderr, " -q Quiet; don't display any warning messages.\n");
105 fprintf(stderr, " -f Fork into background after authentication.\n"); 96 fprintf(stderr, " -f Fork into background after authentication.\n");
106 fprintf(stderr, " -e char Set escape character; ``none'' = disable (default: ~).\n"); 97 fprintf(stderr, " -e char Set escape character; ``none'' = disable (default: ~).\n");
107 98
108 fprintf(stderr, " -c cipher Select encryption algorithm: " 99 fprintf(stderr, " -c cipher Select encryption algorithm: "
109 "``3des'', " 100 "``3des'', "
110 "``blowfish''\n"); 101 "``blowfish''\n");
111 fprintf(stderr, " -p port Connect to this port. Server must be on the same port.\n"); 102 fprintf(stderr, " -p port Connect to this port. Server must be on the same port.\n");
112 fprintf(stderr, " -L listen-port:host:port Forward local port to remote address\n"); 103 fprintf(stderr, " -L listen-port:host:port Forward local port to remote address\n");
113 fprintf(stderr, " -R listen-port:host:port Forward remote port to local address\n"); 104 fprintf(stderr, " -R listen-port:host:port Forward remote port to local address\n");
114 fprintf(stderr, " These cause %s to listen for connections on a port, and\n", av0); 105 fprintf(stderr, " These cause %s to listen for connections on a port, and\n", av0);
115 fprintf(stderr, " forward them to the other side by connecting to host:port.\n"); 106 fprintf(stderr, " forward them to the other side by connecting to host:port.\n");
116 fprintf(stderr, " -C Enable compression.\n"); 107 fprintf(stderr, " -C Enable compression.\n");
117 fprintf(stderr, " -g Allow remote hosts to connect to forwarded ports.\n"); 108 fprintf(stderr, " -g Allow remote hosts to connect to forwarded ports.\n");
118 fprintf(stderr, " -o 'option' Process the option as if it was read from a configuration file.\n"); 109 fprintf(stderr, " -o 'option' Process the option as if it was read from a configuration file.\n");
119 exit(1); 110 exit(1);
120} 111}
121 112
122/* Connects to the given host using rsh (or prints an error message and exits 113/*
123 if rsh is not available). This function never returns. */ 114 * Connects to the given host using rsh (or prints an error message and exits
124 115 * if rsh is not available). This function never returns.
116 */
125void 117void
126rsh_connect(char *host, char *user, Buffer *command) 118rsh_connect(char *host, char *user, Buffer * command)
127{ 119{
128 char *args[10]; 120 char *args[10];
129 int i; 121 int i;
130 122
131 log("Using rsh. WARNING: Connection will not be encrypted."); 123 log("Using rsh. WARNING: Connection will not be encrypted.");
132 /* Build argument list for rsh. */ 124 /* Build argument list for rsh. */
133 i = 0; 125 i = 0;
134 args[i++] = _PATH_RSH; 126 args[i++] = _PATH_RSH;
135 args[i++] = host; /* may have to come after user on some systems */ 127 /* host may have to come after user on some systems */
136 if (user) 128 args[i++] = host;
137 { 129 if (user) {
138 args[i++] = "-l"; 130 args[i++] = "-l";
139 args[i++] = user; 131 args[i++] = user;
140 } 132 }
141 if (buffer_len(command) > 0) 133 if (buffer_len(command) > 0) {
142 { 134 buffer_append(command, "\0", 1);
143 buffer_append(command, "\0", 1); 135 args[i++] = buffer_ptr(command);
144 args[i++] = buffer_ptr(command); 136 }
145 } 137 args[i++] = NULL;
146 args[i++] = NULL; 138 if (debug_flag) {
147 if (debug_flag) 139 for (i = 0; args[i]; i++) {
148 { 140 if (i != 0)
149 for (i = 0; args[i]; i++) 141 fprintf(stderr, " ");
150 { 142 fprintf(stderr, "%s", args[i]);
151 if (i != 0) 143 }
152 fprintf(stderr, " "); 144 fprintf(stderr, "\n");
153 fprintf(stderr, "%s", args[i]);
154 } 145 }
155 fprintf(stderr, "\n"); 146 execv(_PATH_RSH, args);
156 } 147 perror(_PATH_RSH);
157 execv(_PATH_RSH, args); 148 exit(1);
158 perror(_PATH_RSH);
159 exit(1);
160} 149}
161 150
162/* Main program for the ssh client. */ 151/*
163 152 * Main program for the ssh client.
153 */
164int 154int
165main(int ac, char **av) 155main(int ac, char **av)
166{ 156{
167 int i, opt, optind, type, exit_status, ok, fwd_port, fwd_host_port, authfd; 157 int i, opt, optind, type, exit_status, ok, fwd_port, fwd_host_port,
168 char *optarg, *cp, buf[256]; 158 authfd;
169 Buffer command; 159 char *optarg, *cp, buf[256];
170 struct winsize ws; 160 Buffer command;
171 struct stat st; 161 struct winsize ws;
172 struct passwd *pw, pwcopy; 162 struct stat st;
173 int interactive = 0, dummy; 163 struct passwd *pw, pwcopy;
174 uid_t original_effective_uid; 164 int interactive = 0, dummy;
175 int plen; 165 uid_t original_effective_uid;
176 166 int plen;
177 /* Save the original real uid. It will be needed later (uid-swapping may 167
178 clobber the real uid). */ 168 /* Save the original real uid. It will be needed later
179 original_real_uid = getuid(); 169 (uid-swapping may clobber the real uid). */
180 original_effective_uid = geteuid(); 170 original_real_uid = getuid();
181 171 original_effective_uid = geteuid();
182 /* If we are installed setuid root be careful to not drop core. */ 172
183 if (original_real_uid != original_effective_uid) 173 /* If we are installed setuid root be careful to not drop core. */
184 { 174 if (original_real_uid != original_effective_uid) {
185 struct rlimit rlim; 175 struct rlimit rlim;
186 rlim.rlim_cur = rlim.rlim_max = 0; 176 rlim.rlim_cur = rlim.rlim_max = 0;
187 if (setrlimit(RLIMIT_CORE, &rlim) < 0) 177 if (setrlimit(RLIMIT_CORE, &rlim) < 0)
188 fatal("setrlimit failed: %.100s", strerror(errno)); 178 fatal("setrlimit failed: %.100s", strerror(errno));
189 }
190
191 /* Use uid-swapping to give up root privileges for the duration of option
192 processing. We will re-instantiate the rights when we are ready to
193 create the privileged port, and will permanently drop them when the
194 port has been created (actually, when the connection has been made, as
195 we may need to create the port several times). */
196 temporarily_use_uid(original_real_uid);
197
198 /* Set our umask to something reasonable, as some files are created with
199 the default umask. This will make them world-readable but writable
200 only by the owner, which is ok for all files for which we don't set
201 the modes explicitly. */
202 umask(022);
203
204 /* Save our own name. */
205 av0 = av[0];
206
207 /* Initialize option structure to indicate that no values have been set. */
208 initialize_options(&options);
209
210 /* Parse command-line arguments. */
211 host = NULL;
212
213 /* If program name is not one of the standard names, use it as host name. */
214 if (strchr(av0, '/'))
215 cp = strrchr(av0, '/') + 1;
216 else
217 cp = av0;
218 if (strcmp(cp, "rsh") != 0 && strcmp(cp, "ssh") != 0 &&
219 strcmp(cp, "rlogin") != 0 && strcmp(cp, "slogin") != 0)
220 host = cp;
221
222 for (optind = 1; optind < ac; optind++)
223 {
224 if (av[optind][0] != '-')
225 {
226 if (host)
227 break;
228 if ((cp = strchr(av[optind], '@'))) {
229 options.user = av[optind];
230 *cp = '\0';
231 host = ++cp;
232 }
233 else
234 host = av[optind];
235 continue;
236 } 179 }
237 opt = av[optind][1]; 180 /* Use uid-swapping to give up root privileges for the duration of
238 if (!opt) 181 option processing. We will re-instantiate the rights when we
239 usage(); 182 are ready to create the privileged port, and will permanently
240 if (strchr("eilcpLRo", opt)) /* options with arguments */ 183 drop them when the port has been created (actually, when the
241 { 184 connection has been made, as we may need to create the port
242 optarg = av[optind] + 2; 185 several times). */
243 if (strcmp(optarg, "") == 0) 186 temporarily_use_uid(original_real_uid);
244 { 187
245 if (optind >= ac - 1) 188 /* Set our umask to something reasonable, as some files are
189 created with the default umask. This will make them
190 world-readable but writable only by the owner, which is ok for
191 all files for which we don't set the modes explicitly. */
192 umask(022);
193
194 /* Save our own name. */
195 av0 = av[0];
196
197 /* Initialize option structure to indicate that no values have been set. */
198 initialize_options(&options);
199
200 /* Parse command-line arguments. */
201 host = NULL;
202
203 /* If program name is not one of the standard names, use it as host name. */
204 if (strchr(av0, '/'))
205 cp = strrchr(av0, '/') + 1;
206 else
207 cp = av0;
208 if (strcmp(cp, "rsh") != 0 && strcmp(cp, "ssh") != 0 &&
209 strcmp(cp, "rlogin") != 0 && strcmp(cp, "slogin") != 0)
210 host = cp;
211
212 for (optind = 1; optind < ac; optind++) {
213 if (av[optind][0] != '-') {
214 if (host)
215 break;
216 if ((cp = strchr(av[optind], '@'))) {
217 options.user = av[optind];
218 *cp = '\0';
219 host = ++cp;
220 } else
221 host = av[optind];
222 continue;
223 }
224 opt = av[optind][1];
225 if (!opt)
226 usage();
227 if (strchr("eilcpLRo", opt)) { /* options with arguments */
228 optarg = av[optind] + 2;
229 if (strcmp(optarg, "") == 0) {
230 if (optind >= ac - 1)
231 usage();
232 optarg = av[++optind];
233 }
234 } else {
235 if (av[optind][2])
236 usage();
237 optarg = NULL;
238 }
239 switch (opt) {
240 case 'n':
241 stdin_null_flag = 1;
242 break;
243
244 case 'f':
245 fork_after_authentication_flag = 1;
246 stdin_null_flag = 1;
247 break;
248
249 case 'x':
250 options.forward_x11 = 0;
251 break;
252
253 case 'X':
254 options.forward_x11 = 1;
255 break;
256
257 case 'g':
258 options.gateway_ports = 1;
259 break;
260
261 case 'P':
262 options.use_privileged_port = 0;
263 break;
264
265 case 'a':
266 options.forward_agent = 0;
267 break;
268#ifdef AFS
269 case 'k':
270 options.kerberos_tgt_passing = 0;
271 options.afs_token_passing = 0;
272 break;
273#endif
274 case 'i':
275 if (stat(optarg, &st) < 0) {
276 fprintf(stderr, "Warning: Identity file %s does not exist.\n",
277 optarg);
278 break;
279 }
280 if (options.num_identity_files >= SSH_MAX_IDENTITY_FILES)
281 fatal("Too many identity files specified (max %d)",
282 SSH_MAX_IDENTITY_FILES);
283 options.identity_files[options.num_identity_files++] =
284 xstrdup(optarg);
285 break;
286
287 case 't':
288 tty_flag = 1;
289 break;
290
291 case 'v':
292 case 'V':
293 fprintf(stderr, "SSH Version %s, protocol version %d.%d.\n",
294 SSH_VERSION, PROTOCOL_MAJOR, PROTOCOL_MINOR);
295 fprintf(stderr, "Compiled with SSL.\n");
296 if (opt == 'V')
297 exit(0);
298 debug_flag = 1;
299 options.log_level = SYSLOG_LEVEL_DEBUG;
300 break;
301
302 case 'q':
303 options.log_level = SYSLOG_LEVEL_QUIET;
304 break;
305
306 case 'e':
307 if (optarg[0] == '^' && optarg[2] == 0 &&
308 (unsigned char) optarg[1] >= 64 && (unsigned char) optarg[1] < 128)
309 options.escape_char = (unsigned char) optarg[1] & 31;
310 else if (strlen(optarg) == 1)
311 options.escape_char = (unsigned char) optarg[0];
312 else if (strcmp(optarg, "none") == 0)
313 options.escape_char = -2;
314 else {
315 fprintf(stderr, "Bad escape character '%s'.\n", optarg);
316 exit(1);
317 }
318 break;
319
320 case 'c':
321 options.cipher = cipher_number(optarg);
322 if (options.cipher == -1) {
323 fprintf(stderr, "Unknown cipher type '%s'\n", optarg);
324 exit(1);
325 }
326 break;
327
328 case 'p':
329 options.port = atoi(optarg);
330 if (options.port < 1 || options.port > 65535) {
331 fprintf(stderr, "Bad port %s.\n", optarg);
332 exit(1);
333 }
334 break;
335
336 case 'l':
337 options.user = optarg;
338 break;
339
340 case 'R':
341 if (sscanf(optarg, "%d:%255[^:]:%d", &fwd_port, buf,
342 &fwd_host_port) != 3) {
343 fprintf(stderr, "Bad forwarding specification '%s'.\n", optarg);
344 usage();
345 /* NOTREACHED */
346 }
347 add_remote_forward(&options, fwd_port, buf, fwd_host_port);
348 break;
349
350 case 'L':
351 if (sscanf(optarg, "%d:%255[^:]:%d", &fwd_port, buf,
352 &fwd_host_port) != 3) {
353 fprintf(stderr, "Bad forwarding specification '%s'.\n", optarg);
354 usage();
355 /* NOTREACHED */
356 }
357 add_local_forward(&options, fwd_port, buf, fwd_host_port);
358 break;
359
360 case 'C':
361 options.compression = 1;
362 break;
363
364 case 'o':
365 dummy = 1;
366 if (process_config_line(&options, host ? host : "", optarg,
367 "command-line", 0, &dummy) != 0)
368 exit(1);
369 break;
370
371 default:
372 usage();
373 }
374 }
375
376 /* Check that we got a host name. */
377 if (!host)
246 usage(); 378 usage();
247 optarg = av[++optind]; 379
248 } 380 /* check if RSA support exists */
381 if (rsa_alive() == 0) {
382 fprintf(stderr,
383 "%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
384 __progname);
385 exit(1);
249 } 386 }
250 else 387 /* Initialize the command to execute on remote host. */
251 { 388 buffer_init(&command);
252 if (av[optind][2]) 389
253 usage(); 390 /* Save the command to execute on the remote host in a buffer.
254 optarg = NULL; 391 There is no limit on the length of the command, except by the
392 maximum packet size. Also sets the tty flag if there is no
393 command. */
394 if (optind == ac) {
395 /* No command specified - execute shell on a tty. */
396 tty_flag = 1;
397 } else {
398 /* A command has been specified. Store it into the
399 buffer. */
400 for (i = optind; i < ac; i++) {
401 if (i > optind)
402 buffer_append(&command, " ", 1);
403 buffer_append(&command, av[i], strlen(av[i]));
404 }
255 } 405 }
256 switch (opt) 406
257 { 407 /* Cannot fork to background if no command. */
258 case 'n': 408 if (fork_after_authentication_flag && buffer_len(&command) == 0)
259 stdin_null_flag = 1; 409 fatal("Cannot fork into background without a command to execute.");
260 break; 410
261 411 /* Allocate a tty by default if no command specified. */
262 case 'f': 412 if (buffer_len(&command) == 0)
263 fork_after_authentication_flag = 1; 413 tty_flag = 1;
264 stdin_null_flag = 1; 414
265 break; 415 /* Do not allocate a tty if stdin is not a tty. */
266 416 if (!isatty(fileno(stdin))) {
267 case 'x': 417 if (tty_flag)
268 options.forward_x11 = 0; 418 fprintf(stderr, "Pseudo-terminal will not be allocated because stdin is not a terminal.\n");
269 break; 419 tty_flag = 0;
270 420 }
271 case 'X': 421 /* Get user data. */
272 options.forward_x11 = 1; 422 pw = getpwuid(original_real_uid);
273 break; 423 if (!pw) {
274 424 fprintf(stderr, "You don't exist, go away!\n");
275 case 'g': 425 exit(1);
276 options.gateway_ports = 1; 426 }
277 break; 427 /* Take a copy of the returned structure. */
278 428 memset(&pwcopy, 0, sizeof(pwcopy));
279 case 'P': 429 pwcopy.pw_name = xstrdup(pw->pw_name);
280 options.use_privileged_port = 0; 430 pwcopy.pw_passwd = xstrdup(pw->pw_passwd);
281 break; 431 pwcopy.pw_uid = pw->pw_uid;
282 432 pwcopy.pw_gid = pw->pw_gid;
283 case 'a': 433 pwcopy.pw_dir = xstrdup(pw->pw_dir);
284 options.forward_agent = 0; 434 pwcopy.pw_shell = xstrdup(pw->pw_shell);
285 break; 435 pw = &pwcopy;
286#ifdef AFS 436
287 case 'k': 437 /* Initialize "log" output. Since we are the client all output
288 options.kerberos_tgt_passing = 0; 438 actually goes to the terminal. */
289 options.afs_token_passing = 0; 439 log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 0);
290 break; 440
291#endif 441 /* Read per-user configuration file. */
292 case 'i': 442 snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, SSH_USER_CONFFILE);
293 if (stat(optarg, &st) < 0) 443 read_config_file(buf, host, &options);
294 { 444
295 fprintf(stderr, "Warning: Identity file %s does not exist.\n", 445 /* Read systemwide configuration file. */
296 optarg); 446 read_config_file(HOST_CONFIG_FILE, host, &options);
297 break; 447
298 } 448 /* Fill configuration defaults. */
299 if (options.num_identity_files >= SSH_MAX_IDENTITY_FILES) 449 fill_default_options(&options);
300 fatal("Too many identity files specified (max %d)", 450
301 SSH_MAX_IDENTITY_FILES); 451 /* reinit */
302 options.identity_files[options.num_identity_files++] = 452 log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 0);
303 xstrdup(optarg); 453
304 break; 454 if (options.user == NULL)
305 455 options.user = xstrdup(pw->pw_name);
306 case 't': 456
307 tty_flag = 1; 457 if (options.hostname != NULL)
308 break; 458 host = options.hostname;
309 459
310 case 'v': 460 /* Find canonic host name. */
311 case 'V': 461 if (strchr(host, '.') == 0) {
312 fprintf(stderr, "SSH Version %s, protocol version %d.%d.\n", 462 struct hostent *hp = gethostbyname(host);
313 SSH_VERSION, PROTOCOL_MAJOR, PROTOCOL_MINOR); 463 if (hp != 0) {
314 fprintf(stderr, "Compiled with SSL.\n"); 464 if (strchr(hp->h_name, '.') != 0)
315 if (opt == 'V') 465 host = xstrdup(hp->h_name);
316 exit(0); 466 else if (hp->h_aliases != 0
317 debug_flag = 1; 467 && hp->h_aliases[0] != 0
318 options.log_level = SYSLOG_LEVEL_DEBUG; 468 && strchr(hp->h_aliases[0], '.') != 0)
319 break; 469 host = xstrdup(hp->h_aliases[0]);
320
321 case 'q':
322 options.log_level = SYSLOG_LEVEL_QUIET;
323 break;
324
325 case 'e':
326 if (optarg[0] == '^' && optarg[2] == 0 &&
327 (unsigned char)optarg[1] >= 64 && (unsigned char)optarg[1] < 128)
328 options.escape_char = (unsigned char)optarg[1] & 31;
329 else
330 if (strlen(optarg) == 1)
331 options.escape_char = (unsigned char)optarg[0];
332 else
333 if (strcmp(optarg, "none") == 0)
334 options.escape_char = -2;
335 else
336 {
337 fprintf(stderr, "Bad escape character '%s'.\n", optarg);
338 exit(1);
339 } 470 }
340 break;
341
342 case 'c':
343 options.cipher = cipher_number(optarg);
344 if (options.cipher == -1)
345 {
346 fprintf(stderr, "Unknown cipher type '%s'\n", optarg);
347 exit(1);
348 }
349 break;
350
351 case 'p':
352 options.port = atoi(optarg);
353 if (options.port < 1 || options.port > 65535)
354 {
355 fprintf(stderr, "Bad port %s.\n", optarg);
356 exit(1);
357 }
358 break;
359
360 case 'l':
361 options.user = optarg;
362 break;
363
364 case 'R':
365 if (sscanf(optarg, "%d:%255[^:]:%d", &fwd_port, buf,
366 &fwd_host_port) != 3)
367 {
368 fprintf(stderr, "Bad forwarding specification '%s'.\n", optarg);
369 usage();
370 /*NOTREACHED*/
371 }
372 add_remote_forward(&options, fwd_port, buf, fwd_host_port);
373 break;
374
375 case 'L':
376 if (sscanf(optarg, "%d:%255[^:]:%d", &fwd_port, buf,
377 &fwd_host_port) != 3)
378 {
379 fprintf(stderr, "Bad forwarding specification '%s'.\n", optarg);
380 usage();
381 /*NOTREACHED*/
382 }
383 add_local_forward(&options, fwd_port, buf, fwd_host_port);
384 break;
385
386 case 'C':
387 options.compression = 1;
388 break;
389
390 case 'o':
391 dummy = 1;
392 if (process_config_line(&options, host ? host : "", optarg,
393 "command-line", 0, &dummy) != 0)
394 exit(1);
395 break;
396
397 default:
398 usage();
399 } 471 }
400 } 472 /* Disable rhosts authentication if not running as root. */
401 473 if (original_effective_uid != 0 || !options.use_privileged_port) {
402 /* Check that we got a host name. */ 474 options.rhosts_authentication = 0;
403 if (!host) 475 options.rhosts_rsa_authentication = 0;
404 usage(); 476 }
405 477 /* If using rsh has been selected, exec it now (without trying
406 /* check if RSA support exists */ 478 anything else). Note that we must release privileges first. */
407 if (rsa_alive() == 0) { 479 if (options.use_rsh) {
408 480 /* Restore our superuser privileges. This must be done
409 fprintf(stderr, 481 before permanently setting the uid. */
410 "%s: no RSA support in libssl and libcrypto. See ssl(8).\n", 482 restore_uid();
411 __progname); 483
412 exit(1); 484 /* Switch to the original uid permanently. */
413 } 485 permanently_set_uid(original_real_uid);
414 486
415 /* Initialize the command to execute on remote host. */ 487 /* Execute rsh. */
416 buffer_init(&command); 488 rsh_connect(host, options.user, &command);
417 489 fatal("rsh_connect returned");
418 /* Save the command to execute on the remote host in a buffer. There is
419 no limit on the length of the command, except by the maximum packet
420 size. Also sets the tty flag if there is no command. */
421 if (optind == ac)
422 {
423 /* No command specified - execute shell on a tty. */
424 tty_flag = 1;
425 }
426 else
427 {
428 /* A command has been specified. Store it into the buffer. */
429 for (i = optind; i < ac; i++)
430 {
431 if (i > optind)
432 buffer_append(&command, " ", 1);
433 buffer_append(&command, av[i], strlen(av[i]));
434 } 490 }
435 } 491 /* Restore our superuser privileges. */
436 492 restore_uid();
437 /* Cannot fork to background if no command. */ 493
438 if (fork_after_authentication_flag && buffer_len(&command) == 0) 494 /* Open a connection to the remote host. This needs root
439 fatal("Cannot fork into background without a command to execute."); 495 privileges if rhosts_{rsa_}authentication is enabled. */
440 496
441 /* Allocate a tty by default if no command specified. */ 497 ok = ssh_connect(host, &hostaddr, options.port,
442 if (buffer_len(&command) == 0) 498 options.connection_attempts,
443 tty_flag = 1; 499 !options.rhosts_authentication &&
444 500 !options.rhosts_rsa_authentication,
445 /* Do not allocate a tty if stdin is not a tty. */ 501 original_real_uid,
446 if (!isatty(fileno(stdin))) 502 options.proxy_command);
447 { 503
448 if (tty_flag) 504 /* If we successfully made the connection, load the host private
449 fprintf(stderr, "Pseudo-terminal will not be allocated because stdin is not a terminal.\n"); 505 key in case we will need it later for combined rsa-rhosts
450 tty_flag = 0; 506 authentication. This must be done before releasing extra
451 } 507 privileges, because the file is only readable by root. */
452 508 if (ok) {
453 /* Get user data. */ 509 host_private_key = RSA_new();
454 pw = getpwuid(original_real_uid); 510 if (load_private_key(HOST_KEY_FILE, "", host_private_key, NULL))
455 if (!pw) 511 host_private_key_loaded = 1;
456 { 512 }
457 fprintf(stderr, "You don't exist, go away!\n"); 513 /* Get rid of any extra privileges that we may have. We will no
458 exit(1); 514 longer need them. Also, extra privileges could make it very
459 } 515 hard to read identity files and other non-world-readable files
460 516 from the user's home directory if it happens to be on a NFS
461 /* Take a copy of the returned structure. */ 517 volume where root is mapped to nobody. */
462 memset(&pwcopy, 0, sizeof(pwcopy)); 518
463 pwcopy.pw_name = xstrdup(pw->pw_name); 519 /* Note that some legacy systems need to postpone the following
464 pwcopy.pw_passwd = xstrdup(pw->pw_passwd); 520 call to permanently_set_uid() until the private hostkey is
465 pwcopy.pw_uid = pw->pw_uid; 521 destroyed with RSA_free(). Otherwise the calling user could
466 pwcopy.pw_gid = pw->pw_gid; 522 ptrace() the process, read the private hostkey and impersonate
467 pwcopy.pw_dir = xstrdup(pw->pw_dir); 523 the host. OpenBSD does not allow ptracing of setuid processes. */
468 pwcopy.pw_shell = xstrdup(pw->pw_shell); 524
469 pw = &pwcopy; 525 permanently_set_uid(original_real_uid);
470 526
471 /* Initialize "log" output. Since we are the client all output actually 527 /* Now that we are back to our own permissions, create ~/.ssh
472 goes to the terminal. */ 528 directory if it doesn\'t already exist. */
473 log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 0); 529 snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, SSH_USER_DIR);
474 530 if (stat(buf, &st) < 0)
475 /* Read per-user configuration file. */ 531 if (mkdir(buf, 0755) < 0)
476 snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, SSH_USER_CONFFILE); 532 error("Could not create directory '%.200s'.", buf);
477 read_config_file(buf, host, &options); 533
478 534 /* Check if the connection failed, and try "rsh" if appropriate. */
479 /* Read systemwide configuration file. */ 535 if (!ok) {
480 read_config_file(HOST_CONFIG_FILE, host, &options); 536 if (options.port != 0)
481 537 log("Secure connection to %.100s on port %d refused%.100s.",
482 /* Fill configuration defaults. */ 538 host, options.port,
483 fill_default_options(&options); 539 options.fallback_to_rsh ? "; reverting to insecure method" : "");
484 540 else
485 /* reinit */ 541 log("Secure connection to %.100s refused%.100s.", host,
486 log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 0); 542 options.fallback_to_rsh ? "; reverting to insecure method" : "");
487 543
488 if (options.user == NULL) 544 if (options.fallback_to_rsh) {
489 options.user = xstrdup(pw->pw_name); 545 rsh_connect(host, options.user, &command);
490 546 fatal("rsh_connect returned");
491 if (options.hostname != NULL) 547 }
492 host = options.hostname; 548 exit(1);
493
494 /* Find canonic host name. */
495 if (strchr(host, '.') == 0)
496 {
497 struct hostent *hp = gethostbyname(host);
498 if (hp != 0)
499 {
500 if (strchr(hp->h_name, '.') != 0)
501 host = xstrdup(hp->h_name);
502 else if (hp->h_aliases != 0
503 && hp->h_aliases[0] != 0
504 && strchr(hp->h_aliases[0], '.') != 0)
505 host = xstrdup(hp->h_aliases[0]);
506 } 549 }
507 } 550 /* Expand ~ in options.identity_files. */
508 551 for (i = 0; i < options.num_identity_files; i++)
509 /* Disable rhosts authentication if not running as root. */ 552 options.identity_files[i] =
510 if (original_effective_uid != 0 || !options.use_privileged_port) 553 tilde_expand_filename(options.identity_files[i], original_real_uid);
511 { 554
512 options.rhosts_authentication = 0; 555 /* Expand ~ in known host file names. */
513 options.rhosts_rsa_authentication = 0; 556 options.system_hostfile = tilde_expand_filename(options.system_hostfile,
514 } 557 original_real_uid);
515 558 options.user_hostfile = tilde_expand_filename(options.user_hostfile,
516 /* If using rsh has been selected, exec it now (without trying anything 559 original_real_uid);
517 else). Note that we must release privileges first. */ 560
518 if (options.use_rsh) 561 /* Log into the remote system. This never returns if the login fails. */
519 { 562 ssh_login(host_private_key_loaded, host_private_key,
520 /* Restore our superuser privileges. This must be done before 563 host, &hostaddr, original_real_uid);
521 permanently setting the uid. */ 564
522 restore_uid(); 565 /* We no longer need the host private key. Clear it now. */
523 566 if (host_private_key_loaded)
524 /* Switch to the original uid permanently. */ 567 RSA_free(host_private_key); /* Destroys contents safely */
525 permanently_set_uid(original_real_uid); 568
526 569 /* Close connection cleanly after attack. */
527 /* Execute rsh. */ 570 cipher_attack_detected = packet_disconnect;
528 rsh_connect(host, options.user, &command); 571
529 fatal("rsh_connect returned"); 572 /* If requested, fork and let ssh continue in the background. */
530 } 573 if (fork_after_authentication_flag) {
531 574 int ret = fork();
532 /* Restore our superuser privileges. */ 575 if (ret == -1)
533 restore_uid(); 576 fatal("fork failed: %.100s", strerror(errno));
534 577 if (ret != 0)
535 /* Open a connection to the remote host. This needs root privileges if 578 exit(0);
536 rhosts_{rsa_}authentication is enabled. */ 579 setsid();
537
538 ok = ssh_connect(host, &hostaddr, options.port, options.connection_attempts,
539 !options.rhosts_authentication &&
540 !options.rhosts_rsa_authentication,
541 original_real_uid, options.proxy_command);
542
543 /* If we successfully made the connection, load the host private key in
544 case we will need it later for combined rsa-rhosts authentication.
545 This must be done before releasing extra privileges, because the file
546 is only readable by root. */
547 if (ok)
548 {
549 host_private_key = RSA_new();
550 if (load_private_key(HOST_KEY_FILE, "", host_private_key, NULL))
551 host_private_key_loaded = 1;
552 }
553
554 /* Get rid of any extra privileges that we may have. We will no longer need
555 them. Also, extra privileges could make it very hard to read identity
556 files and other non-world-readable files from the user's home directory
557 if it happens to be on a NFS volume where root is mapped to nobody. */
558
559 /* Note that some legacy systems need to postpone the following call to
560 permanently_set_uid() until the private hostkey is destroyed with
561 RSA_free(). Otherwise the calling user could ptrace() the process,
562 read the private hostkey and impersonate the host. OpenBSD does not
563 allow ptracing of setuid processes. */
564
565 permanently_set_uid(original_real_uid);
566
567 /* Now that we are back to our own permissions, create ~/.ssh directory
568 if it doesn\'t already exist. */
569 snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, SSH_USER_DIR);
570 if (stat(buf, &st) < 0)
571 if (mkdir(buf, 0755) < 0)
572 error("Could not create directory '%.200s'.", buf);
573
574 /* Check if the connection failed, and try "rsh" if appropriate. */
575 if (!ok)
576 {
577 if (options.port != 0)
578 log("Secure connection to %.100s on port %d refused%.100s.",
579 host, options.port,
580 options.fallback_to_rsh ? "; reverting to insecure method" : "");
581 else
582 log("Secure connection to %.100s refused%.100s.", host,
583 options.fallback_to_rsh ? "; reverting to insecure method" : "");
584
585 if (options.fallback_to_rsh)
586 {
587 rsh_connect(host, options.user, &command);
588 fatal("rsh_connect returned");
589 } 580 }
590 exit(1); 581 /* Enable compression if requested. */
591 } 582 if (options.compression) {
592 583 debug("Requesting compression at level %d.", options.compression_level);
593 /* Expand ~ in options.identity_files. */ 584
594 for (i = 0; i < options.num_identity_files; i++) 585 if (options.compression_level < 1 || options.compression_level > 9)
595 options.identity_files[i] = 586 fatal("Compression level must be from 1 (fast) to 9 (slow, best).");
596 tilde_expand_filename(options.identity_files[i], original_real_uid); 587
597 588 /* Send the request. */
598 /* Expand ~ in known host file names. */ 589 packet_start(SSH_CMSG_REQUEST_COMPRESSION);
599 options.system_hostfile = tilde_expand_filename(options.system_hostfile, 590 packet_put_int(options.compression_level);
600 original_real_uid); 591 packet_send();
601 options.user_hostfile = tilde_expand_filename(options.user_hostfile, 592 packet_write_wait();
602 original_real_uid); 593 type = packet_read(&plen);
603 594 if (type == SSH_SMSG_SUCCESS)
604 /* Log into the remote system. This never returns if the login fails. */ 595 packet_start_compression(options.compression_level);
605 ssh_login(host_private_key_loaded, host_private_key, 596 else if (type == SSH_SMSG_FAILURE)
606 host, &hostaddr, original_real_uid); 597 log("Warning: Remote host refused compression.");
607 598 else
608 /* We no longer need the host private key. Clear it now. */ 599 packet_disconnect("Protocol error waiting for compression response.");
609 if (host_private_key_loaded) 600 }
610 RSA_free(host_private_key); /* Destroys contents safely */ 601 /* Allocate a pseudo tty if appropriate. */
611 602 if (tty_flag) {
612 /* Close connection cleanly after attack. */ 603 debug("Requesting pty.");
613 cipher_attack_detected = packet_disconnect; 604
614 605 /* Start the packet. */
615 /* Enable compression if requested. */ 606 packet_start(SSH_CMSG_REQUEST_PTY);
616 if (options.compression) 607
617 { 608 /* Store TERM in the packet. There is no limit on the
618 debug("Requesting compression at level %d.", options.compression_level); 609 length of the string. */
619 610 cp = getenv("TERM");
620 if (options.compression_level < 1 || options.compression_level > 9) 611 if (!cp)
621 fatal("Compression level must be from 1 (fast) to 9 (slow, best)."); 612 cp = "";
622 613 packet_put_string(cp, strlen(cp));
623 /* Send the request. */ 614
624 packet_start(SSH_CMSG_REQUEST_COMPRESSION); 615 /* Store window size in the packet. */
625 packet_put_int(options.compression_level); 616 if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
626 packet_send(); 617 memset(&ws, 0, sizeof(ws));
627 packet_write_wait(); 618 packet_put_int(ws.ws_row);
628 type = packet_read(&plen); 619 packet_put_int(ws.ws_col);
629 if (type == SSH_SMSG_SUCCESS) 620 packet_put_int(ws.ws_xpixel);
630 packet_start_compression(options.compression_level); 621 packet_put_int(ws.ws_ypixel);
631 else if (type == SSH_SMSG_FAILURE) 622
632 log("Warning: Remote host refused compression."); 623 /* Store tty modes in the packet. */
633 else 624 tty_make_modes(fileno(stdin));
634 packet_disconnect("Protocol error waiting for compression response."); 625
635 } 626 /* Send the packet, and wait for it to leave. */
636 627 packet_send();
637 /* Allocate a pseudo tty if appropriate. */ 628 packet_write_wait();
638 if (tty_flag) 629
639 { 630 /* Read response from the server. */
640 debug("Requesting pty."); 631 type = packet_read(&plen);
641 632 if (type == SSH_SMSG_SUCCESS)
642 /* Start the packet. */ 633 interactive = 1;
643 packet_start(SSH_CMSG_REQUEST_PTY); 634 else if (type == SSH_SMSG_FAILURE)
644 635 log("Warning: Remote host failed or refused to allocate a pseudo tty.");
645 /* Store TERM in the packet. There is no limit on the length of the 636 else
646 string. */ 637 packet_disconnect("Protocol error waiting for pty request response.");
647 cp = getenv("TERM"); 638 }
648 if (!cp) 639 /* Request X11 forwarding if enabled and DISPLAY is set. */
649 cp = ""; 640 if (options.forward_x11 && getenv("DISPLAY") != NULL) {
650 packet_put_string(cp, strlen(cp)); 641 char line[512], proto[512], data[512];
651 642 FILE *f;
652 /* Store window size in the packet. */ 643 int forwarded = 0, got_data = 0, i;
653 if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
654 memset(&ws, 0, sizeof(ws));
655 packet_put_int(ws.ws_row);
656 packet_put_int(ws.ws_col);
657 packet_put_int(ws.ws_xpixel);
658 packet_put_int(ws.ws_ypixel);
659
660 /* Store tty modes in the packet. */
661 tty_make_modes(fileno(stdin));
662
663 /* Send the packet, and wait for it to leave. */
664 packet_send();
665 packet_write_wait();
666
667 /* Read response from the server. */
668 type = packet_read(&plen);
669 if (type == SSH_SMSG_SUCCESS)
670 interactive = 1;
671 else if (type == SSH_SMSG_FAILURE)
672 log("Warning: Remote host failed or refused to allocate a pseudo tty.");
673 else
674 packet_disconnect("Protocol error waiting for pty request response.");
675 }
676
677 /* Request X11 forwarding if enabled and DISPLAY is set. */
678 if (options.forward_x11 && getenv("DISPLAY") != NULL)
679 {
680 char line[512], proto[512], data[512];
681 FILE *f;
682 int forwarded = 0, got_data = 0, i;
683 644
684#ifdef XAUTH_PATH 645#ifdef XAUTH_PATH
685 /* Try to get Xauthority information for the display. */ 646 /* Try to get Xauthority information for the display. */
686 snprintf(line, sizeof line, "%.100s list %.200s 2>/dev/null", 647 snprintf(line, sizeof line, "%.100s list %.200s 2>/dev/null",
687 XAUTH_PATH, getenv("DISPLAY")); 648 XAUTH_PATH, getenv("DISPLAY"));
688 f = popen(line, "r"); 649 f = popen(line, "r");
689 if (f && fgets(line, sizeof(line), f) && 650 if (f && fgets(line, sizeof(line), f) &&
690 sscanf(line, "%*s %s %s", proto, data) == 2) 651 sscanf(line, "%*s %s %s", proto, data) == 2)
691 got_data = 1; 652 got_data = 1;
692 if (f) 653 if (f)
693 pclose(f); 654 pclose(f);
694#endif /* XAUTH_PATH */ 655#endif /* XAUTH_PATH */
695 /* If we didn't get authentication data, just make up some data. The 656 /* If we didn't get authentication data, just make up some
696 forwarding code will check the validity of the response anyway, and 657 data. The forwarding code will check the validity of
697 substitute this data. The X11 server, however, will ignore this 658 the response anyway, and substitute this data. The X11
698 fake data and use whatever authentication mechanisms it was using 659 server, however, will ignore this fake data and use
699 otherwise for the local connection. */ 660 whatever authentication mechanisms it was using
700 if (!got_data) 661 otherwise for the local connection. */
701 { 662 if (!got_data) {
702 u_int32_t rand = 0; 663 u_int32_t rand = 0;
703 664
704 strlcpy(proto, "MIT-MAGIC-COOKIE-1", sizeof proto); 665 strlcpy(proto, "MIT-MAGIC-COOKIE-1", sizeof proto);
705 for (i = 0; i < 16; i++) { 666 for (i = 0; i < 16; i++) {
706 if (i % 4 == 0) 667 if (i % 4 == 0)
707 rand = arc4random(); 668 rand = arc4random();
708 snprintf(data + 2 * i, sizeof data - 2 * i, "%02x", rand & 0xff); 669 snprintf(data + 2 * i, sizeof data - 2 * i, "%02x", rand & 0xff);
709 rand >>= 8; 670 rand >>= 8;
710 } 671 }
672 }
673 /* Got local authentication reasonable information.
674 Request forwarding with authentication spoofing. */
675 debug("Requesting X11 forwarding with authentication spoofing.");
676 x11_request_forwarding_with_spoofing(proto, data);
677
678 /* Read response from the server. */
679 type = packet_read(&plen);
680 if (type == SSH_SMSG_SUCCESS) {
681 forwarded = 1;
682 interactive = 1;
683 } else if (type == SSH_SMSG_FAILURE)
684 log("Warning: Remote host denied X11 forwarding.");
685 else
686 packet_disconnect("Protocol error waiting for X11 forwarding");
687 }
688 /* Tell the packet module whether this is an interactive session. */
689 packet_set_interactive(interactive, options.keepalives);
690
691 /* Clear agent forwarding if we don\'t have an agent. */
692 authfd = ssh_get_authentication_socket();
693 if (authfd < 0)
694 options.forward_agent = 0;
695 else
696 ssh_close_authentication_socket(authfd);
697
698 /* Request authentication agent forwarding if appropriate. */
699 if (options.forward_agent) {
700 debug("Requesting authentication agent forwarding.");
701 auth_request_forwarding();
702
703 /* Read response from the server. */
704 type = packet_read(&plen);
705 packet_integrity_check(plen, 0, type);
706 if (type != SSH_SMSG_SUCCESS)
707 log("Warning: Remote host denied authentication agent forwarding.");
708 }
709 /* Initiate local TCP/IP port forwardings. */
710 for (i = 0; i < options.num_local_forwards; i++) {
711 debug("Connections to local port %d forwarded to remote address %.200s:%d",
712 options.local_forwards[i].port,
713 options.local_forwards[i].host,
714 options.local_forwards[i].host_port);
715 channel_request_local_forwarding(options.local_forwards[i].port,
716 options.local_forwards[i].host,
717 options.local_forwards[i].host_port);
711 } 718 }
712 719
713 /* Got local authentication reasonable information. Request forwarding 720 /* Initiate remote TCP/IP port forwardings. */
714 with authentication spoofing. */ 721 for (i = 0; i < options.num_remote_forwards; i++) {
715 debug("Requesting X11 forwarding with authentication spoofing."); 722 debug("Connections to remote port %d forwarded to local address %.200s:%d",
716 x11_request_forwarding_with_spoofing(proto, data); 723 options.remote_forwards[i].port,
717 724 options.remote_forwards[i].host,
718 /* Read response from the server. */ 725 options.remote_forwards[i].host_port);
719 type = packet_read(&plen); 726 channel_request_remote_forwarding(options.remote_forwards[i].port,
720 if (type == SSH_SMSG_SUCCESS) 727 options.remote_forwards[i].host,
721 { 728 options.remote_forwards[i].host_port);
722 forwarded = 1;
723 interactive = 1;
724 } 729 }
725 else if (type == SSH_SMSG_FAILURE) 730
726 log("Warning: Remote host denied X11 forwarding."); 731 /* If a command was specified on the command line, execute the
727 else 732 command now. Otherwise request the server to start a shell. */
728 packet_disconnect("Protocol error waiting for X11 forwarding"); 733 if (buffer_len(&command) > 0) {
729 } 734 int len = buffer_len(&command);
730 735 if (len > 900)
731 /* Tell the packet module whether this is an interactive session. */ 736 len = 900;
732 packet_set_interactive(interactive, options.keepalives); 737 debug("Sending command: %.*s", len, buffer_ptr(&command));
733 738 packet_start(SSH_CMSG_EXEC_CMD);
734 /* Clear agent forwarding if we don\'t have an agent. */ 739 packet_put_string(buffer_ptr(&command), buffer_len(&command));
735 authfd = ssh_get_authentication_socket(); 740 packet_send();
736 if (authfd < 0) 741 packet_write_wait();
737 options.forward_agent = 0; 742 } else {
738 else 743 debug("Requesting shell.");
739 ssh_close_authentication_socket(authfd); 744 packet_start(SSH_CMSG_EXEC_SHELL);
740 745 packet_send();
741 /* Request authentication agent forwarding if appropriate. */ 746 packet_write_wait();
742 if (options.forward_agent) 747 }
743 { 748
744 debug("Requesting authentication agent forwarding."); 749 /* Enter the interactive session. */
745 auth_request_forwarding(); 750 exit_status = client_loop(tty_flag, tty_flag ? options.escape_char : -1);
746 751
747 /* Read response from the server. */ 752 /* Close the connection to the remote host. */
748 type = packet_read(&plen); 753 packet_close();
749 packet_integrity_check(plen, 0, type); 754
750 if (type != SSH_SMSG_SUCCESS) 755 /* Exit with the status returned by the program on the remote side. */
751 log("Warning: Remote host denied authentication agent forwarding."); 756 exit(exit_status);
752 }
753
754 /* Initiate local TCP/IP port forwardings. */
755 for (i = 0; i < options.num_local_forwards; i++)
756 {
757 debug("Connections to local port %d forwarded to remote address %.200s:%d",
758 options.local_forwards[i].port, options.local_forwards[i].host,
759 options.local_forwards[i].host_port);
760 channel_request_local_forwarding(options.local_forwards[i].port,
761 options.local_forwards[i].host,
762 options.local_forwards[i].host_port);
763 }
764
765 /* Initiate remote TCP/IP port forwardings. */
766 for (i = 0; i < options.num_remote_forwards; i++)
767 {
768 debug("Connections to remote port %d forwarded to local address %.200s:%d",
769 options.remote_forwards[i].port, options.remote_forwards[i].host,
770 options.remote_forwards[i].host_port);
771 channel_request_remote_forwarding(options.remote_forwards[i].port,
772 options.remote_forwards[i].host,
773 options.remote_forwards[i].host_port);
774 }
775
776 /* If requested, fork and let ssh continue in the background. */
777 if (fork_after_authentication_flag)
778 {
779 int ret = fork();
780 if (ret == -1)
781 fatal("fork failed: %.100s", strerror(errno));
782 if (ret != 0)
783 exit(0);
784 setsid();
785 }
786
787 /* If a command was specified on the command line, execute the command now.
788 Otherwise request the server to start a shell. */
789 if (buffer_len(&command) > 0)
790 {
791 int len = buffer_len(&command);
792 if (len > 900)
793 len = 900;
794 debug("Sending command: %.*s", len, buffer_ptr(&command));
795 packet_start(SSH_CMSG_EXEC_CMD);
796 packet_put_string(buffer_ptr(&command), buffer_len(&command));
797 packet_send();
798 packet_write_wait();
799 }
800 else
801 {
802 debug("Requesting shell.");
803 packet_start(SSH_CMSG_EXEC_SHELL);
804 packet_send();
805 packet_write_wait();
806 }
807
808 /* Enter the interactive session. */
809 exit_status = client_loop(tty_flag, tty_flag ? options.escape_char : -1);
810
811 /* Close the connection to the remote host. */
812 packet_close();
813
814 /* Exit with the status returned by the program on the remote side. */
815 exit(exit_status);
816} 757}
diff --git a/ssh.h b/ssh.h
index 90668286b..f8426bfbb 100644
--- a/ssh.h
+++ b/ssh.h
@@ -1,19 +1,19 @@
1/* 1/*
2 2 *
3ssh.h 3 * ssh.h
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Fri Mar 17 17:09:37 1995 ylo 10 * Created: Fri Mar 17 17:09:37 1995 ylo
11 11 *
12Generic header file for ssh. 12 * Generic header file for ssh.
13 13 *
14*/ 14 */
15 15
16/* RCSID("$Id: ssh.h,v 1.14 1999/11/21 02:23:53 damien Exp $"); */ 16/* RCSID("$Id: ssh.h,v 1.15 1999/11/24 13:26:23 damien Exp $"); */
17 17
18#ifndef SSH_H 18#ifndef SSH_H
19#define SSH_H 19#define SSH_H
@@ -25,7 +25,7 @@ Generic header file for ssh.
25#include "rsa.h" 25#include "rsa.h"
26#include "cipher.h" 26#include "cipher.h"
27 27
28/* The default cipher used if IDEA is not supported by the remote host. 28/* The default cipher used if IDEA is not supported by the remote host.
29 It is recommended that this be one of the mandatory ciphers (DES, 3DES), 29 It is recommended that this be one of the mandatory ciphers (DES, 3DES),
30 though that is not required. */ 30 though that is not required. */
31#define SSH_FALLBACK_CIPHER SSH_CIPHER_3DES 31#define SSH_FALLBACK_CIPHER SSH_CIPHER_3DES
@@ -59,7 +59,9 @@ Generic header file for ssh.
59#define ETCDIR "/etc" 59#define ETCDIR "/etc"
60#endif /* ETCDIR */ 60#endif /* ETCDIR */
61 61
62#ifndef PIDDIR
62#define PIDDIR "/var/run" 63#define PIDDIR "/var/run"
64#endif /* PIDDIR */
63 65
64/* System-wide file containing host keys of known hosts. This file should be 66/* System-wide file containing host keys of known hosts. This file should be
65 world-readable. */ 67 world-readable. */
@@ -76,15 +78,15 @@ only by root, whereas ssh_config should be world-readable. */
76#define HOST_CONFIG_FILE ETCDIR "/ssh_config" 78#define HOST_CONFIG_FILE ETCDIR "/ssh_config"
77 79
78#ifndef SSH_PROGRAM 80#ifndef SSH_PROGRAM
79#define SSH_PROGRAM "/usr/bin/ssh" 81#define SSH_PROGRAM "/usr/bin/ssh"
80#endif /* SSH_PROGRAM */ 82#endif /* SSH_PROGRAM */
81 83
82#ifndef LOGIN_PROGRAM 84#ifndef LOGIN_PROGRAM
83#define LOGIN_PROGRAM "/usr/bin/login" 85#define LOGIN_PROGRAM "/usr/bin/login"
84#endif /* LOGIN_PROGRAM */ 86#endif /* LOGIN_PROGRAM */
85 87
86#ifndef ASKPASS_PROGRAM 88#ifndef ASKPASS_PROGRAM
87#define ASKPASS_PROGRAM "/usr/lib/ssh/ssh-askpass" 89#define ASKPASS_PROGRAM "/usr/lib/ssh/ssh-askpass"
88#endif /* ASKPASS_PROGRAM */ 90#endif /* ASKPASS_PROGRAM */
89 91
90/* The process id of the daemon listening for connections is saved 92/* 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. */
100 not contain anything particularly secret. */ 102 not contain anything particularly secret. */
101#define SSH_USER_HOSTFILE "~/.ssh/known_hosts" 103#define SSH_USER_HOSTFILE "~/.ssh/known_hosts"
102 104
103/* Name of the default file containing client-side authentication key. 105/* Name of the default file containing client-side authentication key.
104 This file should only be readable by the user him/herself. */ 106 This file should only be readable by the user him/herself. */
105#define SSH_CLIENT_IDENTITY ".ssh/identity" 107#define SSH_CLIENT_IDENTITY ".ssh/identity"
106 108
@@ -116,7 +118,7 @@ only by root, whereas ssh_config should be world-readable. */
116 readable by anyone but the user him/herself, but does not contain 118 readable by anyone but the user him/herself, but does not contain
117 anything particularly secret. If the user\'s home directory resides 119 anything particularly secret. If the user\'s home directory resides
118 on an NFS volume where root is mapped to nobody, this may need to be 120 on an NFS volume where root is mapped to nobody, this may need to be
119 world-readable. (This file is read by the daemon which is running as 121 world-readable. (This file is read by the daemon which is running as
120 root.) */ 122 root.) */
121#define SSH_USER_PERMITTED_KEYS ".ssh/authorized_keys" 123#define SSH_USER_PERMITTED_KEYS ".ssh/authorized_keys"
122 124
@@ -130,7 +132,7 @@ only by root, whereas ssh_config should be world-readable. */
130/* Ssh-only version of /etc/hosts.equiv. */ 132/* Ssh-only version of /etc/hosts.equiv. */
131#define SSH_HOSTS_EQUIV ETCDIR "/shosts.equiv" 133#define SSH_HOSTS_EQUIV ETCDIR "/shosts.equiv"
132 134
133/* Additionally, the daemon may use ~/.rhosts and /etc/hosts.equiv if 135/* Additionally, the daemon may use ~/.rhosts and /etc/hosts.equiv if
134 rhosts authentication is enabled. */ 136 rhosts authentication is enabled. */
135 137
136/* Name of the environment variable containing the pathname of the 138/* Name of the environment variable containing the pathname of the
@@ -145,7 +147,7 @@ only by root, whereas ssh_config should be world-readable. */
145 many bits. This is to make double encryption with rsaref work. */ 147 many bits. This is to make double encryption with rsaref work. */
146#define SSH_KEY_BITS_RESERVED 128 148#define SSH_KEY_BITS_RESERVED 128
147 149
148/* Length of the session key in bytes. (Specified as 256 bits in the 150/* Length of the session key in bytes. (Specified as 256 bits in the
149 protocol.) */ 151 protocol.) */
150#define SSH_SESSION_KEY_LENGTH 32 152#define SSH_SESSION_KEY_LENGTH 32
151 153
@@ -158,21 +160,23 @@ only by root, whereas ssh_config should be world-readable. */
158#define SSH_AUTH_RSA 2 160#define SSH_AUTH_RSA 2
159#define SSH_AUTH_PASSWORD 3 161#define SSH_AUTH_PASSWORD 3
160#define SSH_AUTH_RHOSTS_RSA 4 162#define SSH_AUTH_RHOSTS_RSA 4
161 /* 5 is TIS */ 163#define SSH_AUTH_TIS 5
162#define SSH_AUTH_KERBEROS 6 164#define SSH_AUTH_KERBEROS 6
163#define SSH_PASS_KERBEROS_TGT 7 165#define SSH_PASS_KERBEROS_TGT 7
164 /* 8 to 15 are reserved */ 166 /* 8 to 15 are reserved */
165#define SSH_PASS_AFS_TOKEN 21 167#define SSH_PASS_AFS_TOKEN 21
166 168
167/* Protocol flags. These are bit masks. */ 169/* Protocol flags. These are bit masks. */
168#define SSH_PROTOFLAG_SCREEN_NUMBER 1 /* X11 forwarding includes screen */ 170#define SSH_PROTOFLAG_SCREEN_NUMBER 1 /* X11 forwarding includes
169#define SSH_PROTOFLAG_HOST_IN_FWD_OPEN 2 /* forwarding opens contain host */ 171 * screen */
172#define SSH_PROTOFLAG_HOST_IN_FWD_OPEN 2 /* forwarding opens contain
173 * host */
170 174
171/* Definition of message types. New values can be added, but old values 175/* Definition of message types. New values can be added, but old values
172 should not be removed or without careful consideration of the consequences 176 should not be removed or without careful consideration of the consequences
173 for compatibility. The maximum value is 254; value 255 is reserved 177 for compatibility. The maximum value is 254; value 255 is reserved
174 for future extension. */ 178 for future extension. */
175/* Message name */ /* msg code */ /* arguments */ 179 /* Message name *//* msg code *//* arguments */
176#define SSH_MSG_NONE 0 /* no message */ 180#define SSH_MSG_NONE 0 /* no message */
177#define SSH_MSG_DISCONNECT 1 /* cause (string) */ 181#define SSH_MSG_DISCONNECT 1 /* cause (string) */
178#define SSH_SMSG_PUBLIC_KEY 2 /* ck,msk,srvk,hostk */ 182#define SSH_SMSG_PUBLIC_KEY 2 /* ck,msk,srvk,hostk */
@@ -212,10 +216,9 @@ only by root, whereas ssh_config should be world-readable. */
212#define SSH_MSG_DEBUG 36 /* string */ 216#define SSH_MSG_DEBUG 36 /* string */
213#define SSH_CMSG_REQUEST_COMPRESSION 37 /* level 1-9 (int) */ 217#define SSH_CMSG_REQUEST_COMPRESSION 37 /* level 1-9 (int) */
214#define SSH_CMSG_MAX_PACKET_SIZE 38 /* size 4k-1024k (int) */ 218#define SSH_CMSG_MAX_PACKET_SIZE 38 /* size 4k-1024k (int) */
215#define SSH_CMSG_AUTH_TIS 39 /* this is proto-1.5, but we ignore TIS */ 219#define SSH_CMSG_AUTH_TIS 39 /* we use this for s/key */
216#define SSH_SMSG_AUTH_TIS_CHALLENGE 40 220#define SSH_SMSG_AUTH_TIS_CHALLENGE 40 /* challenge (string) */
217#define SSH_CMSG_AUTH_TIS_RESPONSE 41 221#define SSH_CMSG_AUTH_TIS_RESPONSE 41 /* response (string) */
218
219#define SSH_CMSG_AUTH_KERBEROS 42 /* (KTEXT) */ 222#define SSH_CMSG_AUTH_KERBEROS 42 /* (KTEXT) */
220#define SSH_SMSG_AUTH_KERBEROS_RESPONSE 43 /* (KTEXT) */ 223#define SSH_SMSG_AUTH_KERBEROS_RESPONSE 43 /* (KTEXT) */
221#define SSH_CMSG_HAVE_KERBEROS_TGT 44 /* credentials (s) */ 224#define SSH_CMSG_HAVE_KERBEROS_TGT 44 /* credentials (s) */
@@ -223,74 +226,79 @@ only by root, whereas ssh_config should be world-readable. */
223 226
224/*------------ definitions for login.c -------------*/ 227/*------------ definitions for login.c -------------*/
225 228
226/* Returns the time when the user last logged in. Returns 0 if the 229/* Returns the time when the user last logged in. Returns 0 if the
227 information is not available. This must be called before record_login. 230 information is not available. This must be called before record_login.
228 The host from which the user logged in is stored in buf. */ 231 The host from which the user logged in is stored in buf. */
229unsigned long get_last_login_time(uid_t uid, const char *logname, 232unsigned long
230 char *buf, unsigned int bufsize); 233get_last_login_time(uid_t uid, const char *logname,
234 char *buf, unsigned int bufsize);
231 235
232/* Records that the user has logged in. This does many things normally 236/* Records that the user has logged in. This does many things normally
233 done by login(1). */ 237 done by login(1). */
234void record_login(int pid, const char *ttyname, const char *user, uid_t uid, 238void
235 const char *host, struct sockaddr_in *addr); 239record_login(int pid, const char *ttyname, const char *user, uid_t uid,
240 const char *host, struct sockaddr_in * addr);
236 241
237/* Records that the user has logged out. This does many thigs normally 242/* Records that the user has logged out. This does many thigs normally
238 done by login(1) or init. */ 243 done by login(1) or init. */
239void record_logout(int pid, const char *ttyname); 244void record_logout(int pid, const char *ttyname);
240 245
241/*------------ definitions for sshconnect.c ----------*/ 246/*------------ definitions for sshconnect.c ----------*/
242 247
243/* Opens a TCP/IP connection to the remote server on the given host. If 248/* Opens a TCP/IP connection to the remote server on the given host. If
244 port is 0, the default port will be used. If anonymous is zero, 249 port is 0, the default port will be used. If anonymous is zero,
245 a privileged port will be allocated to make the connection. 250 a privileged port will be allocated to make the connection.
246 This requires super-user privileges if anonymous is false. 251 This requires super-user privileges if anonymous is false.
247 Connection_attempts specifies the maximum number of tries, one per 252 Connection_attempts specifies the maximum number of tries, one per
248 second. This returns true on success, and zero on failure. If the 253 second. This returns true on success, and zero on failure. If the
249 connection is successful, this calls packet_set_connection for the 254 connection is successful, this calls packet_set_connection for the
250 connection. */ 255 connection. */
251int ssh_connect(const char *host, struct sockaddr_in *hostaddr, 256int
252 int port, int connection_attempts, 257ssh_connect(const char *host, struct sockaddr_in * hostaddr,
253 int anonymous, uid_t original_real_uid, 258 int port, int connection_attempts,
254 const char *proxy_command); 259 int anonymous, uid_t original_real_uid,
260 const char *proxy_command);
255 261
256/* Starts a dialog with the server, and authenticates the current user on the 262/* Starts a dialog with the server, and authenticates the current user on the
257 server. This does not need any extra privileges. The basic connection 263 server. This does not need any extra privileges. The basic connection
258 to the server must already have been established before this is called. 264 to the server must already have been established before this is called.
259 If login fails, this function prints an error and never returns. 265 If login fails, this function prints an error and never returns.
260 This initializes the random state, and leaves it initialized (it will also 266 This initializes the random state, and leaves it initialized (it will also
261 have references from the packet module). */ 267 have references from the packet module). */
262 268
263void ssh_login(int host_key_valid, RSA *host_key, const char *host, 269void
264 struct sockaddr_in *hostaddr, uid_t original_real_uid); 270ssh_login(int host_key_valid, RSA * host_key, const char *host,
271 struct sockaddr_in * hostaddr, uid_t original_real_uid);
265 272
266/*------------ Definitions for various authentication methods. -------*/ 273/*------------ Definitions for various authentication methods. -------*/
267 274
268/* Tries to authenticate the user using the .rhosts file. Returns true if 275/* Tries to authenticate the user using the .rhosts file. Returns true if
269 authentication succeeds. If ignore_rhosts is non-zero, this will not 276 authentication succeeds. If ignore_rhosts is non-zero, this will not
270 consider .rhosts and .shosts (/etc/hosts.equiv will still be used). */ 277 consider .rhosts and .shosts (/etc/hosts.equiv will still be used). */
271int auth_rhosts(struct passwd *pw, const char *client_user); 278int auth_rhosts(struct passwd * pw, const char *client_user);
272 279
273/* Tries to authenticate the user using the .rhosts file and the host using 280/* Tries to authenticate the user using the .rhosts file and the host using
274 its host key. Returns true if authentication succeeds. */ 281 its host key. Returns true if authentication succeeds. */
275int auth_rhosts_rsa(struct passwd *pw, const char *client_user, 282int
276 BIGNUM *client_host_key_e, BIGNUM *client_host_key_n); 283auth_rhosts_rsa(struct passwd * pw, const char *client_user,
284 BIGNUM * client_host_key_e, BIGNUM * client_host_key_n);
277 285
278/* Tries to authenticate the user using password. Returns true if 286/* Tries to authenticate the user using password. Returns true if
279 authentication succeeds. */ 287 authentication succeeds. */
280int auth_password(struct passwd *pw, const char *password); 288int auth_password(struct passwd * pw, const char *password);
281 289
282/* Performs the RSA authentication dialog with the client. This returns 290/* Performs the RSA authentication dialog with the client. This returns
283 0 if the client could not be authenticated, and 1 if authentication was 291 0 if the client could not be authenticated, and 1 if authentication was
284 successful. This may exit if there is a serious protocol violation. */ 292 successful. This may exit if there is a serious protocol violation. */
285int auth_rsa(struct passwd *pw, BIGNUM *client_n); 293int auth_rsa(struct passwd * pw, BIGNUM * client_n);
286 294
287/* Parses an RSA key (number of bits, e, n) from a string. Moves the pointer 295/* Parses an RSA key (number of bits, e, n) from a string. Moves the pointer
288 over the key. Skips any whitespace at the beginning and at end. */ 296 over the key. Skips any whitespace at the beginning and at end. */
289int auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM *e, BIGNUM *n); 297int auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n);
290 298
291/* Returns the name of the machine at the other end of the socket. The 299/* Returns the name of the machine at the other end of the socket. The
292 returned string should be freed by the caller. */ 300 returned string should be freed by the caller. */
293char *get_remote_hostname(int socket); 301char *get_remote_hostname(int socket);
294 302
295/* Return the canonical name of the host in the other side of the current 303/* Return the canonical name of the host in the other side of the current
296 connection (as returned by packet_get_connection). The host name is 304 connection (as returned by packet_get_connection). The host name is
@@ -302,296 +310,301 @@ const char *get_canonical_hostname(void);
302const char *get_remote_ipaddr(void); 310const char *get_remote_ipaddr(void);
303 311
304/* Returns the port number of the peer of the socket. */ 312/* Returns the port number of the peer of the socket. */
305int get_peer_port(int sock); 313int get_peer_port(int sock);
306 314
307/* Returns the port number of the remote host. */ 315/* Returns the port number of the remote host. */
308int get_remote_port(void); 316int get_remote_port(void);
309 317
310/* Tries to match the host name (which must be in all lowercase) against the 318/* Tries to match the host name (which must be in all lowercase) against the
311 comma-separated sequence of subpatterns (each possibly preceded by ! to 319 comma-separated sequence of subpatterns (each possibly preceded by ! to
312 indicate negation). Returns true if there is a positive match; zero 320 indicate negation). Returns true if there is a positive match; zero
313 otherwise. */ 321 otherwise. */
314int match_hostname(const char *host, const char *pattern, unsigned int len); 322int match_hostname(const char *host, const char *pattern, unsigned int len);
315 323
316/* Checks whether the given host is already in the list of our known hosts. 324/* Checks whether the given host is already in the list of our known hosts.
317 Returns HOST_OK if the host is known and has the specified key, 325 Returns HOST_OK if the host is known and has the specified key,
318 HOST_NEW if the host is not known, and HOST_CHANGED if the host is known 326 HOST_NEW if the host is not known, and HOST_CHANGED if the host is known
319 but used to have a different host key. The host must be in all lowercase. */ 327 but used to have a different host key. The host must be in all lowercase. */
320typedef enum { HOST_OK, HOST_NEW, HOST_CHANGED } HostStatus; 328typedef enum {
321HostStatus check_host_in_hostfile(const char *filename, const char *host, 329 HOST_OK, HOST_NEW, HOST_CHANGED
322 BIGNUM *e, BIGNUM *n, BIGNUM *ke, BIGNUM *kn); 330} HostStatus;
331HostStatus
332check_host_in_hostfile(const char *filename, const char *host,
333 BIGNUM * e, BIGNUM * n, BIGNUM * ke, BIGNUM * kn);
323 334
324/* Appends an entry to the host file. Returns false if the entry 335/* Appends an entry to the host file. Returns false if the entry
325 could not be appended. */ 336 could not be appended. */
326int add_host_to_hostfile(const char *filename, const char *host, 337int
327 BIGNUM *e, BIGNUM *n); 338add_host_to_hostfile(const char *filename, const char *host,
339 BIGNUM * e, BIGNUM * n);
328 340
329/* Performs the RSA authentication challenge-response dialog with the client, 341/* Performs the RSA authentication challenge-response dialog with the client,
330 and returns true (non-zero) if the client gave the correct answer to 342 and returns true (non-zero) if the client gave the correct answer to
331 our challenge; returns zero if the client gives a wrong answer. */ 343 our challenge; returns zero if the client gives a wrong answer. */
332int auth_rsa_challenge_dialog(BIGNUM *e, BIGNUM *n); 344int auth_rsa_challenge_dialog(BIGNUM * e, BIGNUM * n);
333 345
334/* Reads a passphrase from /dev/tty with echo turned off. Returns the 346/* Reads a passphrase from /dev/tty with echo turned off. Returns the
335 passphrase (allocated with xmalloc). Exits if EOF is encountered. 347 passphrase (allocated with xmalloc). Exits if EOF is encountered.
336 If from_stdin is true, the passphrase will be read from stdin instead. */ 348 If from_stdin is true, the passphrase will be read from stdin instead. */
337char *read_passphrase(const char *prompt, int from_stdin); 349char *read_passphrase(const char *prompt, int from_stdin);
338 350
339/* Saves the authentication (private) key in a file, encrypting it with 351/* Saves the authentication (private) key in a file, encrypting it with
340 passphrase. The identification of the file (lowest 64 bits of n) 352 passphrase. The identification of the file (lowest 64 bits of n)
341 will precede the key to provide identification of the key without 353 will precede the key to provide identification of the key without
342 needing a passphrase. */ 354 needing a passphrase. */
343int save_private_key(const char *filename, const char *passphrase, 355int
344 RSA *private_key, const char *comment); 356save_private_key(const char *filename, const char *passphrase,
357 RSA * private_key, const char *comment);
345 358
346/* Loads the public part of the key file (public key and comment). 359/* Loads the public part of the key file (public key and comment).
347 Returns 0 if an error occurred; zero if the public key was successfully 360 Returns 0 if an error occurred; zero if the public key was successfully
348 read. The comment of the key is returned in comment_return if it is 361 read. The comment of the key is returned in comment_return if it is
349 non-NULL; the caller must free the value with xfree. */ 362 non-NULL; the caller must free the value with xfree. */
350int load_public_key(const char *filename, RSA *pub, 363int
351 char **comment_return); 364load_public_key(const char *filename, RSA * pub,
365 char **comment_return);
352 366
353/* Loads the private key from the file. Returns 0 if an error is encountered 367/* Loads the private key from the file. Returns 0 if an error is encountered
354 (file does not exist or is not readable, or passphrase is bad). 368 (file does not exist or is not readable, or passphrase is bad).
355 This initializes the private key. The comment of the key is returned 369 This initializes the private key. The comment of the key is returned
356 in comment_return if it is non-NULL; the caller must free the value 370 in comment_return if it is non-NULL; the caller must free the value
357 with xfree. */ 371 with xfree. */
358int load_private_key(const char *filename, const char *passphrase, 372int
359 RSA *private_key, char **comment_return); 373load_private_key(const char *filename, const char *passphrase,
374 RSA * private_key, char **comment_return);
360 375
361/*------------ Definitions for logging. -----------------------*/ 376/*------------ Definitions for logging. -----------------------*/
362 377
363/* Supported syslog facilities and levels. */ 378/* Supported syslog facilities and levels. */
364typedef enum 379typedef enum {
365{ 380 SYSLOG_FACILITY_DAEMON,
366 SYSLOG_FACILITY_DAEMON, 381 SYSLOG_FACILITY_USER,
367 SYSLOG_FACILITY_USER, 382 SYSLOG_FACILITY_AUTH,
368 SYSLOG_FACILITY_AUTH, 383 SYSLOG_FACILITY_LOCAL0,
369 SYSLOG_FACILITY_LOCAL0, 384 SYSLOG_FACILITY_LOCAL1,
370 SYSLOG_FACILITY_LOCAL1, 385 SYSLOG_FACILITY_LOCAL2,
371 SYSLOG_FACILITY_LOCAL2, 386 SYSLOG_FACILITY_LOCAL3,
372 SYSLOG_FACILITY_LOCAL3, 387 SYSLOG_FACILITY_LOCAL4,
373 SYSLOG_FACILITY_LOCAL4, 388 SYSLOG_FACILITY_LOCAL5,
374 SYSLOG_FACILITY_LOCAL5, 389 SYSLOG_FACILITY_LOCAL6,
375 SYSLOG_FACILITY_LOCAL6, 390 SYSLOG_FACILITY_LOCAL7
376 SYSLOG_FACILITY_LOCAL7 391} SyslogFacility;
377} SyslogFacility; 392
378 393typedef enum {
379typedef enum 394 SYSLOG_LEVEL_QUIET,
380{ 395 SYSLOG_LEVEL_FATAL,
381 SYSLOG_LEVEL_QUIET, 396 SYSLOG_LEVEL_ERROR,
382 SYSLOG_LEVEL_FATAL, 397 SYSLOG_LEVEL_INFO,
383 SYSLOG_LEVEL_ERROR, 398 SYSLOG_LEVEL_VERBOSE,
384 SYSLOG_LEVEL_INFO, 399 SYSLOG_LEVEL_DEBUG
385 SYSLOG_LEVEL_CHAT, 400} LogLevel;
386 SYSLOG_LEVEL_DEBUG
387} LogLevel;
388
389/* Initializes logging. */ 401/* Initializes logging. */
390void log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr); 402void log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr);
391 403
392/* Logging implementation, depending on server or client */ 404/* Logging implementation, depending on server or client */
393void do_log(LogLevel level, const char *fmt, va_list args); 405void do_log(LogLevel level, const char *fmt, va_list args);
394 406
395/* name to facility/level */ 407/* name to facility/level */
396SyslogFacility log_facility_number(char *name); 408SyslogFacility log_facility_number(char *name);
397LogLevel log_level_number(char *name); 409LogLevel log_level_number(char *name);
398 410
399/* Output a message to syslog or stderr */ 411/* Output a message to syslog or stderr */
400void fatal(const char *fmt, ...); 412void fatal(const char *fmt,...) __attribute__((format(printf, 1, 2)));
401void error(const char *fmt, ...); 413void error(const char *fmt,...) __attribute__((format(printf, 1, 2)));
402void log(const char *fmt, ...); 414void log(const char *fmt,...) __attribute__((format(printf, 1, 2)));
403void chat(const char *fmt, ...); 415void verbose(const char *fmt,...) __attribute__((format(printf, 1, 2)));
404void debug(const char *fmt, ...); 416void debug(const char *fmt,...) __attribute__((format(printf, 1, 2)));
405 417
406/* same as fatal() but w/o logging */ 418/* same as fatal() but w/o logging */
407void fatal_cleanup(void); 419void fatal_cleanup(void);
408 420
409/* Registers a cleanup function to be called by fatal()/fatal_cleanup() before exiting. 421/* Registers a cleanup function to be called by fatal()/fatal_cleanup() before exiting.
410 It is permissible to call fatal_remove_cleanup for the function itself 422 It is permissible to call fatal_remove_cleanup for the function itself
411 from the function. */ 423 from the function. */
412void fatal_add_cleanup(void (*proc)(void *context), void *context); 424void fatal_add_cleanup(void (*proc) (void *context), void *context);
413 425
414/* Removes a cleanup function to be called at fatal(). */ 426/* Removes a cleanup function to be called at fatal(). */
415void fatal_remove_cleanup(void (*proc)(void *context), void *context); 427void fatal_remove_cleanup(void (*proc) (void *context), void *context);
416 428
417/*---------------- definitions for channels ------------------*/ 429/*---------------- definitions for channels ------------------*/
418 430
419/* Sets specific protocol options. */ 431/* Sets specific protocol options. */
420void channel_set_options(int hostname_in_open); 432void channel_set_options(int hostname_in_open);
421 433
422/* Allocate a new channel object and set its type and socket. Remote_name 434/* Allocate a new channel object and set its type and socket. Remote_name
423 must have been allocated with xmalloc; this will free it when the channel 435 must have been allocated with xmalloc; this will free it when the channel
424 is freed. */ 436 is freed. */
425int channel_allocate(int type, int sock, char *remote_name); 437int channel_allocate(int type, int sock, char *remote_name);
426 438
427/* Free the channel and close its socket. */ 439/* Free the channel and close its socket. */
428void channel_free(int channel); 440void channel_free(int channel);
429 441
430/* Add any bits relevant to channels in select bitmasks. */ 442/* Add any bits relevant to channels in select bitmasks. */
431void channel_prepare_select(fd_set *readset, fd_set *writeset); 443void channel_prepare_select(fd_set * readset, fd_set * writeset);
432 444
433/* After select, perform any appropriate operations for channels which 445/* After select, perform any appropriate operations for channels which
434 have events pending. */ 446 have events pending. */
435void channel_after_select(fd_set *readset, fd_set *writeset); 447void channel_after_select(fd_set * readset, fd_set * writeset);
436 448
437/* If there is data to send to the connection, send some of it now. */ 449/* If there is data to send to the connection, send some of it now. */
438void channel_output_poll(void); 450void channel_output_poll(void);
439 451
440/* This is called when a packet of type CHANNEL_DATA has just been received. 452/* This is called when a packet of type CHANNEL_DATA has just been received.
441 The message type has already been consumed, but channel number and data 453 The message type has already been consumed, but channel number and data
442 is still there. */ 454 is still there. */
443void channel_input_data(int payload_len); 455void channel_input_data(int payload_len);
444 456
445/* Returns true if no channel has too much buffered data. */ 457/* Returns true if no channel has too much buffered data. */
446int channel_not_very_much_buffered_data(void); 458int channel_not_very_much_buffered_data(void);
447 459
448/* This is called after receiving CHANNEL_CLOSE. */ 460/* This is called after receiving CHANNEL_CLOSE. */
449void channel_input_close(void); 461void channel_input_close(void);
450 462
451/* This is called after receiving CHANNEL_CLOSE_CONFIRMATION. */ 463/* This is called after receiving CHANNEL_CLOSE_CONFIRMATION. */
452void channel_input_close_confirmation(void); 464void channel_input_close_confirmation(void);
453 465
454/* This is called after receiving CHANNEL_OPEN_CONFIRMATION. */ 466/* This is called after receiving CHANNEL_OPEN_CONFIRMATION. */
455void channel_input_open_confirmation(void); 467void channel_input_open_confirmation(void);
456 468
457/* This is called after receiving CHANNEL_OPEN_FAILURE from the other side. */ 469/* This is called after receiving CHANNEL_OPEN_FAILURE from the other side. */
458void channel_input_open_failure(void); 470void channel_input_open_failure(void);
459 471
460/* This closes any sockets that are listening for connections; this removes 472/* This closes any sockets that are listening for connections; this removes
461 any unix domain sockets. */ 473 any unix domain sockets. */
462void channel_stop_listening(void); 474void channel_stop_listening(void);
463 475
464/* Closes the sockets of all channels. This is used to close extra file 476/* Closes the sockets of all channels. This is used to close extra file
465 descriptors after a fork. */ 477 descriptors after a fork. */
466void channel_close_all(void); 478void channel_close_all(void);
467 479
468/* Returns the maximum file descriptor number used by the channels. */ 480/* Returns the maximum file descriptor number used by the channels. */
469int channel_max_fd(void); 481int channel_max_fd(void);
470 482
471/* Returns true if there is still an open channel over the connection. */ 483/* Returns true if there is still an open channel over the connection. */
472int channel_still_open(void); 484int channel_still_open(void);
473 485
474/* Returns a string containing a list of all open channels. The list is 486/* Returns a string containing a list of all open channels. The list is
475 suitable for displaying to the user. It uses crlf instead of newlines. 487 suitable for displaying to the user. It uses crlf instead of newlines.
476 The caller should free the string with xfree. */ 488 The caller should free the string with xfree. */
477char *channel_open_message(void); 489char *channel_open_message(void);
478 490
479/* Initiate forwarding of connections to local port "port" through the secure 491/* Initiate forwarding of connections to local port "port" through the secure
480 channel to host:port from remote side. This never returns if there 492 channel to host:port from remote side. This never returns if there
481 was an error. */ 493 was an error. */
482void channel_request_local_forwarding(int port, const char *host, 494void
483 int remote_port); 495channel_request_local_forwarding(int port, const char *host,
496 int remote_port);
484 497
485/* Initiate forwarding of connections to port "port" on remote host through 498/* Initiate forwarding of connections to port "port" on remote host through
486 the secure channel to host:port from local side. This never returns 499 the secure channel to host:port from local side. This never returns
487 if there was an error. This registers that open requests for that 500 if there was an error. This registers that open requests for that
488 port are permitted. */ 501 port are permitted. */
489void channel_request_remote_forwarding(int port, const char *host, 502void
490 int remote_port); 503channel_request_remote_forwarding(int port, const char *host,
504 int remote_port);
491 505
492/* Permits opening to any host/port in SSH_MSG_PORT_OPEN. This is usually 506/* Permits opening to any host/port in SSH_MSG_PORT_OPEN. This is usually
493 called by the server, because the user could connect to any port anyway, 507 called by the server, because the user could connect to any port anyway,
494 and the server has no way to know but to trust the client anyway. */ 508 and the server has no way to know but to trust the client anyway. */
495void channel_permit_all_opens(void); 509void channel_permit_all_opens(void);
496 510
497/* This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates 511/* This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates
498 listening for the port, and sends back a success reply (or disconnect 512 listening for the port, and sends back a success reply (or disconnect
499 message if there was an error). This never returns if there was an 513 message if there was an error). This never returns if there was an
500 error. */ 514 error. */
501void channel_input_port_forward_request(int is_root); 515void channel_input_port_forward_request(int is_root);
502 516
503/* This is called after receiving PORT_OPEN message. This attempts to connect 517/* This is called after receiving PORT_OPEN message. This attempts to connect
504 to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION or 518 to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION or
505 CHANNEL_OPEN_FAILURE. */ 519 CHANNEL_OPEN_FAILURE. */
506void channel_input_port_open(int payload_len); 520void channel_input_port_open(int payload_len);
507 521
508/* Creates a port for X11 connections, and starts listening for it. 522/* Creates a port for X11 connections, and starts listening for it.
509 Returns the display name, or NULL if an error was encountered. */ 523 Returns the display name, or NULL if an error was encountered. */
510char *x11_create_display(int screen); 524char *x11_create_display(int screen);
511 525
512/* Creates an internet domain socket for listening for X11 connections. 526/* Creates an internet domain socket for listening for X11 connections.
513 Returns a suitable value for the DISPLAY variable, or NULL if an error 527 Returns a suitable value for the DISPLAY variable, or NULL if an error
514 occurs. */ 528 occurs. */
515char *x11_create_display_inet(int screen); 529char *x11_create_display_inet(int screen);
516 530
517/* This is called when SSH_SMSG_X11_OPEN is received. The packet contains 531/* This is called when SSH_SMSG_X11_OPEN is received. The packet contains
518 the remote channel number. We should do whatever we want, and respond 532 the remote channel number. We should do whatever we want, and respond
519 with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE. */ 533 with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE. */
520void x11_input_open(int payload_len); 534void x11_input_open(int payload_len);
521 535
522/* Requests forwarding of X11 connections. This should be called on the 536/* Requests forwarding of X11 connections. This should be called on the
523 client only. */ 537 client only. */
524void x11_request_forwarding(void); 538void x11_request_forwarding(void);
525 539
526/* Requests forwarding for X11 connections, with authentication spoofing. 540/* Requests forwarding for X11 connections, with authentication spoofing.
527 This should be called in the client only. */ 541 This should be called in the client only. */
528void x11_request_forwarding_with_spoofing(const char *proto, const char *data); 542void x11_request_forwarding_with_spoofing(const char *proto, const char *data);
529 543
530/* Sends a message to the server to request authentication fd forwarding. */ 544/* Sends a message to the server to request authentication fd forwarding. */
531void auth_request_forwarding(void); 545void auth_request_forwarding(void);
532 546
533/* Returns the name of the forwarded authentication socket. Returns NULL 547/* Returns the name of the forwarded authentication socket. Returns NULL
534 if there is no forwarded authentication socket. The returned value points 548 if there is no forwarded authentication socket. The returned value points
535 to a static buffer. */ 549 to a static buffer. */
536char *auth_get_socket_name(void); 550char *auth_get_socket_name(void);
537 551
538/* This if called to process SSH_CMSG_AGENT_REQUEST_FORWARDING on the server. 552/* This if called to process SSH_CMSG_AGENT_REQUEST_FORWARDING on the server.
539 This starts forwarding authentication requests. */ 553 This starts forwarding authentication requests. */
540void auth_input_request_forwarding(struct passwd *pw); 554void auth_input_request_forwarding(struct passwd * pw);
541 555
542/* This is called to process an SSH_SMSG_AGENT_OPEN message. */ 556/* This is called to process an SSH_SMSG_AGENT_OPEN message. */
543void auth_input_open_request(void); 557void auth_input_open_request(void);
544 558
545/* Returns true if the given string matches the pattern (which may contain 559/* Returns true if the given string matches the pattern (which may contain
546 ? and * as wildcards), and zero if it does not match. */ 560 ? and * as wildcards), and zero if it does not match. */
547int match_pattern(const char *s, const char *pattern); 561int match_pattern(const char *s, const char *pattern);
548 562
549/* Expands tildes in the file name. Returns data allocated by xmalloc. 563/* Expands tildes in the file name. Returns data allocated by xmalloc.
550 Warning: this calls getpw*. */ 564 Warning: this calls getpw*. */
551char *tilde_expand_filename(const char *filename, uid_t my_uid); 565char *tilde_expand_filename(const char *filename, uid_t my_uid);
552 566
553/* Performs the interactive session. This handles data transmission between 567/* Performs the interactive session. This handles data transmission between
554 the client and the program. Note that the notion of stdin, stdout, and 568 the client and the program. Note that the notion of stdin, stdout, and
555 stderr in this function is sort of reversed: this function writes to 569 stderr in this function is sort of reversed: this function writes to
556 stdin (of the child program), and reads from stdout and stderr (of the 570 stdin (of the child program), and reads from stdout and stderr (of the
557 child program). */ 571 child program). */
558void server_loop(int pid, int fdin, int fdout, int fderr); 572void server_loop(int pid, int fdin, int fdout, int fderr);
559 573
560/* Client side main loop for the interactive session. */ 574/* Client side main loop for the interactive session. */
561int client_loop(int have_pty, int escape_char); 575int client_loop(int have_pty, int escape_char);
562 576
563/* Linked list of custom environment strings (see auth-rsa.c). */ 577/* Linked list of custom environment strings (see auth-rsa.c). */
564struct envstring { 578struct envstring {
565 struct envstring *next; 579 struct envstring *next;
566 char *s; 580 char *s;
567}; 581};
568
569#ifdef KRB4 582#ifdef KRB4
570#include <krb.h> 583#include <krb.h>
571 584
572/* Performs Kerberos v4 mutual authentication with the client. This returns 585/* Performs Kerberos v4 mutual authentication with the client. This returns
573 0 if the client could not be authenticated, and 1 if authentication was 586 0 if the client could not be authenticated, and 1 if authentication was
574 successful. This may exit if there is a serious protocol violation. */ 587 successful. This may exit if there is a serious protocol violation. */
575int auth_krb4(const char *server_user, KTEXT auth, char **client); 588int auth_krb4(const char *server_user, KTEXT auth, char **client);
576int krb4_init(uid_t uid); 589int krb4_init(uid_t uid);
577void krb4_cleanup_proc(void *ignore); 590void krb4_cleanup_proc(void *ignore);
578 591
579#ifdef AFS 592#ifdef AFS
580#include <kafs.h> 593#include <kafs.h>
581 594
582/* Accept passed Kerberos v4 ticket-granting ticket and AFS tokens. */ 595/* Accept passed Kerberos v4 ticket-granting ticket and AFS tokens. */
583int auth_kerberos_tgt(struct passwd *pw, const char *string); 596int auth_kerberos_tgt(struct passwd * pw, const char *string);
584int auth_afs_token(struct passwd *pw, const char *token_string); 597int auth_afs_token(struct passwd * pw, const char *token_string);
585 598
586int creds_to_radix(CREDENTIALS *creds, unsigned char *buf); 599int creds_to_radix(CREDENTIALS * creds, unsigned char *buf);
587int radix_to_creds(const char *buf, CREDENTIALS *creds); 600int radix_to_creds(const char *buf, CREDENTIALS * creds);
588#endif /* AFS */ 601#endif /* AFS */
589 602
590#endif /* KRB4 */ 603#endif /* KRB4 */
591 604
592#ifdef SKEY 605#ifdef SKEY
593#include <skey.h> 606#include <skey.h>
594char *skey_fake_keyinfo(char *username); 607char *skey_fake_keyinfo(char *username);
595#endif /* SKEY */ 608#endif /* SKEY */
596 609
597#endif /* SSH_H */ 610#endif /* SSH_H */
diff --git a/sshconnect.c b/sshconnect.c
index fba389d8b..0657c37e8 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -1,21 +1,14 @@
1/* 1/*
2 2 * Author: Tatu Ylonen <ylo@cs.hut.fi>
3sshconnect.c 3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 4 * All rights reserved
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Created: Sat Mar 18 22:15:47 1995 ylo
6 6 * Code to connect to a remote host, and to perform the client side of the
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * login (authentication) dialog.
8 All rights reserved 8 */
9
10Created: Sat Mar 18 22:15:47 1995 ylo
11
12Code to connect to a remote host, and to perform the client side of the
13login (authentication) dialog.
14
15*/
16 9
17#include "includes.h" 10#include "includes.h"
18RCSID("$Id: sshconnect.c,v 1.13 1999/11/21 02:23:53 damien Exp $"); 11RCSID("$Id: sshconnect.c,v 1.14 1999/11/24 13:26:23 damien Exp $");
19 12
20#ifdef HAVE_OPENSSL 13#ifdef HAVE_OPENSSL
21#include <openssl/bn.h> 14#include <openssl/bn.h>
@@ -41,1497 +34,1495 @@ RCSID("$Id: sshconnect.c,v 1.13 1999/11/21 02:23:53 damien Exp $");
41/* Session id for the current session. */ 34/* Session id for the current session. */
42unsigned char session_id[16]; 35unsigned char session_id[16];
43 36
44/* Connect to the given ssh server using a proxy command. */ 37/*
45 38 * Connect to the given ssh server using a proxy command.
39 */
46int 40int
47ssh_proxy_connect(const char *host, int port, uid_t original_real_uid, 41ssh_proxy_connect(const char *host, int port, uid_t original_real_uid,
48 const char *proxy_command) 42 const char *proxy_command)
49{ 43{
50 Buffer command; 44 Buffer command;
51 const char *cp; 45 const char *cp;
52 char *command_string; 46 char *command_string;
53 int pin[2], pout[2]; 47 int pin[2], pout[2];
54 int pid; 48 int pid;
55 char portstring[100]; 49 char portstring[100];
56 50
57 /* Convert the port number into a string. */ 51 /* Convert the port number into a string. */
58 snprintf(portstring, sizeof portstring, "%d", port); 52 snprintf(portstring, sizeof portstring, "%d", port);
59 53
60 /* Build the final command string in the buffer by making the appropriate 54 /* Build the final command string in the buffer by making the
61 substitutions to the given proxy command. */ 55 appropriate substitutions to the given proxy command. */
62 buffer_init(&command); 56 buffer_init(&command);
63 for (cp = proxy_command; *cp; cp++) 57 for (cp = proxy_command; *cp; cp++) {
64 { 58 if (cp[0] == '%' && cp[1] == '%') {
65 if (cp[0] == '%' && cp[1] == '%') 59 buffer_append(&command, "%", 1);
66 { 60 cp++;
67 buffer_append(&command, "%", 1); 61 continue;
68 cp++; 62 }
69 continue; 63 if (cp[0] == '%' && cp[1] == 'h') {
70 } 64 buffer_append(&command, host, strlen(host));
71 if (cp[0] == '%' && cp[1] == 'h') 65 cp++;
72 { 66 continue;
73 buffer_append(&command, host, strlen(host)); 67 }
74 cp++; 68 if (cp[0] == '%' && cp[1] == 'p') {
75 continue; 69 buffer_append(&command, portstring, strlen(portstring));
76 } 70 cp++;
77 if (cp[0] == '%' && cp[1] == 'p') 71 continue;
78 { 72 }
79 buffer_append(&command, portstring, strlen(portstring)); 73 buffer_append(&command, cp, 1);
80 cp++;
81 continue;
82 } 74 }
83 buffer_append(&command, cp, 1); 75 buffer_append(&command, "\0", 1);
84 } 76
85 buffer_append(&command, "\0", 1); 77 /* Get the final command string. */
86 78 command_string = buffer_ptr(&command);
87 /* Get the final command string. */ 79
88 command_string = buffer_ptr(&command); 80 /* Create pipes for communicating with the proxy. */
89 81 if (pipe(pin) < 0 || pipe(pout) < 0)
90 /* Create pipes for communicating with the proxy. */ 82 fatal("Could not create pipes to communicate with the proxy: %.100s",
91 if (pipe(pin) < 0 || pipe(pout) < 0) 83 strerror(errno));
92 fatal("Could not create pipes to communicate with the proxy: %.100s", 84
93 strerror(errno)); 85 debug("Executing proxy command: %.500s", command_string);
94 86
95 debug("Executing proxy command: %.500s", command_string); 87 /* Fork and execute the proxy command. */
96 88 if ((pid = fork()) == 0) {
97 /* Fork and execute the proxy command. */ 89 char *argv[10];
98 if ((pid = fork()) == 0) 90
99 { 91 /* Child. Permanently give up superuser privileges. */
100 char *argv[10]; 92 permanently_set_uid(original_real_uid);
101 93
102 /* Child. Permanently give up superuser privileges. */ 94 /* Redirect stdin and stdout. */
103 permanently_set_uid(original_real_uid); 95 close(pin[1]);
104 96 if (pin[0] != 0) {
105 /* Redirect stdin and stdout. */ 97 if (dup2(pin[0], 0) < 0)
106 close(pin[1]); 98 perror("dup2 stdin");
107 if (pin[0] != 0) 99 close(pin[0]);
108 { 100 }
109 if (dup2(pin[0], 0) < 0) 101 close(pout[0]);
110 perror("dup2 stdin"); 102 if (dup2(pout[1], 1) < 0)
111 close(pin[0]); 103 perror("dup2 stdout");
104 /* Cannot be 1 because pin allocated two descriptors. */
105 close(pout[1]);
106
107 /* Stderr is left as it is so that error messages get
108 printed on the user's terminal. */
109 argv[0] = "/bin/sh";
110 argv[1] = "-c";
111 argv[2] = command_string;
112 argv[3] = NULL;
113
114 /* Execute the proxy command. Note that we gave up any
115 extra privileges above. */
116 execv("/bin/sh", argv);
117 perror("/bin/sh");
118 exit(1);
112 } 119 }
113 close(pout[0]); 120 /* Parent. */
114 if (dup2(pout[1], 1) < 0) 121 if (pid < 0)
115 perror("dup2 stdout"); 122 fatal("fork failed: %.100s", strerror(errno));
116 close(pout[1]); /* Cannot be 1 because pin allocated two descriptors. */ 123
117 124 /* Close child side of the descriptors. */
118 /* Stderr is left as it is so that error messages get printed on 125 close(pin[0]);
119 the user's terminal. */ 126 close(pout[1]);
120 argv[0] = "/bin/sh"; 127
121 argv[1] = "-c"; 128 /* Free the command name. */
122 argv[2] = command_string; 129 buffer_free(&command);
123 argv[3] = NULL; 130
124 131 /* Set the connection file descriptors. */
125 /* Execute the proxy command. Note that we gave up any extra 132 packet_set_connection(pout[0], pin[1]);
126 privileges above. */
127 execv("/bin/sh", argv);
128 perror("/bin/sh");
129 exit(1);
130 }
131 /* Parent. */
132 if (pid < 0)
133 fatal("fork failed: %.100s", strerror(errno));
134
135 /* Close child side of the descriptors. */
136 close(pin[0]);
137 close(pout[1]);
138
139 /* Free the command name. */
140 buffer_free(&command);
141
142 /* Set the connection file descriptors. */
143 packet_set_connection(pout[0], pin[1]);
144
145 return 1;
146}
147 133
148/* Creates a (possibly privileged) socket for use as the ssh connection. */ 134 return 1;
135}
149 136
150int ssh_create_socket(uid_t original_real_uid, int privileged) 137/*
138 * Creates a (possibly privileged) socket for use as the ssh connection.
139 */
140int
141ssh_create_socket(uid_t original_real_uid, int privileged)
151{ 142{
152 int sock; 143 int sock;
153 144
154 /* If we are running as root and want to connect to a privileged port, 145 /* If we are running as root and want to connect to a privileged
155 bind our own socket to a privileged port. */ 146 port, bind our own socket to a privileged port. */
156 if (privileged) 147 if (privileged) {
157 { 148 int p = IPPORT_RESERVED - 1;
158 int p = IPPORT_RESERVED - 1; 149
159 150 sock = rresvport(&p);
160 sock = rresvport(&p); 151 if (sock < 0)
161 if (sock < 0) 152 fatal("rresvport: %.100s", strerror(errno));
162 fatal("rresvport: %.100s", strerror(errno)); 153 debug("Allocated local port %d.", p);
163 debug("Allocated local port %d.", p); 154 } else {
164 } 155 /* Just create an ordinary socket on arbitrary port. We
165 else 156 use the user's uid to create the socket. */
166 { 157 temporarily_use_uid(original_real_uid);
167 /* Just create an ordinary socket on arbitrary port. We use the 158 sock = socket(AF_INET, SOCK_STREAM, 0);
168 user's uid to create the socket. */ 159 if (sock < 0)
169 temporarily_use_uid(original_real_uid); 160 fatal("socket: %.100s", strerror(errno));
170 sock = socket(AF_INET, SOCK_STREAM, 0); 161 restore_uid();
171 if (sock < 0) 162 }
172 fatal("socket: %.100s", strerror(errno)); 163 return sock;
173 restore_uid();
174 }
175 return sock;
176} 164}
177 165
178/* Opens a TCP/IP connection to the remote server on the given host. If 166/*
179 port is 0, the default port will be used. If anonymous is zero, 167 * Opens a TCP/IP connection to the remote server on the given host. If
180 a privileged port will be allocated to make the connection. 168 * port is 0, the default port will be used. If anonymous is zero,
181 This requires super-user privileges if anonymous is false. 169 * a privileged port will be allocated to make the connection.
182 Connection_attempts specifies the maximum number of tries (one per 170 * This requires super-user privileges if anonymous is false.
183 second). If proxy_command is non-NULL, it specifies the command (with %h 171 * Connection_attempts specifies the maximum number of tries (one per
184 and %p substituted for host and port, respectively) to use to contact 172 * second). If proxy_command is non-NULL, it specifies the command (with %h
185 the daemon. */ 173 * and %p substituted for host and port, respectively) to use to contact
186 174 * the daemon.
187int ssh_connect(const char *host, struct sockaddr_in *hostaddr, 175 */
188 int port, int connection_attempts, 176int
189 int anonymous, uid_t original_real_uid, 177ssh_connect(const char *host, struct sockaddr_in * hostaddr,
190 const char *proxy_command) 178 int port, int connection_attempts,
179 int anonymous, uid_t original_real_uid,
180 const char *proxy_command)
191{ 181{
192 int sock = -1, attempt, i; 182 int sock = -1, attempt, i;
193 int on = 1; 183 int on = 1;
194 struct servent *sp; 184 struct servent *sp;
195 struct hostent *hp; 185 struct hostent *hp;
196 struct linger linger; 186 struct linger linger;
197 187
198 debug("ssh_connect: getuid %d geteuid %d anon %d", 188 debug("ssh_connect: getuid %d geteuid %d anon %d",
199 (int)getuid(), (int)geteuid(), anonymous); 189 (int) getuid(), (int) geteuid(), anonymous);
200 190
201 /* Get default port if port has not been set. */ 191 /* Get default port if port has not been set. */
202 if (port == 0) 192 if (port == 0) {
203 { 193 sp = getservbyname(SSH_SERVICE_NAME, "tcp");
204 sp = getservbyname(SSH_SERVICE_NAME, "tcp"); 194 if (sp)
205 if (sp) 195 port = ntohs(sp->s_port);
206 port = ntohs(sp->s_port); 196 else
207 else 197 port = SSH_DEFAULT_PORT;
208 port = SSH_DEFAULT_PORT;
209 }
210
211 /* If a proxy command is given, connect using it. */
212 if (proxy_command != NULL)
213 return ssh_proxy_connect(host, port, original_real_uid, proxy_command);
214
215 /* No proxy command. */
216
217 /* No host lookup made yet. */
218 hp = NULL;
219
220 /* Try to connect several times. On some machines, the first time will
221 sometimes fail. In general socket code appears to behave quite
222 magically on many machines. */
223 for (attempt = 0; attempt < connection_attempts; attempt++)
224 {
225 if (attempt > 0)
226 debug("Trying again...");
227
228 /* Try to parse the host name as a numeric inet address. */
229 memset(hostaddr, 0, sizeof(hostaddr));
230 hostaddr->sin_family = AF_INET;
231 hostaddr->sin_port = htons(port);
232 hostaddr->sin_addr.s_addr = inet_addr(host);
233 if ((hostaddr->sin_addr.s_addr & 0xffffffff) != 0xffffffff)
234 {
235 /* Valid numeric IP address */
236 debug("Connecting to %.100s port %d.",
237 inet_ntoa(hostaddr->sin_addr), port);
238
239 /* Create a socket. */
240 sock = ssh_create_socket(original_real_uid,
241 !anonymous && geteuid() == 0 &&
242 port < IPPORT_RESERVED);
243
244 /* Connect to the host. We use the user's uid in the hope that
245 it will help with the problems of tcp_wrappers showing the
246 remote uid as root. */
247 temporarily_use_uid(original_real_uid);
248 if (connect(sock, (struct sockaddr *)hostaddr, sizeof(*hostaddr))
249 >= 0)
250 {
251 /* Successful connect. */
252 restore_uid();
253 break;
254 }
255 debug("connect: %.100s", strerror(errno));
256 restore_uid();
257
258 /* Destroy the failed socket. */
259 shutdown(sock, SHUT_RDWR);
260 close(sock);
261 } 198 }
262 else 199 /* If a proxy command is given, connect using it. */
263 { 200 if (proxy_command != NULL)
264 /* Not a valid numeric inet address. */ 201 return ssh_proxy_connect(host, port, original_real_uid, proxy_command);
265 /* Map host name to an address. */ 202
266 if (!hp) 203 /* No proxy command. */
267 hp = gethostbyname(host); 204
268 if (!hp) 205 /* No host lookup made yet. */
269 fatal("Bad host name: %.100s", host); 206 hp = NULL;
270 if (!hp->h_addr_list[0]) 207
271 fatal("Host does not have an IP address: %.100s", host); 208 /* Try to connect several times. On some machines, the first time
272 209 will sometimes fail. In general socket code appears to behave
273 /* Loop through addresses for this host, and try each one in 210 quite magically on many machines. */
274 sequence until the connection succeeds. */ 211 for (attempt = 0; attempt < connection_attempts; attempt++) {
275 for (i = 0; hp->h_addr_list[i]; i++) 212 if (attempt > 0)
276 { 213 debug("Trying again...");
277 /* Set the address to connect to. */ 214
278 hostaddr->sin_family = hp->h_addrtype; 215 /* Try to parse the host name as a numeric inet address. */
279 memcpy(&hostaddr->sin_addr, hp->h_addr_list[i], 216 memset(hostaddr, 0, sizeof(hostaddr));
280 sizeof(hostaddr->sin_addr)); 217 hostaddr->sin_family = AF_INET;
281 218 hostaddr->sin_port = htons(port);
282 debug("Connecting to %.200s [%.100s] port %d.", 219 hostaddr->sin_addr.s_addr = inet_addr(host);
283 host, inet_ntoa(hostaddr->sin_addr), port); 220 if ((hostaddr->sin_addr.s_addr & 0xffffffff) != 0xffffffff) {
284 221 /* Valid numeric IP address */
285 /* Create a socket for connecting. */ 222 debug("Connecting to %.100s port %d.",
286 sock = ssh_create_socket(original_real_uid, 223 inet_ntoa(hostaddr->sin_addr), port);
287 !anonymous && geteuid() == 0 && 224
288 port < IPPORT_RESERVED); 225 /* Create a socket. */
289 226 sock = ssh_create_socket(original_real_uid,
290 /* Connect to the host. We use the user's uid in the hope that 227 !anonymous && geteuid() == 0 &&
291 it will help with tcp_wrappers showing the remote uid as 228 port < IPPORT_RESERVED);
292 root. */ 229
293 temporarily_use_uid(original_real_uid); 230 /* Connect to the host. We use the user's uid in
294 if (connect(sock, (struct sockaddr *)hostaddr, 231 the hope that it will help with the problems of
295 sizeof(*hostaddr)) >= 0) 232 tcp_wrappers showing the remote uid as root. */
296 { 233 temporarily_use_uid(original_real_uid);
297 /* Successful connection. */ 234 if (connect(sock, (struct sockaddr *) hostaddr, sizeof(*hostaddr))
298 restore_uid(); 235 >= 0) {
299 break; 236 /* Successful connect. */
237 restore_uid();
238 break;
239 }
240 debug("connect: %.100s", strerror(errno));
241 restore_uid();
242
243 /* Destroy the failed socket. */
244 shutdown(sock, SHUT_RDWR);
245 close(sock);
246 } else {
247 /* Not a valid numeric inet address. */
248 /* Map host name to an address. */
249 if (!hp)
250 hp = gethostbyname(host);
251 if (!hp)
252 fatal("Bad host name: %.100s", host);
253 if (!hp->h_addr_list[0])
254 fatal("Host does not have an IP address: %.100s", host);
255
256 /* Loop through addresses for this host, and try
257 each one in sequence until the connection
258 succeeds. */
259 for (i = 0; hp->h_addr_list[i]; i++) {
260 /* Set the address to connect to. */
261 hostaddr->sin_family = hp->h_addrtype;
262 memcpy(&hostaddr->sin_addr, hp->h_addr_list[i],
263 sizeof(hostaddr->sin_addr));
264
265 debug("Connecting to %.200s [%.100s] port %d.",
266 host, inet_ntoa(hostaddr->sin_addr), port);
267
268 /* Create a socket for connecting. */
269 sock = ssh_create_socket(original_real_uid,
270 !anonymous && geteuid() == 0 &&
271 port < IPPORT_RESERVED);
272
273 /* Connect to the host. We use the user's uid in the hope that
274 it will help with tcp_wrappers showing the remote uid as root. */
275 temporarily_use_uid(original_real_uid);
276 if (connect(sock, (struct sockaddr *) hostaddr,
277 sizeof(*hostaddr)) >= 0) {
278 /* Successful connection. */
279 restore_uid();
280 break;
281 }
282 debug("connect: %.100s", strerror(errno));
283 restore_uid();
284
285 /* Close the failed socket; there appear to be some problems when
286 reusing a socket for which connect() has already returned an error. */
287 shutdown(sock, SHUT_RDWR);
288 close(sock);
289 }
290 if (hp->h_addr_list[i])
291 break; /* Successful connection. */
300 } 292 }
301 debug("connect: %.100s", strerror(errno));
302 restore_uid();
303
304 /* Close the failed socket; there appear to be some problems
305 when reusing a socket for which connect() has already
306 returned an error. */
307 shutdown(sock, SHUT_RDWR);
308 close(sock);
309 }
310 if (hp->h_addr_list[i])
311 break; /* Successful connection. */
312 }
313 293
314 /* Sleep a moment before retrying. */ 294 /* Sleep a moment before retrying. */
315 sleep(1); 295 sleep(1);
316 } 296 }
317 /* Return failure if we didn't get a successful connection. */ 297 /* Return failure if we didn't get a successful connection. */
318 if (attempt >= connection_attempts) 298 if (attempt >= connection_attempts)
319 return 0; 299 return 0;
320 300
321 debug("Connection established."); 301 debug("Connection established.");
322 302
323 /* Set socket options. We would like the socket to disappear as soon as 303 /* Set socket options. We would like the socket to disappear as
324 it has been closed for whatever reason. */ 304 soon as it has been closed for whatever reason. */
325 /* setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */ 305 /* setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on,
326 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *)&on, sizeof(on)); 306 sizeof(on)); */
327 linger.l_onoff = 1; 307 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *) &on, sizeof(on));
328 linger.l_linger = 5; 308 linger.l_onoff = 1;
329 setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger)); 309 linger.l_linger = 5;
310 setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof(linger));
330 311
331 /* Set the connection. */ 312 /* Set the connection. */
332 packet_set_connection(sock, sock); 313 packet_set_connection(sock, sock);
333 314
334 return 1; 315 return 1;
335} 316}
336 317
337/* Checks if the user has an authentication agent, and if so, tries to 318/*
338 authenticate using the agent. */ 319 * Checks if the user has an authentication agent, and if so, tries to
339 320 * authenticate using the agent.
321 */
340int 322int
341try_agent_authentication() 323try_agent_authentication()
342{ 324{
343 int status, type; 325 int status, type;
344 char *comment; 326 char *comment;
345 AuthenticationConnection *auth; 327 AuthenticationConnection *auth;
346 unsigned char response[16]; 328 unsigned char response[16];
347 unsigned int i; 329 unsigned int i;
348 BIGNUM *e, *n, *challenge; 330 BIGNUM *e, *n, *challenge;
349 331
350 /* Get connection to the agent. */ 332 /* Get connection to the agent. */
351 auth = ssh_get_authentication_connection(); 333 auth = ssh_get_authentication_connection();
352 if (!auth) 334 if (!auth)
353 return 0; 335 return 0;
354 336
355 e = BN_new(); 337 e = BN_new();
356 n = BN_new(); 338 n = BN_new();
357 challenge = BN_new(); 339 challenge = BN_new();
358 340
359 /* Loop through identities served by the agent. */ 341 /* Loop through identities served by the agent. */
360 for (status = ssh_get_first_identity(auth, e, n, &comment); 342 for (status = ssh_get_first_identity(auth, e, n, &comment);
361 status; 343 status;
362 status = ssh_get_next_identity(auth, e, n, &comment)) 344 status = ssh_get_next_identity(auth, e, n, &comment)) {
363 { 345 int plen, clen;
364 int plen, clen; 346
365 347 /* Try this identity. */
366 /* Try this identity. */ 348 debug("Trying RSA authentication via agent with '%.100s'", comment);
367 debug("Trying RSA authentication via agent with '%.100s'", comment); 349 xfree(comment);
368 xfree(comment); 350
369 351 /* Tell the server that we are willing to authenticate using this key. */
370 /* Tell the server that we are willing to authenticate using this key. */ 352 packet_start(SSH_CMSG_AUTH_RSA);
371 packet_start(SSH_CMSG_AUTH_RSA); 353 packet_put_bignum(n);
372 packet_put_bignum(n); 354 packet_send();
373 packet_send(); 355 packet_write_wait();
374 packet_write_wait(); 356
375 357 /* Wait for server's response. */
376 /* Wait for server's response. */ 358 type = packet_read(&plen);
377 type = packet_read(&plen); 359
378 360 /* The server sends failure if it doesn\'t like our key or
379 /* The server sends failure if it doesn\'t like our key or does not 361 does not support RSA authentication. */
380 support RSA authentication. */ 362 if (type == SSH_SMSG_FAILURE) {
381 if (type == SSH_SMSG_FAILURE) 363 debug("Server refused our key.");
382 { 364 continue;
383 debug("Server refused our key."); 365 }
384 continue; 366 /* Otherwise it should have sent a challenge. */
385 } 367 if (type != SSH_SMSG_AUTH_RSA_CHALLENGE)
386 368 packet_disconnect("Protocol error during RSA authentication: %d",
387 /* Otherwise it should have sent a challenge. */ 369 type);
388 if (type != SSH_SMSG_AUTH_RSA_CHALLENGE)
389 packet_disconnect("Protocol error during RSA authentication: %d",
390 type);
391
392 packet_get_bignum(challenge, &clen);
393
394 packet_integrity_check(plen, clen, type);
395
396 debug("Received RSA challenge from server.");
397
398 /* Ask the agent to decrypt the challenge. */
399 if (!ssh_decrypt_challenge(auth, e, n, challenge,
400 session_id, 1, response))
401 {
402 /* The agent failed to authenticate this identifier although it
403 advertised it supports this. Just return a wrong value. */
404 log("Authentication agent failed to decrypt challenge.");
405 memset(response, 0, sizeof(response));
406 }
407
408 debug("Sending response to RSA challenge.");
409
410 /* Send the decrypted challenge back to the server. */
411 packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
412 for (i = 0; i < 16; i++)
413 packet_put_char(response[i]);
414 packet_send();
415 packet_write_wait();
416
417 /* Wait for response from the server. */
418 type = packet_read(&plen);
419
420 /* The server returns success if it accepted the authentication. */
421 if (type == SSH_SMSG_SUCCESS)
422 {
423 debug("RSA authentication accepted by server.");
424 BN_clear_free(e);
425 BN_clear_free(n);
426 BN_clear_free(challenge);
427 return 1;
428 }
429 370
430 /* Otherwise it should return failure. */ 371 packet_get_bignum(challenge, &clen);
431 if (type != SSH_SMSG_FAILURE)
432 packet_disconnect("Protocol error waiting RSA auth response: %d",
433 type);
434 }
435 372
436 BN_clear_free(e); 373 packet_integrity_check(plen, clen, type);
437 BN_clear_free(n);
438 BN_clear_free(challenge);
439 374
440 debug("RSA authentication using agent refused."); 375 debug("Received RSA challenge from server.");
441 return 0; 376
442} 377 /* Ask the agent to decrypt the challenge. */
378 if (!ssh_decrypt_challenge(auth, e, n, challenge,
379 session_id, 1, response)) {
380 /* The agent failed to authenticate this identifier although it
381 advertised it supports this. Just return a wrong value. */
382 log("Authentication agent failed to decrypt challenge.");
383 memset(response, 0, sizeof(response));
384 }
385 debug("Sending response to RSA challenge.");
386
387 /* Send the decrypted challenge back to the server. */
388 packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
389 for (i = 0; i < 16; i++)
390 packet_put_char(response[i]);
391 packet_send();
392 packet_write_wait();
393
394 /* Wait for response from the server. */
395 type = packet_read(&plen);
396
397 /* The server returns success if it accepted the authentication. */
398 if (type == SSH_SMSG_SUCCESS) {
399 debug("RSA authentication accepted by server.");
400 BN_clear_free(e);
401 BN_clear_free(n);
402 BN_clear_free(challenge);
403 return 1;
404 }
405 /* Otherwise it should return failure. */
406 if (type != SSH_SMSG_FAILURE)
407 packet_disconnect("Protocol error waiting RSA auth response: %d",
408 type);
409 }
410
411 BN_clear_free(e);
412 BN_clear_free(n);
413 BN_clear_free(challenge);
443 414
444/* Computes the proper response to a RSA challenge, and sends the response to 415 debug("RSA authentication using agent refused.");
445 the server. */ 416 return 0;
417}
446 418
419/*
420 * Computes the proper response to a RSA challenge, and sends the response to
421 * the server.
422 */
447void 423void
448respond_to_rsa_challenge(BIGNUM *challenge, RSA *prv) 424respond_to_rsa_challenge(BIGNUM * challenge, RSA * prv)
449{ 425{
450 unsigned char buf[32], response[16]; 426 unsigned char buf[32], response[16];
451 MD5_CTX md; 427 MD5_CTX md;
452 int i, len; 428 int i, len;
453 429
454 /* Decrypt the challenge using the private key. */ 430 /* Decrypt the challenge using the private key. */
455 rsa_private_decrypt(challenge, challenge, prv); 431 rsa_private_decrypt(challenge, challenge, prv);
456 432
457 /* Compute the response. */ 433 /* Compute the response. */
458 /* The response is MD5 of decrypted challenge plus session id. */ 434 /* The response is MD5 of decrypted challenge plus session id. */
459 len = BN_num_bytes(challenge); 435 len = BN_num_bytes(challenge);
460 if (len <= 0 || len > sizeof(buf)) 436 if (len <= 0 || len > sizeof(buf))
461 packet_disconnect("respond_to_rsa_challenge: bad challenge length %d", 437 packet_disconnect("respond_to_rsa_challenge: bad challenge length %d",
462 len); 438 len);
463 439
464 memset(buf, 0, sizeof(buf)); 440 memset(buf, 0, sizeof(buf));
465 BN_bn2bin(challenge, buf + sizeof(buf) - len); 441 BN_bn2bin(challenge, buf + sizeof(buf) - len);
466 MD5_Init(&md); 442 MD5_Init(&md);
467 MD5_Update(&md, buf, 32); 443 MD5_Update(&md, buf, 32);
468 MD5_Update(&md, session_id, 16); 444 MD5_Update(&md, session_id, 16);
469 MD5_Final(response, &md); 445 MD5_Final(response, &md);
470 446
471 debug("Sending response to host key RSA challenge."); 447 debug("Sending response to host key RSA challenge.");
472 448
473 /* Send the response back to the server. */ 449 /* Send the response back to the server. */
474 packet_start(SSH_CMSG_AUTH_RSA_RESPONSE); 450 packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
475 for (i = 0; i < 16; i++) 451 for (i = 0; i < 16; i++)
476 packet_put_char(response[i]); 452 packet_put_char(response[i]);
477 packet_send(); 453 packet_send();
478 packet_write_wait(); 454 packet_write_wait();
479
480 memset(buf, 0, sizeof(buf));
481 memset(response, 0, sizeof(response));
482 memset(&md, 0, sizeof(md));
483}
484 455
485/* Checks if the user has authentication file, and if so, tries to authenticate 456 memset(buf, 0, sizeof(buf));
486 the user using it. */ 457 memset(response, 0, sizeof(response));
458 memset(&md, 0, sizeof(md));
459}
487 460
461/*
462 * Checks if the user has authentication file, and if so, tries to authenticate
463 * the user using it.
464 */
488int 465int
489try_rsa_authentication(struct passwd *pw, const char *authfile) 466try_rsa_authentication(struct passwd * pw, const char *authfile)
490{ 467{
491 extern Options options; 468 extern Options options;
492 BIGNUM *challenge; 469 BIGNUM *challenge;
493 RSA *private_key; 470 RSA *private_key;
494 RSA *public_key; 471 RSA *public_key;
495 char *passphrase, *comment; 472 char *passphrase, *comment;
496 int type, i; 473 int type, i;
497 int plen, clen; 474 int plen, clen;
498 475
499 /* Try to load identification for the authentication key. */ 476 /* Try to load identification for the authentication key. */
500 public_key = RSA_new(); 477 public_key = RSA_new();
501 if (!load_public_key(authfile, public_key, &comment)) { 478 if (!load_public_key(authfile, public_key, &comment)) {
502 RSA_free(public_key); 479 RSA_free(public_key);
503 return 0; /* Could not load it. Fail. */ 480 return 0; /* Could not load it. Fail. */
504 }
505
506 debug("Trying RSA authentication with key '%.100s'", comment);
507
508 /* Tell the server that we are willing to authenticate using this key. */
509 packet_start(SSH_CMSG_AUTH_RSA);
510 packet_put_bignum(public_key->n);
511 packet_send();
512 packet_write_wait();
513
514 /* We no longer need the public key. */
515 RSA_free(public_key);
516
517 /* Wait for server's response. */
518 type = packet_read(&plen);
519
520 /* The server responds with failure if it doesn\'t like our key or doesn\'t
521 support RSA authentication. */
522 if (type == SSH_SMSG_FAILURE)
523 {
524 debug("Server refused our key.");
525 xfree(comment);
526 return 0; /* Server refuses to authenticate with this key. */
527 }
528
529 /* Otherwise, the server should respond with a challenge. */
530 if (type != SSH_SMSG_AUTH_RSA_CHALLENGE)
531 packet_disconnect("Protocol error during RSA authentication: %d", type);
532
533 /* Get the challenge from the packet. */
534 challenge = BN_new();
535 packet_get_bignum(challenge, &clen);
536
537 packet_integrity_check(plen, clen, type);
538
539 debug("Received RSA challenge from server.");
540
541 private_key = RSA_new();
542 /* Load the private key. Try first with empty passphrase; if it fails,
543 ask for a passphrase. */
544 if (!load_private_key(authfile, "", private_key, NULL))
545 {
546 char buf[300];
547 /* Request passphrase from the user. We read from /dev/tty to make
548 this work even if stdin has been redirected. If running in
549 batch mode, we just use the empty passphrase, which will fail and
550 return. */
551 snprintf(buf, sizeof buf,
552 "Enter passphrase for RSA key '%.100s': ", comment);
553 if (!options.batch_mode)
554 passphrase = read_passphrase(buf, 0);
555 else
556 {
557 debug("Will not query passphrase for %.100s in batch mode.",
558 comment);
559 passphrase = xstrdup("");
560 } 481 }
561 482 debug("Trying RSA authentication with key '%.100s'", comment);
562 /* Load the authentication file using the pasphrase. */ 483
563 if (!load_private_key(authfile, passphrase, private_key, NULL)) 484 /* Tell the server that we are willing to authenticate using this key. */
564 { 485 packet_start(SSH_CMSG_AUTH_RSA);
565 memset(passphrase, 0, strlen(passphrase)); 486 packet_put_bignum(public_key->n);
566 xfree(passphrase); 487 packet_send();
567 error("Bad passphrase."); 488 packet_write_wait();
568 489
569 /* Send a dummy response packet to avoid protocol error. */ 490 /* We no longer need the public key. */
570 packet_start(SSH_CMSG_AUTH_RSA_RESPONSE); 491 RSA_free(public_key);
571 for (i = 0; i < 16; i++) 492
572 packet_put_char(0); 493 /* Wait for server's response. */
573 packet_send(); 494 type = packet_read(&plen);
574 packet_write_wait(); 495
575 496 /* The server responds with failure if it doesn\'t like our key or
576 /* Expect the server to reject it... */ 497 doesn\'t support RSA authentication. */
577 packet_read_expect(&plen, SSH_SMSG_FAILURE); 498 if (type == SSH_SMSG_FAILURE) {
578 xfree(comment); 499 debug("Server refused our key.");
579 return 0; 500 xfree(comment);
501 return 0; /* Server refuses to authenticate with
502 this key. */
580 } 503 }
504 /* Otherwise, the server should respond with a challenge. */
505 if (type != SSH_SMSG_AUTH_RSA_CHALLENGE)
506 packet_disconnect("Protocol error during RSA authentication: %d", type);
507
508 /* Get the challenge from the packet. */
509 challenge = BN_new();
510 packet_get_bignum(challenge, &clen);
511
512 packet_integrity_check(plen, clen, type);
513
514 debug("Received RSA challenge from server.");
515
516 private_key = RSA_new();
517 /* Load the private key. Try first with empty passphrase; if it
518 fails, ask for a passphrase. */
519 if (!load_private_key(authfile, "", private_key, NULL)) {
520 char buf[300];
521 snprintf(buf, sizeof buf, "Enter passphrase for RSA key '%.100s': ",
522 comment);
523 if (!options.batch_mode)
524 passphrase = read_passphrase(buf, 0);
525 else {
526 debug("Will not query passphrase for %.100s in batch mode.",
527 comment);
528 passphrase = xstrdup("");
529 }
581 530
582 /* Destroy the passphrase. */ 531 /* Load the authentication file using the pasphrase. */
583 memset(passphrase, 0, strlen(passphrase)); 532 if (!load_private_key(authfile, passphrase, private_key, NULL)) {
584 xfree(passphrase); 533 memset(passphrase, 0, strlen(passphrase));
585 } 534 xfree(passphrase);
586 535 error("Bad passphrase.");
587 /* We no longer need the comment. */ 536
588 xfree(comment); 537 /* Send a dummy response packet to avoid protocol error. */
589 538 packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
590 /* Compute and send a response to the challenge. */ 539 for (i = 0; i < 16; i++)
591 respond_to_rsa_challenge(challenge, private_key); 540 packet_put_char(0);
592 541 packet_send();
593 /* Destroy the private key. */ 542 packet_write_wait();
594 RSA_free(private_key); 543
595 544 /* Expect the server to reject it... */
596 /* We no longer need the challenge. */ 545 packet_read_expect(&plen, SSH_SMSG_FAILURE);
597 BN_clear_free(challenge); 546 xfree(comment);
598 547 return 0;
599 /* Wait for response from the server. */ 548 }
600 type = packet_read(&plen); 549 /* Destroy the passphrase. */
601 if (type == SSH_SMSG_SUCCESS) 550 memset(passphrase, 0, strlen(passphrase));
602 { 551 xfree(passphrase);
603 debug("RSA authentication accepted by server."); 552 }
604 return 1; 553 /* We no longer need the comment. */
605 } 554 xfree(comment);
606 if (type != SSH_SMSG_FAILURE) 555
607 packet_disconnect("Protocol error waiting RSA auth response: %d", type); 556 /* Compute and send a response to the challenge. */
608 debug("RSA authentication refused."); 557 respond_to_rsa_challenge(challenge, private_key);
609 return 0; 558
610} 559 /* Destroy the private key. */
560 RSA_free(private_key);
611 561
612/* Tries to authenticate the user using combined rhosts or /etc/hosts.equiv 562 /* We no longer need the challenge. */
613 authentication and RSA host authentication. */ 563 BN_clear_free(challenge);
564
565 /* Wait for response from the server. */
566 type = packet_read(&plen);
567 if (type == SSH_SMSG_SUCCESS) {
568 debug("RSA authentication accepted by server.");
569 return 1;
570 }
571 if (type != SSH_SMSG_FAILURE)
572 packet_disconnect("Protocol error waiting RSA auth response: %d", type);
573 debug("RSA authentication refused.");
574 return 0;
575}
614 576
577/*
578 * Tries to authenticate the user using combined rhosts or /etc/hosts.equiv
579 * authentication and RSA host authentication.
580 */
615int 581int
616try_rhosts_rsa_authentication(const char *local_user, RSA *host_key) 582try_rhosts_rsa_authentication(const char *local_user, RSA * host_key)
617{ 583{
618 int type; 584 int type;
619 BIGNUM *challenge; 585 BIGNUM *challenge;
620 int plen, clen; 586 int plen, clen;
621 587
622 debug("Trying rhosts or /etc/hosts.equiv with RSA host authentication."); 588 debug("Trying rhosts or /etc/hosts.equiv with RSA host authentication.");
623 589
624 /* Tell the server that we are willing to authenticate using this key. */ 590 /* Tell the server that we are willing to authenticate using this key. */
625 packet_start(SSH_CMSG_AUTH_RHOSTS_RSA); 591 packet_start(SSH_CMSG_AUTH_RHOSTS_RSA);
626 packet_put_string(local_user, strlen(local_user)); 592 packet_put_string(local_user, strlen(local_user));
627 packet_put_int(BN_num_bits(host_key->n)); 593 packet_put_int(BN_num_bits(host_key->n));
628 packet_put_bignum(host_key->e); 594 packet_put_bignum(host_key->e);
629 packet_put_bignum(host_key->n); 595 packet_put_bignum(host_key->n);
630 packet_send(); 596 packet_send();
631 packet_write_wait(); 597 packet_write_wait();
632 598
633 /* Wait for server's response. */ 599 /* Wait for server's response. */
634 type = packet_read(&plen); 600 type = packet_read(&plen);
635 601
636 /* The server responds with failure if it doesn't admit our .rhosts 602 /* The server responds with failure if it doesn't admit our
637 authentication or doesn't know our host key. */ 603 .rhosts authentication or doesn't know our host key. */
638 if (type == SSH_SMSG_FAILURE) 604 if (type == SSH_SMSG_FAILURE) {
639 { 605 debug("Server refused our rhosts authentication or host key.");
640 debug("Server refused our rhosts authentication or host key."); 606 return 0;
641 return 0; /* Server refuses to authenticate us with this method. */ 607 }
642 } 608 /* Otherwise, the server should respond with a challenge. */
643 609 if (type != SSH_SMSG_AUTH_RSA_CHALLENGE)
644 /* Otherwise, the server should respond with a challenge. */ 610 packet_disconnect("Protocol error during RSA authentication: %d", type);
645 if (type != SSH_SMSG_AUTH_RSA_CHALLENGE) 611
646 packet_disconnect("Protocol error during RSA authentication: %d", type); 612 /* Get the challenge from the packet. */
647 613 challenge = BN_new();
648 /* Get the challenge from the packet. */ 614 packet_get_bignum(challenge, &clen);
649 challenge = BN_new(); 615
650 packet_get_bignum(challenge, &clen); 616 packet_integrity_check(plen, clen, type);
651 617
652 packet_integrity_check(plen, clen, type); 618 debug("Received RSA challenge for host key from server.");
653 619
654 debug("Received RSA challenge for host key from server."); 620 /* Compute a response to the challenge. */
655 621 respond_to_rsa_challenge(challenge, host_key);
656 /* Compute a response to the challenge. */ 622
657 respond_to_rsa_challenge(challenge, host_key); 623 /* We no longer need the challenge. */
658 624 BN_clear_free(challenge);
659 /* We no longer need the challenge. */ 625
660 BN_clear_free(challenge); 626 /* Wait for response from the server. */
661 627 type = packet_read(&plen);
662 /* Wait for response from the server. */ 628 if (type == SSH_SMSG_SUCCESS) {
663 type = packet_read(&plen); 629 debug("Rhosts or /etc/hosts.equiv with RSA host authentication accepted by server.");
664 if (type == SSH_SMSG_SUCCESS) 630 return 1;
665 { 631 }
666 debug("Rhosts or /etc/hosts.equiv with RSA host authentication accepted by server."); 632 if (type != SSH_SMSG_FAILURE)
667 return 1; 633 packet_disconnect("Protocol error waiting RSA auth response: %d", type);
668 } 634 debug("Rhosts or /etc/hosts.equiv with RSA host authentication refused.");
669 if (type != SSH_SMSG_FAILURE) 635 return 0;
670 packet_disconnect("Protocol error waiting RSA auth response: %d", type);
671 debug("Rhosts or /etc/hosts.equiv with RSA host authentication refused.");
672 return 0;
673} 636}
674 637
675#ifdef KRB4 638#ifdef KRB4
676int try_kerberos_authentication() 639int
640try_kerberos_authentication()
677{ 641{
678 KTEXT_ST auth; /* Kerberos data */ 642 KTEXT_ST auth; /* Kerberos data */
679 char *reply; 643 char *reply;
680 char inst[INST_SZ]; 644 char inst[INST_SZ];
681 char *realm; 645 char *realm;
682 CREDENTIALS cred; 646 CREDENTIALS cred;
683 int r, type, plen; 647 int r, type, plen;
684 Key_schedule schedule; 648 Key_schedule schedule;
685 u_long checksum, cksum; 649 u_long checksum, cksum;
686 MSG_DAT msg_data; 650 MSG_DAT msg_data;
687 struct sockaddr_in local, foreign; 651 struct sockaddr_in local, foreign;
688 struct stat st; 652 struct stat st;
689 653
690 /* Don't do anything if we don't have any tickets. */ 654 /* Don't do anything if we don't have any tickets. */
691 if (stat(tkt_string(), &st) < 0) return 0; 655 if (stat(tkt_string(), &st) < 0)
692 656 return 0;
693 strncpy(inst, (char *) krb_get_phost(get_canonical_hostname()), INST_SZ); 657
694 658 strncpy(inst, (char *) krb_get_phost(get_canonical_hostname()), INST_SZ);
695 realm = (char *)krb_realmofhost(get_canonical_hostname()); 659
696 if (!realm) { 660 realm = (char *) krb_realmofhost(get_canonical_hostname());
697 debug("Kerberos V4: no realm for %s", get_canonical_hostname()); 661 if (!realm) {
698 return 0; 662 debug("Kerberos V4: no realm for %s", get_canonical_hostname());
699 } 663 return 0;
700 /* This can really be anything. */ 664 }
701 checksum = (u_long) getpid(); 665 /* This can really be anything. */
702 666 checksum = (u_long) getpid();
703 r = krb_mk_req(&auth, KRB4_SERVICE_NAME, inst, realm, checksum); 667
704 if (r != KSUCCESS) { 668 r = krb_mk_req(&auth, KRB4_SERVICE_NAME, inst, realm, checksum);
705 debug("Kerberos V4 krb_mk_req failed: %s", krb_err_txt[r]); 669 if (r != KSUCCESS) {
706 return 0; 670 debug("Kerberos V4 krb_mk_req failed: %s", krb_err_txt[r]);
707 } 671 return 0;
708 /* Get session key to decrypt the server's reply with. */ 672 }
709 r = krb_get_cred(KRB4_SERVICE_NAME, inst, realm, &cred); 673 /* Get session key to decrypt the server's reply with. */
710 if (r != KSUCCESS) { 674 r = krb_get_cred(KRB4_SERVICE_NAME, inst, realm, &cred);
711 debug("get_cred failed: %s", krb_err_txt[r]); 675 if (r != KSUCCESS) {
712 return 0; 676 debug("get_cred failed: %s", krb_err_txt[r]);
713 } 677 return 0;
714 des_key_sched((des_cblock *)cred.session, schedule); 678 }
715 679 des_key_sched((des_cblock *) cred.session, schedule);
716 /* Send authentication info to server. */ 680
717 packet_start(SSH_CMSG_AUTH_KERBEROS); 681 /* Send authentication info to server. */
718 packet_put_string((char *)auth.dat, auth.length); 682 packet_start(SSH_CMSG_AUTH_KERBEROS);
719 packet_send(); 683 packet_put_string((char *) auth.dat, auth.length);
720 packet_write_wait(); 684 packet_send();
721 685 packet_write_wait();
722 /* Zero the buffer. */ 686
723 (void) memset(auth.dat, 0, MAX_KTXT_LEN); 687 /* Zero the buffer. */
724 688 (void) memset(auth.dat, 0, MAX_KTXT_LEN);
725 r = sizeof(local); 689
726 memset(&local, 0, sizeof(local)); 690 r = sizeof(local);
727 if (getsockname(packet_get_connection_in(), 691 memset(&local, 0, sizeof(local));
728 (struct sockaddr *) &local, &r) < 0) 692 if (getsockname(packet_get_connection_in(),
729 debug("getsockname failed: %s", strerror(errno)); 693 (struct sockaddr *) & local, &r) < 0)
730 694 debug("getsockname failed: %s", strerror(errno));
731 r = sizeof(foreign); 695
732 memset(&foreign, 0, sizeof(foreign)); 696 r = sizeof(foreign);
733 if (getpeername(packet_get_connection_in(), 697 memset(&foreign, 0, sizeof(foreign));
734 (struct sockaddr *)&foreign, &r) < 0) { 698 if (getpeername(packet_get_connection_in(),
735 debug("getpeername failed: %s", strerror(errno)); 699 (struct sockaddr *) & foreign, &r) < 0) {
736 fatal_cleanup(); 700 debug("getpeername failed: %s", strerror(errno));
737 } 701 fatal_cleanup();
738 702 }
739 /* Get server reply. */ 703 /* Get server reply. */
740 type = packet_read(&plen); 704 type = packet_read(&plen);
741 switch(type) { 705 switch (type) {
742 706 case SSH_SMSG_FAILURE:
743 case SSH_SMSG_FAILURE: /* Should really be SSH_SMSG_AUTH_KERBEROS_FAILURE */ 707 /* Should really be SSH_SMSG_AUTH_KERBEROS_FAILURE */
744 debug("Kerberos V4 authentication failed."); 708 debug("Kerberos V4 authentication failed.");
745 return 0; 709 return 0;
746 break; 710 break;
747 711
748 case SSH_SMSG_AUTH_KERBEROS_RESPONSE: /* SSH_SMSG_AUTH_KERBEROS_SUCCESS */ 712 case SSH_SMSG_AUTH_KERBEROS_RESPONSE:
749 debug("Kerberos V4 authentication accepted."); 713 /* SSH_SMSG_AUTH_KERBEROS_SUCCESS */
750 714 debug("Kerberos V4 authentication accepted.");
751 /* Get server's response. */ 715
752 reply = packet_get_string((unsigned int *)&auth.length); 716 /* Get server's response. */
753 memcpy(auth.dat, reply, auth.length); 717 reply = packet_get_string((unsigned int *) &auth.length);
754 xfree(reply); 718 memcpy(auth.dat, reply, auth.length);
755 719 xfree(reply);
756 packet_integrity_check(plen, 4 + auth.length, type); 720
757 721 packet_integrity_check(plen, 4 + auth.length, type);
758 /* If his response isn't properly encrypted with the session key, 722
759 and the decrypted checksum fails to match, he's bogus. Bail out. */ 723 /* If his response isn't properly encrypted with the
760 r = krb_rd_priv(auth.dat, auth.length, schedule, &cred.session, 724 session key, and the decrypted checksum fails to match,
761 &foreign, &local, &msg_data); 725 he's bogus. Bail out. */
762 if (r != KSUCCESS) { 726 r = krb_rd_priv(auth.dat, auth.length, schedule, &cred.session,
763 debug("Kerberos V4 krb_rd_priv failed: %s", krb_err_txt[r]); 727 &foreign, &local, &msg_data);
764 packet_disconnect("Kerberos V4 challenge failed!"); 728 if (r != KSUCCESS) {
765 } 729 debug("Kerberos V4 krb_rd_priv failed: %s", krb_err_txt[r]);
766 /* Fetch the (incremented) checksum that we supplied in the request. */ 730 packet_disconnect("Kerberos V4 challenge failed!");
767 (void)memcpy((char *)&cksum, (char *)msg_data.app_data, sizeof(cksum)); 731 }
768 cksum = ntohl(cksum); 732 /* Fetch the (incremented) checksum that we supplied in the request. */
769 733 (void) memcpy((char *) &cksum, (char *) msg_data.app_data, sizeof(cksum));
770 /* If it matches, we're golden. */ 734 cksum = ntohl(cksum);
771 if (cksum == checksum + 1) { 735
772 debug("Kerberos V4 challenge successful."); 736 /* If it matches, we're golden. */
773 return 1; 737 if (cksum == checksum + 1) {
774 } 738 debug("Kerberos V4 challenge successful.");
775 else 739 return 1;
776 packet_disconnect("Kerberos V4 challenge failed!"); 740 } else
777 break; 741 packet_disconnect("Kerberos V4 challenge failed!");
778 742 break;
779 default: 743
780 packet_disconnect("Protocol error on Kerberos V4 response: %d", type); 744 default:
781 } 745 packet_disconnect("Protocol error on Kerberos V4 response: %d", type);
782 return 0; 746 }
747 return 0;
783} 748}
749
784#endif /* KRB4 */ 750#endif /* KRB4 */
785 751
786#ifdef AFS 752#ifdef AFS
787int send_kerberos_tgt() 753int
754send_kerberos_tgt()
788{ 755{
789 CREDENTIALS *creds; 756 CREDENTIALS *creds;
790 char pname[ANAME_SZ], pinst[INST_SZ], prealm[REALM_SZ]; 757 char pname[ANAME_SZ], pinst[INST_SZ], prealm[REALM_SZ];
791 int r, type, plen; 758 int r, type, plen;
792 unsigned char buffer[8192]; 759 unsigned char buffer[8192];
793 struct stat st; 760 struct stat st;
794 761
795 /* Don't do anything if we don't have any tickets. */ 762 /* Don't do anything if we don't have any tickets. */
796 if (stat(tkt_string(), &st) < 0) return 0; 763 if (stat(tkt_string(), &st) < 0)
797 764 return 0;
798 creds = xmalloc(sizeof(*creds)); 765
799 766 creds = xmalloc(sizeof(*creds));
800 if ((r = krb_get_tf_fullname(TKT_FILE, pname, pinst, prealm)) != KSUCCESS) { 767
801 debug("Kerberos V4 tf_fullname failed: %s",krb_err_txt[r]); 768 if ((r = krb_get_tf_fullname(TKT_FILE, pname, pinst, prealm)) != KSUCCESS) {
802 return 0; 769 debug("Kerberos V4 tf_fullname failed: %s", krb_err_txt[r]);
803 } 770 return 0;
804 if ((r = krb_get_cred("krbtgt", prealm, prealm, creds)) != GC_OK) { 771 }
805 debug("Kerberos V4 get_cred failed: %s", krb_err_txt[r]); 772 if ((r = krb_get_cred("krbtgt", prealm, prealm, creds)) != GC_OK) {
806 return 0; 773 debug("Kerberos V4 get_cred failed: %s", krb_err_txt[r]);
807 } 774 return 0;
808 if (time(0) > krb_life_to_time(creds->issue_date, creds->lifetime)) { 775 }
809 debug("Kerberos V4 ticket expired: %s", TKT_FILE); 776 if (time(0) > krb_life_to_time(creds->issue_date, creds->lifetime)) {
810 return 0; 777 debug("Kerberos V4 ticket expired: %s", TKT_FILE);
811 } 778 return 0;
812 779 }
813 creds_to_radix(creds, buffer); 780 creds_to_radix(creds, buffer);
814 xfree(creds); 781 xfree(creds);
815 782
816 packet_start(SSH_CMSG_HAVE_KERBEROS_TGT); 783 packet_start(SSH_CMSG_HAVE_KERBEROS_TGT);
817 packet_put_string((char *)buffer, strlen(buffer)); 784 packet_put_string((char *) buffer, strlen(buffer));
818 packet_send(); 785 packet_send();
819 packet_write_wait(); 786 packet_write_wait();
820 787
821 type = packet_read(&plen); 788 type = packet_read(&plen);
822 789
823 if (type == SSH_SMSG_FAILURE) 790 if (type == SSH_SMSG_FAILURE)
824 debug("Kerberos TGT for realm %s rejected.", prealm); 791 debug("Kerberos TGT for realm %s rejected.", prealm);
825 else if (type != SSH_SMSG_SUCCESS) 792 else if (type != SSH_SMSG_SUCCESS)
826 packet_disconnect("Protocol error on Kerberos TGT response: %d", type); 793 packet_disconnect("Protocol error on Kerberos TGT response: %d", type);
827 794
828 return 1; 795 return 1;
829} 796}
830 797
831void send_afs_tokens(void) 798void
799send_afs_tokens(void)
832{ 800{
833 CREDENTIALS creds; 801 CREDENTIALS creds;
834 struct ViceIoctl parms; 802 struct ViceIoctl parms;
835 struct ClearToken ct; 803 struct ClearToken ct;
836 int i, type, len, plen; 804 int i, type, len, plen;
837 char buf[2048], *p, *server_cell; 805 char buf[2048], *p, *server_cell;
838 unsigned char buffer[8192]; 806 unsigned char buffer[8192];
839 807
840 /* Move over ktc_GetToken, here's something leaner. */ 808 /* Move over ktc_GetToken, here's something leaner. */
841 for (i = 0; i < 100; i++) { /* just in case */ 809 for (i = 0; i < 100; i++) { /* just in case */
842 parms.in = (char *)&i; 810 parms.in = (char *) &i;
843 parms.in_size = sizeof(i); 811 parms.in_size = sizeof(i);
844 parms.out = buf; 812 parms.out = buf;
845 parms.out_size = sizeof(buf); 813 parms.out_size = sizeof(buf);
846 if (k_pioctl(0, VIOCGETTOK, &parms, 0) != 0) break; 814 if (k_pioctl(0, VIOCGETTOK, &parms, 0) != 0)
847 p = buf; 815 break;
848 816 p = buf;
849 /* Get secret token. */ 817
850 memcpy(&creds.ticket_st.length, p, sizeof(unsigned int)); 818 /* Get secret token. */
851 if (creds.ticket_st.length > MAX_KTXT_LEN) break; 819 memcpy(&creds.ticket_st.length, p, sizeof(unsigned int));
852 p += sizeof(unsigned int); 820 if (creds.ticket_st.length > MAX_KTXT_LEN)
853 memcpy(creds.ticket_st.dat, p, creds.ticket_st.length); 821 break;
854 p += creds.ticket_st.length; 822 p += sizeof(unsigned int);
855 823 memcpy(creds.ticket_st.dat, p, creds.ticket_st.length);
856 /* Get clear token. */ 824 p += creds.ticket_st.length;
857 memcpy(&len, p, sizeof(len)); 825
858 if (len != sizeof(struct ClearToken)) break; 826 /* Get clear token. */
859 p += sizeof(len); 827 memcpy(&len, p, sizeof(len));
860 memcpy(&ct, p, len); 828 if (len != sizeof(struct ClearToken))
861 p += len; 829 break;
862 p += sizeof(len); /* primary flag */ 830 p += sizeof(len);
863 server_cell = p; 831 memcpy(&ct, p, len);
864 832 p += len;
865 /* Flesh out our credentials. */ 833 p += sizeof(len); /* primary flag */
866 strlcpy(creds.service, "afs", sizeof creds.service); 834 server_cell = p;
867 creds.instance[0] = '\0'; 835
868 strlcpy(creds.realm, server_cell, REALM_SZ); 836 /* Flesh out our credentials. */
869 memcpy(creds.session, ct.HandShakeKey, DES_KEY_SZ); 837 strlcpy(creds.service, "afs", sizeof creds.service);
870 creds.issue_date = ct.BeginTimestamp; 838 creds.instance[0] = '\0';
871 creds.lifetime = krb_time_to_life(creds.issue_date, ct.EndTimestamp); 839 strlcpy(creds.realm, server_cell, REALM_SZ);
872 creds.kvno = ct.AuthHandle; 840 memcpy(creds.session, ct.HandShakeKey, DES_KEY_SZ);
873 snprintf(creds.pname, sizeof(creds.pname), "AFS ID %d", ct.ViceId); 841 creds.issue_date = ct.BeginTimestamp;
874 creds.pinst[0] = '\0'; 842 creds.lifetime = krb_time_to_life(creds.issue_date, ct.EndTimestamp);
875 843 creds.kvno = ct.AuthHandle;
876 /* Encode token, ship it off. */ 844 snprintf(creds.pname, sizeof(creds.pname), "AFS ID %d", ct.ViceId);
877 if (!creds_to_radix(&creds, buffer)) break; 845 creds.pinst[0] = '\0';
878 packet_start(SSH_CMSG_HAVE_AFS_TOKEN); 846
879 packet_put_string((char *)buffer, strlen(buffer)); 847 /* Encode token, ship it off. */
880 packet_send(); 848 if (!creds_to_radix(&creds, buffer))
881 packet_write_wait(); 849 break;
882 850 packet_start(SSH_CMSG_HAVE_AFS_TOKEN);
883 /* Roger, Roger. Clearance, Clarence. What's your vector, Victor? */ 851 packet_put_string((char *) buffer, strlen(buffer));
884 type = packet_read(&plen); 852 packet_send();
885 853 packet_write_wait();
886 if (type == SSH_SMSG_FAILURE) 854
887 debug("AFS token for cell %s rejected.", server_cell); 855 /* Roger, Roger. Clearance, Clarence. What's your vector,
888 else if (type != SSH_SMSG_SUCCESS) 856 Victor? */
889 packet_disconnect("Protocol error on AFS token response: %d", type); 857 type = packet_read(&plen);
890 } 858
859 if (type == SSH_SMSG_FAILURE)
860 debug("AFS token for cell %s rejected.", server_cell);
861 else if (type != SSH_SMSG_SUCCESS)
862 packet_disconnect("Protocol error on AFS token response: %d", type);
863 }
891} 864}
892#endif /* AFS */
893 865
894/* Waits for the server identification string, and sends our own identification 866#endif /* AFS */
895 string. */
896 867
897void ssh_exchange_identification() 868/*
869 * Waits for the server identification string, and sends our own
870 * identification string.
871 */
872void
873ssh_exchange_identification()
898{ 874{
899 char buf[256], remote_version[256]; /* must be same size! */ 875 char buf[256], remote_version[256]; /* must be same size! */
900 int remote_major, remote_minor, i; 876 int remote_major, remote_minor, i;
901 int connection_in = packet_get_connection_in(); 877 int connection_in = packet_get_connection_in();
902 int connection_out = packet_get_connection_out(); 878 int connection_out = packet_get_connection_out();
903 extern Options options; 879 extern Options options;
904 880
905 /* Read other side\'s version identification. */ 881 /* Read other side\'s version identification. */
906 for (i = 0; i < sizeof(buf) - 1; i++) 882 for (i = 0; i < sizeof(buf) - 1; i++) {
907 { 883 if (read(connection_in, &buf[i], 1) != 1)
908 if (read(connection_in, &buf[i], 1) != 1) 884 fatal("ssh_exchange_identification: read: %.100s", strerror(errno));
909 fatal("ssh_exchange_identification: read: %.100s", strerror(errno)); 885 if (buf[i] == '\r') {
910 if (buf[i] == '\r') 886 buf[i] = '\n';
911 { 887 buf[i + 1] = 0;
912 buf[i] = '\n'; 888 break;
913 buf[i + 1] = 0; 889 }
914 break; 890 if (buf[i] == '\n') {
891 buf[i + 1] = 0;
892 break;
893 }
915 } 894 }
916 if (buf[i] == '\n') 895 buf[sizeof(buf) - 1] = 0;
917 { 896
918 buf[i + 1] = 0; 897 /* Check that the versions match. In future this might accept
919 break; 898 several versions and set appropriate flags to handle them. */
899 if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor,
900 remote_version) != 3)
901 fatal("Bad remote protocol version identification: '%.100s'", buf);
902 debug("Remote protocol version %d.%d, remote software version %.100s",
903 remote_major, remote_minor, remote_version);
904
905 /* Check if the remote protocol version is too old. */
906 if (remote_major == 1 && remote_minor < 3)
907 fatal("Remote machine has too old SSH software version.");
908
909 /* We speak 1.3, too. */
910 if (remote_major == 1 && remote_minor == 3) {
911 enable_compat13();
912 if (options.forward_agent && strcmp(remote_version, SSH_VERSION) != 0) {
913 log("Agent forwarding disabled, remote version '%s' is not compatible.",
914 remote_version);
915 options.forward_agent = 0;
916 }
920 } 917 }
921 }
922 buf[sizeof(buf) - 1] = 0;
923
924 /* Check that the versions match. In future this might accept several
925 versions and set appropriate flags to handle them. */
926 if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor,
927 remote_version) != 3)
928 fatal("Bad remote protocol version identification: '%.100s'", buf);
929 debug("Remote protocol version %d.%d, remote software version %.100s",
930 remote_major, remote_minor, remote_version);
931
932 /* Check if the remote protocol version is too old. */
933 if (remote_major == 1 && remote_minor < 3)
934 fatal("Remote machine has too old SSH software version.");
935
936 /* We speak 1.3, too. */
937 if (remote_major == 1 && remote_minor == 3) {
938 enable_compat13();
939 if (options.forward_agent && strcmp(remote_version, SSH_VERSION) != 0) {
940 log("Agent forwarding disabled, remote version '%s' is not compatible.",
941 remote_version);
942 options.forward_agent = 0;
943 }
944 }
945#if 0 918#if 0
946 /* Removed for now, to permit compatibility with latter versions. The server 919 /* Removed for now, to permit compatibility with latter versions.
947 will reject our version and disconnect if it doesn't support it. */ 920 The server will reject our version and disconnect if it doesn't
948 if (remote_major != PROTOCOL_MAJOR) 921 support it. */
949 fatal("Protocol major versions differ: %d vs. %d", 922 if (remote_major != PROTOCOL_MAJOR)
950 PROTOCOL_MAJOR, remote_major); 923 fatal("Protocol major versions differ: %d vs. %d",
924 PROTOCOL_MAJOR, remote_major);
951#endif 925#endif
952 926
953 /* Send our own protocol version identification. */ 927 /* Send our own protocol version identification. */
954 snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", 928 snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
955 PROTOCOL_MAJOR, PROTOCOL_MINOR, SSH_VERSION); 929 PROTOCOL_MAJOR, PROTOCOL_MINOR, SSH_VERSION);
956 if (write(connection_out, buf, strlen(buf)) != strlen(buf)) 930 if (write(connection_out, buf, strlen(buf)) != strlen(buf))
957 fatal("write: %.100s", strerror(errno)); 931 fatal("write: %.100s", strerror(errno));
958} 932}
959 933
960int ssh_cipher_default = SSH_CIPHER_3DES; 934int ssh_cipher_default = SSH_CIPHER_3DES;
961 935
962int read_yes_or_no(const char *prompt, int defval) 936int
937read_yes_or_no(const char *prompt, int defval)
963{ 938{
964 char buf[1024]; 939 char buf[1024];
965 FILE *f; 940 FILE *f;
966 int retval = -1; 941 int retval = -1;
967 942
968 if (isatty(0)) 943 if (isatty(0))
969 f = stdin; 944 f = stdin;
970 else 945 else
971 f = fopen("/dev/tty", "rw"); 946 f = fopen("/dev/tty", "rw");
972 947
973 if (f == NULL) 948 if (f == NULL)
974 return 0; 949 return 0;
975 950
976 fflush(stdout); 951 fflush(stdout);
977 952
978 while (1) 953 while (1) {
979 { 954 fprintf(stderr, "%s", prompt);
980 fprintf(stderr, "%s", prompt); 955 if (fgets(buf, sizeof(buf), f) == NULL) {
981 if (fgets(buf, sizeof(buf), f) == NULL) 956 /* Print a newline (the prompt probably didn\'t have one). */
982 { 957 fprintf(stderr, "\n");
983 /* Print a newline (the prompt probably didn\'t have one). */ 958 strlcpy(buf, "no", sizeof buf);
984 fprintf(stderr, "\n"); 959 }
985 strlcpy(buf, "no", sizeof buf); 960 /* Remove newline from response. */
986 } 961 if (strchr(buf, '\n'))
987 /* Remove newline from response. */ 962 *strchr(buf, '\n') = 0;
988 if (strchr(buf, '\n')) 963
989 *strchr(buf, '\n') = 0; 964 if (buf[0] == 0)
990 965 retval = defval;
991 if (buf[0] == 0) 966 if (strcmp(buf, "yes") == 0)
992 retval = defval; 967 retval = 1;
993 if (strcmp(buf, "yes") == 0) 968 if (strcmp(buf, "no") == 0)
994 retval = 1; 969 retval = 0;
995 if (strcmp(buf, "no") == 0) 970
996 retval = 0; 971 if (retval != -1) {
997 972 if (f != stdin)
998 if (retval != -1) 973 fclose(f);
999 { 974 return retval;
1000 if (f != stdin) 975 }
1001 fclose(f);
1002 return retval;
1003 } 976 }
1004 }
1005} 977}
1006 978
1007/* Starts a dialog with the server, and authenticates the current user on the 979/*
1008 server. This does not need any extra privileges. The basic connection 980 * Starts a dialog with the server, and authenticates the current user on the
1009 to the server must already have been established before this is called. 981 * server. This does not need any extra privileges. The basic connection
1010 User is the remote user; if it is NULL, the current local user name will 982 * to the server must already have been established before this is called.
1011 be used. Anonymous indicates that no rhosts authentication will be used. 983 * User is the remote user; if it is NULL, the current local user name will
1012 If login fails, this function prints an error and never returns. 984 * be used. Anonymous indicates that no rhosts authentication will be used.
1013 This function does not require super-user privileges. */ 985 * If login fails, this function prints an error and never returns.
1014 986 * This function does not require super-user privileges.
1015void ssh_login(int host_key_valid, 987 */
1016 RSA *own_host_key, 988void
1017 const char *orighost, 989ssh_login(int host_key_valid,
1018 struct sockaddr_in *hostaddr, 990 RSA *own_host_key,
1019 uid_t original_real_uid) 991 const char *orighost,
992 struct sockaddr_in *hostaddr,
993 uid_t original_real_uid)
1020{ 994{
1021 extern Options options; 995 extern Options options;
1022 int i, type; 996 int i, type;
1023 char *password; 997 char *password;
1024 struct passwd *pw; 998 struct passwd *pw;
1025 BIGNUM *key; 999 BIGNUM *key;
1026 RSA *host_key, *file_key; 1000 RSA *host_key, *file_key;
1027 RSA *public_key; 1001 RSA *public_key;
1028 int bits, rbits; 1002 int bits, rbits;
1029 unsigned char session_key[SSH_SESSION_KEY_LENGTH]; 1003 unsigned char session_key[SSH_SESSION_KEY_LENGTH];
1030 const char *server_user, *local_user; 1004 const char *server_user, *local_user;
1031 char *cp, *host, *ip = NULL; 1005 char *cp, *host, *ip = NULL;
1032 unsigned char check_bytes[8]; 1006 char hostline[1000], *hostp;
1033 unsigned int supported_ciphers, supported_authentications, protocol_flags; 1007 unsigned char check_bytes[8];
1034 HostStatus host_status; 1008 unsigned int supported_ciphers, supported_authentications, protocol_flags;
1035 HostStatus ip_status; 1009 HostStatus host_status;
1036 int host_ip_differ = 0; 1010 HostStatus ip_status;
1037 int local = (ntohl(hostaddr->sin_addr.s_addr) >> 24) == IN_LOOPBACKNET; 1011 int host_ip_differ = 0;
1038 int payload_len, clen, sum_len = 0; 1012 int local = (ntohl(hostaddr->sin_addr.s_addr) >> 24) == IN_LOOPBACKNET;
1039 u_int32_t rand = 0; 1013 int payload_len, clen, sum_len = 0;
1040 1014 u_int32_t rand = 0;
1041 if (options.check_host_ip) 1015
1042 ip = xstrdup(inet_ntoa(hostaddr->sin_addr)); 1016 if (options.check_host_ip)
1043 1017 ip = xstrdup(inet_ntoa(hostaddr->sin_addr));
1044 /* Convert the user-supplied hostname into all lowercase. */ 1018
1045 host = xstrdup(orighost); 1019 /* Convert the user-supplied hostname into all lowercase. */
1046 for (cp = host; *cp; cp++) 1020 host = xstrdup(orighost);
1047 if (isupper(*cp)) 1021 for (cp = host; *cp; cp++)
1048 *cp = tolower(*cp); 1022 if (isupper(*cp))
1049 1023 *cp = tolower(*cp);
1050 /* Exchange protocol version identification strings with the server. */ 1024
1051 ssh_exchange_identification(); 1025 /* Exchange protocol version identification strings with the server. */
1052 1026 ssh_exchange_identification();
1053 /* Put the connection into non-blocking mode. */ 1027
1054 packet_set_nonblocking(); 1028 /* Put the connection into non-blocking mode. */
1055 1029 packet_set_nonblocking();
1056 /* Get local user name. Use it as server user if no user name 1030
1057 was given. */ 1031 /* Get local user name. Use it as server user if no user name was given. */
1058 pw = getpwuid(original_real_uid); 1032 pw = getpwuid(original_real_uid);
1059 if (!pw) 1033 if (!pw)
1060 fatal("User id %d not found from user database.", original_real_uid); 1034 fatal("User id %d not found from user database.", original_real_uid);
1061 local_user = xstrdup(pw->pw_name); 1035 local_user = xstrdup(pw->pw_name);
1062 server_user = options.user ? options.user : local_user; 1036 server_user = options.user ? options.user : local_user;
1063 1037
1064 debug("Waiting for server public key."); 1038 debug("Waiting for server public key.");
1065 1039
1066 /* Wait for a public key packet from the server. */ 1040 /* Wait for a public key packet from the server. */
1067 packet_read_expect(&payload_len, SSH_SMSG_PUBLIC_KEY); 1041 packet_read_expect(&payload_len, SSH_SMSG_PUBLIC_KEY);
1068 1042
1069 /* Get check bytes from the packet. */ 1043 /* Get check bytes from the packet. */
1070 for (i = 0; i < 8; i++) 1044 for (i = 0; i < 8; i++)
1071 check_bytes[i] = packet_get_char(); 1045 check_bytes[i] = packet_get_char();
1072 1046
1073 /* Get the public key. */ 1047 /* Get the public key. */
1074 public_key = RSA_new(); 1048 public_key = RSA_new();
1075 bits = packet_get_int(); /* bits */ 1049 bits = packet_get_int();/* bits */
1076 public_key->e = BN_new(); 1050 public_key->e = BN_new();
1077 packet_get_bignum(public_key->e, &clen); 1051 packet_get_bignum(public_key->e, &clen);
1078 sum_len += clen; 1052 sum_len += clen;
1079 public_key->n = BN_new(); 1053 public_key->n = BN_new();
1080 packet_get_bignum(public_key->n, &clen); 1054 packet_get_bignum(public_key->n, &clen);
1081 sum_len += clen; 1055 sum_len += clen;
1082 1056
1083 rbits = BN_num_bits(public_key->n); 1057 rbits = BN_num_bits(public_key->n);
1084 if (bits != rbits) { 1058 if (bits != rbits) {
1085 log("Warning: Server lies about size of server public key: " 1059 log("Warning: Server lies about size of server public key: "
1086 "actual size is %d bits vs. announced %d.", rbits, bits); 1060 "actual size is %d bits vs. announced %d.", rbits, bits);
1087 log("Warning: This may be due to an old implementation of ssh."); 1061 log("Warning: This may be due to an old implementation of ssh.");
1088 } 1062 }
1089 1063 /* Get the host key. */
1090 /* Get the host key. */ 1064 host_key = RSA_new();
1091 host_key = RSA_new(); 1065 bits = packet_get_int();/* bits */
1092 bits = packet_get_int(); /* bits */ 1066 host_key->e = BN_new();
1093 host_key->e = BN_new(); 1067 packet_get_bignum(host_key->e, &clen);
1094 packet_get_bignum(host_key->e, &clen); 1068 sum_len += clen;
1095 sum_len += clen; 1069 host_key->n = BN_new();
1096 host_key->n = BN_new(); 1070 packet_get_bignum(host_key->n, &clen);
1097 packet_get_bignum(host_key->n, &clen); 1071 sum_len += clen;
1098 sum_len += clen; 1072
1099 1073 rbits = BN_num_bits(host_key->n);
1100 rbits = BN_num_bits(host_key->n); 1074 if (bits != rbits) {
1101 if (bits != rbits) { 1075 log("Warning: Server lies about size of server host key: "
1102 log("Warning: Server lies about size of server host key: " 1076 "actual size is %d bits vs. announced %d.", rbits, bits);
1103 "actual size is %d bits vs. announced %d.", rbits, bits); 1077 log("Warning: This may be due to an old implementation of ssh.");
1104 log("Warning: This may be due to an old implementation of ssh."); 1078 }
1105 } 1079 /* Store the host key from the known host file in here so that we
1106 1080 can compare it with the key for the IP address. */
1107 /* Store the host key from the known host file in here 1081 file_key = RSA_new();
1108 * so that we can compare it with the key for the IP 1082 file_key->n = BN_new();
1109 * address. */ 1083 file_key->e = BN_new();
1110 file_key = RSA_new(); 1084
1111 file_key->n = BN_new(); 1085 /* Get protocol flags. */
1112 file_key->e = BN_new(); 1086 protocol_flags = packet_get_int();
1113 1087 packet_set_protocol_flags(protocol_flags);
1114 /* Get protocol flags. */ 1088
1115 protocol_flags = packet_get_int(); 1089 /* Get supported cipher types. */
1116 packet_set_protocol_flags(protocol_flags); 1090 supported_ciphers = packet_get_int();
1117 1091
1118 /* Get supported cipher types. */ 1092 /* Get supported authentication types. */
1119 supported_ciphers = packet_get_int(); 1093 supported_authentications = packet_get_int();
1120 1094
1121 /* Get supported authentication types. */ 1095 debug("Received server public key (%d bits) and host key (%d bits).",
1122 supported_authentications = packet_get_int(); 1096 BN_num_bits(public_key->n), BN_num_bits(host_key->n));
1123 1097
1124 debug("Received server public key (%d bits) and host key (%d bits).", 1098 packet_integrity_check(payload_len,
1125 BN_num_bits(public_key->n), BN_num_bits(host_key->n)); 1099 8 + 4 + sum_len + 0 + 4 + 0 + 0 + 4 + 4 + 4,
1126 1100 SSH_SMSG_PUBLIC_KEY);
1127 packet_integrity_check(payload_len, 1101
1128 8 + 4 + sum_len + 0 + 4 + 0 + 0 + 4 + 4 + 4, 1102 /* Compute the session id. */
1129 SSH_SMSG_PUBLIC_KEY); 1103 compute_session_id(session_id, check_bytes, host_key->n, public_key->n);
1130 1104
1131 /* Compute the session id. */ 1105 /* Check if the host key is present in the user\'s list of known
1132 compute_session_id(session_id, check_bytes, host_key->n, public_key->n); 1106 hosts or in the systemwide list. */
1133 1107 host_status = check_host_in_hostfile(options.user_hostfile, host,
1134 /* Check if the host key is present in the user\'s list of known hosts 1108 host_key->e, host_key->n,
1135 or in the systemwide list. */ 1109 file_key->e, file_key->n);
1136 host_status = check_host_in_hostfile(options.user_hostfile, host, 1110 if (host_status == HOST_NEW)
1137 host_key->e, host_key->n, 1111 host_status = check_host_in_hostfile(options.system_hostfile, host,
1138 file_key->e, file_key->n); 1112 host_key->e, host_key->n,
1139 if (host_status == HOST_NEW) 1113 file_key->e, file_key->n);
1140 host_status = check_host_in_hostfile(options.system_hostfile, host, 1114 /* Force accepting of the host key for localhost and 127.0.0.1.
1141 host_key->e, host_key->n, 1115 The problem is that if the home directory is NFS-mounted to
1142 file_key->e, file_key->n); 1116 multiple machines, localhost will refer to a different machine
1143 /* Force accepting of the host key for localhost and 127.0.0.1. 1117 in each of them, and the user will get bogus HOST_CHANGED
1144 The problem is that if the home directory is NFS-mounted to multiple 1118 warnings. This essentially disables host authentication for
1145 machines, localhost will refer to a different machine in each of them, 1119 localhost; however, this is probably not a real problem. */
1146 and the user will get bogus HOST_CHANGED warnings. This essentially 1120 if (local) {
1147 disables host authentication for localhost; however, this is probably 1121 debug("Forcing accepting of host key for localhost.");
1148 not a real problem. */ 1122 host_status = HOST_OK;
1149 if (local) { 1123 }
1150 debug("Forcing accepting of host key for localhost."); 1124 /* Also perform check for the ip address, skip the check if we are
1151 host_status = HOST_OK; 1125 localhost or the hostname was an ip address to begin with */
1152 } 1126 if (options.check_host_ip && !local && strcmp(host, ip)) {
1153 1127 RSA *ip_key = RSA_new();
1154 /* Also perform check for the ip address, skip the check if we are 1128 ip_key->n = BN_new();
1155 localhost or the hostname was an ip address to begin with */ 1129 ip_key->e = BN_new();
1156 if (options.check_host_ip && !local && strcmp(host, ip)) { 1130 ip_status = check_host_in_hostfile(options.user_hostfile, ip,
1157 RSA *ip_key = RSA_new(); 1131 host_key->e, host_key->n,
1158 ip_key->n = BN_new(); 1132 ip_key->e, ip_key->n);
1159 ip_key->e = BN_new(); 1133
1160 ip_status = check_host_in_hostfile(options.user_hostfile, ip, 1134 if (ip_status == HOST_NEW)
1161 host_key->e, host_key->n, 1135 ip_status = check_host_in_hostfile(options.system_hostfile, ip,
1162 ip_key->e, ip_key->n); 1136 host_key->e, host_key->n,
1163 1137 ip_key->e, ip_key->n);
1164 if (ip_status == HOST_NEW) 1138 if (host_status == HOST_CHANGED &&
1165 ip_status = check_host_in_hostfile(options.system_hostfile, ip, 1139 (ip_status != HOST_CHANGED ||
1166 host_key->e, host_key->n, 1140 (BN_cmp(ip_key->e, file_key->e) || BN_cmp(ip_key->n, file_key->n))))
1167 ip_key->e, ip_key->n); 1141 host_ip_differ = 1;
1168 if (host_status == HOST_CHANGED && 1142
1169 (ip_status != HOST_CHANGED || 1143 RSA_free(ip_key);
1170 (BN_cmp(ip_key->e, file_key->e) || BN_cmp(ip_key->n, file_key->n)))) 1144 } else
1171 host_ip_differ = 1; 1145 ip_status = host_status;
1172 1146
1173 RSA_free(ip_key); 1147 RSA_free(file_key);
1174 } else 1148
1175 ip_status = host_status; 1149 switch (host_status) {
1176 1150 case HOST_OK:
1177 RSA_free(file_key); 1151 /* The host is known and the key matches. */
1178 1152 debug("Host '%.200s' is known and matches the host key.", host);
1179 switch (host_status) { 1153 if (options.check_host_ip) {
1180 case HOST_OK: 1154 if (ip_status == HOST_NEW) {
1181 /* The host is known and the key matches. */ 1155 if (!add_host_to_hostfile(options.user_hostfile, ip,
1182 debug("Host '%.200s' is known and matches the host key.", host); 1156 host_key->e, host_key->n))
1183 if (options.check_host_ip) { 1157 log("Failed to add the host key for IP address '%.30s' to the list of known hosts (%.30s).",
1184 if (ip_status == HOST_NEW) { 1158 ip, options.user_hostfile);
1185 if (!add_host_to_hostfile(options.user_hostfile, ip, 1159 else
1186 host_key->e, host_key->n)) 1160 log("Warning: Permanently added host key for IP address '%.30s' to the list of known hosts.",
1187 log("Failed to add the host key for IP address '%.30s' to the list of known hosts (%.30s).", 1161 ip);
1188 ip, options.user_hostfile); 1162 } else if (ip_status != HOST_OK)
1189 else 1163 log("Warning: the host key for '%.200s' differs from the key for the IP address '%.30s'",
1190 log("Warning: Permanently added host key for IP address '%.30s' to the list of known hosts.", 1164 host, ip);
1191 ip); 1165 }
1192 } else if (ip_status != HOST_OK) 1166 break;
1193 log("Warning: the host key for '%.200s' differs from the key for the IP address '%.30s'", 1167 case HOST_NEW:
1194 host, ip); 1168 /* The host is new. */
1195 } 1169 if (options.strict_host_key_checking == 1) {
1196 1170 /* User has requested strict host key checking. We will not add the host key
1197 break; 1171 automatically. The only alternative left is to abort. */
1198 case HOST_NEW: 1172 fatal("No host key is known for %.200s and you have requested strict checking.", host);
1199 { 1173 } else if (options.strict_host_key_checking == 2) {
1200 char hostline[1000], *hostp = hostline; 1174 /* The default */
1201 /* The host is new. */ 1175 char prompt[1024];
1202 if (options.strict_host_key_checking == 1) { 1176 char *fp = fingerprint(host_key->e, host_key->n);
1203 /* User has requested strict host key checking. We will not 1177 snprintf(prompt, sizeof(prompt),
1204 add the host key automatically. The only alternative left 1178 "The authenticity of host '%.200s' can't be established.\n"
1205 is to abort. */ 1179 "Key fingerprint is %d %s.\n"
1206 fatal("No host key is known for %.200s and you have requested strict checking.", host); 1180 "Are you sure you want to continue connecting (yes/no)? ",
1207 } else if (options.strict_host_key_checking == 2) { /* The default */ 1181 host, BN_num_bits(host_key->n), fp);
1208 char prompt[1024]; 1182 if (!read_yes_or_no(prompt, -1))
1209 char *fp = fingerprint(host_key->e, host_key->n); 1183 fatal("Aborted by user!\n");
1210 snprintf(prompt, sizeof(prompt), 1184 }
1211 "The authenticity of host '%.200s' can't be established.\n" 1185 if (options.check_host_ip && ip_status == HOST_NEW && strcmp(host, ip)) {
1212 "Key fingerprint is %d %s.\n" 1186 snprintf(hostline, sizeof(hostline), "%s,%s", host, ip);
1213 "Are you sure you want to continue connecting (yes/no)? ", 1187 hostp = hostline;
1214 host, BN_num_bits(host_key->n), fp); 1188 } else
1215 if (!read_yes_or_no(prompt, -1)) 1189 hostp = host;
1216 fatal("Aborted by user!\n"); 1190
1217 } 1191 /* If not in strict mode, add the key automatically to the local known_hosts file. */
1218 1192 if (!add_host_to_hostfile(options.user_hostfile, hostp,
1219 if (options.check_host_ip && ip_status == HOST_NEW && strcmp(host, ip)) 1193 host_key->e, host_key->n))
1220 snprintf(hostline, sizeof(hostline), "%s,%s", host, ip); 1194 log("Failed to add the host to the list of known hosts (%.500s).",
1221 else 1195 options.user_hostfile);
1222 hostp = host; 1196 else
1223 1197 log("Warning: Permanently added '%.200s' to the list of known hosts.",
1224 /* If not in strict mode, add the key automatically to the local 1198 hostp);
1225 known_hosts file. */ 1199 break;
1226 if (!add_host_to_hostfile(options.user_hostfile, hostp, 1200 case HOST_CHANGED:
1227 host_key->e, host_key->n)) 1201 if (options.check_host_ip && host_ip_differ) {
1228 log("Failed to add the host to the list of known hosts (%.500s).", 1202 char *msg;
1229 options.user_hostfile); 1203 if (ip_status == HOST_NEW)
1230 else 1204 msg = "is unknown";
1231 log("Warning: Permanently added '%.200s' to the list of known hosts.", 1205 else if (ip_status == HOST_OK)
1232 hostp); 1206 msg = "is unchanged";
1233 break; 1207 else
1234 } 1208 msg = "has a different value";
1235 case HOST_CHANGED: 1209 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1236 if (options.check_host_ip) { 1210 error("@ WARNING: POSSIBLE DNS SPOOFING DETECTED! @");
1237 if (host_ip_differ) { 1211 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1238 char *msg; 1212 error("The host key for %s has changed,", host);
1239 if (ip_status == HOST_NEW) 1213 error("and the key for the according IP address %s", ip);
1240 msg = "is unknown"; 1214 error("%s. This could either mean that", msg);
1241 else if (ip_status == HOST_OK) 1215 error("DNS SPOOFING is happening or the IP address for the host");
1242 msg = "is unchanged"; 1216 error("and its host key have changed at the same time");
1243 else 1217 }
1244 msg = "has a different value"; 1218 /* The host key has changed. */
1245 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 1219 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1246 error("@ WARNING: POSSIBLE DNS SPOOFING DETECTED! @"); 1220 error("@ WARNING: HOST IDENTIFICATION HAS CHANGED! @");
1247 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 1221 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1248 error("The host key for %s has changed,", host); 1222 error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!");
1249 error("and the key for the according IP address %s", ip); 1223 error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!");
1250 error("%s. This could either mean that", msg); 1224 error("It is also possible that the host key has just been changed.");
1251 error("DNS SPOOFING is happening or the IP address for the host"); 1225 error("Please contact your system administrator.");
1252 error("and its host key have changed at the same time"); 1226 error("Add correct host key in %.100s to get rid of this message.",
1253 } 1227 options.user_hostfile);
1254 } 1228
1255 1229 /* If strict host key checking is in use, the user will
1256 /* The host key has changed. */ 1230 have to edit the key manually and we can only abort. */
1257 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 1231 if (options.strict_host_key_checking)
1258 error("@ WARNING: HOST IDENTIFICATION HAS CHANGED! @"); 1232 fatal("Host key for %.200s has changed and you have requested strict checking.", host);
1259 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 1233
1260 error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); 1234 /* If strict host key checking has not been requested, allow the connection
1261 error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); 1235 but without password authentication or agent forwarding. */
1262 error("It is also possible that the host key has just been changed."); 1236 if (options.password_authentication) {
1263 error("Please contact your system administrator."); 1237 error("Password authentication is disabled to avoid trojan horses.");
1264 error("Add correct host key in %.100s to get rid of this message.", 1238 options.password_authentication = 0;
1265 options.user_hostfile); 1239 }
1266 1240 if (options.forward_agent) {
1267 /* If strict host key checking is in use, the user will have to edit 1241 error("Agent forwarding is disabled to avoid trojan horses.");
1268 the key manually and we can only abort. */ 1242 options.forward_agent = 0;
1269 if (options.strict_host_key_checking) 1243 }
1270 fatal("Host key for %.200s has changed and you have requested strict checking.", host); 1244 /* XXX Should permit the user to change to use the new id.
1271 1245 This could be done by converting the host key to an
1272 /* If strict host key checking has not been requested, allow the 1246 identifying sentence, tell that the host identifies
1273 connection but without password authentication or 1247 itself by that sentence, and ask the user if he/she
1274 agent forwarding. */ 1248 whishes to accept the authentication. */
1275 if (options.password_authentication) { 1249 break;
1276 error("Password authentication is disabled to avoid trojan horses."); 1250 }
1277 options.password_authentication = 0; 1251
1278 } 1252 if (options.check_host_ip)
1279 if (options.forward_agent) { 1253 xfree(ip);
1280 error("Agent forwarding is disabled to avoid trojan horses."); 1254
1281 options.forward_agent = 0; 1255 /* Generate a session key. */
1282 } 1256 arc4random_stir();
1283 /* XXX Should permit the user to change to use the new id. This could 1257
1284 be done by converting the host key to an identifying sentence, tell 1258 /* Generate an encryption key for the session. The key is a 256
1285 that the host identifies itself by that sentence, and ask the user 1259 bit random number, interpreted as a 32-byte key, with the least
1286 if he/she whishes to accept the authentication. */ 1260 significant 8 bits being the first byte of the key. */
1287 break; 1261 for (i = 0; i < 32; i++) {
1288 } 1262 if (i % 4 == 0)
1289 1263 rand = arc4random();
1290 if (options.check_host_ip) 1264 session_key[i] = rand & 0xff;
1291 xfree(ip); 1265 rand >>= 8;
1292 1266 }
1293 /* Generate a session key. */ 1267
1294 arc4random_stir(); 1268 /* According to the protocol spec, the first byte of the session
1295 1269 key is the highest byte of the integer. The session key is
1296 /* Generate an encryption key for the session. The key is a 256 bit 1270 xored with the first 16 bytes of the session id. */
1297 random number, interpreted as a 32-byte key, with the least significant 1271 key = BN_new();
1298 8 bits being the first byte of the key. */ 1272 BN_set_word(key, 0);
1299 for (i = 0; i < 32; i++) { 1273 for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) {
1300 if (i % 4 == 0) 1274 BN_lshift(key, key, 8);
1301 rand = arc4random(); 1275 if (i < 16)
1302 session_key[i] = rand & 0xff; 1276 BN_add_word(key, session_key[i] ^ session_id[i]);
1303 rand >>= 8; 1277 else
1304 } 1278 BN_add_word(key, session_key[i]);
1305 1279 }
1306 /* According to the protocol spec, the first byte of the session key is 1280
1307 the highest byte of the integer. The session key is xored with the 1281 /* Encrypt the integer using the public key and host key of the
1308 first 16 bytes of the session id. */ 1282 server (key with smaller modulus first). */
1309 key = BN_new(); 1283 if (BN_cmp(public_key->n, host_key->n) < 0) {
1310 BN_set_word(key, 0); 1284 /* Public key has smaller modulus. */
1311 for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) 1285 if (BN_num_bits(host_key->n) <
1312 { 1286 BN_num_bits(public_key->n) + SSH_KEY_BITS_RESERVED) {
1313 BN_lshift(key, key, 8); 1287 fatal("respond_to_rsa_challenge: host_key %d < public_key %d + "
1314 if (i < 16) 1288 "SSH_KEY_BITS_RESERVED %d",
1315 BN_add_word(key, session_key[i] ^ session_id[i]); 1289 BN_num_bits(host_key->n),
1316 else 1290 BN_num_bits(public_key->n),
1317 BN_add_word(key, session_key[i]); 1291 SSH_KEY_BITS_RESERVED);
1318 } 1292 }
1319 1293 rsa_public_encrypt(key, key, public_key);
1320 /* Encrypt the integer using the public key and host key of the server 1294 rsa_public_encrypt(key, key, host_key);
1321 (key with smaller modulus first). */ 1295 } else {
1322 if (BN_cmp(public_key->n, host_key->n) < 0) 1296 /* Host key has smaller modulus (or they are equal). */
1323 { 1297 if (BN_num_bits(public_key->n) <
1324 /* Public key has smaller modulus. */ 1298 BN_num_bits(host_key->n) + SSH_KEY_BITS_RESERVED) {
1325 if (BN_num_bits(host_key->n) < 1299 fatal("respond_to_rsa_challenge: public_key %d < host_key %d + "
1326 BN_num_bits(public_key->n) + SSH_KEY_BITS_RESERVED) { 1300 "SSH_KEY_BITS_RESERVED %d",
1327 fatal("respond_to_rsa_challenge: host_key %d < public_key %d + " 1301 BN_num_bits(public_key->n),
1328 "SSH_KEY_BITS_RESERVED %d", 1302 BN_num_bits(host_key->n),
1329 BN_num_bits(host_key->n), 1303 SSH_KEY_BITS_RESERVED);
1330 BN_num_bits(public_key->n), 1304 }
1331 SSH_KEY_BITS_RESERVED); 1305 rsa_public_encrypt(key, key, host_key);
1332 } 1306 rsa_public_encrypt(key, key, public_key);
1333 1307 }
1334 rsa_public_encrypt(key, key, public_key); 1308
1335 rsa_public_encrypt(key, key, host_key); 1309 if (options.cipher == SSH_CIPHER_NOT_SET) {
1336 } 1310 if (cipher_mask() & supported_ciphers & (1 << ssh_cipher_default))
1337 else 1311 options.cipher = ssh_cipher_default;
1338 { 1312 else {
1339 /* Host key has smaller modulus (or they are equal). */ 1313 debug("Cipher %s not supported, using %.100s instead.",
1340 if (BN_num_bits(public_key->n) < 1314 cipher_name(ssh_cipher_default),
1341 BN_num_bits(host_key->n) + SSH_KEY_BITS_RESERVED) { 1315 cipher_name(SSH_FALLBACK_CIPHER));
1342 fatal("respond_to_rsa_challenge: public_key %d < host_key %d + " 1316 options.cipher = SSH_FALLBACK_CIPHER;
1343 "SSH_KEY_BITS_RESERVED %d", 1317 }
1344 BN_num_bits(public_key->n), 1318 }
1345 BN_num_bits(host_key->n), 1319 /* Check that the selected cipher is supported. */
1346 SSH_KEY_BITS_RESERVED); 1320 if (!(supported_ciphers & (1 << options.cipher)))
1347 } 1321 fatal("Selected cipher type %.100s not supported by server.",
1348 1322 cipher_name(options.cipher));
1349 rsa_public_encrypt(key, key, host_key); 1323
1350 rsa_public_encrypt(key, key, public_key); 1324 debug("Encryption type: %.100s", cipher_name(options.cipher));
1351 } 1325
1352 1326 /* Send the encrypted session key to the server. */
1353 if (options.cipher == SSH_CIPHER_NOT_SET) { 1327 packet_start(SSH_CMSG_SESSION_KEY);
1354 if (cipher_mask() & supported_ciphers & (1 << ssh_cipher_default)) 1328 packet_put_char(options.cipher);
1355 options.cipher = ssh_cipher_default; 1329
1356 else { 1330 /* Send the check bytes back to the server. */
1357 debug("Cipher %s not supported, using %.100s instead.", 1331 for (i = 0; i < 8; i++)
1358 cipher_name(ssh_cipher_default), 1332 packet_put_char(check_bytes[i]);
1359 cipher_name(SSH_FALLBACK_CIPHER)); 1333
1360 options.cipher = SSH_FALLBACK_CIPHER; 1334 /* Send the encrypted encryption key. */
1361 } 1335 packet_put_bignum(key);
1362 } 1336
1363 1337 /* Send protocol flags. */
1364 /* Check that the selected cipher is supported. */ 1338 packet_put_int(SSH_PROTOFLAG_SCREEN_NUMBER | SSH_PROTOFLAG_HOST_IN_FWD_OPEN);
1365 if (!(supported_ciphers & (1 << options.cipher))) 1339
1366 fatal("Selected cipher type %.100s not supported by server.", 1340 /* Send the packet now. */
1367 cipher_name(options.cipher));
1368
1369 debug("Encryption type: %.100s", cipher_name(options.cipher));
1370
1371 /* Send the encrypted session key to the server. */
1372 packet_start(SSH_CMSG_SESSION_KEY);
1373 packet_put_char(options.cipher);
1374
1375 /* Send the check bytes back to the server. */
1376 for (i = 0; i < 8; i++)
1377 packet_put_char(check_bytes[i]);
1378
1379 /* Send the encrypted encryption key. */
1380 packet_put_bignum(key);
1381
1382 /* Send protocol flags. */
1383 packet_put_int(SSH_PROTOFLAG_SCREEN_NUMBER | SSH_PROTOFLAG_HOST_IN_FWD_OPEN);
1384
1385 /* Send the packet now. */
1386 packet_send();
1387 packet_write_wait();
1388
1389 /* Destroy the session key integer and the public keys since we no longer
1390 need them. */
1391 BN_clear_free(key);
1392 RSA_free(public_key);
1393 RSA_free(host_key);
1394
1395 debug("Sent encrypted session key.");
1396
1397 /* Set the encryption key. */
1398 packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH, options.cipher);
1399
1400 /* We will no longer need the session key here. Destroy any extra copies. */
1401 memset(session_key, 0, sizeof(session_key));
1402
1403 /* Expect a success message from the server. Note that this message will
1404 be received in encrypted form. */
1405 packet_read_expect(&payload_len, SSH_SMSG_SUCCESS);
1406
1407 debug("Received encrypted confirmation.");
1408
1409 /* Send the name of the user to log in as on the server. */
1410 packet_start(SSH_CMSG_USER);
1411 packet_put_string(server_user, strlen(server_user));
1412 packet_send();
1413 packet_write_wait();
1414
1415 /* The server should respond with success if no authentication is needed
1416 (the user has no password). Otherwise the server responds with
1417 failure. */
1418 type = packet_read(&payload_len);
1419 if (type == SSH_SMSG_SUCCESS)
1420 return; /* Connection was accepted without authentication. */
1421 if (type != SSH_SMSG_FAILURE)
1422 packet_disconnect("Protocol error: got %d in response to SSH_CMSG_USER",
1423 type);
1424
1425#ifdef AFS
1426 /* Try Kerberos tgt passing if the server supports it. */
1427 if ((supported_authentications & (1 << SSH_PASS_KERBEROS_TGT)) &&
1428 options.kerberos_tgt_passing)
1429 {
1430 if (options.cipher == SSH_CIPHER_NONE)
1431 log("WARNING: Encryption is disabled! Ticket will be transmitted in the clear!");
1432 (void)send_kerberos_tgt();
1433 }
1434
1435 /* Try AFS token passing if the server supports it. */
1436 if ((supported_authentications & (1 << SSH_PASS_AFS_TOKEN)) &&
1437 options.afs_token_passing && k_hasafs()) {
1438 if (options.cipher == SSH_CIPHER_NONE)
1439 log("WARNING: Encryption is disabled! Token will be transmitted in the clear!");
1440 send_afs_tokens();
1441 }
1442#endif /* AFS */
1443
1444#ifdef KRB4
1445 if ((supported_authentications & (1 << SSH_AUTH_KERBEROS)) &&
1446 options.kerberos_authentication)
1447 {
1448 debug("Trying Kerberos authentication.");
1449 if (try_kerberos_authentication()) {
1450 /* The server should respond with success or failure. */
1451 type = packet_read(&payload_len);
1452 if (type == SSH_SMSG_SUCCESS)
1453 return; /* Successful connection. */
1454 if (type != SSH_SMSG_FAILURE)
1455 packet_disconnect("Protocol error: got %d in response to Kerberos auth", type);
1456 }
1457 }
1458#endif /* KRB4 */
1459
1460 /* Use rhosts authentication if running in privileged socket and we do not
1461 wish to remain anonymous. */
1462 if ((supported_authentications & (1 << SSH_AUTH_RHOSTS)) &&
1463 options.rhosts_authentication)
1464 {
1465 debug("Trying rhosts authentication.");
1466 packet_start(SSH_CMSG_AUTH_RHOSTS);
1467 packet_put_string(local_user, strlen(local_user));
1468 packet_send();
1469 packet_write_wait();
1470
1471 /* The server should respond with success or failure. */
1472 type = packet_read(&payload_len);
1473 if (type == SSH_SMSG_SUCCESS)
1474 return; /* Successful connection. */
1475 if (type != SSH_SMSG_FAILURE)
1476 packet_disconnect("Protocol error: got %d in response to rhosts auth",
1477 type);
1478 }
1479
1480 /* Try .rhosts or /etc/hosts.equiv authentication with RSA host
1481 authentication. */
1482 if ((supported_authentications & (1 << SSH_AUTH_RHOSTS_RSA)) &&
1483 options.rhosts_rsa_authentication && host_key_valid)
1484 {
1485 if (try_rhosts_rsa_authentication(local_user, own_host_key))
1486 return; /* Successful authentication. */
1487 }
1488
1489 /* Try RSA authentication if the server supports it. */
1490 if ((supported_authentications & (1 << SSH_AUTH_RSA)) &&
1491 options.rsa_authentication)
1492 {
1493 /* Try RSA authentication using the authentication agent. The agent
1494 is tried first because no passphrase is needed for it, whereas
1495 identity files may require passphrases. */
1496 if (try_agent_authentication())
1497 return; /* Successful connection. */
1498
1499 /* Try RSA authentication for each identity. */
1500 for (i = 0; i < options.num_identity_files; i++)
1501 if (try_rsa_authentication(pw, options.identity_files[i]))
1502 return; /* Successful connection. */
1503 }
1504
1505 /* Try password authentication if the server supports it. */
1506 if ((supported_authentications & (1 << SSH_AUTH_PASSWORD)) &&
1507 options.password_authentication && !options.batch_mode)
1508 {
1509 char prompt[80];
1510 snprintf(prompt, sizeof(prompt), "%.30s@%.30s's password: ",
1511 server_user, host);
1512 debug("Doing password authentication.");
1513 if (options.cipher == SSH_CIPHER_NONE)
1514 log("WARNING: Encryption is disabled! Password will be transmitted in clear text.");
1515 for (i = 0; i < options.number_of_password_prompts; i++) {
1516 if (i != 0)
1517 error("Permission denied, please try again.");
1518 password = read_passphrase(prompt, 0);
1519 packet_start(SSH_CMSG_AUTH_PASSWORD);
1520 packet_put_string(password, strlen(password));
1521 memset(password, 0, strlen(password));
1522 xfree(password);
1523 packet_send(); 1341 packet_send();
1524 packet_write_wait(); 1342 packet_write_wait();
1525 1343
1344 /* Destroy the session key integer and the public keys since we no longer need them. */
1345 BN_clear_free(key);
1346 RSA_free(public_key);
1347 RSA_free(host_key);
1348
1349 debug("Sent encrypted session key.");
1350
1351 /* Set the encryption key. */
1352 packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH, options.cipher);
1353
1354 /* We will no longer need the session key here. Destroy any extra copies. */
1355 memset(session_key, 0, sizeof(session_key));
1356
1357 /* Expect a success message from the server. Note that this
1358 message will be received in encrypted form. */
1359 packet_read_expect(&payload_len, SSH_SMSG_SUCCESS);
1360
1361 debug("Received encrypted confirmation.");
1362
1363 /* Send the name of the user to log in as on the server. */
1364 packet_start(SSH_CMSG_USER);
1365 packet_put_string(server_user, strlen(server_user));
1366 packet_send();
1367 packet_write_wait();
1368
1369 /* The server should respond with success if no authentication is
1370 needed (the user has no password). Otherwise the server
1371 responds with failure. */
1526 type = packet_read(&payload_len); 1372 type = packet_read(&payload_len);
1373
1374 /* check whether the connection was accepted without authentication. */
1527 if (type == SSH_SMSG_SUCCESS) 1375 if (type == SSH_SMSG_SUCCESS)
1528 return; /* Successful connection. */ 1376 return;
1529 if (type != SSH_SMSG_FAILURE) 1377 if (type != SSH_SMSG_FAILURE)
1530 packet_disconnect("Protocol error: got %d in response to passwd auth", type); 1378 packet_disconnect("Protocol error: got %d in response to SSH_CMSG_USER",
1531 } 1379 type);
1532 } 1380
1381#ifdef AFS
1382 /* Try Kerberos tgt passing if the server supports it. */
1383 if ((supported_authentications & (1 << SSH_PASS_KERBEROS_TGT)) &&
1384 options.kerberos_tgt_passing) {
1385 if (options.cipher == SSH_CIPHER_NONE)
1386 log("WARNING: Encryption is disabled! Ticket will be transmitted in the clear!");
1387 (void) send_kerberos_tgt();
1388 }
1389 /* Try AFS token passing if the server supports it. */
1390 if ((supported_authentications & (1 << SSH_PASS_AFS_TOKEN)) &&
1391 options.afs_token_passing && k_hasafs()) {
1392 if (options.cipher == SSH_CIPHER_NONE)
1393 log("WARNING: Encryption is disabled! Token will be transmitted in the clear!");
1394 send_afs_tokens();
1395 }
1396#endif /* AFS */
1533 1397
1534 /* All authentication methods have failed. Exit with an error message. */ 1398#ifdef KRB4
1535 fatal("Permission denied."); 1399 if ((supported_authentications & (1 << SSH_AUTH_KERBEROS)) &&
1536 /*NOTREACHED*/ 1400 options.kerberos_authentication) {
1401 debug("Trying Kerberos authentication.");
1402 if (try_kerberos_authentication()) {
1403 /* The server should respond with success or failure. */
1404 type = packet_read(&payload_len);
1405 if (type == SSH_SMSG_SUCCESS)
1406 return;
1407 if (type != SSH_SMSG_FAILURE)
1408 packet_disconnect("Protocol error: got %d in response to Kerberos auth", type);
1409 }
1410 }
1411#endif /* KRB4 */
1412
1413 /* Use rhosts authentication if running in privileged socket and
1414 we do not wish to remain anonymous. */
1415 if ((supported_authentications & (1 << SSH_AUTH_RHOSTS)) &&
1416 options.rhosts_authentication) {
1417 debug("Trying rhosts authentication.");
1418 packet_start(SSH_CMSG_AUTH_RHOSTS);
1419 packet_put_string(local_user, strlen(local_user));
1420 packet_send();
1421 packet_write_wait();
1422
1423 /* The server should respond with success or failure. */
1424 type = packet_read(&payload_len);
1425 if (type == SSH_SMSG_SUCCESS)
1426 return;
1427 if (type != SSH_SMSG_FAILURE)
1428 packet_disconnect("Protocol error: got %d in response to rhosts auth",
1429 type);
1430 }
1431 /* Try .rhosts or /etc/hosts.equiv authentication with RSA host
1432 authentication. */
1433 if ((supported_authentications & (1 << SSH_AUTH_RHOSTS_RSA)) &&
1434 options.rhosts_rsa_authentication && host_key_valid) {
1435 if (try_rhosts_rsa_authentication(local_user, own_host_key))
1436 return;
1437 }
1438 /* Try RSA authentication if the server supports it. */
1439 if ((supported_authentications & (1 << SSH_AUTH_RSA)) &&
1440 options.rsa_authentication) {
1441 /* Try RSA authentication using the authentication agent.
1442 The agent is tried first because no passphrase is
1443 needed for it, whereas identity files may require
1444 passphrases. */
1445 if (try_agent_authentication())
1446 return;
1447
1448 /* Try RSA authentication for each identity. */
1449 for (i = 0; i < options.num_identity_files; i++)
1450 if (try_rsa_authentication(pw, options.identity_files[i]))
1451 return;
1452 }
1453 /* Try skey authentication if the server supports it. */
1454 if ((supported_authentications & (1 << SSH_AUTH_TIS)) &&
1455 options.skey_authentication && !options.batch_mode) {
1456 debug("Doing skey authentication.");
1457
1458 /* request a challenge */
1459 packet_start(SSH_CMSG_AUTH_TIS);
1460 packet_send();
1461 packet_write_wait();
1462
1463 type = packet_read(&payload_len);
1464 if (type != SSH_SMSG_FAILURE &&
1465 type != SSH_SMSG_AUTH_TIS_CHALLENGE) {
1466 packet_disconnect("Protocol error: got %d in response "
1467 "to skey auth", type);
1468 }
1469 if (type != SSH_SMSG_AUTH_TIS_CHALLENGE) {
1470 debug("No challenge for skey authentication.");
1471 } else {
1472 char *challenge, *response;
1473 challenge = packet_get_string(&payload_len);
1474 if (options.cipher == SSH_CIPHER_NONE)
1475 log("WARNING: Encryption is disabled! "
1476 "Reponse will be transmitted in clear text.");
1477 fprintf(stderr, "%s\n", challenge);
1478 fflush(stderr);
1479 for (i = 0; i < options.number_of_password_prompts; i++) {
1480 if (i != 0)
1481 error("Permission denied, please try again.");
1482 response = read_passphrase("Response: ", 0);
1483 packet_start(SSH_CMSG_AUTH_TIS_RESPONSE);
1484 packet_put_string(response, strlen(response));
1485 memset(response, 0, strlen(response));
1486 xfree(response);
1487 packet_send();
1488 packet_write_wait();
1489 type = packet_read(&payload_len);
1490 if (type == SSH_SMSG_SUCCESS)
1491 return;
1492 if (type != SSH_SMSG_FAILURE)
1493 packet_disconnect("Protocol error: got %d in response "
1494 "to skey auth", type);
1495 }
1496 }
1497 }
1498 /* Try password authentication if the server supports it. */
1499 if ((supported_authentications & (1 << SSH_AUTH_PASSWORD)) &&
1500 options.password_authentication && !options.batch_mode) {
1501 char prompt[80];
1502 snprintf(prompt, sizeof(prompt), "%.30s@%.30s's password: ",
1503 server_user, host);
1504 debug("Doing password authentication.");
1505 if (options.cipher == SSH_CIPHER_NONE)
1506 log("WARNING: Encryption is disabled! Password will be transmitted in clear text.");
1507 for (i = 0; i < options.number_of_password_prompts; i++) {
1508 if (i != 0)
1509 error("Permission denied, please try again.");
1510 password = read_passphrase(prompt, 0);
1511 packet_start(SSH_CMSG_AUTH_PASSWORD);
1512 packet_put_string(password, strlen(password));
1513 memset(password, 0, strlen(password));
1514 xfree(password);
1515 packet_send();
1516 packet_write_wait();
1517
1518 type = packet_read(&payload_len);
1519 if (type == SSH_SMSG_SUCCESS)
1520 return;
1521 if (type != SSH_SMSG_FAILURE)
1522 packet_disconnect("Protocol error: got %d in response to passwd auth", type);
1523 }
1524 }
1525 /* All authentication methods have failed. Exit with an error message. */
1526 fatal("Permission denied.");
1527 /* NOTREACHED */
1537} 1528}
diff --git a/sshd.8 b/sshd.8
index ac728f847..b02057bbb 100644
--- a/sshd.8
+++ b/sshd.8
@@ -9,7 +9,7 @@
9.\" 9.\"
10.\" Created: Sat Apr 22 21:55:14 1995 ylo 10.\" Created: Sat Apr 22 21:55:14 1995 ylo
11.\" 11.\"
12.\" $Id: sshd.8,v 1.8 1999/11/21 02:23:53 damien Exp $ 12.\" $Id: sshd.8,v 1.9 1999/11/24 13:26:23 damien Exp $
13.\" 13.\"
14.Dd September 25, 1999 14.Dd September 25, 1999
15.Dt SSHD 8 15.Dt SSHD 8
@@ -26,6 +26,7 @@
26.Op Fl h Ar host_key_file 26.Op Fl h Ar host_key_file
27.Op Fl k Ar key_gen_time 27.Op Fl k Ar key_gen_time
28.Op Fl p Ar port 28.Op Fl p Ar port
29.Op Fl V Ar client_protocol_id
29.Sh DESCRIPTION 30.Sh DESCRIPTION
30.Nm 31.Nm
31(Secure Shell Daemon) is the daemon program for 32(Secure Shell Daemon) is the daemon program for
@@ -165,6 +166,13 @@ Quiet mode. Nothing is sent to the system log. Normally the beginning,
165authentication, and termination of each connection is logged. 166authentication, and termination of each connection is logged.
166.It Fl Q 167.It Fl Q
167Do not print an error message if RSA support is missing. 168Do not print an error message if RSA support is missing.
169.It Fl V Ar client_protocol_id
170SSH2 compatibility mode.
171When this options is specified
172.Nm
173assumes the client has sent the given version string
174and skips the
175Protocol Version Identification Exchange.
168.El 176.El
169.Sh CONFIGURATION FILE 177.Sh CONFIGURATION FILE
170.Nm 178.Nm
@@ -320,7 +328,7 @@ The default is 600 (seconds).
320Gives the verbosity level that is used when logging messages from 328Gives the verbosity level that is used when logging messages from
321.Nm sshd . 329.Nm sshd .
322The possible values are: 330The possible values are:
323QUIET, FATAL, ERROR, INFO, CHAT and DEBUG. 331QUIET, FATAL, ERROR, INFO, VERBOSE and DEBUG.
324The default is INFO. 332The default is INFO.
325Logging with level DEBUG violates the privacy of users 333Logging with level DEBUG violates the privacy of users
326and is not recommended. 334and is not recommended.
diff --git a/sshd.c b/sshd.c
index 5718eae94..dba2d474d 100644
--- a/sshd.c
+++ b/sshd.c
@@ -1,24 +1,17 @@
1/* 1/*
2 2 * Author: Tatu Ylonen <ylo@cs.hut.fi>
3sshd.c 3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 4 * All rights reserved
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Created: Fri Mar 17 17:09:28 1995 ylo
6 6 * This program is the ssh daemon. It listens for connections from clients, and
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * performs authentication, executes use commands or shell, and forwards
8 All rights reserved 8 * information to/from the application to the user client over an encrypted
9 9 * connection. This can also handle forwarding of X11, TCP/IP, and authentication
10Created: Fri Mar 17 17:09:28 1995 ylo 10 * agent connections.
11 11 */
12This program is the ssh daemon. It listens for connections from clients, and
13performs authentication, executes use commands or shell, and forwards
14information to/from the application to the user client over an encrypted
15connection. This can also handle forwarding of X11, TCP/IP, and authentication
16agent connections.
17
18*/
19 12
20#include "includes.h" 13#include "includes.h"
21RCSID("$Id: sshd.c,v 1.29 1999/11/23 00:24:32 damien Exp $"); 14RCSID("$Id: sshd.c,v 1.30 1999/11/24 13:26:23 damien Exp $");
22 15
23#include "xmalloc.h" 16#include "xmalloc.h"
24#include "rsa.h" 17#include "rsa.h"
@@ -52,10 +45,12 @@ ServerOptions options;
52/* Name of the server configuration file. */ 45/* Name of the server configuration file. */
53char *config_file_name = SERVER_CONFIG_FILE; 46char *config_file_name = SERVER_CONFIG_FILE;
54 47
55/* Debug mode flag. This can be set on the command line. If debug 48/*
56 mode is enabled, extra debugging output will be sent to the system 49 * Debug mode flag. This can be set on the command line. If debug
57 log, the daemon will not go to background, and will exit after processing 50 * mode is enabled, extra debugging output will be sent to the system
58 the first connection. */ 51 * log, the daemon will not go to background, and will exit after processing
52 * the first connection.
53 */
59int debug_flag = 0; 54int debug_flag = 0;
60 55
61/* Flag indicating that the daemon is being started from inetd. */ 56/* Flag indicating that the daemon is being started from inetd. */
@@ -74,15 +69,21 @@ char **saved_argv;
74 the SIGHUP signal handler. */ 69 the SIGHUP signal handler. */
75int listen_sock; 70int listen_sock;
76 71
77/* Flags set in auth-rsa from authorized_keys flags. These are set in 72/* the client's version string, passed by sshd2 in compat mode.
78 auth-rsa.c. */ 73 if != NULL, sshd will skip the version-number exchange */
74char *client_version_string = NULL;
75
76/* Flags set in auth-rsa from authorized_keys flags. These are set in auth-rsa.c. */
79int no_port_forwarding_flag = 0; 77int no_port_forwarding_flag = 0;
80int no_agent_forwarding_flag = 0; 78int no_agent_forwarding_flag = 0;
81int no_x11_forwarding_flag = 0; 79int no_x11_forwarding_flag = 0;
82int no_pty_flag = 0; 80int no_pty_flag = 0;
83char *forced_command = NULL; /* RSA authentication "command=" option. */ 81
84struct envstring *custom_environment = NULL; 82/* RSA authentication "command=" option. */
85 /* RSA authentication "environment=" options. */ 83char *forced_command = NULL;
84
85/* RSA authentication "environment=" options. */
86struct envstring *custom_environment = NULL;
86 87
87/* Session id for the current session. */ 88/* Session id for the current session. */
88unsigned char session_id[16]; 89unsigned char session_id[16];
@@ -93,13 +94,9 @@ unsigned char session_id[16];
93 The private key contains BIGNUMs, and we do not (in principle) have 94 The private key contains BIGNUMs, and we do not (in principle) have
94 access to the internals of them, and locking just the structure is not 95 access to the internals of them, and locking just the structure is not
95 very useful. Currently, memory locking is not implemented. */ 96 very useful. Currently, memory locking is not implemented. */
96struct 97struct {
97{ 98 RSA *private_key; /* Private part of server key. */
98 /* Private part of server key. */ 99 RSA *host_key; /* Private part of host key. */
99 RSA *private_key;
100
101 /* Private part of host key. */
102 RSA *host_key;
103} sensitive_data; 100} sensitive_data;
104 101
105/* Flag indicating whether the current session key has been used. This flag 102/* Flag indicating whether the current session key has been used. This flag
@@ -116,2454 +113,2458 @@ RSA *public_key;
116/* Prototypes for various functions defined later in this file. */ 113/* Prototypes for various functions defined later in this file. */
117void do_connection(); 114void do_connection();
118void do_authentication(char *user); 115void do_authentication(char *user);
119void do_authloop(struct passwd *pw); 116void do_authloop(struct passwd * pw);
120void do_fake_authloop(char *user); 117void do_fake_authloop(char *user);
121void do_authenticated(struct passwd *pw); 118void do_authenticated(struct passwd * pw);
122void do_exec_pty(const char *command, int ptyfd, int ttyfd, 119void do_exec_pty(const char *command, int ptyfd, int ttyfd,
123 const char *ttyname, struct passwd *pw, const char *term, 120 const char *ttyname, struct passwd * pw, const char *term,
124 const char *display, const char *auth_proto, 121 const char *display, const char *auth_proto,
125 const char *auth_data); 122 const char *auth_data);
126void do_exec_no_pty(const char *command, struct passwd *pw, 123void do_exec_no_pty(const char *command, struct passwd * pw,
127 const char *display, const char *auth_proto, 124 const char *display, const char *auth_proto,
128 const char *auth_data); 125 const char *auth_data);
129void do_child(const char *command, struct passwd *pw, const char *term, 126void do_child(const char *command, struct passwd * pw, const char *term,
130 const char *display, const char *auth_proto, 127 const char *display, const char *auth_proto,
131 const char *auth_data, const char *ttyname); 128 const char *auth_data, const char *ttyname);
132 129
133#ifdef HAVE_LIBPAM 130#ifdef HAVE_LIBPAM
134static int pamconv(int num_msg, const struct pam_message **msg, 131static int pamconv(int num_msg, const struct pam_message **msg,
135 struct pam_response **resp, void *appdata_ptr); 132 struct pam_response **resp, void *appdata_ptr);
136void do_pam_account_and_session(char *username, char *remote_user, 133void do_pam_account_and_session(char *username, char *remote_user,
137 const char *remote_host); 134 const char *remote_host);
138void pam_cleanup_proc(void *context); 135void pam_cleanup_proc(void *context);
139 136
140static struct pam_conv conv = { 137static struct pam_conv conv = {
141 pamconv, 138 pamconv,
142 NULL 139 NULL
143}; 140};
144struct pam_handle_t *pamh = NULL; 141struct pam_handle_t *pamh = NULL;
145const char *pampasswd = NULL; 142const char *pampasswd = NULL;
146char *pamconv_msg = NULL; 143char *pamconv_msg = NULL;
147 144
148static int pamconv(int num_msg, const struct pam_message **msg, 145static int pamconv(int num_msg, const struct pam_message **msg,
149 struct pam_response **resp, void *appdata_ptr) 146 struct pam_response **resp, void *appdata_ptr)
150{ 147{
151 struct pam_response *reply; 148 struct pam_response *reply;
152 int count; 149 int count;
153 size_t msg_len; 150 size_t msg_len;
154 char *p; 151 char *p;
155 152
156 /* PAM will free this later */ 153 /* PAM will free this later */
157 reply = malloc(num_msg * sizeof(*reply)); 154 reply = malloc(num_msg * sizeof(*reply));
158 if (reply == NULL) 155 if (reply == NULL)
159 return PAM_CONV_ERR; 156 return PAM_CONV_ERR;
160 157
161 for(count = 0; count < num_msg; count++) 158 for(count = 0; count < num_msg; count++) {
162 { 159 switch (msg[count]->msg_style) {
163 switch (msg[count]->msg_style) 160 case PAM_PROMPT_ECHO_OFF:
164 { 161 if (pampasswd == NULL) {
165 case PAM_PROMPT_ECHO_OFF: 162 free(reply);
166 if (pampasswd == NULL) 163 return PAM_CONV_ERR;
167 { 164 }
168 free(reply); 165 reply[count].resp_retcode = PAM_SUCCESS;
169 return PAM_CONV_ERR; 166 reply[count].resp = xstrdup(pampasswd);
170 } 167 break;
171 reply[count].resp_retcode = PAM_SUCCESS; 168
172 reply[count].resp = xstrdup(pampasswd); 169 case PAM_TEXT_INFO:
173 break; 170 reply[count].resp_retcode = PAM_SUCCESS;
174 171 reply[count].resp = xstrdup("");
175 case PAM_TEXT_INFO: 172
176 reply[count].resp_retcode = PAM_SUCCESS; 173 if (msg[count]->msg == NULL)
177 reply[count].resp = xstrdup(""); 174 break;
178 175
179 if (msg[count]->msg == NULL) 176 debug("Adding PAM message: %s", msg[count]->msg);
180 break; 177
181 debug("Adding PAM message: %s", msg[count]->msg); 178 msg_len = strlen(msg[count]->msg);
182 179 if (pamconv_msg) {
183 msg_len = strlen(msg[count]->msg); 180 size_t n = strlen(pamconv_msg);
184 if (pamconv_msg) 181 pamconv_msg = xrealloc(pamconv_msg, n + msg_len + 2);
185 { 182 p = pamconv_msg + n;
186 size_t n = strlen(pamconv_msg); 183 } else {
187 pamconv_msg = xrealloc(pamconv_msg, n + msg_len + 2); 184 pamconv_msg = p = xmalloc(msg_len + 2);
188 p = pamconv_msg + n; 185 }
186 memcpy(p, msg[count]->msg, msg_len);
187 p[msg_len] = '\n';
188 p[msg_len + 1] = '\0';
189 break;
190
191 case PAM_PROMPT_ECHO_ON:
192 case PAM_ERROR_MSG:
193 default:
194 free(reply);
195 return PAM_CONV_ERR;
196 }
189 } 197 }
190 else 198
191 pamconv_msg = p = xmalloc(msg_len + 2); 199 *resp = reply;
192 memcpy(p, msg[count]->msg, msg_len); 200
193 p[msg_len] = '\n'; 201 return PAM_SUCCESS;
194 p[msg_len + 1] = '\0';
195 break;
196
197 case PAM_PROMPT_ECHO_ON:
198 case PAM_ERROR_MSG:
199 default:
200 free(reply);
201 return PAM_CONV_ERR;
202 }
203 }
204
205 *resp = reply;
206
207 return PAM_SUCCESS;
208} 202}
209 203
210void pam_cleanup_proc(void *context) 204void pam_cleanup_proc(void *context)
211{ 205{
212 int pam_retval; 206 int pam_retval;
213 207
214 if (pamh != NULL) 208 if (pamh != NULL)
215 { 209 {
216 pam_retval = pam_close_session((pam_handle_t *)pamh, 0); 210 pam_retval = pam_close_session((pam_handle_t *)pamh, 0);
217 if (pam_retval != PAM_SUCCESS) 211 if (pam_retval != PAM_SUCCESS) {
218 { 212 log("Cannot close PAM session: %.200s",
219 log("Cannot close PAM session: %.200s", 213 PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
220 PAM_STRERROR((pam_handle_t *)pamh, pam_retval)); 214 }
221 } 215
222 216 pam_retval = pam_end((pam_handle_t *)pamh, pam_retval);
223 pam_retval = pam_end((pam_handle_t *)pamh, pam_retval); 217 if (pam_retval != PAM_SUCCESS) {
224 if (pam_retval != PAM_SUCCESS) 218 log("Cannot release PAM authentication: %.200s",
225 { 219 PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
226 log("Cannot release PAM authentication: %.200s", 220 }
227 PAM_STRERROR((pam_handle_t *)pamh, pam_retval)); 221 }
228 }
229 }
230} 222}
231 223
232void do_pam_account_and_session(char *username, char *remote_user, 224void do_pam_account_and_session(char *username, char *remote_user,
233 const char *remote_host) 225 const char *remote_host)
234{ 226{
235 int pam_retval; 227 int pam_retval;
236 228
237 if (remote_host != NULL) 229 if (remote_host != NULL) {
238 { 230 debug("PAM setting rhost to \"%.200s\"", remote_host);
239 debug("PAM setting rhost to \"%.200s\"", remote_host); 231 pam_retval = pam_set_item((pam_handle_t *)pamh, PAM_RHOST, remote_host);
240 pam_retval = pam_set_item((pam_handle_t *)pamh, PAM_RHOST, remote_host); 232 if (pam_retval != PAM_SUCCESS) {
241 if (pam_retval != PAM_SUCCESS) 233 log("PAM set rhost failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
242 { 234 do_fake_authloop(username);
243 log("PAM set rhost failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval)); 235 }
244 do_fake_authloop(username); 236 }
245 } 237
246 } 238 if (remote_user != NULL) {
247 239 debug("PAM setting ruser to \"%.200s\"", remote_user);
248 if (remote_user != NULL) 240 pam_retval = pam_set_item((pam_handle_t *)pamh, PAM_RUSER, remote_user);
249 { 241 if (pam_retval != PAM_SUCCESS) {
250 debug("PAM setting ruser to \"%.200s\"", remote_user); 242 log("PAM set ruser failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
251 pam_retval = pam_set_item((pam_handle_t *)pamh, PAM_RUSER, remote_user); 243 do_fake_authloop(username);
252 if (pam_retval != PAM_SUCCESS) 244 }
253 { 245 }
254 log("PAM set ruser failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval)); 246
255 do_fake_authloop(username); 247 pam_retval = pam_acct_mgmt((pam_handle_t *)pamh, 0);
256 } 248 if (pam_retval != PAM_SUCCESS) {
257 } 249 log("PAM rejected by account configuration: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
258 250 do_fake_authloop(username);
259 pam_retval = pam_acct_mgmt((pam_handle_t *)pamh, 0); 251 }
260 if (pam_retval != PAM_SUCCESS) 252
261 { 253 pam_retval = pam_open_session((pam_handle_t *)pamh, 0);
262 log("PAM rejected by account configuration: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval)); 254 if (pam_retval != PAM_SUCCESS) {
263 do_fake_authloop(username); 255 log("PAM session setup failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
264 } 256 do_fake_authloop(username);
265 257 }
266 pam_retval = pam_open_session((pam_handle_t *)pamh, 0);
267 if (pam_retval != PAM_SUCCESS)
268 {
269 log("PAM session setup failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
270 do_fake_authloop(username);
271 }
272} 258}
273#endif /* HAVE_LIBPAM */ 259#endif /* HAVE_LIBPAM */
274 260
275/* Signal handler for SIGHUP. Sshd execs itself when it receives SIGHUP; 261/*
276 the effect is to reread the configuration file (and to regenerate 262 * Signal handler for SIGHUP. Sshd execs itself when it receives SIGHUP;
277 the server key). */ 263 * the effect is to reread the configuration file (and to regenerate
278 264 * the server key).
279void sighup_handler(int sig) 265 */
266void
267sighup_handler(int sig)
280{ 268{
281 received_sighup = 1; 269 received_sighup = 1;
282 signal(SIGHUP, sighup_handler); 270 signal(SIGHUP, sighup_handler);
283} 271}
284 272
285/* Called from the main program after receiving SIGHUP. Restarts the 273/*
286 server. */ 274 * Called from the main program after receiving SIGHUP.
287 275 * Restarts the server.
288void sighup_restart() 276 */
277void
278sighup_restart()
289{ 279{
290 log("Received SIGHUP; restarting."); 280 log("Received SIGHUP; restarting.");
291 close(listen_sock); 281 close(listen_sock);
292 execv(saved_argv[0], saved_argv); 282 execv(saved_argv[0], saved_argv);
293 log("RESTART FAILED: av0='%s', error: %s.", av0, strerror(errno)); 283 log("RESTART FAILED: av0='%s', error: %s.", av0, strerror(errno));
294 exit(1); 284 exit(1);
295} 285}
296 286
297/* Generic signal handler for terminating signals in the master daemon. 287/*
298 These close the listen socket; not closing it seems to cause "Address 288 * Generic signal handler for terminating signals in the master daemon.
299 already in use" problems on some machines, which is inconvenient. */ 289 * These close the listen socket; not closing it seems to cause "Address
300 290 * already in use" problems on some machines, which is inconvenient.
301void sigterm_handler(int sig) 291 */
292void
293sigterm_handler(int sig)
302{ 294{
303 log("Received signal %d; terminating.", sig); 295 log("Received signal %d; terminating.", sig);
304 close(listen_sock); 296 close(listen_sock);
305 exit(255); 297 exit(255);
306} 298}
307 299
308/* SIGCHLD handler. This is called whenever a child dies. This will then 300/*
309 reap any zombies left by exited c. */ 301 * SIGCHLD handler. This is called whenever a child dies. This will then
310 302 * reap any zombies left by exited c.
311void main_sigchld_handler(int sig) 303 */
304void
305main_sigchld_handler(int sig)
312{ 306{
313 int save_errno = errno; 307 int save_errno = errno;
314 int status; 308 int status;
315 309
316 while (waitpid(-1, &status, WNOHANG) > 0) 310 while (waitpid(-1, &status, WNOHANG) > 0)
317 ; 311 ;
318 312
319 signal(SIGCHLD, main_sigchld_handler); 313 signal(SIGCHLD, main_sigchld_handler);
320 errno = save_errno; 314 errno = save_errno;
321} 315}
322 316
323/* Signal handler for the alarm after the login grace period has expired. */ 317/*
324 318 * Signal handler for the alarm after the login grace period has expired.
325void grace_alarm_handler(int sig) 319 */
320void
321grace_alarm_handler(int sig)
326{ 322{
327 /* Close the connection. */ 323 /* Close the connection. */
328 packet_close(); 324 packet_close();
329
330 /* Log error and exit. */
331 fatal("Timeout before authentication.");
332}
333 325
334/* Signal handler for the key regeneration alarm. Note that this 326 /* Log error and exit. */
335 alarm only occurs in the daemon waiting for connections, and it does not 327 fatal("Timeout before authentication for %s.", get_remote_ipaddr());
336 do anything with the private key or random state before forking. Thus there 328}
337 should be no concurrency control/asynchronous execution problems. */
338 329
339void key_regeneration_alarm(int sig) 330/*
331 * convert ssh auth msg type into description
332 */
333char *
334get_authname(int type)
340{ 335{
341 int save_errno = errno; 336 switch (type) {
342 337 case SSH_CMSG_AUTH_PASSWORD:
343 /* Check if we should generate a new key. */ 338 return "password";
344 if (key_used) 339 case SSH_CMSG_AUTH_RSA:
345 { 340 return "rsa";
346 /* This should really be done in the background. */ 341 case SSH_CMSG_AUTH_RHOSTS_RSA:
347 log("Generating new %d bit RSA key.", options.server_key_bits); 342 return "rhosts-rsa";
348 343 case SSH_CMSG_AUTH_RHOSTS:
349 if (sensitive_data.private_key != NULL) 344 return "rhosts";
350 RSA_free(sensitive_data.private_key); 345#ifdef KRB4
351 sensitive_data.private_key = RSA_new(); 346 case SSH_CMSG_AUTH_KERBEROS:
352 347 return "kerberos";
353 if (public_key != NULL) 348#endif
354 RSA_free(public_key); 349#ifdef SKEY
355 public_key = RSA_new(); 350 case SSH_CMSG_AUTH_TIS_RESPONSE:
356 351 return "s/key";
357 rsa_generate_key(sensitive_data.private_key, public_key, 352#endif
358 options.server_key_bits); 353 }
359 arc4random_stir(); 354 fatal("get_authname: unknown auth %d: internal error", type);
360 key_used = 0; 355 return NULL;
361 log("RSA key generation complete.");
362 }
363
364 /* Reschedule the alarm. */
365 signal(SIGALRM, key_regeneration_alarm);
366 alarm(options.key_regeneration_time);
367 errno = save_errno;
368} 356}
369 357
370/* Main program for the daemon. */ 358/*
359 * Signal handler for the key regeneration alarm. Note that this
360 * alarm only occurs in the daemon waiting for connections, and it does not
361 * do anything with the private key or random state before forking.
362 * Thus there should be no concurrency control/asynchronous execution
363 * problems.
364 */
365void
366key_regeneration_alarm(int sig)
367{
368 int save_errno = errno;
369
370 /* Check if we should generate a new key. */
371 if (key_used) {
372 /* This should really be done in the background. */
373 log("Generating new %d bit RSA key.", options.server_key_bits);
374
375 if (sensitive_data.private_key != NULL)
376 RSA_free(sensitive_data.private_key);
377 sensitive_data.private_key = RSA_new();
378
379 if (public_key != NULL)
380 RSA_free(public_key);
381 public_key = RSA_new();
382
383 rsa_generate_key(sensitive_data.private_key, public_key,
384 options.server_key_bits);
385 arc4random_stir();
386 key_used = 0;
387 log("RSA key generation complete.");
388 }
389 /* Reschedule the alarm. */
390 signal(SIGALRM, key_regeneration_alarm);
391 alarm(options.key_regeneration_time);
392 errno = save_errno;
393}
371 394
395/*
396 * Main program for the daemon.
397 */
372int 398int
373main(int ac, char **av) 399main(int ac, char **av)
374{ 400{
375 extern char *optarg; 401 extern char *optarg;
376 extern int optind; 402 extern int optind;
377 int opt, aux, sock_in, sock_out, newsock, i, pid, on = 1; 403 int opt, aux, sock_in, sock_out, newsock, i, pid, on = 1;
378 int remote_major, remote_minor; 404 int remote_major, remote_minor;
379 int silentrsa = 0; 405 int silentrsa = 0;
380 struct sockaddr_in sin; 406 struct sockaddr_in sin;
381 char buf[100]; /* Must not be larger than remote_version. */ 407 char buf[100]; /* Must not be larger than remote_version. */
382 char remote_version[100]; /* Must be at least as big as buf. */ 408 char remote_version[100]; /* Must be at least as big as buf. */
383 int remote_port; 409 const char *remote_ip;
384 char *comment; 410 int remote_port;
385 FILE *f; 411 char *comment;
386 struct linger linger; 412 FILE *f;
387 413 struct linger linger;
388 /* Save argv[0]. */ 414
389 saved_argv = av; 415 /* Save argv[0]. */
390 if (strchr(av[0], '/')) 416 saved_argv = av;
391 av0 = strrchr(av[0], '/') + 1; 417 if (strchr(av[0], '/'))
392 else 418 av0 = strrchr(av[0], '/') + 1;
393 av0 = av[0]; 419 else
394 420 av0 = av[0];
395 /* Initialize configuration options to their default values. */ 421
396 initialize_server_options(&options); 422 /* Initialize configuration options to their default values. */
397 423 initialize_server_options(&options);
398 /* Parse command-line arguments. */ 424
399 while ((opt = getopt(ac, av, "f:p:b:k:h:g:diqQ")) != EOF) 425 /* Parse command-line arguments. */
400 { 426 while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:diqQ")) != EOF) {
401 switch (opt) 427 switch (opt) {
402 { 428 case 'f':
403 case 'f': 429 config_file_name = optarg;
404 config_file_name = optarg; 430 break;
405 break; 431 case 'd':
406 case 'd': 432 debug_flag = 1;
407 debug_flag = 1; 433 options.log_level = SYSLOG_LEVEL_DEBUG;
408 options.log_level = SYSLOG_LEVEL_DEBUG; 434 break;
409 break; 435 case 'i':
410 case 'i': 436 inetd_flag = 1;
411 inetd_flag = 1; 437 break;
412 break; 438 case 'Q':
413 case 'Q': 439 silentrsa = 1;
414 silentrsa = 1; 440 break;
415 break; 441 case 'q':
416 case 'q': 442 options.log_level = SYSLOG_LEVEL_QUIET;
417 options.log_level = SYSLOG_LEVEL_QUIET; 443 break;
418 break; 444 case 'b':
419 case 'b': 445 options.server_key_bits = atoi(optarg);
420 options.server_key_bits = atoi(optarg); 446 break;
421 break; 447 case 'p':
422 case 'p': 448 options.port = atoi(optarg);
423 options.port = atoi(optarg); 449 break;
424 break; 450 case 'g':
425 case 'g': 451 options.login_grace_time = atoi(optarg);
426 options.login_grace_time = atoi(optarg); 452 break;
427 break; 453 case 'k':
428 case 'k': 454 options.key_regeneration_time = atoi(optarg);
429 options.key_regeneration_time = atoi(optarg); 455 break;
430 break; 456 case 'h':
431 case 'h': 457 options.host_key_file = optarg;
432 options.host_key_file = optarg; 458 break;
433 break; 459 case 'V':
434 case '?': 460 client_version_string = optarg;
435 default: 461 /* only makes sense with inetd_flag, i.e. no listen() */
436 fprintf(stderr, "sshd version %s\n", SSH_VERSION); 462 inetd_flag = 1;
437 fprintf(stderr, "Usage: %s [options]\n", av0); 463 break;
438 fprintf(stderr, "Options:\n"); 464 case '?':
439 fprintf(stderr, " -f file Configuration file (default %s/sshd_config)\n", ETCDIR); 465 default:
440 fprintf(stderr, " -d Debugging mode\n"); 466 fprintf(stderr, "sshd version %s\n", SSH_VERSION);
441 fprintf(stderr, " -i Started from inetd\n"); 467 fprintf(stderr, "Usage: %s [options]\n", av0);
442 fprintf(stderr, " -q Quiet (no logging)\n"); 468 fprintf(stderr, "Options:\n");
443 fprintf(stderr, " -p port Listen on the specified port (default: 22)\n"); 469 fprintf(stderr, " -f file Configuration file (default %s/sshd_config)\n", ETCDIR);
444 fprintf(stderr, " -k seconds Regenerate server key every this many seconds (default: 3600)\n"); 470 fprintf(stderr, " -d Debugging mode\n");
445 fprintf(stderr, " -g seconds Grace period for authentication (default: 300)\n"); 471 fprintf(stderr, " -i Started from inetd\n");
446 fprintf(stderr, " -b bits Size of server RSA key (default: 768 bits)\n"); 472 fprintf(stderr, " -q Quiet (no logging)\n");
447 fprintf(stderr, " -h file File from which to read host key (default: %s)\n", 473 fprintf(stderr, " -p port Listen on the specified port (default: 22)\n");
448 HOST_KEY_FILE); 474 fprintf(stderr, " -k seconds Regenerate server key every this many seconds (default: 3600)\n");
449 exit(1); 475 fprintf(stderr, " -g seconds Grace period for authentication (default: 300)\n");
476 fprintf(stderr, " -b bits Size of server RSA key (default: 768 bits)\n");
477 fprintf(stderr, " -h file File from which to read host key (default: %s)\n",
478 HOST_KEY_FILE);
479 exit(1);
480 }
481 }
482
483 /* check if RSA support exists */
484 if (rsa_alive() == 0) {
485 if (silentrsa == 0)
486 printf("sshd: no RSA support in libssl and libcrypto -- exiting. See ssl(8)\n");
487 log("no RSA support in libssl and libcrypto -- exiting. See ssl(8)");
488 exit(1);
489 }
490 /* Read server configuration options from the configuration file. */
491 read_server_config(&options, config_file_name);
492
493 /* Fill in default values for those options not explicitly set. */
494 fill_default_server_options(&options);
495
496 /* Check certain values for sanity. */
497 if (options.server_key_bits < 512 ||
498 options.server_key_bits > 32768) {
499 fprintf(stderr, "Bad server key size.\n");
500 exit(1);
501 }
502 if (options.port < 1 || options.port > 65535) {
503 fprintf(stderr, "Bad port number.\n");
504 exit(1);
505 }
506 /* Check that there are no remaining arguments. */
507 if (optind < ac) {
508 fprintf(stderr, "Extra argument %s.\n", av[optind]);
509 exit(1);
450 } 510 }
451 } 511 /* Force logging to stderr while loading the private host key
452 512 unless started from inetd */
453 /* check if RSA support exists */ 513 log_init(av0, options.log_level, options.log_facility, !inetd_flag);
454 if (rsa_alive() == 0) { 514
455 if (silentrsa == 0) 515 debug("sshd version %.100s", SSH_VERSION);
456 printf("sshd: no RSA support in libssl and libcrypto -- exiting. See ssl(8)\n"); 516
457 log("no RSA support in libssl and libcrypto -- exiting. See ssl(8)"); 517 sensitive_data.host_key = RSA_new();
458 exit(1); 518 errno = 0;
459 } 519 /* Load the host key. It must have empty passphrase. */
460 520 if (!load_private_key(options.host_key_file, "",
461 /* Read server configuration options from the configuration file. */ 521 sensitive_data.host_key, &comment)) {
462 read_server_config(&options, config_file_name); 522 error("Could not load host key: %.200s: %.100s",
463 523 options.host_key_file, strerror(errno));
464 /* Fill in default values for those options not explicitly set. */ 524 exit(1);
465 fill_default_server_options(&options); 525 }
466 526 xfree(comment);
467 /* Check certain values for sanity. */ 527
468 if (options.server_key_bits < 512 || 528 /* Initialize the log (it is reinitialized below in case we
469 options.server_key_bits > 32768) 529 forked). */
470 { 530 if (debug_flag && !inetd_flag)
471 fprintf(stderr, "Bad server key size.\n"); 531 log_stderr = 1;
472 exit(1); 532 log_init(av0, options.log_level, options.log_facility, log_stderr);
473 } 533
474 if (options.port < 1 || options.port > 65535) 534 /* If not in debugging mode, and not started from inetd,
475 { 535 disconnect from the controlling terminal, and fork. The
476 fprintf(stderr, "Bad port number.\n"); 536 original process exits. */
477 exit(1); 537 if (!debug_flag && !inetd_flag) {
478 }
479
480 /* Check that there are no remaining arguments. */
481 if (optind < ac)
482 {
483 fprintf(stderr, "Extra argument %s.\n", av[optind]);
484 exit(1);
485 }
486
487 /* Force logging to stderr while loading the private host key
488 unless started from inetd */
489 log_init(av0, options.log_level, options.log_facility, !inetd_flag);
490
491 debug("sshd version %.100s", SSH_VERSION);
492
493 sensitive_data.host_key = RSA_new();
494 errno = 0;
495 /* Load the host key. It must have empty passphrase. */
496 if (!load_private_key(options.host_key_file, "",
497 sensitive_data.host_key, &comment))
498 {
499 error("Could not load host key: %.200s: %.100s",
500 options.host_key_file, strerror(errno));
501 exit(1);
502 }
503 xfree(comment);
504
505 /* Initialize the log (it is reinitialized below in case we forked). */
506 if (debug_flag && !inetd_flag)
507 log_stderr = 1;
508 log_init(av0, options.log_level, options.log_facility, log_stderr);
509
510 /* If not in debugging mode, and not started from inetd, disconnect from
511 the controlling terminal, and fork. The original process exits. */
512 if (!debug_flag && !inetd_flag)
513 {
514#ifdef TIOCNOTTY 538#ifdef TIOCNOTTY
515 int fd; 539 int fd;
516#endif /* TIOCNOTTY */ 540#endif /* TIOCNOTTY */
517 if (daemon(0, 0) < 0) 541 if (daemon(0, 0) < 0)
518 fatal("daemon() failed: %.200s", strerror(errno)); 542 fatal("daemon() failed: %.200s", strerror(errno));
519 543
520 /* Disconnect from the controlling tty. */ 544 /* Disconnect from the controlling tty. */
521#ifdef TIOCNOTTY 545#ifdef TIOCNOTTY
522 fd = open("/dev/tty", O_RDWR|O_NOCTTY); 546 fd = open("/dev/tty", O_RDWR | O_NOCTTY);
523 if (fd >= 0) 547 if (fd >= 0) {
524 { 548 (void) ioctl(fd, TIOCNOTTY, NULL);
525 (void)ioctl(fd, TIOCNOTTY, NULL); 549 close(fd);
526 close(fd); 550 }
527 }
528#endif /* TIOCNOTTY */ 551#endif /* TIOCNOTTY */
529 }
530
531 /* Reinitialize the log (because of the fork above). */
532 log_init(av0, options.log_level, options.log_facility, log_stderr);
533
534 /* Check that server and host key lengths differ sufficiently. This is
535 necessary to make double encryption work with rsaref. Oh, I hate
536 software patents. I dont know if this can go? Niels */
537 if (options.server_key_bits >
538 BN_num_bits(sensitive_data.host_key->n) - SSH_KEY_BITS_RESERVED &&
539 options.server_key_bits <
540 BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED)
541 {
542 options.server_key_bits =
543 BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED;
544 debug("Forcing server key to %d bits to make it differ from host key.",
545 options.server_key_bits);
546 }
547
548 /* Do not display messages to stdout in RSA code. */
549 rsa_set_verbose(0);
550
551 /* Initialize the random number generator. */
552 arc4random_stir();
553
554 /* Chdir to the root directory so that the current disk can be unmounted
555 if desired. */
556 chdir("/");
557
558 /* Close connection cleanly after attack. */
559 cipher_attack_detected = packet_disconnect;
560
561 /* Start listening for a socket, unless started from inetd. */
562 if (inetd_flag)
563 {
564 int s1, s2;
565 s1 = dup(0); /* Make sure descriptors 0, 1, and 2 are in use. */
566 s2 = dup(s1);
567 sock_in = dup(0);
568 sock_out = dup(1);
569 /* We intentionally do not close the descriptors 0, 1, and 2 as our
570 code for setting the descriptors won\'t work if ttyfd happens to
571 be one of those. */
572 debug("inetd sockets after dupping: %d, %d", sock_in, sock_out);
573
574 public_key = RSA_new();
575 sensitive_data.private_key = RSA_new();
576 /* Generate an rsa key. */
577 log("Generating %d bit RSA key.", options.server_key_bits);
578 rsa_generate_key(sensitive_data.private_key, public_key,
579 options.server_key_bits);
580 arc4random_stir();
581 log("RSA key generation complete.");
582 }
583 else
584 {
585 /* Create socket for listening. */
586 listen_sock = socket(AF_INET, SOCK_STREAM, 0);
587 if (listen_sock < 0)
588 fatal("socket: %.100s", strerror(errno));
589
590 /* Set socket options. We try to make the port reusable and have it
591 close as fast as possible without waiting in unnecessary wait states
592 on close. */
593 setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on,
594 sizeof(on));
595 linger.l_onoff = 1;
596 linger.l_linger = 5;
597 setsockopt(listen_sock, SOL_SOCKET, SO_LINGER, (void *)&linger,
598 sizeof(linger));
599
600 /* Initialize the socket address. */
601 memset(&sin, 0, sizeof(sin));
602 sin.sin_family = AF_INET;
603 sin.sin_addr = options.listen_addr;
604 sin.sin_port = htons(options.port);
605
606 /* Bind the socket to the desired port. */
607 if (bind(listen_sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
608 {
609 error("bind: %.100s", strerror(errno));
610 shutdown(listen_sock, SHUT_RDWR);
611 close(listen_sock);
612 fatal("Bind to port %d failed.", options.port);
613 } 552 }
614 553 /* Reinitialize the log (because of the fork above). */
615 if (!debug_flag) 554 log_init(av0, options.log_level, options.log_facility, log_stderr);
616 { 555
617 /* Record our pid in /etc/sshd_pid to make it easier to kill the 556 /* Check that server and host key lengths differ sufficiently.
618 correct sshd. We don\'t want to do this before the bind above 557 This is necessary to make double encryption work with rsaref.
619 because the bind will fail if there already is a daemon, and this 558 Oh, I hate software patents. I dont know if this can go? Niels */
620 will overwrite any old pid in the file. */ 559 if (options.server_key_bits >
621 f = fopen(SSH_DAEMON_PID_FILE, "w"); 560 BN_num_bits(sensitive_data.host_key->n) - SSH_KEY_BITS_RESERVED &&
622 if (f) 561 options.server_key_bits <
623 { 562 BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED) {
624 fprintf(f, "%u\n", (unsigned int)getpid()); 563 options.server_key_bits =
625 fclose(f); 564 BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED;
626 } 565 debug("Forcing server key to %d bits to make it differ from host key.",
566 options.server_key_bits);
627 } 567 }
628 568 /* Do not display messages to stdout in RSA code. */
629 /* Start listening on the port. */ 569 rsa_set_verbose(0);
630 log("Server listening on port %d.", options.port); 570
631 if (listen(listen_sock, 5) < 0) 571 /* Initialize the random number generator. */
632 fatal("listen: %.100s", strerror(errno)); 572 arc4random_stir();
633 573
634 public_key = RSA_new(); 574 /* Chdir to the root directory so that the current disk can be
635 sensitive_data.private_key = RSA_new(); 575 unmounted if desired. */
636 /* Generate an rsa key. */ 576 chdir("/");
637 log("Generating %d bit RSA key.", options.server_key_bits); 577
638 rsa_generate_key(sensitive_data.private_key, public_key, 578 /* Close connection cleanly after attack. */
639 options.server_key_bits); 579 cipher_attack_detected = packet_disconnect;
640 arc4random_stir(); 580
641 log("RSA key generation complete."); 581 /* Start listening for a socket, unless started from inetd. */
642 582 if (inetd_flag) {
643 /* Schedule server key regeneration alarm. */ 583 int s1, s2;
644 signal(SIGALRM, key_regeneration_alarm); 584 s1 = dup(0); /* Make sure descriptors 0, 1, and 2 are in use. */
645 alarm(options.key_regeneration_time); 585 s2 = dup(s1);
646 586 sock_in = dup(0);
647 /* Arrange to restart on SIGHUP. The handler needs listen_sock. */ 587 sock_out = dup(1);
648 signal(SIGHUP, sighup_handler); 588 /* We intentionally do not close the descriptors 0, 1, and 2
649 signal(SIGTERM, sigterm_handler); 589 as our code for setting the descriptors won\'t work
650 signal(SIGQUIT, sigterm_handler); 590 if ttyfd happens to be one of those. */
651 591 debug("inetd sockets after dupping: %d, %d", sock_in, sock_out);
652 /* Arrange SIGCHLD to be caught. */ 592
653 signal(SIGCHLD, main_sigchld_handler); 593 public_key = RSA_new();
654 594 sensitive_data.private_key = RSA_new();
655 /* Stay listening for connections until the system crashes or the 595
656 daemon is killed with a signal. */ 596 log("Generating %d bit RSA key.", options.server_key_bits);
657 for (;;) 597 rsa_generate_key(sensitive_data.private_key, public_key,
658 { 598 options.server_key_bits);
659 if (received_sighup) 599 arc4random_stir();
660 sighup_restart(); 600 log("RSA key generation complete.");
661 /* Wait in accept until there is a connection. */ 601 } else {
662 aux = sizeof(sin); 602 /* Create socket for listening. */
663 newsock = accept(listen_sock, (struct sockaddr *)&sin, &aux); 603 listen_sock = socket(AF_INET, SOCK_STREAM, 0);
664 if (received_sighup) 604 if (listen_sock < 0)
665 sighup_restart(); 605 fatal("socket: %.100s", strerror(errno));
666 if (newsock < 0) 606
667 { 607 /* Set socket options. We try to make the port reusable
668 if (errno == EINTR) 608 and have it close as fast as possible without waiting
669 continue; 609 in unnecessary wait states on close. */
670 error("accept: %.100s", strerror(errno)); 610 setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, (void *) &on,
671 continue; 611 sizeof(on));
672 } 612 linger.l_onoff = 1;
673 613 linger.l_linger = 5;
674 /* Got connection. Fork a child to handle it, unless we are in 614 setsockopt(listen_sock, SOL_SOCKET, SO_LINGER, (void *) &linger,
675 debugging mode. */ 615 sizeof(linger));
676 if (debug_flag) 616
677 { 617 /* Initialize the socket address. */
678 /* In debugging mode. Close the listening socket, and start 618 memset(&sin, 0, sizeof(sin));
679 processing the connection without forking. */ 619 sin.sin_family = AF_INET;
680 debug("Server will not fork when running in debugging mode."); 620 sin.sin_addr = options.listen_addr;
681 close(listen_sock); 621 sin.sin_port = htons(options.port);
682 sock_in = newsock; 622
683 sock_out = newsock; 623 /* Bind the socket to the desired port. */
684 pid = getpid(); 624 if (bind(listen_sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) {
685 break; 625 error("bind: %.100s", strerror(errno));
686 } 626 shutdown(listen_sock, SHUT_RDWR);
687 else 627 close(listen_sock);
688 { 628 fatal("Bind to port %d failed.", options.port);
689 /* Normal production daemon. Fork, and have the child process 629 }
690 the connection. The parent continues listening. */ 630 if (!debug_flag) {
691 if ((pid = fork()) == 0) 631 /* Record our pid in /etc/sshd_pid to make it
692 { 632 easier to kill the correct sshd. We don\'t
693 /* Child. Close the listening socket, and start using 633 want to do this before the bind above because
694 the accepted socket. Reinitialize logging (since our 634 the bind will fail if there already is a
695 pid has changed). We break out of the loop to handle 635 daemon, and this will overwrite any old pid in
696 the connection. */ 636 the file. */
697 close(listen_sock); 637 f = fopen(SSH_DAEMON_PID_FILE, "w");
698 sock_in = newsock; 638 if (f) {
699 sock_out = newsock; 639 fprintf(f, "%u\n", (unsigned int) getpid());
700 log_init(av0, options.log_level, options.log_facility, log_stderr); 640 fclose(f);
701 break; 641 }
702 } 642 }
703 }
704 643
705 /* Parent. Stay in the loop. */ 644 log("Server listening on port %d.", options.port);
706 if (pid < 0) 645 if (listen(listen_sock, 5) < 0)
707 error("fork: %.100s", strerror(errno)); 646 fatal("listen: %.100s", strerror(errno));
708 else 647
709 debug("Forked child %d.", pid); 648 public_key = RSA_new();
649 sensitive_data.private_key = RSA_new();
650
651 log("Generating %d bit RSA key.", options.server_key_bits);
652 rsa_generate_key(sensitive_data.private_key, public_key,
653 options.server_key_bits);
654 arc4random_stir();
655 log("RSA key generation complete.");
656
657 /* Schedule server key regeneration alarm. */
658 signal(SIGALRM, key_regeneration_alarm);
659 alarm(options.key_regeneration_time);
660
661 /* Arrange to restart on SIGHUP. The handler needs listen_sock. */
662 signal(SIGHUP, sighup_handler);
663 signal(SIGTERM, sigterm_handler);
664 signal(SIGQUIT, sigterm_handler);
665
666 /* Arrange SIGCHLD to be caught. */
667 signal(SIGCHLD, main_sigchld_handler);
668
669 /* Stay listening for connections until the system crashes
670 or the daemon is killed with a signal. */
671 for (;;) {
672 if (received_sighup)
673 sighup_restart();
674 /* Wait in accept until there is a connection. */
675 aux = sizeof(sin);
676 newsock = accept(listen_sock, (struct sockaddr *) & sin, &aux);
677 if (received_sighup)
678 sighup_restart();
679 if (newsock < 0) {
680 if (errno == EINTR)
681 continue;
682 error("accept: %.100s", strerror(errno));
683 continue;
684 }
685 /* Got connection. Fork a child to handle it,
686 unless we are in debugging mode. */
687 if (debug_flag) {
688 /* In debugging mode. Close the listening
689 socket, and start processing the
690 connection without forking. */
691 debug("Server will not fork when running in debugging mode.");
692 close(listen_sock);
693 sock_in = newsock;
694 sock_out = newsock;
695 pid = getpid();
696 break;
697 } else {
698 /* Normal production daemon. Fork, and
699 have the child process the connection.
700 The parent continues listening. */
701 if ((pid = fork()) == 0) {
702 /* Child. Close the listening
703 socket, and start using the
704 accepted socket. Reinitialize
705 logging (since our pid has
706 changed). We break out of the
707 loop to handle the connection. */
708 close(listen_sock);
709 sock_in = newsock;
710 sock_out = newsock;
711 log_init(av0, options.log_level, options.log_facility, log_stderr);
712 break;
713 }
714 }
715
716 /* Parent. Stay in the loop. */
717 if (pid < 0)
718 error("fork: %.100s", strerror(errno));
719 else
720 debug("Forked child %d.", pid);
721
722 /* Mark that the key has been used (it was "given" to the child). */
723 key_used = 1;
724
725 arc4random_stir();
726
727 /* Close the new socket (the child is now taking care of it). */
728 close(newsock);
729 }
730 }
710 731
711 /* Mark that the key has been used (it was "given" to the child). */ 732 /* This is the child processing a new connection. */
712 key_used = 1; 733
734 /* Disable the key regeneration alarm. We will not regenerate the
735 key since we are no longer in a position to give it to anyone.
736 We will not restart on SIGHUP since it no longer makes sense. */
737 alarm(0);
738 signal(SIGALRM, SIG_DFL);
739 signal(SIGHUP, SIG_DFL);
740 signal(SIGTERM, SIG_DFL);
741 signal(SIGQUIT, SIG_DFL);
742 signal(SIGCHLD, SIG_DFL);
743
744 /* Set socket options for the connection. We want the socket to
745 close as fast as possible without waiting for anything. If the
746 connection is not a socket, these will do nothing. */
747 /* setsockopt(sock_in, SOL_SOCKET, SO_REUSEADDR, (void *)&on,
748 sizeof(on)); */
749 linger.l_onoff = 1;
750 linger.l_linger = 5;
751 setsockopt(sock_in, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof(linger));
752
753 /* Register our connection. This turns encryption off because we
754 do not have a key. */
755 packet_set_connection(sock_in, sock_out);
756
757 remote_port = get_remote_port();
758 remote_ip = get_remote_ipaddr();
759
760 /* Check whether logins are denied from this host. */
761#ifdef LIBWRAP
762 {
763 struct request_info req;
713 764
714 arc4random_stir(); 765 request_init(&req, RQ_DAEMON, av0, RQ_FILE, sock_in, NULL);
766 fromhost(&req);
715 767
716 /* Close the new socket (the child is now taking care of it). */ 768 if (!hosts_access(&req)) {
717 close(newsock); 769 close(sock_in);
770 close(sock_out);
771 refuse(&req);
772 }
773 verbose("Connection from %.500s port %d", eval_client(&req), remote_port);
718 } 774 }
719 }
720
721 /* This is the child processing a new connection. */
722
723 /* Disable the key regeneration alarm. We will not regenerate the key
724 since we are no longer in a position to give it to anyone. We will
725 not restart on SIGHUP since it no longer makes sense. */
726 alarm(0);
727 signal(SIGALRM, SIG_DFL);
728 signal(SIGHUP, SIG_DFL);
729 signal(SIGTERM, SIG_DFL);
730 signal(SIGQUIT, SIG_DFL);
731 signal(SIGCHLD, SIG_DFL);
732
733 /* Set socket options for the connection. We want the socket to close
734 as fast as possible without waiting for anything. If the connection
735 is not a socket, these will do nothing. */
736 /* setsockopt(sock_in, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */
737 linger.l_onoff = 1;
738 linger.l_linger = 5;
739 setsockopt(sock_in, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger));
740
741 /* Register our connection. This turns encryption off because we do not
742 have a key. */
743 packet_set_connection(sock_in, sock_out);
744
745 remote_port = get_remote_port();
746
747 /* Check whether logins are denied from this host. */
748#ifdef LIBWRAP
749 {
750 struct request_info req;
751
752 request_init(&req, RQ_DAEMON, av0, RQ_FILE, sock_in, NULL);
753 fromhost(&req);
754
755 if (!hosts_access(&req)) {
756 close(sock_in);
757 close(sock_out);
758 refuse(&req);
759 }
760 log("Connection from %.500s port %d", eval_client(&req), remote_port);
761 }
762#else 775#else
763 /* Log the connection. */ 776 /* Log the connection. */
764 log("Connection from %.100s port %d", get_remote_ipaddr(), remote_port); 777 verbose("Connection from %.500s port %d", remote_ip, remote_port);
765#endif /* LIBWRAP */ 778#endif /* LIBWRAP */
766 779
767 /* We don\'t want to listen forever unless the other side successfully 780 /* We don\'t want to listen forever unless the other side
768 authenticates itself. So we set up an alarm which is cleared after 781 successfully authenticates itself. So we set up an alarm which
769 successful authentication. A limit of zero indicates no limit. 782 is cleared after successful authentication. A limit of zero
770 Note that we don\'t set the alarm in debugging mode; it is just annoying 783 indicates no limit. Note that we don\'t set the alarm in
771 to have the server exit just when you are about to discover the bug. */ 784 debugging mode; it is just annoying to have the server exit
772 signal(SIGALRM, grace_alarm_handler); 785 just when you are about to discover the bug. */
773 if (!debug_flag) 786 signal(SIGALRM, grace_alarm_handler);
774 alarm(options.login_grace_time); 787 if (!debug_flag)
775 788 alarm(options.login_grace_time);
776 /* Send our protocol version identification. */ 789
777 snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", 790 if (client_version_string != NULL) {
778 PROTOCOL_MAJOR, PROTOCOL_MINOR, SSH_VERSION); 791 /* we are exec'ed by sshd2, so skip exchange of protocol version */
779 if (write(sock_out, buf, strlen(buf)) != strlen(buf)) 792 strlcpy(buf, client_version_string, sizeof(buf));
780 fatal("Could not write ident string."); 793 } else {
781 794 /* Send our protocol version identification. */
782 /* Read other side\'s version identification. */ 795 snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
783 for (i = 0; i < sizeof(buf) - 1; i++) 796 PROTOCOL_MAJOR, PROTOCOL_MINOR, SSH_VERSION);
784 { 797 if (write(sock_out, buf, strlen(buf)) != strlen(buf))
785 if (read(sock_in, &buf[i], 1) != 1) 798 fatal("Could not write ident string to %s.", get_remote_ipaddr());
786 fatal("Did not receive ident string."); 799
787 if (buf[i] == '\r') 800 /* Read other side\'s version identification. */
788 { 801 for (i = 0; i < sizeof(buf) - 1; i++) {
789 buf[i] = '\n'; 802 if (read(sock_in, &buf[i], 1) != 1)
790 buf[i + 1] = 0; 803 fatal("Did not receive ident string from %s.", get_remote_ipaddr());
791 break; 804 if (buf[i] == '\r') {
805 buf[i] = '\n';
806 buf[i + 1] = 0;
807 break;
808 }
809 if (buf[i] == '\n') {
810 /* buf[i] == '\n' */
811 buf[i + 1] = 0;
812 break;
813 }
814 }
815 buf[sizeof(buf) - 1] = 0;
792 } 816 }
793 if (buf[i] == '\n') 817
794 { 818 /* Check that the versions match. In future this might accept
795 /* buf[i] == '\n' */ 819 several versions and set appropriate flags to handle them. */
796 buf[i + 1] = 0; 820 if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor,
797 break; 821 remote_version) != 3) {
822 const char *s = "Protocol mismatch.\n";
823 (void) write(sock_out, s, strlen(s));
824 close(sock_in);
825 close(sock_out);
826 fatal("Bad protocol version identification '%.100s' from %s",
827 buf, get_remote_ipaddr());
828 }
829 debug("Client protocol version %d.%d; client software version %.100s",
830 remote_major, remote_minor, remote_version);
831 if (remote_major != PROTOCOL_MAJOR) {
832 const char *s = "Protocol major versions differ.\n";
833 (void) write(sock_out, s, strlen(s));
834 close(sock_in);
835 close(sock_out);
836 fatal("Protocol major versions differ for %s: %d vs. %d",
837 get_remote_ipaddr(),
838 PROTOCOL_MAJOR, remote_major);
798 } 839 }
799 } 840 /* Check that the client has sufficiently high software version. */
800 buf[sizeof(buf) - 1] = 0; 841 if (remote_major == 1 && remote_minor < 3)
801 842 packet_disconnect("Your ssh version is too old and is no longer supported. Please install a newer version.");
802 /* Check that the versions match. In future this might accept several 843
803 versions and set appropriate flags to handle them. */ 844 if (remote_major == 1 && remote_minor == 3) {
804 if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor, 845 enable_compat13();
805 remote_version) != 3) 846 if (strcmp(remote_version, "OpenSSH-1.1") != 0) {
806 { 847 debug("Agent forwarding disabled, remote version is not compatible.");
807 const char *s = "Protocol mismatch.\n"; 848 no_agent_forwarding_flag = 1;
808 (void) write(sock_out, s, strlen(s)); 849 }
809 close(sock_in); 850 }
810 close(sock_out); 851 /* Check that the connection comes from a privileged port. Rhosts-
811 fatal("Bad protocol version identification: %.100s", buf); 852 and Rhosts-RSA-Authentication only make sense from priviledged
812 } 853 programs. Of course, if the intruder has root access on his
813 debug("Client protocol version %d.%d; client software version %.100s", 854 local machine, he can connect from any port. So do not use
814 remote_major, remote_minor, remote_version); 855 these authentication methods from machines that you do not trust. */
815 if (remote_major != PROTOCOL_MAJOR) 856 if (remote_port >= IPPORT_RESERVED ||
816 { 857 remote_port < IPPORT_RESERVED / 2) {
817 const char *s = "Protocol major versions differ.\n"; 858 options.rhosts_authentication = 0;
818 (void) write(sock_out, s, strlen(s)); 859 options.rhosts_rsa_authentication = 0;
819 close(sock_in); 860 }
820 close(sock_out); 861 packet_set_nonblocking();
821 fatal("Protocol major versions differ: %d vs. %d", 862
822 PROTOCOL_MAJOR, remote_major); 863 /* Handle the connection. */
823 } 864 do_connection();
824
825 /* Check that the client has sufficiently high software version. */
826 if (remote_major == 1 && remote_minor < 3)
827 packet_disconnect("Your ssh version is too old and is no longer supported. Please install a newer version.");
828
829 if (remote_major == 1 && remote_minor == 3) {
830 enable_compat13();
831 if (strcmp(remote_version, "OpenSSH-1.1") != 0) {
832 debug("Agent forwarding disabled, remote version is not compatible.");
833 no_agent_forwarding_flag = 1;
834 }
835 }
836
837 /* Check that the connection comes from a privileged port.
838 Rhosts- and Rhosts-RSA-Authentication only make sense
839 from priviledged programs.
840 Of course, if the intruder has root access on his local machine,
841 he can connect from any port. So do not use these authentication
842 methods from machines that you do not trust. */
843 if (remote_port >= IPPORT_RESERVED ||
844 remote_port < IPPORT_RESERVED / 2)
845 {
846 options.rhosts_authentication = 0;
847 options.rhosts_rsa_authentication = 0;
848 }
849
850 packet_set_nonblocking();
851
852 /* Handle the connection. */
853 do_connection();
854 865
855#ifdef KRB4 866#ifdef KRB4
856 /* Cleanup user's ticket cache file. */ 867 /* Cleanup user's ticket cache file. */
857 if (options.kerberos_ticket_cleanup) 868 if (options.kerberos_ticket_cleanup)
858 (void) dest_tkt(); 869 (void) dest_tkt();
859#endif /* KRB4 */ 870#endif /* KRB4 */
860 871
861 /* Cleanup user's local Xauthority file. */ 872 /* Cleanup user's local Xauthority file. */
862 if (xauthfile) unlink(xauthfile); 873 if (xauthfile)
874 unlink(xauthfile);
863 875
864 /* The connection has been terminated. */ 876 /* The connection has been terminated. */
865 log("Closing connection to %.100s", inet_ntoa(sin.sin_addr)); 877 verbose("Closing connection to %.100s", remote_ip);
866 878
867#ifdef HAVE_LIBPAM 879#ifdef HAVE_LIBPAM
868 { 880 {
869 int retval; 881 int retval;
870
871 if (pamh != NULL)
872 {
873 debug("Closing PAM session.");
874 retval = pam_close_session((pam_handle_t *)pamh, 0);
875
876 debug("Terminating PAM library.");
877 if (pam_end((pam_handle_t *)pamh, retval) != PAM_SUCCESS)
878 log("Cannot release PAM authentication.");
879
880 fatal_remove_cleanup(&pam_cleanup_proc, NULL);
881 }
882 }
883#endif /* HAVE_LIBPAM */
884 882
885 packet_close(); 883 if (pamh != NULL) {
884 debug("Closing PAM session.");
885 retval = pam_close_session((pam_handle_t *)pamh, 0);
886 886
887 exit(0); 887 debug("Terminating PAM library.");
888} 888 if (pam_end((pam_handle_t *)pamh, retval) != PAM_SUCCESS)
889 log("Cannot release PAM authentication.");
890
891 fatal_remove_cleanup(&pam_cleanup_proc, NULL);
892 }
893 }
894#endif /* HAVE_LIBPAM */
889 895
890/* Process an incoming connection. Protocol version identifiers have already 896 packet_close();
891 been exchanged. This sends server key and performs the key exchange. 897 exit(0);
892 Server and host keys will no longer be needed after this functions. */ 898}
893 899
900/*
901 * Process an incoming connection. Protocol version identifiers have already
902 * been exchanged. This sends server key and performs the key exchange.
903 * Server and host keys will no longer be needed after this functions.
904 */
894void 905void
895do_connection() 906do_connection()
896{ 907{
897 int i, len; 908 int i, len;
898 BIGNUM *session_key_int; 909 BIGNUM *session_key_int;
899 unsigned char session_key[SSH_SESSION_KEY_LENGTH]; 910 unsigned char session_key[SSH_SESSION_KEY_LENGTH];
900 unsigned char check_bytes[8]; 911 unsigned char check_bytes[8];
901 char *user; 912 char *user;
902 unsigned int cipher_type, auth_mask, protocol_flags; 913 unsigned int cipher_type, auth_mask, protocol_flags;
903 int plen, slen; 914 int plen, slen;
904 u_int32_t rand = 0; 915 u_int32_t rand = 0;
905 916
906 /* Generate check bytes that the client must send back in the user packet 917 /* Generate check bytes that the client must send back in the user
907 in order for it to be accepted; this is used to defy ip spoofing 918 packet in order for it to be accepted; this is used to defy ip
908 attacks. Note that this only works against somebody doing IP spoofing 919 spoofing attacks. Note that this only works against somebody
909 from a remote machine; any machine on the local network can still see 920 doing IP spoofing from a remote machine; any machine on the
910 outgoing packets and catch the random cookie. This only affects 921 local network can still see outgoing packets and catch the
911 rhosts authentication, and this is one of the reasons why it is 922 random cookie. This only affects rhosts authentication, and
912 inherently insecure. */ 923 this is one of the reasons why it is inherently insecure. */
913 for (i = 0; i < 8; i++) { 924 for (i = 0; i < 8; i++) {
914 if (i % 4 == 0) 925 if (i % 4 == 0)
915 rand = arc4random(); 926 rand = arc4random();
916 check_bytes[i] = rand & 0xff; 927 check_bytes[i] = rand & 0xff;
917 rand >>= 8; 928 rand >>= 8;
918 } 929 }
919 930
920 /* Send our public key. We include in the packet 64 bits of random 931 /* Send our public key. We include in the packet 64 bits of
921 data that must be matched in the reply in order to prevent IP spoofing. */ 932 random data that must be matched in the reply in order to
922 packet_start(SSH_SMSG_PUBLIC_KEY); 933 prevent IP spoofing. */
923 for (i = 0; i < 8; i++) 934 packet_start(SSH_SMSG_PUBLIC_KEY);
924 packet_put_char(check_bytes[i]); 935 for (i = 0; i < 8; i++)
925 936 packet_put_char(check_bytes[i]);
926 /* Store our public server RSA key. */ 937
927 packet_put_int(BN_num_bits(public_key->n)); 938 /* Store our public server RSA key. */
928 packet_put_bignum(public_key->e); 939 packet_put_int(BN_num_bits(public_key->n));
929 packet_put_bignum(public_key->n); 940 packet_put_bignum(public_key->e);
930 941 packet_put_bignum(public_key->n);
931 /* Store our public host RSA key. */ 942
932 packet_put_int(BN_num_bits(sensitive_data.host_key->n)); 943 /* Store our public host RSA key. */
933 packet_put_bignum(sensitive_data.host_key->e); 944 packet_put_int(BN_num_bits(sensitive_data.host_key->n));
934 packet_put_bignum(sensitive_data.host_key->n); 945 packet_put_bignum(sensitive_data.host_key->e);
935 946 packet_put_bignum(sensitive_data.host_key->n);
936 /* Put protocol flags. */ 947
937 packet_put_int(SSH_PROTOFLAG_HOST_IN_FWD_OPEN); 948 /* Put protocol flags. */
938 949 packet_put_int(SSH_PROTOFLAG_HOST_IN_FWD_OPEN);
939 /* Declare which ciphers we support. */ 950
940 packet_put_int(cipher_mask()); 951 /* Declare which ciphers we support. */
941 952 packet_put_int(cipher_mask());
942 /* Declare supported authentication types. */ 953
943 auth_mask = 0; 954 /* Declare supported authentication types. */
944 if (options.rhosts_authentication) 955 auth_mask = 0;
945 auth_mask |= 1 << SSH_AUTH_RHOSTS; 956 if (options.rhosts_authentication)
946 if (options.rhosts_rsa_authentication) 957 auth_mask |= 1 << SSH_AUTH_RHOSTS;
947 auth_mask |= 1 << SSH_AUTH_RHOSTS_RSA; 958 if (options.rhosts_rsa_authentication)
948 if (options.rsa_authentication) 959 auth_mask |= 1 << SSH_AUTH_RHOSTS_RSA;
949 auth_mask |= 1 << SSH_AUTH_RSA; 960 if (options.rsa_authentication)
961 auth_mask |= 1 << SSH_AUTH_RSA;
950#ifdef KRB4 962#ifdef KRB4
951 if (options.kerberos_authentication) 963 if (options.kerberos_authentication)
952 auth_mask |= 1 << SSH_AUTH_KERBEROS; 964 auth_mask |= 1 << SSH_AUTH_KERBEROS;
953#endif 965#endif
954#ifdef AFS 966#ifdef AFS
955 if (options.kerberos_tgt_passing) 967 if (options.kerberos_tgt_passing)
956 auth_mask |= 1 << SSH_PASS_KERBEROS_TGT; 968 auth_mask |= 1 << SSH_PASS_KERBEROS_TGT;
957 if (options.afs_token_passing) 969 if (options.afs_token_passing)
958 auth_mask |= 1 << SSH_PASS_AFS_TOKEN; 970 auth_mask |= 1 << SSH_PASS_AFS_TOKEN;
959#endif 971#endif
960 if (options.password_authentication) 972#ifdef SKEY
961 auth_mask |= 1 << SSH_AUTH_PASSWORD; 973 if (options.skey_authentication == 1)
962 packet_put_int(auth_mask); 974 auth_mask |= 1 << SSH_AUTH_TIS;
963 975#endif
964 /* Send the packet and wait for it to be sent. */ 976 if (options.password_authentication)
965 packet_send(); 977 auth_mask |= 1 << SSH_AUTH_PASSWORD;
966 packet_write_wait(); 978 packet_put_int(auth_mask);
967 979
968 debug("Sent %d bit public key and %d bit host key.", 980 /* Send the packet and wait for it to be sent. */
969 BN_num_bits(public_key->n), BN_num_bits(sensitive_data.host_key->n)); 981 packet_send();
970 982 packet_write_wait();
971 /* Read clients reply (cipher type and session key). */ 983
972 packet_read_expect(&plen, SSH_CMSG_SESSION_KEY); 984 debug("Sent %d bit public key and %d bit host key.",
973 985 BN_num_bits(public_key->n), BN_num_bits(sensitive_data.host_key->n));
974 /* Get cipher type. */ 986
975 cipher_type = packet_get_char(); 987 /* Read clients reply (cipher type and session key). */
976 988 packet_read_expect(&plen, SSH_CMSG_SESSION_KEY);
977 /* Get check bytes from the packet. These must match those we sent earlier 989
978 with the public key packet. */ 990 /* Get cipher type. */
979 for (i = 0; i < 8; i++) 991 cipher_type = packet_get_char();
980 if (check_bytes[i] != packet_get_char()) 992
981 packet_disconnect("IP Spoofing check bytes do not match."); 993 /* Get check bytes from the packet. These must match those we
982 994 sent earlier with the public key packet. */
983 debug("Encryption type: %.200s", cipher_name(cipher_type)); 995 for (i = 0; i < 8; i++)
984 996 if (check_bytes[i] != packet_get_char())
985 /* Get the encrypted integer. */ 997 packet_disconnect("IP Spoofing check bytes do not match.");
986 session_key_int = BN_new(); 998
987 packet_get_bignum(session_key_int, &slen); 999 debug("Encryption type: %.200s", cipher_name(cipher_type));
988 1000
989 /* Get protocol flags. */ 1001 /* Get the encrypted integer. */
990 protocol_flags = packet_get_int(); 1002 session_key_int = BN_new();
991 packet_set_protocol_flags(protocol_flags); 1003 packet_get_bignum(session_key_int, &slen);
992 1004
993 packet_integrity_check(plen, 1 + 8 + slen + 4, SSH_CMSG_SESSION_KEY); 1005 /* Get protocol flags. */
994 1006 protocol_flags = packet_get_int();
995 /* Decrypt it using our private server key and private host key (key with 1007 packet_set_protocol_flags(protocol_flags);
996 larger modulus first). */ 1008
997 if (BN_cmp(sensitive_data.private_key->n, sensitive_data.host_key->n) > 0) 1009 packet_integrity_check(plen, 1 + 8 + slen + 4, SSH_CMSG_SESSION_KEY);
998 { 1010
999 /* Private key has bigger modulus. */ 1011 /* Decrypt it using our private server key and private host key
1000 if (BN_num_bits(sensitive_data.private_key->n) < 1012 (key with larger modulus first). */
1001 BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED) { 1013 if (BN_cmp(sensitive_data.private_key->n, sensitive_data.host_key->n) > 0) {
1002 fatal("do_connection: private_key %d < host_key %d + SSH_KEY_BITS_RESERVED %d", 1014 /* Private key has bigger modulus. */
1003 BN_num_bits(sensitive_data.private_key->n), 1015 if (BN_num_bits(sensitive_data.private_key->n) <
1004 BN_num_bits(sensitive_data.host_key->n), 1016 BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED) {
1005 SSH_KEY_BITS_RESERVED); 1017 fatal("do_connection: %s: private_key %d < host_key %d + SSH_KEY_BITS_RESERVED %d",
1006 } 1018 get_remote_ipaddr(),
1007 1019 BN_num_bits(sensitive_data.private_key->n),
1008 rsa_private_decrypt(session_key_int, session_key_int, 1020 BN_num_bits(sensitive_data.host_key->n),
1009 sensitive_data.private_key); 1021 SSH_KEY_BITS_RESERVED);
1010 rsa_private_decrypt(session_key_int, session_key_int, 1022 }
1011 sensitive_data.host_key); 1023 rsa_private_decrypt(session_key_int, session_key_int,
1012 } 1024 sensitive_data.private_key);
1013 else 1025 rsa_private_decrypt(session_key_int, session_key_int,
1014 { 1026 sensitive_data.host_key);
1015 /* Host key has bigger modulus (or they are equal). */ 1027 } else {
1016 if (BN_num_bits(sensitive_data.host_key->n) < 1028 /* Host key has bigger modulus (or they are equal). */
1017 BN_num_bits(sensitive_data.private_key->n) + SSH_KEY_BITS_RESERVED) { 1029 if (BN_num_bits(sensitive_data.host_key->n) <
1018 fatal("do_connection: host_key %d < private_key %d + SSH_KEY_BITS_RESERVED %d", 1030 BN_num_bits(sensitive_data.private_key->n) + SSH_KEY_BITS_RESERVED) {
1019 BN_num_bits(sensitive_data.host_key->n), 1031 fatal("do_connection: %s: host_key %d < private_key %d + SSH_KEY_BITS_RESERVED %d",
1020 BN_num_bits(sensitive_data.private_key->n), 1032 get_remote_ipaddr(),
1021 SSH_KEY_BITS_RESERVED); 1033 BN_num_bits(sensitive_data.host_key->n),
1022 } 1034 BN_num_bits(sensitive_data.private_key->n),
1023 rsa_private_decrypt(session_key_int, session_key_int, 1035 SSH_KEY_BITS_RESERVED);
1024 sensitive_data.host_key); 1036 }
1025 rsa_private_decrypt(session_key_int, session_key_int, 1037 rsa_private_decrypt(session_key_int, session_key_int,
1026 sensitive_data.private_key); 1038 sensitive_data.host_key);
1027 } 1039 rsa_private_decrypt(session_key_int, session_key_int,
1028 1040 sensitive_data.private_key);
1029 /* Compute session id for this session. */ 1041 }
1030 compute_session_id(session_id, check_bytes, 1042
1031 sensitive_data.host_key->n, 1043 /* Compute session id for this session. */
1032 sensitive_data.private_key->n); 1044 compute_session_id(session_id, check_bytes,
1033 1045 sensitive_data.host_key->n,
1034 /* Extract session key from the decrypted integer. The key is in the 1046 sensitive_data.private_key->n);
1035 least significant 256 bits of the integer; the first byte of the 1047
1036 key is in the highest bits. */ 1048 /* Extract session key from the decrypted integer. The key is in
1037 BN_mask_bits(session_key_int, sizeof(session_key) * 8); 1049 the least significant 256 bits of the integer; the first byte
1038 len = BN_num_bytes(session_key_int); 1050 of the key is in the highest bits. */
1039 if (len < 0 || len > sizeof(session_key)) 1051 BN_mask_bits(session_key_int, sizeof(session_key) * 8);
1040 fatal("do_connection: bad len: session_key_int %d > sizeof(session_key) %d", 1052 len = BN_num_bytes(session_key_int);
1041 len, sizeof(session_key)); 1053 if (len < 0 || len > sizeof(session_key))
1042 memset(session_key, 0, sizeof(session_key)); 1054 fatal("do_connection: bad len from %s: session_key_int %d > sizeof(session_key) %d",
1043 BN_bn2bin(session_key_int, session_key + sizeof(session_key) - len); 1055 get_remote_ipaddr(),
1044 1056 len, sizeof(session_key));
1045 /* Xor the first 16 bytes of the session key with the session id. */ 1057 memset(session_key, 0, sizeof(session_key));
1046 for (i = 0; i < 16; i++) 1058 BN_bn2bin(session_key_int, session_key + sizeof(session_key) - len);
1047 session_key[i] ^= session_id[i]; 1059
1048 1060 /* Xor the first 16 bytes of the session key with the session id. */
1049 /* Destroy the decrypted integer. It is no longer needed. */ 1061 for (i = 0; i < 16; i++)
1050 BN_clear_free(session_key_int); 1062 session_key[i] ^= session_id[i];
1051 1063
1052 /* Set the session key. From this on all communications will be 1064 /* Destroy the decrypted integer. It is no longer needed. */
1053 encrypted. */ 1065 BN_clear_free(session_key_int);
1054 packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH, cipher_type); 1066
1055 1067 /* Set the session key. From this on all communications will be encrypted. */
1056 /* Destroy our copy of the session key. It is no longer needed. */ 1068 packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH, cipher_type);
1057 memset(session_key, 0, sizeof(session_key)); 1069
1058 1070 /* Destroy our copy of the session key. It is no longer needed. */
1059 debug("Received session key; encryption turned on."); 1071 memset(session_key, 0, sizeof(session_key));
1060 1072
1061 /* Send an acknowledgement packet. Note that this packet is sent 1073 debug("Received session key; encryption turned on.");
1062 encrypted. */ 1074
1063 packet_start(SSH_SMSG_SUCCESS); 1075 /* Send an acknowledgement packet. Note that this packet is sent encrypted. */
1064 packet_send(); 1076 packet_start(SSH_SMSG_SUCCESS);
1065 packet_write_wait(); 1077 packet_send();
1066 1078 packet_write_wait();
1067 /* Get the name of the user that we wish to log in as. */ 1079
1068 packet_read_expect(&plen, SSH_CMSG_USER); 1080 /* Get the name of the user that we wish to log in as. */
1069 1081 packet_read_expect(&plen, SSH_CMSG_USER);
1070 /* Get the user name. */ 1082
1071 { 1083 /* Get the user name. */
1072 int ulen; 1084 {
1073 user = packet_get_string(&ulen); 1085 int ulen;
1074 packet_integrity_check(plen, (4 + ulen), SSH_CMSG_USER); 1086 user = packet_get_string(&ulen);
1075 } 1087 packet_integrity_check(plen, (4 + ulen), SSH_CMSG_USER);
1076 1088 }
1077 /* Destroy the private and public keys. They will no longer be needed. */ 1089
1078 RSA_free(public_key); 1090 /* Destroy the private and public keys. They will no longer be needed. */
1079 RSA_free(sensitive_data.private_key); 1091 RSA_free(public_key);
1080 RSA_free(sensitive_data.host_key); 1092 RSA_free(sensitive_data.private_key);
1081 1093 RSA_free(sensitive_data.host_key);
1082 setproctitle("%s", user);
1083 /* Do the authentication. */
1084 do_authentication(user);
1085}
1086 1094
1087/* Check if the user is allowed to log in via ssh. If user is listed in 1095 setproctitle("%s", user);
1088 DenyUsers or user's primary group is listed in DenyGroups, false will 1096 /* Do the authentication. */
1089 be returned. If AllowUsers isn't empty and user isn't listed there, or 1097 do_authentication(user);
1090 if AllowGroups isn't empty and user isn't listed there, false will be 1098}
1091 returned. Otherwise true is returned.
1092 XXX This function should also check if user has a valid shell */
1093 1099
1100/*
1101 * Check if the user is allowed to log in via ssh. If user is listed in
1102 * DenyUsers or user's primary group is listed in DenyGroups, false will
1103 * be returned. If AllowUsers isn't empty and user isn't listed there, or
1104 * if AllowGroups isn't empty and user isn't listed there, false will be
1105 * returned. Otherwise true is returned.
1106 * XXX This function should also check if user has a valid shell
1107 */
1094static int 1108static int
1095allowed_user(struct passwd *pw) 1109allowed_user(struct passwd * pw)
1096{ 1110{
1097 struct group *grp; 1111 struct group *grp;
1098 int i; 1112 int i;
1099 1113
1100 /* Shouldn't be called if pw is NULL, but better safe than sorry... */ 1114 /* Shouldn't be called if pw is NULL, but better safe than sorry... */
1101 if (!pw) 1115 if (!pw)
1102 return 0; 1116 return 0;
1103 1117
1104 /* XXX Should check for valid login shell */ 1118 /* XXX Should check for valid login shell */
1105 1119
1106 /* Return false if user is listed in DenyUsers */ 1120 /* Return false if user is listed in DenyUsers */
1107 if (options.num_deny_users > 0) 1121 if (options.num_deny_users > 0) {
1108 { 1122 if (!pw->pw_name)
1109 if (!pw->pw_name) 1123 return 0;
1110 return 0; 1124 for (i = 0; i < options.num_deny_users; i++)
1111 for (i = 0; i < options.num_deny_users; i++) 1125 if (match_pattern(pw->pw_name, options.deny_users[i]))
1112 if (match_pattern(pw->pw_name, options.deny_users[i])) 1126 return 0;
1113 return 0; 1127 }
1114 } 1128 /* Return false if AllowUsers isn't empty and user isn't listed
1115 1129 there */
1116 /* Return false if AllowUsers isn't empty and user isn't listed there */ 1130 if (options.num_allow_users > 0) {
1117 if (options.num_allow_users > 0) 1131 if (!pw->pw_name)
1118 { 1132 return 0;
1119 if (!pw->pw_name) 1133 for (i = 0; i < options.num_allow_users; i++)
1120 return 0; 1134 if (match_pattern(pw->pw_name, options.allow_users[i]))
1121 for (i = 0; i < options.num_allow_users; i++) 1135 break;
1122 if (match_pattern(pw->pw_name, options.allow_users[i])) 1136 /* i < options.num_allow_users iff we break for loop */
1123 break; 1137 if (i >= options.num_allow_users)
1124 /* i < options.num_allow_users iff we break for loop */ 1138 return 0;
1125 if (i >= options.num_allow_users) 1139 }
1126 return 0; 1140 /* Get the primary group name if we need it. Return false if it fails */
1127 } 1141 if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
1128 1142 grp = getgrgid(pw->pw_gid);
1129 /* Get the primary group name if we need it. Return false if it fails */ 1143 if (!grp)
1130 if (options.num_deny_groups > 0 || options.num_allow_groups > 0 ) 1144 return 0;
1131 { 1145
1132 grp = getgrgid(pw->pw_gid); 1146 /* Return false if user's group is listed in DenyGroups */
1133 if (!grp) 1147 if (options.num_deny_groups > 0) {
1134 return 0; 1148 if (!grp->gr_name)
1135 1149 return 0;
1136 /* Return false if user's group is listed in DenyGroups */ 1150 for (i = 0; i < options.num_deny_groups; i++)
1137 if (options.num_deny_groups > 0) 1151 if (match_pattern(grp->gr_name, options.deny_groups[i]))
1138 { 1152 return 0;
1139 if (!grp->gr_name) 1153 }
1140 return 0; 1154 /* Return false if AllowGroups isn't empty and user's
1141 for (i = 0; i < options.num_deny_groups; i++) 1155 group isn't listed there */
1142 if (match_pattern(grp->gr_name, options.deny_groups[i])) 1156 if (options.num_allow_groups > 0) {
1143 return 0; 1157 if (!grp->gr_name)
1144 } 1158 return 0;
1145 1159 for (i = 0; i < options.num_allow_groups; i++)
1146 /* Return false if AllowGroups isn't empty and user's group isn't 1160 if (match_pattern(grp->gr_name, options.allow_groups[i]))
1147 listed there */ 1161 break;
1148 if (options.num_allow_groups > 0) 1162 /* i < options.num_allow_groups iff we break for
1149 { 1163 loop */
1150 if (!grp->gr_name) 1164 if (i >= options.num_allow_groups)
1151 return 0; 1165 return 0;
1152 for (i = 0; i < options.num_allow_groups; i++) 1166 }
1153 if (match_pattern(grp->gr_name, options.allow_groups[i])) 1167 }
1154 break; 1168 /* We found no reason not to let this user try to log on... */
1155 /* i < options.num_allow_groups iff we break for loop */ 1169 return 1;
1156 if (i >= options.num_allow_groups)
1157 return 0;
1158 }
1159 }
1160
1161 /* We found no reason not to let this user try to log on... */
1162 return 1;
1163} 1170}
1164 1171
1165/* Performs authentication of an incoming connection. Session key has already 1172/*
1166 been exchanged and encryption is enabled. User is the user name to log 1173 * Performs authentication of an incoming connection. Session key has already
1167 in as (received from the client). */ 1174 * been exchanged and encryption is enabled. User is the user name to log
1168 1175 * in as (received from the client).
1176 */
1169void 1177void
1170do_authentication(char *user) 1178do_authentication(char *user)
1171{ 1179{
1172 struct passwd *pw, pwcopy; 1180 struct passwd *pw, pwcopy;
1173 1181
1174#ifdef AFS 1182#ifdef AFS
1175 /* If machine has AFS, set process authentication group. */ 1183 /* If machine has AFS, set process authentication group. */
1176 if (k_hasafs()) { 1184 if (k_hasafs()) {
1177 k_setpag(); 1185 k_setpag();
1178 k_unlog(); 1186 k_unlog();
1179 } 1187 }
1180#endif /* AFS */ 1188#endif /* AFS */
1181 1189
1182 /* Verify that the user is a valid user. */ 1190 /* Verify that the user is a valid user. */
1183 pw = getpwnam(user); 1191 pw = getpwnam(user);
1184 if (!pw || !allowed_user(pw)) 1192 if (!pw || !allowed_user(pw))
1185 do_fake_authloop(user); 1193 do_fake_authloop(user);
1186 1194
1187 /* Take a copy of the returned structure. */ 1195 /* Take a copy of the returned structure. */
1188 memset(&pwcopy, 0, sizeof(pwcopy)); 1196 memset(&pwcopy, 0, sizeof(pwcopy));
1189 pwcopy.pw_name = xstrdup(pw->pw_name); 1197 pwcopy.pw_name = xstrdup(pw->pw_name);
1190 pwcopy.pw_passwd = xstrdup(pw->pw_passwd); 1198 pwcopy.pw_passwd = xstrdup(pw->pw_passwd);
1191 pwcopy.pw_uid = pw->pw_uid; 1199 pwcopy.pw_uid = pw->pw_uid;
1192 pwcopy.pw_gid = pw->pw_gid; 1200 pwcopy.pw_gid = pw->pw_gid;
1193 pwcopy.pw_dir = xstrdup(pw->pw_dir); 1201 pwcopy.pw_dir = xstrdup(pw->pw_dir);
1194 pwcopy.pw_shell = xstrdup(pw->pw_shell); 1202 pwcopy.pw_shell = xstrdup(pw->pw_shell);
1195 pw = &pwcopy; 1203 pw = &pwcopy;
1196 1204
1197#ifdef HAVE_LIBPAM 1205#ifdef HAVE_LIBPAM
1198 { 1206 {
1199 int pam_retval; 1207 int pam_retval;
1200 1208
1201 debug("Starting up PAM with username \"%.200s\"", pw->pw_name); 1209 debug("Starting up PAM with username \"%.200s\"", pw->pw_name);
1202 1210
1203 pam_retval = pam_start("sshd", pw->pw_name, &conv, (pam_handle_t**)&pamh); 1211 pam_retval = pam_start("sshd", pw->pw_name, &conv, (pam_handle_t**)&pamh);
1204 if (pam_retval != PAM_SUCCESS) 1212 if (pam_retval != PAM_SUCCESS)
1205 fatal("PAM initialisation failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval)); 1213 fatal("PAM initialisation failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
1206 1214
1207 fatal_add_cleanup(&pam_cleanup_proc, NULL); 1215 fatal_add_cleanup(&pam_cleanup_proc, NULL);
1208 } 1216 }
1209#endif 1217#endif
1210 1218
1211 /* If we are not running as root, the user must have the same uid as the 1219 /* If we are not running as root, the user must have the same uid
1212 server. */ 1220 as the server. */
1213 if (getuid() != 0 && pw->pw_uid != getuid()) 1221 if (getuid() != 0 && pw->pw_uid != getuid())
1214 packet_disconnect("Cannot change user when server not running as root."); 1222 packet_disconnect("Cannot change user when server not running as root.");
1215 1223
1216 debug("Attempting authentication for %.100s.", user); 1224 debug("Attempting authentication for %.100s.", user);
1217 1225
1218 /* If the user has no password, accept authentication immediately. */ 1226 /* If the user has no password, accept authentication immediately. */
1219 if (options.password_authentication && 1227 if (options.password_authentication &&
1220#ifdef KRB4 1228#ifdef KRB4
1221 (!options.kerberos_authentication || options.kerberos_or_local_passwd) && 1229 (!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
1222#endif /* KRB4 */ 1230#endif /* KRB4 */
1223 auth_password(pw, "")) 1231 auth_password(pw, "")) {
1224 { 1232 /* Authentication with empty password succeeded. */
1225 /* Authentication with empty password succeeded. */ 1233 log("Login for user %s from %.100s, accepted without authentication.",
1226 debug("Login for user %.100s accepted without authentication.", user); 1234 pw->pw_name, get_remote_ipaddr());
1227 } else { 1235 } else {
1228 /* Loop until the user has been authenticated or the connection is closed, 1236 /* Loop until the user has been authenticated or the
1229 do_authloop() returns only if authentication is successfull */ 1237 connection is closed, do_authloop() returns only if
1230 do_authloop(pw); 1238 authentication is successfull */
1231 } 1239 do_authloop(pw);
1232 1240 }
1233 /* XXX log unified auth message */ 1241
1234 1242 /* Check if the user is logging in as root and root logins are disallowed. */
1235 /* Check if the user is logging in as root and root logins are disallowed. */ 1243 if (pw->pw_uid == 0 && !options.permit_root_login) {
1236 if (pw->pw_uid == 0 && !options.permit_root_login) 1244 if (forced_command)
1237 { 1245 log("Root login accepted for forced command.");
1238 if (forced_command) 1246 else
1239 log("Root login accepted for forced command."); 1247 packet_disconnect("ROOT LOGIN REFUSED FROM %.200s",
1240 else 1248 get_canonical_hostname());
1241 packet_disconnect("ROOT LOGIN REFUSED FROM %.200s", 1249 }
1242 get_canonical_hostname()); 1250 /* The user has been authenticated and accepted. */
1243 } 1251 packet_start(SSH_SMSG_SUCCESS);
1244 1252 packet_send();
1245 /* The user has been authenticated and accepted. */ 1253 packet_write_wait();
1246 packet_start(SSH_SMSG_SUCCESS); 1254
1247 packet_send(); 1255 /* Perform session preparation. */
1248 packet_write_wait(); 1256 do_authenticated(pw);
1249
1250 /* Perform session preparation. */
1251 do_authenticated(pw);
1252} 1257}
1253 1258
1254#define MAX_AUTH_FAILURES 5 1259#define AUTH_FAIL_MAX 6
1260#define AUTH_FAIL_LOG (AUTH_FAIL_MAX/2)
1261#define AUTH_FAIL_MSG "Too many authentication failures for %.100s"
1255 1262
1256/* read packets and try to authenticate local user *pw. 1263/*
1257 return if authentication is successfull */ 1264 * read packets and try to authenticate local user *pw.
1265 * return if authentication is successfull
1266 */
1258void 1267void
1259do_authloop(struct passwd *pw) 1268do_authloop(struct passwd * pw)
1260{ 1269{
1261 int authentication_failures = 0; 1270 int attempt = 0;
1262 unsigned int bits; 1271 unsigned int bits;
1263 BIGNUM *client_host_key_e, *client_host_key_n; 1272 BIGNUM *client_host_key_e, *client_host_key_n;
1264 BIGNUM *n; 1273 BIGNUM *n;
1265 char *client_user = NULL, *password = NULL; 1274 char *client_user = NULL, *password = NULL;
1266 int plen, dlen, nlen, ulen, elen; 1275 char user[1024];
1276 int plen, dlen, nlen, ulen, elen;
1277 int type = 0;
1278 void (*authlog) (const char *fmt,...) = verbose;
1267#ifdef HAVE_LIBPAM 1279#ifdef HAVE_LIBPAM
1268 int pam_retval; 1280 int pam_retval;
1269#endif /* HAVE_LIBPAM */ 1281#endif /* HAVE_LIBPAM */
1270 1282
1271 /* Indicate that authentication is needed. */ 1283 /* Indicate that authentication is needed. */
1272 packet_start(SSH_SMSG_FAILURE); 1284 packet_start(SSH_SMSG_FAILURE);
1273 packet_send(); 1285 packet_send();
1274 packet_write_wait(); 1286 packet_write_wait();
1275 1287
1276 for (;;) { 1288 for (attempt = 1;; attempt++) {
1277 int authenticated = 0; 1289 int authenticated = 0;
1290 strlcpy(user, "", sizeof user);
1278 1291
1279 /* Get a packet from the client. */ 1292 /* Get a packet from the client. */
1280 int type = packet_read(&plen); 1293 type = packet_read(&plen);
1281 1294
1282 /* Process the packet. */ 1295 /* Process the packet. */
1283 switch (type) 1296 switch (type) {
1284 {
1285#ifdef AFS 1297#ifdef AFS
1286 case SSH_CMSG_HAVE_KERBEROS_TGT: 1298 case SSH_CMSG_HAVE_KERBEROS_TGT:
1287 if (!options.kerberos_tgt_passing) 1299 if (!options.kerberos_tgt_passing) {
1288 { 1300 /* packet_get_all(); */
1289 /* packet_get_all(); */ 1301 verbose("Kerberos tgt passing disabled.");
1290 log("Kerberos tgt passing disabled."); 1302 break;
1291 break; 1303 } else {
1292 } 1304 /* Accept Kerberos tgt. */
1293 else { 1305 char *tgt = packet_get_string(&dlen);
1294 /* Accept Kerberos tgt. */ 1306 packet_integrity_check(plen, 4 + dlen, type);
1295 char *tgt = packet_get_string(&dlen); 1307 if (!auth_kerberos_tgt(pw, tgt))
1296 packet_integrity_check(plen, 4 + dlen, type); 1308 verbose("Kerberos tgt REFUSED for %s", pw->pw_name);
1297 if (!auth_kerberos_tgt(pw, tgt)) 1309 xfree(tgt);
1298 debug("Kerberos tgt REFUSED for %s", pw->pw_name); 1310 }
1299 xfree(tgt); 1311 continue;
1300 } 1312
1301 continue; 1313 case SSH_CMSG_HAVE_AFS_TOKEN:
1302 1314 if (!options.afs_token_passing || !k_hasafs()) {
1303 case SSH_CMSG_HAVE_AFS_TOKEN: 1315 /* packet_get_all(); */
1304 if (!options.afs_token_passing || !k_hasafs()) { 1316 verbose("AFS token passing disabled.");
1305 /* packet_get_all(); */ 1317 break;
1306 log("AFS token passing disabled."); 1318 } else {
1307 break; 1319 /* Accept AFS token. */
1308 } 1320 char *token_string = packet_get_string(&dlen);
1309 else { 1321 packet_integrity_check(plen, 4 + dlen, type);
1310 /* Accept AFS token. */ 1322 if (!auth_afs_token(pw, token_string))
1311 char *token_string = packet_get_string(&dlen); 1323 verbose("AFS token REFUSED for %s", pw->pw_name);
1312 packet_integrity_check(plen, 4 + dlen, type); 1324 xfree(token_string);
1313 if (!auth_afs_token(pw, token_string)) 1325 }
1314 debug("AFS token REFUSED for %s", pw->pw_name); 1326 continue;
1315 xfree(token_string);
1316 }
1317 continue;
1318#endif /* AFS */ 1327#endif /* AFS */
1319
1320#ifdef KRB4 1328#ifdef KRB4
1321 case SSH_CMSG_AUTH_KERBEROS: 1329 case SSH_CMSG_AUTH_KERBEROS:
1322 if (!options.kerberos_authentication) 1330 if (!options.kerberos_authentication) {
1323 { 1331 /* packet_get_all(); */
1324 /* packet_get_all(); */ 1332 verbose("Kerberos authentication disabled.");
1325 log("Kerberos authentication disabled."); 1333 break;
1326 break; 1334 } else {
1327 } 1335 /* Try Kerberos v4 authentication. */
1328 else { 1336 KTEXT_ST auth;
1329 /* Try Kerberos v4 authentication. */ 1337 char *tkt_user = NULL;
1330 KTEXT_ST auth; 1338 char *kdata = packet_get_string((unsigned int *) &auth.length);
1331 char *tkt_user = NULL; 1339 packet_integrity_check(plen, 4 + auth.length, type);
1332 char *kdata = packet_get_string((unsigned int *)&auth.length); 1340
1333 packet_integrity_check(plen, 4 + auth.length, type); 1341 if (auth.length < MAX_KTXT_LEN)
1334 1342 memcpy(auth.dat, kdata, auth.length);
1335 if (auth.length < MAX_KTXT_LEN) 1343 xfree(kdata);
1336 memcpy(auth.dat, kdata, auth.length); 1344
1337 xfree(kdata); 1345 authenticated = auth_krb4(pw->pw_name, &auth, &tkt_user);
1338 1346
1339 authenticated = auth_krb4(pw->pw_name, &auth, &tkt_user); 1347 if (authenticated) {
1340 1348 snprintf(user, sizeof user, " tktuser %s", tkt_user);
1341 log("Kerberos authentication %s%s for account %s from %s", 1349 xfree(tkt_user);
1342 authenticated ? "accepted " : "failed", 1350 }
1343 tkt_user != NULL ? tkt_user : "", 1351 }
1344 pw->pw_name, get_canonical_hostname()); 1352 break;
1345 if (authenticated)
1346 xfree(tkt_user);
1347 }
1348 break;
1349#endif /* KRB4 */ 1353#endif /* KRB4 */
1350 1354
1351 case SSH_CMSG_AUTH_RHOSTS: 1355 case SSH_CMSG_AUTH_RHOSTS:
1352 if (!options.rhosts_authentication) 1356 if (!options.rhosts_authentication) {
1353 { 1357 verbose("Rhosts authentication disabled.");
1354 log("Rhosts authentication disabled."); 1358 break;
1355 break; 1359 }
1356 } 1360 /* Get client user name. Note that we just have
1357 1361 to trust the client; this is one reason why
1358 /* Get client user name. Note that we just have to trust the client; 1362 rhosts authentication is insecure. (Another is
1359 this is one reason why rhosts authentication is insecure. 1363 IP-spoofing on a local network.) */
1360 (Another is IP-spoofing on a local network.) */ 1364 client_user = packet_get_string(&ulen);
1361 client_user = packet_get_string(&dlen); 1365 packet_integrity_check(plen, 4 + ulen, type);
1362 packet_integrity_check(plen, 4 + dlen, type); 1366
1363 1367 /* Try to authenticate using /etc/hosts.equiv and
1364 /* Try to authenticate using /etc/hosts.equiv and .rhosts. */ 1368 .rhosts. */
1365 authenticated = auth_rhosts(pw, client_user); 1369 authenticated = auth_rhosts(pw, client_user);
1366 1370
1367 log("Rhosts authentication %s for %.100s, remote %.100s on %.700s.", 1371 snprintf(user, sizeof user, " ruser %s", client_user);
1368 authenticated ? "accepted" : "failed",
1369 pw->pw_name, client_user, get_canonical_hostname());
1370#ifndef HAVE_LIBPAM 1372#ifndef HAVE_LIBPAM
1371 xfree(client_user); 1373 xfree(client_user);
1372#endif /* HAVE_LIBPAM */ 1374#endif /* HAVE_LIBPAM */
1373 break; 1375 break;
1374 1376
1375 case SSH_CMSG_AUTH_RHOSTS_RSA: 1377 case SSH_CMSG_AUTH_RHOSTS_RSA:
1376 if (!options.rhosts_rsa_authentication) 1378 if (!options.rhosts_rsa_authentication) {
1377 { 1379 verbose("Rhosts with RSA authentication disabled.");
1378 log("Rhosts with RSA authentication disabled."); 1380 break;
1379 break; 1381 }
1380 } 1382 /* Get client user name. Note that we just have
1381 1383 to trust the client; root on the client machine
1382 /* Get client user name. Note that we just have to trust 1384 can claim to be any user. */
1383 the client; root on the client machine can claim to be 1385 client_user = packet_get_string(&ulen);
1384 any user. */ 1386
1385 client_user = packet_get_string(&ulen); 1387 /* Get the client host key. */
1386 1388 client_host_key_e = BN_new();
1387 /* Get the client host key. */ 1389 client_host_key_n = BN_new();
1388 client_host_key_e = BN_new(); 1390 bits = packet_get_int();
1389 client_host_key_n = BN_new(); 1391 packet_get_bignum(client_host_key_e, &elen);
1390 bits = packet_get_int(); 1392 packet_get_bignum(client_host_key_n, &nlen);
1391 packet_get_bignum(client_host_key_e, &elen); 1393
1392 packet_get_bignum(client_host_key_n, &nlen); 1394 if (bits != BN_num_bits(client_host_key_n))
1393 1395 error("Warning: keysize mismatch for client_host_key: "
1394 if (bits != BN_num_bits(client_host_key_n)) 1396 "actual %d, announced %d", BN_num_bits(client_host_key_n), bits);
1395 error("Warning: keysize mismatch for client_host_key: " 1397 packet_integrity_check(plen, (4 + ulen) + 4 + elen + nlen, type);
1396 "actual %d, announced %d", BN_num_bits(client_host_key_n), bits); 1398
1397 packet_integrity_check(plen, (4 + ulen) + 4 + elen + nlen, type); 1399 authenticated = auth_rhosts_rsa(pw, client_user,
1398 1400 client_host_key_e, client_host_key_n);
1399 authenticated = auth_rhosts_rsa(pw, client_user, 1401 BN_clear_free(client_host_key_e);
1400 client_host_key_e, client_host_key_n); 1402 BN_clear_free(client_host_key_n);
1401 log("Rhosts authentication %s for %.100s, remote %.100s.", 1403
1402 authenticated ? "accepted" : "failed", 1404 snprintf(user, sizeof user, " ruser %s", client_user);
1403 pw->pw_name, client_user);
1404#ifndef HAVE_LIBPAM 1405#ifndef HAVE_LIBPAM
1405 xfree(client_user); 1406 xfree(client_user);
1406#endif /* HAVE_LIBPAM */ 1407#endif /* HAVE_LIBPAM */
1407 BN_clear_free(client_host_key_e); 1408 break;
1408 BN_clear_free(client_host_key_n); 1409
1409 break; 1410 case SSH_CMSG_AUTH_RSA:
1410 1411 if (!options.rsa_authentication) {
1411 case SSH_CMSG_AUTH_RSA: 1412 verbose("RSA authentication disabled.");
1412 if (!options.rsa_authentication) 1413 break;
1413 { 1414 }
1414 log("RSA authentication disabled."); 1415 /* RSA authentication requested. */
1415 break; 1416 n = BN_new();
1416 } 1417 packet_get_bignum(n, &nlen);
1417 1418 packet_integrity_check(plen, nlen, type);
1418 /* RSA authentication requested. */ 1419 authenticated = auth_rsa(pw, n);
1419 n = BN_new(); 1420 BN_clear_free(n);
1420 packet_get_bignum(n, &nlen); 1421 break;
1421 packet_integrity_check(plen, nlen, type); 1422
1422 1423 case SSH_CMSG_AUTH_PASSWORD:
1423 authenticated = auth_rsa(pw, n); 1424 if (!options.password_authentication) {
1424 log("RSA authentication %s for %.100s.", 1425 verbose("Password authentication disabled.");
1425 authenticated ? "accepted" : "failed", 1426 break;
1426 pw->pw_name); 1427 }
1427 BN_clear_free(n); 1428 /* Read user password. It is in plain text, but
1428 break; 1429 was transmitted over the encrypted channel so
1429 1430 it is not visible to an outside observer. */
1430 case SSH_CMSG_AUTH_PASSWORD: 1431 password = packet_get_string(&dlen);
1431 if (!options.password_authentication) 1432 packet_integrity_check(plen, 4 + dlen, type);
1432 { 1433
1433 log("Password authentication disabled.");
1434 break;
1435 }
1436
1437 /* Read user password. It is in plain text, but was transmitted
1438 over the encrypted channel so it is not visible to an outside
1439 observer. */
1440 password = packet_get_string(&dlen);
1441 packet_integrity_check(plen, 4 + dlen, type);
1442
1443#ifdef HAVE_LIBPAM 1434#ifdef HAVE_LIBPAM
1444 /* Do PAM auth with password */ 1435 /* Do PAM auth with password */
1445 pampasswd = password; 1436 pampasswd = password;
1446 pam_retval = pam_authenticate((pam_handle_t *)pamh, 0); 1437 pam_retval = pam_authenticate((pam_handle_t *)pamh, 0);
1447 if (pam_retval == PAM_SUCCESS) 1438 if (pam_retval == PAM_SUCCESS) {
1448 { 1439 log("PAM Password authentication accepted for user \"%.100s\"", pw->pw_name);
1449 log("PAM Password authentication accepted for user \"%.100s\"", pw->pw_name); 1440 authenticated = 1;
1450 authenticated = 1; 1441 break;
1451 break; 1442 }
1452 } 1443
1453 1444 log("PAM Password authentication for \"%.100s\" failed: %s",
1454 log("PAM Password authentication for \"%.100s\" failed: %s", 1445 pw->pw_name, PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
1455 pw->pw_name, PAM_STRERROR((pam_handle_t *)pamh, pam_retval)); 1446 break;
1456 break;
1457#else /* HAVE_LIBPAM */ 1447#else /* HAVE_LIBPAM */
1458 /* Try authentication with the password. */ 1448 /* Try authentication with the password. */
1459 authenticated = auth_password(pw, password); 1449 authenticated = auth_password(pw, password);
1460 log("Password authentication %s for %.100s.", 1450
1461 authenticated ? "accepted" : "failed", 1451 memset(password, 0, strlen(password));
1462 pw->pw_name); 1452 xfree(password);
1463 1453 break;
1464 memset(password, 0, strlen(password));
1465 xfree(password);
1466 break;
1467#endif /* HAVE_LIBPAM */ 1454#endif /* HAVE_LIBPAM */
1468 1455
1469 case SSH_CMSG_AUTH_TIS: 1456#ifdef SKEY
1470 /* TIS Authentication is unsupported */ 1457 case SSH_CMSG_AUTH_TIS:
1471 log("TIS authentication disabled."); 1458 debug("rcvd SSH_CMSG_AUTH_TIS");
1472 break; 1459 if (options.skey_authentication == 1) {
1473 1460 char *skeyinfo = skey_keyinfo(pw->pw_name);
1474 default: 1461 if (skeyinfo == NULL) {
1475 /* Any unknown messages will be ignored (and failure returned) 1462 debug("generating fake skeyinfo for %.100s.", pw->pw_name);
1476 during authentication. */ 1463 skeyinfo = skey_fake_keyinfo(pw->pw_name);
1477 log("Unknown message during authentication: type %d", type); 1464 }
1478 break; /* Respond with a failure message. */ 1465 if (skeyinfo != NULL) {
1479 } 1466 /* we send our s/key- in
1480 1467 tis-challenge messages */
1481 if (authenticated) 1468 debug("sending challenge '%s'", skeyinfo);
1482 break; 1469 packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
1483 if (++authentication_failures >= MAX_AUTH_FAILURES) 1470 packet_put_string(skeyinfo, strlen(skeyinfo));
1484 packet_disconnect("Too many authentication failures for %.100s from %.200s", 1471 packet_send();
1485 pw->pw_name, get_canonical_hostname()); 1472 packet_write_wait();
1486 /* Send a message indicating that the authentication attempt failed. */ 1473 continue;
1487 packet_start(SSH_SMSG_FAILURE); 1474 }
1488 packet_send(); 1475 }
1489 packet_write_wait(); 1476 break;
1490 } 1477 case SSH_CMSG_AUTH_TIS_RESPONSE:
1478 debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE");
1479 if (options.skey_authentication == 1) {
1480 char *response = packet_get_string(&dlen);
1481 debug("skey response == '%s'", response);
1482 packet_integrity_check(plen, 4 + dlen, type);
1483 authenticated = (skey_haskey(pw->pw_name) == 0 &&
1484 skey_passcheck(pw->pw_name, response) != -1);
1485 xfree(response);
1486 }
1487 break;
1488#else
1489 case SSH_CMSG_AUTH_TIS:
1490 /* TIS Authentication is unsupported */
1491 log("TIS authentication unsupported.");
1492 break;
1493#endif
1494
1495 default:
1496 /* Any unknown messages will be ignored (and
1497 failure returned) during authentication. */
1498 log("Unknown message during authentication: type %d", type);
1499 break;
1500 }
1501
1502 /* Raise logging level */
1503 if (authenticated ||
1504 attempt == AUTH_FAIL_LOG ||
1505 type == SSH_CMSG_AUTH_PASSWORD)
1506 authlog = log;
1507
1508 authlog("%s %s for %.200s from %.200s port %d%s",
1509 authenticated ? "Accepted" : "Failed",
1510 get_authname(type),
1511 pw->pw_uid == 0 ? "ROOT" : pw->pw_name,
1512 get_remote_ipaddr(),
1513 get_remote_port(),
1514 user);
1491 1515
1492#ifdef HAVE_LIBPAM 1516#ifdef HAVE_LIBPAM
1493 do_pam_account_and_session(pw->pw_name, client_user, get_canonical_hostname()); 1517 do_pam_account_and_session(pw->pw_name, client_user,
1518 get_canonical_hostname());
1494 1519
1495 /* Clean up */ 1520 /* Clean up */
1496 if (client_user != NULL) 1521 if (client_user != NULL)
1497 xfree(client_user); 1522 xfree(client_user);
1498 1523
1499 if (password != NULL) 1524 if (password != NULL) {
1500 { 1525 memset(password, 0, strlen(password));
1501 memset(password, 0, strlen(password)); 1526 xfree(password);
1502 xfree(password); 1527 }
1503 }
1504#endif /* HAVE_LIBPAM */ 1528#endif /* HAVE_LIBPAM */
1529
1530 if (authenticated)
1531 return;
1532
1533 if (attempt > AUTH_FAIL_MAX)
1534 packet_disconnect(AUTH_FAIL_MSG, pw->pw_name);
1535
1536 /* Send a message indicating that the authentication attempt failed. */
1537 packet_start(SSH_SMSG_FAILURE);
1538 packet_send();
1539 packet_write_wait();
1540 }
1505} 1541}
1506 1542
1507/* The user does not exist or access is denied, 1543/*
1508 but fake indication that authentication is needed. */ 1544 * The user does not exist or access is denied,
1545 * but fake indication that authentication is needed.
1546 */
1509void 1547void
1510do_fake_authloop(char *user) 1548do_fake_authloop(char *user)
1511{ 1549{
1512 int authentication_failures = 0; 1550 int attempt = 0;
1513 1551
1514 /* Indicate that authentication is needed. */ 1552 log("Faking authloop for illegal user %.200s from %.200s port %d",
1515 packet_start(SSH_SMSG_FAILURE); 1553 user,
1516 packet_send(); 1554 get_remote_ipaddr(),
1517 packet_write_wait(); 1555 get_remote_port());
1518 1556
1519 /* Keep reading packets, and always respond with a failure. This is to 1557 /* Indicate that authentication is needed. */
1520 avoid disclosing whether such a user really exists. */ 1558 packet_start(SSH_SMSG_FAILURE);
1521 for (;;) 1559 packet_send();
1522 { 1560 packet_write_wait();
1523 /* Read a packet. This will not return if the client disconnects. */ 1561
1524 int plen; 1562 /* Keep reading packets, and always respond with a failure. This
1525 int type = packet_read(&plen); 1563 is to avoid disclosing whether such a user really exists. */
1564 for (attempt = 1;; attempt++) {
1565 /* Read a packet. This will not return if the client
1566 disconnects. */
1567 int plen;
1568 int type = packet_read(&plen);
1526#ifdef SKEY 1569#ifdef SKEY
1527 int passw_len; 1570 int dlen;
1528 char *password, *skeyinfo; 1571 char *password, *skeyinfo;
1529 if (options.password_authentication && 1572 if (options.password_authentication &&
1530 options.skey_authentication == 1 && 1573 options.skey_authentication == 1 &&
1531 type == SSH_CMSG_AUTH_PASSWORD && 1574 type == SSH_CMSG_AUTH_PASSWORD &&
1532 (password = packet_get_string(&passw_len)) != NULL && 1575 (password = packet_get_string(&dlen)) != NULL &&
1533 passw_len == 5 && 1576 dlen == 5 &&
1534 strncasecmp(password, "s/key", 5) == 0 && 1577 strncasecmp(password, "s/key", 5) == 0 &&
1535 (skeyinfo = skey_fake_keyinfo(user)) != NULL ){ 1578 (skeyinfo = skey_fake_keyinfo(user)) != NULL) {
1536 /* Send a fake s/key challenge. */ 1579 /* Send a fake s/key challenge. */
1537 packet_send_debug(skeyinfo); 1580 packet_send_debug(skeyinfo);
1538 } 1581 }
1539#endif 1582#endif
1540 if (++authentication_failures >= MAX_AUTH_FAILURES) 1583 if (attempt > AUTH_FAIL_MAX)
1541 packet_disconnect("Too many authentication failures for %.100s from %.200s", 1584 packet_disconnect(AUTH_FAIL_MSG, user);
1542 user, get_canonical_hostname()); 1585
1543 /* Send failure. This should be indistinguishable from a failed 1586 /* Send failure. This should be indistinguishable from a
1544 authentication. */ 1587 failed authentication. */
1545 packet_start(SSH_SMSG_FAILURE); 1588 packet_start(SSH_SMSG_FAILURE);
1546 packet_send(); 1589 packet_send();
1547 packet_write_wait(); 1590 packet_write_wait();
1548 } 1591 }
1549 /*NOTREACHED*/ 1592 /* NOTREACHED */
1550 abort(); 1593 abort();
1551} 1594}
1552 1595
1553 1596
1554/* Remove local Xauthority file. */ 1597/*
1598 * Remove local Xauthority file.
1599 */
1555static void 1600static void
1556xauthfile_cleanup_proc(void *ignore) 1601xauthfile_cleanup_proc(void *ignore)
1557{ 1602{
1558 debug("xauthfile_cleanup_proc called"); 1603 debug("xauthfile_cleanup_proc called");
1559 1604
1560 if (xauthfile != NULL) { 1605 if (xauthfile != NULL) {
1561 unlink(xauthfile); 1606 unlink(xauthfile);
1562 xfree(xauthfile); 1607 xfree(xauthfile);
1563 xauthfile = NULL; 1608 xauthfile = NULL;
1564 } 1609 }
1565} 1610}
1566 1611
1567/* Prepares for an interactive session. This is called after the user has 1612/*
1568 been successfully authenticated. During this message exchange, pseudo 1613 * Prepares for an interactive session. This is called after the user has
1569 terminals are allocated, X11, TCP/IP, and authentication agent forwardings 1614 * been successfully authenticated. During this message exchange, pseudo
1570 are requested, etc. */ 1615 * terminals are allocated, X11, TCP/IP, and authentication agent forwardings
1571 1616 * are requested, etc.
1572void do_authenticated(struct passwd *pw) 1617 */
1618void
1619do_authenticated(struct passwd * pw)
1573{ 1620{
1574 int type; 1621 int type;
1575 int compression_level = 0, enable_compression_after_reply = 0; 1622 int compression_level = 0, enable_compression_after_reply = 0;
1576 int have_pty = 0, ptyfd = -1, ttyfd = -1, xauthfd = -1; 1623 int have_pty = 0, ptyfd = -1, ttyfd = -1, xauthfd = -1;
1577 int row, col, xpixel, ypixel, screen; 1624 int row, col, xpixel, ypixel, screen;
1578 char ttyname[64]; 1625 char ttyname[64];
1579 char *command, *term = NULL, *display = NULL, *proto = NULL, *data = NULL; 1626 char *command, *term = NULL, *display = NULL, *proto = NULL,
1580 struct group *grp; 1627 *data = NULL;
1581 gid_t tty_gid; 1628 struct group *grp;
1582 mode_t tty_mode; 1629 gid_t tty_gid;
1583 int n_bytes; 1630 mode_t tty_mode;
1584 1631 int n_bytes;
1585 /* Cancel the alarm we set to limit the time taken for authentication. */ 1632
1586 alarm(0); 1633 /* Cancel the alarm we set to limit the time taken for
1587 1634 authentication. */
1588 /* Inform the channel mechanism that we are the server side and that 1635 alarm(0);
1589 the client may request to connect to any port at all. (The user could 1636
1590 do it anyway, and we wouldn\'t know what is permitted except by the 1637 /* Inform the channel mechanism that we are the server side and
1591 client telling us, so we can equally well trust the client not to request 1638 that the client may request to connect to any port at all.
1592 anything bogus.) */ 1639 (The user could do it anyway, and we wouldn\'t know what is
1593 channel_permit_all_opens(); 1640 permitted except by the client telling us, so we can equally
1594 1641 well trust the client not to request anything bogus.) */
1595 /* We stay in this loop until the client requests to execute a shell or a 1642 channel_permit_all_opens();
1596 command. */ 1643
1597 while (1) 1644 /* We stay in this loop until the client requests to execute a
1598 { 1645 shell or a command. */
1599 int plen, dlen; 1646 while (1) {
1600 1647 int plen, dlen;
1601 /* Get a packet from the client. */ 1648
1602 type = packet_read(&plen); 1649 /* Get a packet from the client. */
1603 1650 type = packet_read(&plen);
1604 /* Process the packet. */ 1651
1605 switch (type) 1652 /* Process the packet. */
1606 { 1653 switch (type) {
1607 case SSH_CMSG_REQUEST_COMPRESSION: 1654 case SSH_CMSG_REQUEST_COMPRESSION:
1608 packet_integrity_check(plen, 4, type); 1655 packet_integrity_check(plen, 4, type);
1609 compression_level = packet_get_int(); 1656 compression_level = packet_get_int();
1610 if (compression_level < 1 || compression_level > 9) 1657 if (compression_level < 1 || compression_level > 9) {
1611 { 1658 packet_send_debug("Received illegal compression level %d.",
1612 packet_send_debug("Received illegal compression level %d.", 1659 compression_level);
1613 compression_level); 1660 goto fail;
1614 goto fail; 1661 }
1615 } 1662 /* Enable compression after we have responded with SUCCESS. */
1616 /* Enable compression after we have responded with SUCCESS. */ 1663 enable_compression_after_reply = 1;
1617 enable_compression_after_reply = 1; 1664 break;
1618 break; 1665
1619 1666 case SSH_CMSG_REQUEST_PTY:
1620 case SSH_CMSG_REQUEST_PTY: 1667 if (no_pty_flag) {
1621 if (no_pty_flag) 1668 debug("Allocating a pty not permitted for this authentication.");
1622 { 1669 goto fail;
1623 debug("Allocating a pty not permitted for this authentication."); 1670 }
1624 goto fail; 1671 if (have_pty)
1625 } 1672 packet_disconnect("Protocol error: you already have a pty.");
1626 if (have_pty) 1673
1627 packet_disconnect("Protocol error: you already have a pty."); 1674 debug("Allocating pty.");
1628 1675
1629 debug("Allocating pty."); 1676 /* Allocate a pty and open it. */
1630 1677 if (!pty_allocate(&ptyfd, &ttyfd, ttyname)) {
1631 /* Allocate a pty and open it. */ 1678 error("Failed to allocate pty.");
1632 if (!pty_allocate(&ptyfd, &ttyfd, ttyname)) 1679 goto fail;
1633 { 1680 }
1634 error("Failed to allocate pty."); 1681 /* Determine the group to make the owner of the tty. */
1635 goto fail; 1682 grp = getgrnam("tty");
1636 } 1683 if (grp) {
1637 1684 tty_gid = grp->gr_gid;
1638 /* Determine the group to make the owner of the tty. */ 1685 tty_mode = S_IRUSR | S_IWUSR | S_IWGRP;
1639 grp = getgrnam("tty"); 1686 } else {
1640 if (grp) 1687 tty_gid = pw->pw_gid;
1641 { 1688 tty_mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH;
1642 tty_gid = grp->gr_gid; 1689 }
1643 tty_mode = S_IRUSR|S_IWUSR|S_IWGRP; 1690
1644 } 1691 /* Change ownership of the tty. */
1645 else 1692 if (chown(ttyname, pw->pw_uid, tty_gid) < 0)
1646 { 1693 fatal("chown(%.100s, %d, %d) failed: %.100s",
1647 tty_gid = pw->pw_gid; 1694 ttyname, pw->pw_uid, tty_gid, strerror(errno));
1648 tty_mode = S_IRUSR|S_IWUSR|S_IWGRP|S_IWOTH; 1695 if (chmod(ttyname, tty_mode) < 0)
1649 } 1696 fatal("chmod(%.100s, 0%o) failed: %.100s",
1650 1697 ttyname, tty_mode, strerror(errno));
1651 /* Change ownership of the tty. */ 1698
1652 if (chown(ttyname, pw->pw_uid, tty_gid) < 0) 1699 /* Get TERM from the packet. Note that the value may be of arbitrary length. */
1653 fatal("chown(%.100s, %d, %d) failed: %.100s", 1700 term = packet_get_string(&dlen);
1654 ttyname, pw->pw_uid, tty_gid, strerror(errno)); 1701 packet_integrity_check(dlen, strlen(term), type);
1655 if (chmod(ttyname, tty_mode) < 0) 1702 /* packet_integrity_check(plen, 4 + dlen + 4*4 + n_bytes, type); */
1656 fatal("chmod(%.100s, 0%o) failed: %.100s", 1703 /* Remaining bytes */
1657 ttyname, tty_mode, strerror(errno)); 1704 n_bytes = plen - (4 + dlen + 4 * 4);
1658 1705
1659 /* Get TERM from the packet. Note that the value may be of arbitrary 1706 if (strcmp(term, "") == 0)
1660 length. */ 1707 term = NULL;
1661 1708
1662 term = packet_get_string(&dlen); 1709 /* Get window size from the packet. */
1663 packet_integrity_check(dlen, strlen(term), type); 1710 row = packet_get_int();
1664 /* packet_integrity_check(plen, 4 + dlen + 4*4 + n_bytes, type); */ 1711 col = packet_get_int();
1665 /* Remaining bytes */ 1712 xpixel = packet_get_int();
1666 n_bytes = plen - (4 + dlen + 4*4); 1713 ypixel = packet_get_int();
1667 1714 pty_change_window_size(ptyfd, row, col, xpixel, ypixel);
1668 if (strcmp(term, "") == 0) 1715
1669 term = NULL; 1716 /* Get tty modes from the packet. */
1670 1717 tty_parse_modes(ttyfd, &n_bytes);
1671 /* Get window size from the packet. */ 1718 packet_integrity_check(plen, 4 + dlen + 4 * 4 + n_bytes, type);
1672 row = packet_get_int(); 1719
1673 col = packet_get_int(); 1720 /* Indicate that we now have a pty. */
1674 xpixel = packet_get_int(); 1721 have_pty = 1;
1675 ypixel = packet_get_int(); 1722 break;
1676 pty_change_window_size(ptyfd, row, col, xpixel, ypixel); 1723
1677 1724 case SSH_CMSG_X11_REQUEST_FORWARDING:
1678 /* Get tty modes from the packet. */ 1725 if (!options.x11_forwarding) {
1679 tty_parse_modes(ttyfd, &n_bytes); 1726 packet_send_debug("X11 forwarding disabled in server configuration file.");
1680 packet_integrity_check(plen, 4 + dlen + 4*4 + n_bytes, type); 1727 goto fail;
1681 1728 }
1682 /* Indicate that we now have a pty. */
1683 have_pty = 1;
1684 break;
1685
1686 case SSH_CMSG_X11_REQUEST_FORWARDING:
1687 if (!options.x11_forwarding)
1688 {
1689 packet_send_debug("X11 forwarding disabled in server configuration file.");
1690 goto fail;
1691 }
1692#ifdef XAUTH_PATH 1729#ifdef XAUTH_PATH
1693 if (no_x11_forwarding_flag) 1730 if (no_x11_forwarding_flag) {
1694 { 1731 packet_send_debug("X11 forwarding not permitted for this authentication.");
1695 packet_send_debug("X11 forwarding not permitted for this authentication."); 1732 goto fail;
1696 goto fail; 1733 }
1697 } 1734 debug("Received request for X11 forwarding with auth spoofing.");
1698 debug("Received request for X11 forwarding with auth spoofing."); 1735 if (display)
1699 if (display) 1736 packet_disconnect("Protocol error: X11 display already set.");
1700 packet_disconnect("Protocol error: X11 display already set."); 1737 {
1701 { 1738 int proto_len, data_len;
1702 int proto_len, data_len; 1739 proto = packet_get_string(&proto_len);
1703 proto = packet_get_string(&proto_len); 1740 data = packet_get_string(&data_len);
1704 data = packet_get_string(&data_len); 1741 packet_integrity_check(plen, 4 + proto_len + 4 + data_len + 4, type);
1705 packet_integrity_check(plen, 4+proto_len + 4+data_len + 4, type); 1742 }
1706 } 1743 if (packet_get_protocol_flags() & SSH_PROTOFLAG_SCREEN_NUMBER)
1707 if (packet_get_protocol_flags() & SSH_PROTOFLAG_SCREEN_NUMBER) 1744 screen = packet_get_int();
1708 screen = packet_get_int(); 1745 else
1709 else 1746 screen = 0;
1710 screen = 0; 1747 display = x11_create_display_inet(screen);
1711 display = x11_create_display_inet(screen); 1748 if (!display)
1712 if (!display) 1749 goto fail;
1713 goto fail; 1750
1714 1751 /* Setup to always have a local .Xauthority. */
1715 /* Setup to always have a local .Xauthority. */ 1752 xauthfile = xmalloc(MAXPATHLEN);
1716 xauthfile = xmalloc(MAXPATHLEN); 1753 snprintf(xauthfile, MAXPATHLEN, "/tmp/XauthXXXXXX");
1717 snprintf(xauthfile, MAXPATHLEN, "/tmp/XauthXXXXXX"); 1754
1718 1755 if ((xauthfd = mkstemp(xauthfile)) != -1) {
1719 if ((xauthfd = mkstemp(xauthfile)) != -1) { 1756 fchown(xauthfd, pw->pw_uid, pw->pw_gid);
1720 fchown(xauthfd, pw->pw_uid, pw->pw_gid); 1757 close(xauthfd);
1721 close(xauthfd); 1758 fatal_add_cleanup(xauthfile_cleanup_proc, NULL);
1722 fatal_add_cleanup(xauthfile_cleanup_proc, NULL); 1759 } else {
1723 } 1760 xfree(xauthfile);
1724 else { 1761 xauthfile = NULL;
1725 xfree(xauthfile); 1762 }
1726 xauthfile = NULL; 1763 break;
1727 }
1728 break;
1729#else /* XAUTH_PATH */ 1764#else /* XAUTH_PATH */
1730 /* No xauth program; we won't accept forwarding with spoofing. */ 1765 packet_send_debug("No xauth program; cannot forward with spoofing.");
1731 packet_send_debug("No xauth program; cannot forward with spoofing."); 1766 goto fail;
1732 goto fail;
1733#endif /* XAUTH_PATH */ 1767#endif /* XAUTH_PATH */
1734 1768
1735 case SSH_CMSG_AGENT_REQUEST_FORWARDING: 1769 case SSH_CMSG_AGENT_REQUEST_FORWARDING:
1736 if (no_agent_forwarding_flag) 1770 if (no_agent_forwarding_flag) {
1737 { 1771 debug("Authentication agent forwarding not permitted for this authentication.");
1738 debug("Authentication agent forwarding not permitted for this authentication."); 1772 goto fail;
1739 goto fail; 1773 }
1740 } 1774 debug("Received authentication agent forwarding request.");
1741 debug("Received authentication agent forwarding request."); 1775 auth_input_request_forwarding(pw);
1742 auth_input_request_forwarding(pw); 1776 break;
1743 break; 1777
1744 1778 case SSH_CMSG_PORT_FORWARD_REQUEST:
1745 case SSH_CMSG_PORT_FORWARD_REQUEST: 1779 if (no_port_forwarding_flag) {
1746 if (no_port_forwarding_flag) 1780 debug("Port forwarding not permitted for this authentication.");
1747 { 1781 goto fail;
1748 debug("Port forwarding not permitted for this authentication."); 1782 }
1749 goto fail; 1783 debug("Received TCP/IP port forwarding request.");
1750 } 1784 channel_input_port_forward_request(pw->pw_uid == 0);
1751 debug("Received TCP/IP port forwarding request."); 1785 break;
1752 channel_input_port_forward_request(pw->pw_uid == 0); 1786
1753 break; 1787 case SSH_CMSG_MAX_PACKET_SIZE:
1754 1788 if (packet_set_maxsize(packet_get_int()) < 0)
1755 case SSH_CMSG_MAX_PACKET_SIZE: 1789 goto fail;
1756 if (packet_set_maxsize(packet_get_int()) < 0) 1790 break;
1757 goto fail; 1791
1758 break; 1792 case SSH_CMSG_EXEC_SHELL:
1759 1793 /* Set interactive/non-interactive mode. */
1760 case SSH_CMSG_EXEC_SHELL: 1794 packet_set_interactive(have_pty || display != NULL,
1761 /* Set interactive/non-interactive mode. */ 1795 options.keepalives);
1762 packet_set_interactive(have_pty || display != NULL, 1796
1763 options.keepalives); 1797 if (forced_command != NULL)
1764 1798 goto do_forced_command;
1765 if (forced_command != NULL) 1799 debug("Forking shell.");
1766 goto do_forced_command; 1800 packet_integrity_check(plen, 0, type);
1767 debug("Forking shell."); 1801 if (have_pty)
1768 packet_integrity_check(plen, 0, type); 1802 do_exec_pty(NULL, ptyfd, ttyfd, ttyname, pw, term, display, proto, data);
1769 if (have_pty) 1803 else
1770 do_exec_pty(NULL, ptyfd, ttyfd, ttyname, pw, term, display, proto, 1804 do_exec_no_pty(NULL, pw, display, proto, data);
1771 data); 1805 return;
1772 else 1806
1773 do_exec_no_pty(NULL, pw, display, proto, data); 1807 case SSH_CMSG_EXEC_CMD:
1774 return; 1808 /* Set interactive/non-interactive mode. */
1775 1809 packet_set_interactive(have_pty || display != NULL,
1776 case SSH_CMSG_EXEC_CMD: 1810 options.keepalives);
1777 /* Set interactive/non-interactive mode. */ 1811
1778 packet_set_interactive(have_pty || display != NULL, 1812 if (forced_command != NULL)
1779 options.keepalives); 1813 goto do_forced_command;
1780 1814 /* Get command from the packet. */
1781 if (forced_command != NULL) 1815 {
1782 goto do_forced_command; 1816 int dlen;
1783 /* Get command from the packet. */ 1817 command = packet_get_string(&dlen);
1784 { 1818 debug("Executing command '%.500s'", command);
1785 int dlen; 1819 packet_integrity_check(plen, 4 + dlen, type);
1786 command = packet_get_string(&dlen); 1820 }
1787 debug("Executing command '%.500s'", command); 1821 if (have_pty)
1788 packet_integrity_check(plen, 4 + dlen, type); 1822 do_exec_pty(command, ptyfd, ttyfd, ttyname, pw, term, display, proto, data);
1789 } 1823 else
1790 if (have_pty) 1824 do_exec_no_pty(command, pw, display, proto, data);
1791 do_exec_pty(command, ptyfd, ttyfd, ttyname, pw, term, display, 1825 xfree(command);
1792 proto, data); 1826 return;
1793 else 1827
1794 do_exec_no_pty(command, pw, display, proto, data); 1828 default:
1795 xfree(command); 1829 /* Any unknown messages in this phase are ignored,
1796 return; 1830 and a failure message is returned. */
1797 1831 log("Unknown packet type received after authentication: %d", type);
1798 default: 1832 goto fail;
1799 /* Any unknown messages in this phase are ignored, and a failure 1833 }
1800 message is returned. */
1801 log("Unknown packet type received after authentication: %d", type);
1802 goto fail;
1803 }
1804 1834
1805 /* The request was successfully processed. */ 1835 /* The request was successfully processed. */
1806 packet_start(SSH_SMSG_SUCCESS); 1836 packet_start(SSH_SMSG_SUCCESS);
1807 packet_send(); 1837 packet_send();
1808 packet_write_wait(); 1838 packet_write_wait();
1809 1839
1810 /* Enable compression now that we have replied if appropriate. */ 1840 /* Enable compression now that we have replied if appropriate. */
1811 if (enable_compression_after_reply) 1841 if (enable_compression_after_reply) {
1812 { 1842 enable_compression_after_reply = 0;
1813 enable_compression_after_reply = 0; 1843 packet_start_compression(compression_level);
1814 packet_start_compression(compression_level); 1844 }
1815 } 1845 continue;
1816 1846
1817 continue; 1847fail:
1818 1848 /* The request failed. */
1819 fail: 1849 packet_start(SSH_SMSG_FAILURE);
1820 /* The request failed. */ 1850 packet_send();
1821 packet_start(SSH_SMSG_FAILURE); 1851 packet_write_wait();
1822 packet_send(); 1852 continue;
1823 packet_write_wait();
1824 continue;
1825
1826 do_forced_command:
1827 /* There is a forced command specified for this login. Execute it. */
1828 debug("Executing forced command: %.900s", forced_command);
1829 if (have_pty)
1830 do_exec_pty(forced_command, ptyfd, ttyfd, ttyname, pw, term, display,
1831 proto, data);
1832 else
1833 do_exec_no_pty(forced_command, pw, display, proto, data);
1834 return;
1835 }
1836}
1837 1853
1838/* This is called to fork and execute a command when we have no tty. This 1854do_forced_command:
1839 will call do_child from the child, and server_loop from the parent after 1855 /* There is a forced command specified for this login.
1840 setting up file descriptors and such. */ 1856 Execute it. */
1857 debug("Executing forced command: %.900s", forced_command);
1858 if (have_pty)
1859 do_exec_pty(forced_command, ptyfd, ttyfd, ttyname, pw, term, display, proto, data);
1860 else
1861 do_exec_no_pty(forced_command, pw, display, proto, data);
1862 return;
1863 }
1864}
1841 1865
1842void do_exec_no_pty(const char *command, struct passwd *pw, 1866/*
1843 const char *display, const char *auth_proto, 1867 * This is called to fork and execute a command when we have no tty. This
1844 const char *auth_data) 1868 * will call do_child from the child, and server_loop from the parent after
1845{ 1869 * setting up file descriptors and such.
1846 int pid; 1870 */
1871void
1872do_exec_no_pty(const char *command, struct passwd * pw,
1873 const char *display, const char *auth_proto,
1874 const char *auth_data)
1875{
1876 int pid;
1847 1877
1848#ifdef USE_PIPES 1878#ifdef USE_PIPES
1849 int pin[2], pout[2], perr[2]; 1879 int pin[2], pout[2], perr[2];
1850 /* Allocate pipes for communicating with the program. */ 1880 /* Allocate pipes for communicating with the program. */
1851 if (pipe(pin) < 0 || pipe(pout) < 0 || pipe(perr) < 0) 1881 if (pipe(pin) < 0 || pipe(pout) < 0 || pipe(perr) < 0)
1852 packet_disconnect("Could not create pipes: %.100s", 1882 packet_disconnect("Could not create pipes: %.100s",
1853 strerror(errno)); 1883 strerror(errno));
1854#else /* USE_PIPES */ 1884#else /* USE_PIPES */
1855 int inout[2], err[2]; 1885 int inout[2], err[2];
1856 /* Uses socket pairs to communicate with the program. */ 1886 /* Uses socket pairs to communicate with the program. */
1857 if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0 || 1887 if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0 ||
1858 socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0) 1888 socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0)
1859 packet_disconnect("Could not create socket pairs: %.100s", 1889 packet_disconnect("Could not create socket pairs: %.100s",
1860 strerror(errno)); 1890 strerror(errno));
1861#endif /* USE_PIPES */ 1891#endif /* USE_PIPES */
1862
1863 setproctitle("%s@notty", pw->pw_name);
1864 1892
1865 /* Fork the child. */ 1893 setproctitle("%s@notty", pw->pw_name);
1866 if ((pid = fork()) == 0)
1867 {
1868 /* Child. Reinitialize the log since the pid has changed. */
1869 log_init(av0, options.log_level, options.log_facility, log_stderr);
1870 1894
1871 /* Create a new session and process group since the 4.4BSD setlogin() 1895 /* Fork the child. */
1872 affects the entire process group. */ 1896 if ((pid = fork()) == 0) {
1873 if (setsid() < 0) 1897 /* Child. Reinitialize the log since the pid has changed. */
1874 error("setsid failed: %.100s", strerror(errno)); 1898 log_init(av0, options.log_level, options.log_facility, log_stderr);
1899
1900 /* Create a new session and process group since the 4.4BSD
1901 setlogin() affects the entire process group. */
1902 if (setsid() < 0)
1903 error("setsid failed: %.100s", strerror(errno));
1875 1904
1876#ifdef USE_PIPES 1905#ifdef USE_PIPES
1877 /* Redirect stdin. We close the parent side of the socket pair, 1906 /* Redirect stdin. We close the parent side of the socket
1878 and make the child side the standard input. */ 1907 pair, and make the child side the standard input. */
1879 close(pin[1]); 1908 close(pin[1]);
1880 if (dup2(pin[0], 0) < 0) 1909 if (dup2(pin[0], 0) < 0)
1881 perror("dup2 stdin"); 1910 perror("dup2 stdin");
1882 close(pin[0]); 1911 close(pin[0]);
1883 1912
1884 /* Redirect stdout. */ 1913 /* Redirect stdout. */
1885 close(pout[0]); 1914 close(pout[0]);
1886 if (dup2(pout[1], 1) < 0) 1915 if (dup2(pout[1], 1) < 0)
1887 perror("dup2 stdout"); 1916 perror("dup2 stdout");
1888 close(pout[1]); 1917 close(pout[1]);
1889 1918
1890 /* Redirect stderr. */ 1919 /* Redirect stderr. */
1891 close(perr[0]); 1920 close(perr[0]);
1892 if (dup2(perr[1], 2) < 0) 1921 if (dup2(perr[1], 2) < 0)
1893 perror("dup2 stderr"); 1922 perror("dup2 stderr");
1894 close(perr[1]); 1923 close(perr[1]);
1895#else /* USE_PIPES */ 1924#else /* USE_PIPES */
1896 /* Redirect stdin, stdout, and stderr. Stdin and stdout will use the 1925 /* Redirect stdin, stdout, and stderr. Stdin and stdout
1897 same socket, as some programs (particularly rdist) seem to depend 1926 will use the same socket, as some programs
1898 on it. */ 1927 (particularly rdist) seem to depend on it. */
1899 close(inout[1]); 1928 close(inout[1]);
1900 close(err[1]); 1929 close(err[1]);
1901 if (dup2(inout[0], 0) < 0) /* stdin */ 1930 if (dup2(inout[0], 0) < 0) /* stdin */
1902 perror("dup2 stdin"); 1931 perror("dup2 stdin");
1903 if (dup2(inout[0], 1) < 0) /* stdout. Note: same socket as stdin. */ 1932 if (dup2(inout[0], 1) < 0) /* stdout. Note: same socket as stdin. */
1904 perror("dup2 stdout"); 1933 perror("dup2 stdout");
1905 if (dup2(err[0], 2) < 0) /* stderr */ 1934 if (dup2(err[0], 2) < 0) /* stderr */
1906 perror("dup2 stderr"); 1935 perror("dup2 stderr");
1907#endif /* USE_PIPES */ 1936#endif /* USE_PIPES */
1908 1937
1909 /* Do processing for the child (exec command etc). */ 1938 /* Do processing for the child (exec command etc). */
1910 do_child(command, pw, NULL, display, auth_proto, auth_data, NULL); 1939 do_child(command, pw, NULL, display, auth_proto, auth_data, NULL);
1911 /*NOTREACHED*/ 1940 /* NOTREACHED */
1912 } 1941 }
1913 if (pid < 0) 1942 if (pid < 0)
1914 packet_disconnect("fork failed: %.100s", strerror(errno)); 1943 packet_disconnect("fork failed: %.100s", strerror(errno));
1915#ifdef USE_PIPES 1944#ifdef USE_PIPES
1916 /* We are the parent. Close the child sides of the pipes. */ 1945 /* We are the parent. Close the child sides of the pipes. */
1917 close(pin[0]); 1946 close(pin[0]);
1918 close(pout[1]); 1947 close(pout[1]);
1919 close(perr[1]); 1948 close(perr[1]);
1920 1949
1921 /* Enter the interactive session. */ 1950 /* Enter the interactive session. */
1922 server_loop(pid, pin[1], pout[0], perr[0]); 1951 server_loop(pid, pin[1], pout[0], perr[0]);
1923 /* server_loop has closed pin[1], pout[1], and perr[1]. */ 1952 /* server_loop has closed pin[1], pout[1], and perr[1]. */
1924#else /* USE_PIPES */ 1953#else /* USE_PIPES */
1925 /* We are the parent. Close the child sides of the socket pairs. */ 1954 /* We are the parent. Close the child sides of the socket pairs. */
1926 close(inout[0]); 1955 close(inout[0]);
1927 close(err[0]); 1956 close(err[0]);
1928 1957
1929 /* Enter the interactive session. Note: server_loop must be able to handle 1958 /* Enter the interactive session. Note: server_loop must be able
1930 the case that fdin and fdout are the same. */ 1959 to handle the case that fdin and fdout are the same. */
1931 server_loop(pid, inout[1], inout[1], err[1]); 1960 server_loop(pid, inout[1], inout[1], err[1]);
1932 /* server_loop has closed inout[1] and err[1]. */ 1961 /* server_loop has closed inout[1] and err[1]. */
1933#endif /* USE_PIPES */ 1962#endif /* USE_PIPES */
1934} 1963}
1935 1964
1936struct pty_cleanup_context 1965struct pty_cleanup_context {
1937{ 1966 const char *ttyname;
1938 const char *ttyname; 1967 int pid;
1939 int pid;
1940}; 1968};
1941 1969
1942/* Function to perform cleanup if we get aborted abnormally (e.g., due to a 1970/*
1943 dropped connection). */ 1971 * Function to perform cleanup if we get aborted abnormally (e.g., due to a
1944 1972 * dropped connection).
1945void pty_cleanup_proc(void *context) 1973 */
1974void
1975pty_cleanup_proc(void *context)
1946{ 1976{
1947 struct pty_cleanup_context *cu = context; 1977 struct pty_cleanup_context *cu = context;
1948 1978
1949 debug("pty_cleanup_proc called"); 1979 debug("pty_cleanup_proc called");
1950 1980
1951 /* Record that the user has logged out. */ 1981 /* Record that the user has logged out. */
1952 record_logout(cu->pid, cu->ttyname); 1982 record_logout(cu->pid, cu->ttyname);
1953 1983
1954 /* Release the pseudo-tty. */ 1984 /* Release the pseudo-tty. */
1955 pty_release(cu->ttyname); 1985 pty_release(cu->ttyname);
1956} 1986}
1957 1987
1958/* This is called to fork and execute a command when we have a tty. This 1988/*
1959 will call do_child from the child, and server_loop from the parent after 1989 * This is called to fork and execute a command when we have a tty. This
1960 setting up file descriptors, controlling tty, updating wtmp, utmp, 1990 * will call do_child from the child, and server_loop from the parent after
1961 lastlog, and other such operations. */ 1991 * setting up file descriptors, controlling tty, updating wtmp, utmp,
1962 1992 * lastlog, and other such operations.
1963void do_exec_pty(const char *command, int ptyfd, int ttyfd, 1993 */
1964 const char *ttyname, struct passwd *pw, const char *term, 1994void
1965 const char *display, const char *auth_proto, 1995do_exec_pty(const char *command, int ptyfd, int ttyfd,
1966 const char *auth_data) 1996 const char *ttyname, struct passwd * pw, const char *term,
1997 const char *display, const char *auth_proto,
1998 const char *auth_data)
1967{ 1999{
1968 int pid, fdout; 2000 int pid, fdout;
1969 const char *hostname; 2001 const char *hostname;
1970 time_t last_login_time; 2002 time_t last_login_time;
1971 char buf[100], *time_string; 2003 char buf[100], *time_string;
1972 FILE *f; 2004 FILE *f;
1973 char line[256]; 2005 char line[256];
1974 struct stat st; 2006 struct stat st;
1975 int quiet_login; 2007 int quiet_login;
1976 struct sockaddr_in from; 2008 struct sockaddr_in from;
1977 int fromlen; 2009 int fromlen;
1978 struct pty_cleanup_context cleanup_context; 2010 struct pty_cleanup_context cleanup_context;
1979 2011
1980 /* Get remote host name. */ 2012 /* Get remote host name. */
1981 hostname = get_canonical_hostname(); 2013 hostname = get_canonical_hostname();
1982 2014
1983 /* Get the time when the user last logged in. Buf will be set to contain 2015 /* Get the time when the user last logged in. Buf will be set to
1984 the hostname the last login was from. */ 2016 contain the hostname the last login was from. */
1985 if(!options.use_login) { 2017 if (!options.use_login) {
1986 last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name, 2018 last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name,
1987 buf, sizeof(buf)); 2019 buf, sizeof(buf));
1988 }
1989
1990 setproctitle("%s@%s", pw->pw_name, strrchr(ttyname, '/') + 1);
1991
1992 /* Fork the child. */
1993 if ((pid = fork()) == 0)
1994 {
1995 pid = getpid();
1996
1997 /* Child. Reinitialize the log because the pid has changed. */
1998 log_init(av0, options.log_level, options.log_facility, log_stderr);
1999
2000 /* Close the master side of the pseudo tty. */
2001 close(ptyfd);
2002
2003 /* Make the pseudo tty our controlling tty. */
2004 pty_make_controlling_tty(&ttyfd, ttyname);
2005
2006 /* Redirect stdin from the pseudo tty. */
2007 if (dup2(ttyfd, fileno(stdin)) < 0)
2008 error("dup2 stdin failed: %.100s", strerror(errno));
2009
2010 /* Redirect stdout to the pseudo tty. */
2011 if (dup2(ttyfd, fileno(stdout)) < 0)
2012 error("dup2 stdin failed: %.100s", strerror(errno));
2013
2014 /* Redirect stderr to the pseudo tty. */
2015 if (dup2(ttyfd, fileno(stderr)) < 0)
2016 error("dup2 stdin failed: %.100s", strerror(errno));
2017
2018 /* Close the extra descriptor for the pseudo tty. */
2019 close(ttyfd);
2020
2021 /* Get IP address of client. This is needed because we want to record
2022 where the user logged in from. If the connection is not a socket,
2023 let the ip address be 0.0.0.0. */
2024 memset(&from, 0, sizeof(from));
2025 if (packet_get_connection_in() == packet_get_connection_out())
2026 {
2027 fromlen = sizeof(from);
2028 if (getpeername(packet_get_connection_in(),
2029 (struct sockaddr *)&from, &fromlen) < 0) {
2030 debug("getpeername: %.100s", strerror(errno));
2031 fatal_cleanup();
2032 }
2033 } 2020 }
2021 setproctitle("%s@%s", pw->pw_name, strrchr(ttyname, '/') + 1);
2022
2023 /* Fork the child. */
2024 if ((pid = fork()) == 0) {
2025 pid = getpid();
2026
2027 /* Child. Reinitialize the log because the pid has
2028 changed. */
2029 log_init(av0, options.log_level, options.log_facility, log_stderr);
2030
2031 /* Close the master side of the pseudo tty. */
2032 close(ptyfd);
2033
2034 /* Make the pseudo tty our controlling tty. */
2035 pty_make_controlling_tty(&ttyfd, ttyname);
2036
2037 /* Redirect stdin from the pseudo tty. */
2038 if (dup2(ttyfd, fileno(stdin)) < 0)
2039 error("dup2 stdin failed: %.100s", strerror(errno));
2040
2041 /* Redirect stdout to the pseudo tty. */
2042 if (dup2(ttyfd, fileno(stdout)) < 0)
2043 error("dup2 stdin failed: %.100s", strerror(errno));
2044
2045 /* Redirect stderr to the pseudo tty. */
2046 if (dup2(ttyfd, fileno(stderr)) < 0)
2047 error("dup2 stdin failed: %.100s", strerror(errno));
2048
2049 /* Close the extra descriptor for the pseudo tty. */
2050 close(ttyfd);
2051
2052 /* Get IP address of client. This is needed because we
2053 want to record where the user logged in from. If the
2054 connection is not a socket, let the ip address be 0.0.0.0. */
2055 memset(&from, 0, sizeof(from));
2056 if (packet_get_connection_in() == packet_get_connection_out()) {
2057 fromlen = sizeof(from);
2058 if (getpeername(packet_get_connection_in(),
2059 (struct sockaddr *) & from, &fromlen) < 0) {
2060 debug("getpeername: %.100s", strerror(errno));
2061 fatal_cleanup();
2062 }
2063 }
2064 /* Record that there was a login on that terminal. */
2065 record_login(pid, ttyname, pw->pw_name, pw->pw_uid, hostname,
2066 &from);
2034 2067
2035 /* Record that there was a login on that terminal. */ 2068 /* Check if .hushlogin exists. */
2036 record_login(pid, ttyname, pw->pw_name, pw->pw_uid, hostname, 2069 snprintf(line, sizeof line, "%.200s/.hushlogin", pw->pw_dir);
2037 &from); 2070 quiet_login = stat(line, &st) >= 0;
2038
2039 /* Check if .hushlogin exists. */
2040 snprintf(line, sizeof line, "%.200s/.hushlogin", pw->pw_dir);
2041 quiet_login = stat(line, &st) >= 0;
2042 2071
2043#ifdef HAVE_LIBPAM 2072#ifdef HAVE_LIBPAM
2044 /* output the results of the pamconv() */ 2073 /* output the results of the pamconv() */
2045 if (!quiet_login && pamconv_msg != NULL) 2074 if (!quiet_login && pamconv_msg != NULL)
2046 fprintf(stderr, pamconv_msg); 2075 fprintf(stderr, pamconv_msg);
2047#endif 2076#endif
2048
2049 /* If the user has logged in before, display the time of last login.
2050 However, don't display anything extra if a command has been
2051 specified (so that ssh can be used to execute commands on a remote
2052 machine without users knowing they are going to another machine).
2053 Login(1) will do this for us as well, so check if login(1) is used */
2054 if (command == NULL && last_login_time != 0 && !quiet_login &&
2055 !options.use_login)
2056 {
2057 /* Convert the date to a string. */
2058 time_string = ctime(&last_login_time);
2059 /* Remove the trailing newline. */
2060 if (strchr(time_string, '\n'))
2061 *strchr(time_string, '\n') = 0;
2062 /* Display the last login time. Host if displayed if known. */
2063 if (strcmp(buf, "") == 0)
2064 printf("Last login: %s\r\n", time_string);
2065 else
2066 printf("Last login: %s from %s\r\n", time_string, buf);
2067 }
2068 2077
2069 /* Print /etc/motd unless a command was specified or printing it was 2078 /* If the user has logged in before, display the time of
2070 disabled in server options or login(1) will be used. Note that 2079 last login. However, don't display anything extra if a
2071 some machines appear to print it in /etc/profile or similar. */ 2080 command has been specified (so that ssh can be used to
2072 if (command == NULL && options.print_motd && !quiet_login && 2081 execute commands on a remote machine without users
2073 !options.use_login) 2082 knowing they are going to another machine). Login(1)
2074 { 2083 will do this for us as well, so check if login(1) is used */
2075 /* Print /etc/motd if it exists. */ 2084 if (command == NULL && last_login_time != 0 && !quiet_login &&
2076 f = fopen("/etc/motd", "r"); 2085 !options.use_login) {
2077 if (f) 2086 /* Convert the date to a string. */
2078 { 2087 time_string = ctime(&last_login_time);
2079 while (fgets(line, sizeof(line), f)) 2088 /* Remove the trailing newline. */
2080 fputs(line, stdout); 2089 if (strchr(time_string, '\n'))
2081 fclose(f); 2090 *strchr(time_string, '\n') = 0;
2082 } 2091 /* Display the last login time. Host if displayed
2092 if known. */
2093 if (strcmp(buf, "") == 0)
2094 printf("Last login: %s\r\n", time_string);
2095 else
2096 printf("Last login: %s from %s\r\n", time_string, buf);
2097 }
2098 /* Print /etc/motd unless a command was specified or
2099 printing it was disabled in server options or login(1)
2100 will be used. Note that some machines appear to print
2101 it in /etc/profile or similar. */
2102 if (command == NULL && options.print_motd && !quiet_login &&
2103 !options.use_login) {
2104 /* Print /etc/motd if it exists. */
2105 f = fopen("/etc/motd", "r");
2106 if (f) {
2107 while (fgets(line, sizeof(line), f))
2108 fputs(line, stdout);
2109 fclose(f);
2110 }
2111 }
2112 /* Do common processing for the child, such as execing the command. */
2113 do_child(command, pw, term, display, auth_proto, auth_data, ttyname);
2114 /* NOTREACHED */
2083 } 2115 }
2084 2116 if (pid < 0)
2085 /* Do common processing for the child, such as execing the command. */ 2117 packet_disconnect("fork failed: %.100s", strerror(errno));
2086 do_child(command, pw, term, display, auth_proto, auth_data, ttyname); 2118 /* Parent. Close the slave side of the pseudo tty. */
2087 /*NOTREACHED*/ 2119 close(ttyfd);
2088 } 2120
2089 if (pid < 0) 2121 /* Create another descriptor of the pty master side for use as the
2090 packet_disconnect("fork failed: %.100s", strerror(errno)); 2122 standard input. We could use the original descriptor, but this
2091 /* Parent. Close the slave side of the pseudo tty. */ 2123 simplifies code in server_loop. The descriptor is bidirectional. */
2092 close(ttyfd); 2124 fdout = dup(ptyfd);
2093 2125 if (fdout < 0)
2094 /* Create another descriptor of the pty master side for use as the standard 2126 packet_disconnect("dup failed: %.100s", strerror(errno));
2095 input. We could use the original descriptor, but this simplifies code 2127
2096 in server_loop. The descriptor is bidirectional. */ 2128 /* Add a cleanup function to clear the utmp entry and record logout
2097 fdout = dup(ptyfd); 2129 time in case we call fatal() (e.g., the connection gets closed). */
2098 if (fdout < 0) 2130 cleanup_context.pid = pid;
2099 packet_disconnect("dup failed: %.100s", strerror(errno)); 2131 cleanup_context.ttyname = ttyname;
2100 2132 fatal_add_cleanup(pty_cleanup_proc, (void *) &cleanup_context);
2101 /* Add a cleanup function to clear the utmp entry and record logout time 2133
2102 in case we call fatal() (e.g., the connection gets closed). */ 2134 /* Enter interactive session. */
2103 cleanup_context.pid = pid; 2135 server_loop(pid, ptyfd, fdout, -1);
2104 cleanup_context.ttyname = ttyname; 2136 /* server_loop has not closed ptyfd and fdout. */
2105 fatal_add_cleanup(pty_cleanup_proc, (void *)&cleanup_context); 2137
2106 2138 /* Cancel the cleanup function. */
2107 /* Enter interactive session. */ 2139 fatal_remove_cleanup(pty_cleanup_proc, (void *) &cleanup_context);
2108 server_loop(pid, ptyfd, fdout, -1); 2140
2109 /* server_loop has not closed ptyfd and fdout. */ 2141 /* Record that the user has logged out. */
2110 2142 record_logout(pid, ttyname);
2111 /* Cancel the cleanup function. */ 2143
2112 fatal_remove_cleanup(pty_cleanup_proc, (void *)&cleanup_context); 2144 /* Release the pseudo-tty. */
2113 2145 pty_release(ttyname);
2114 /* Record that the user has logged out. */ 2146
2115 record_logout(pid, ttyname); 2147 /* Close the server side of the socket pairs. We must do this
2116 2148 after the pty cleanup, so that another process doesn't get this
2117 /* Release the pseudo-tty. */ 2149 pty while we're still cleaning up. */
2118 pty_release(ttyname); 2150 close(ptyfd);
2119 2151 close(fdout);
2120 /* Close the server side of the socket pairs. We must do this after the
2121 pty cleanup, so that another process doesn't get this pty while we're
2122 still cleaning up. */
2123 close(ptyfd);
2124 close(fdout);
2125} 2152}
2126 2153
2127/* Sets the value of the given variable in the environment. If the variable 2154/*
2128 already exists, its value is overriden. */ 2155 * Sets the value of the given variable in the environment. If the variable
2129 2156 * already exists, its value is overriden.
2130void child_set_env(char ***envp, unsigned int *envsizep, const char *name, 2157 */
2131 const char *value) 2158void
2159child_set_env(char ***envp, unsigned int *envsizep, const char *name,
2160 const char *value)
2132{ 2161{
2133 unsigned int i, namelen; 2162 unsigned int i, namelen;
2134 char **env; 2163 char **env;
2135 2164
2136 /* Find the slot where the value should be stored. If the variable already 2165 /* Find the slot where the value should be stored. If the
2137 exists, we reuse the slot; otherwise we append a new slot at the end 2166 variable already exists, we reuse the slot; otherwise we append
2138 of the array, expanding if necessary. */ 2167 a new slot at the end of the array, expanding if necessary. */
2139 env = *envp; 2168 env = *envp;
2140 namelen = strlen(name); 2169 namelen = strlen(name);
2141 for (i = 0; env[i]; i++) 2170 for (i = 0; env[i]; i++)
2142 if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=') 2171 if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=')
2143 break; 2172 break;
2144 if (env[i]) 2173 if (env[i]) {
2145 { 2174 /* Name already exists. Reuse the slot. */
2146 /* Name already exists. Reuse the slot. */ 2175 xfree(env[i]);
2147 xfree(env[i]); 2176 } else {
2148 } 2177 /* New variable. Expand the array if necessary. */
2149 else 2178 if (i >= (*envsizep) - 1) {
2150 { 2179 (*envsizep) += 50;
2151 /* New variable. Expand the array if necessary. */ 2180 env = (*envp) = xrealloc(env, (*envsizep) * sizeof(char *));
2152 if (i >= (*envsizep) - 1) 2181 }
2153 { 2182 /* Need to set the NULL pointer at end of array beyond the new slot. */
2154 (*envsizep) += 50; 2183 env[i + 1] = NULL;
2155 env = (*envp) = xrealloc(env, (*envsizep) * sizeof(char *));
2156 } 2184 }
2157 2185
2158 /* Need to set the NULL pointer at end of array beyond the new 2186 /* Allocate space and format the variable in the appropriate slot. */
2159 slot. */ 2187 env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1);
2160 env[i + 1] = NULL; 2188 snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value);
2161 }
2162
2163 /* Allocate space and format the variable in the appropriate slot. */
2164 env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1);
2165 snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value);
2166} 2189}
2167 2190
2168/* Reads environment variables from the given file and adds/overrides them 2191/*
2169 into the environment. If the file does not exist, this does nothing. 2192 * Reads environment variables from the given file and adds/overrides them
2170 Otherwise, it must consist of empty lines, comments (line starts with '#') 2193 * into the environment. If the file does not exist, this does nothing.
2171 and assignments of the form name=value. No other forms are allowed. */ 2194 * Otherwise, it must consist of empty lines, comments (line starts with '#')
2172 2195 * and assignments of the form name=value. No other forms are allowed.
2173void read_environment_file(char ***env, unsigned int *envsize, 2196 */
2174 const char *filename) 2197void
2198read_environment_file(char ***env, unsigned int *envsize,
2199 const char *filename)
2175{ 2200{
2176 FILE *f; 2201 FILE *f;
2177 char buf[4096]; 2202 char buf[4096];
2178 char *cp, *value; 2203 char *cp, *value;
2179 2204
2180 /* Open the environment file. */ 2205 /* Open the environment file. */
2181 f = fopen(filename, "r"); 2206 f = fopen(filename, "r");
2182 if (!f) 2207 if (!f)
2183 return; /* Not found. */ 2208 return;
2184 2209
2185 /* Process each line. */ 2210 /* Process each line. */
2186 while (fgets(buf, sizeof(buf), f)) 2211 while (fgets(buf, sizeof(buf), f)) {
2187 { 2212 /* Skip leading whitespace. */
2188 /* Skip leading whitespace. */ 2213 for (cp = buf; *cp == ' ' || *cp == '\t'; cp++);
2189 for (cp = buf; *cp == ' ' || *cp == '\t'; cp++) 2214
2190 ; 2215 /* Ignore empty and comment lines. */
2191 2216 if (!*cp || *cp == '#' || *cp == '\n')
2192 /* Ignore empty and comment lines. */ 2217 continue;
2193 if (!*cp || *cp == '#' || *cp == '\n') 2218
2194 continue; 2219 /* Remove newline. */
2195 2220 if (strchr(cp, '\n'))
2196 /* Remove newline. */ 2221 *strchr(cp, '\n') = '\0';
2197 if (strchr(cp, '\n')) 2222
2198 *strchr(cp, '\n') = '\0'; 2223 /* Find the equals sign. Its lack indicates badly
2199 2224 formatted line. */
2200 /* Find the equals sign. Its lack indicates badly formatted line. */ 2225 value = strchr(cp, '=');
2201 value = strchr(cp, '='); 2226 if (value == NULL) {
2202 if (value == NULL) 2227 fprintf(stderr, "Bad line in %.100s: %.200s\n", filename, buf);
2203 { 2228 continue;
2204 fprintf(stderr, "Bad line in %.100s: %.200s\n", filename, buf); 2229 }
2205 continue; 2230 /* Replace the equals sign by nul, and advance value to
2206 } 2231 the value string. */
2232 *value = '\0';
2233 value++;
2207 2234
2208 /* Replace the equals sign by nul, and advance value to the value 2235 /* Set the value in environment. */
2209 string. */ 2236 child_set_env(env, envsize, cp, value);
2210 *value = '\0'; 2237 }
2211 value++;
2212 2238
2213 /* Set the value in environment. */ 2239 fclose(f);
2214 child_set_env(env, envsize, cp, value);
2215 }
2216
2217 fclose(f);
2218} 2240}
2219 2241
2220/* Performs common processing for the child, such as setting up the 2242/*
2221 environment, closing extra file descriptors, setting the user and group 2243 * Performs common processing for the child, such as setting up the
2222 ids, and executing the command or shell. */ 2244 * environment, closing extra file descriptors, setting the user and group
2223 2245 * ids, and executing the command or shell.
2224void do_child(const char *command, struct passwd *pw, const char *term, 2246 */
2225 const char *display, const char *auth_proto, 2247void
2226 const char *auth_data, const char *ttyname) 2248do_child(const char *command, struct passwd * pw, const char *term,
2249 const char *display, const char *auth_proto,
2250 const char *auth_data, const char *ttyname)
2227{ 2251{
2228 const char *shell, *cp = NULL; 2252 const char *shell, *cp = NULL;
2229 char buf[256]; 2253 char buf[256];
2230 FILE *f; 2254 FILE *f;
2231 unsigned int envsize, i; 2255 unsigned int envsize, i;
2232 char **env; 2256 char **env;
2233 extern char **environ; 2257 extern char **environ;
2234 struct stat st; 2258 struct stat st;
2235 char *argv[10]; 2259 char *argv[10];
2236 2260
2237#ifndef HAVE_LIBPAM /* pam_nologin handles this */ 2261#ifndef HAVE_LIBPAM /* pam_nologin handles this */
2238 /* Check /etc/nologin. */ 2262 /* Check /etc/nologin. */
2239 f = fopen("/etc/nologin", "r"); 2263 f = fopen("/etc/nologin", "r");
2240 if (f) 2264 if (f) {
2241 { /* /etc/nologin exists. Print its contents and exit. */ 2265 /* /etc/nologin exists. Print its contents and exit. */
2242 while (fgets(buf, sizeof(buf), f)) 2266 while (fgets(buf, sizeof(buf), f))
2243 fputs(buf, stderr); 2267 fputs(buf, stderr);
2244 fclose(f); 2268 fclose(f);
2245 if (pw->pw_uid != 0) 2269 if (pw->pw_uid != 0)
2246 exit(254); 2270 exit(254);
2247 } 2271 }
2248#endif /* HAVE_LIBPAM */ 2272#endif /* HAVE_LIBPAM */
2249 2273
2250#ifdef HAVE_SETLOGIN 2274#ifdef HAVE_SETLOGIN
2251 /* Set login name in the kernel. */ 2275 /* Set login name in the kernel. */
2252 if (setlogin(pw->pw_name) < 0) 2276 if (setlogin(pw->pw_name) < 0)
2253 error("setlogin failed: %s", strerror(errno)); 2277 error("setlogin failed: %s", strerror(errno));
2254#endif /* HAVE_SETLOGIN */ 2278#endif /* HAVE_SETLOGIN */
2255 2279
2256 /* Set uid, gid, and groups. */ 2280 /* Set uid, gid, and groups. */
2257 /* Login(1) does this as well, and it needs uid 0 for the "-h" switch, 2281 /* Login(1) does this as well, and it needs uid 0 for the "-h"
2258 so we let login(1) to this for us. */ 2282 switch, so we let login(1) to this for us. */
2259 if(!options.use_login) { 2283 if (!options.use_login) {
2260 if (getuid() == 0 || geteuid() == 0) 2284 if (getuid() == 0 || geteuid() == 0) {
2261 { 2285 if (setgid(pw->pw_gid) < 0) {
2262 if (setgid(pw->pw_gid) < 0) 2286 perror("setgid");
2263 { 2287 exit(1);
2264 perror("setgid"); 2288 }
2265 exit(1); 2289 /* Initialize the group list. */
2266 } 2290 if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
2267 /* Initialize the group list. */ 2291 perror("initgroups");
2268 if (initgroups(pw->pw_name, pw->pw_gid) < 0) 2292 exit(1);
2269 { 2293 }
2270 perror("initgroups"); 2294 endgrent();
2271 exit(1); 2295
2272 } 2296 /* Permanently switch to the desired uid. */
2273 endgrent(); 2297 permanently_set_uid(pw->pw_uid);
2274 2298 }
2275 /* Permanently switch to the desired uid. */ 2299 if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
2276 permanently_set_uid(pw->pw_uid); 2300 fatal("Failed to set uids to %d.", (int) pw->pw_uid);
2277 } 2301 }
2278 2302 /* Get the shell from the password data. An empty shell field is
2279 if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) 2303 legal, and means /bin/sh. */
2280 fatal("Failed to set uids to %d.", (int)pw->pw_uid); 2304 shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
2281 }
2282
2283 /* Get the shell from the password data. An empty shell field is legal,
2284 and means /bin/sh. */
2285 shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
2286 2305
2287#ifdef AFS 2306#ifdef AFS
2288 /* Try to get AFS tokens for the local cell. */ 2307 /* Try to get AFS tokens for the local cell. */
2289 if (k_hasafs()) { 2308 if (k_hasafs()) {
2290 char cell[64]; 2309 char cell[64];
2291 2310
2292 if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0) 2311 if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0)
2293 krb_afslog(cell, 0); 2312 krb_afslog(cell, 0);
2294 2313
2295 krb_afslog(0, 0); 2314 krb_afslog(0, 0);
2296 } 2315 }
2297#endif /* AFS */ 2316#endif /* AFS */
2298 2317
2299 /* Initialize the environment. In the first part we allocate space for 2318 /* Initialize the environment. In the first part we allocate
2300 all environment variables. */ 2319 space for all environment variables. */
2301 envsize = 100; 2320 envsize = 100;
2302 env = xmalloc(envsize * sizeof(char *)); 2321 env = xmalloc(envsize * sizeof(char *));
2303 env[0] = NULL; 2322 env[0] = NULL;
2304 2323
2305 if(!options.use_login) { 2324 if (!options.use_login) {
2306 /* Set basic environment. */ 2325 /* Set basic environment. */
2307 child_set_env(&env, &envsize, "USER", pw->pw_name); 2326 child_set_env(&env, &envsize, "USER", pw->pw_name);
2308 child_set_env(&env, &envsize, "LOGNAME", pw->pw_name); 2327 child_set_env(&env, &envsize, "LOGNAME", pw->pw_name);
2309 child_set_env(&env, &envsize, "HOME", pw->pw_dir); 2328 child_set_env(&env, &envsize, "HOME", pw->pw_dir);
2310 child_set_env(&env, &envsize, "PATH", _PATH_STDPATH); 2329 child_set_env(&env, &envsize, "PATH", _PATH_STDPATH);
2311 2330
2312 snprintf(buf, sizeof buf, "%.200s/%.50s", 2331 snprintf(buf, sizeof buf, "%.200s/%.50s",
2313 _PATH_MAILDIR, pw->pw_name); 2332 _PATH_MAILDIR, pw->pw_name);
2314 child_set_env(&env, &envsize, "MAIL", buf); 2333 child_set_env(&env, &envsize, "MAIL", buf);
2315 2334
2316 /* Normal systems set SHELL by default. */ 2335 /* Normal systems set SHELL by default. */
2317 child_set_env(&env, &envsize, "SHELL", shell); 2336 child_set_env(&env, &envsize, "SHELL", shell);
2318 } 2337 }
2319 2338 /* Let it inherit timezone if we have one. */
2320 /* Let it inherit timezone if we have one. */ 2339 if (getenv("TZ"))
2321 if (getenv("TZ")) 2340 child_set_env(&env, &envsize, "TZ", getenv("TZ"));
2322 child_set_env(&env, &envsize, "TZ", getenv("TZ")); 2341
2323 2342 /* Set custom environment options from RSA authentication. */
2324 /* Set custom environment options from RSA authentication. */ 2343 while (custom_environment) {
2325 while (custom_environment) 2344 struct envstring *ce = custom_environment;
2326 { 2345 char *s = ce->s;
2327 struct envstring *ce = custom_environment; 2346 int i;
2328 char *s = ce->s; 2347 for (i = 0; s[i] != '=' && s[i]; i++);
2329 int i; 2348 if (s[i] == '=') {
2330 for (i = 0; s[i] != '=' && s[i]; i++) 2349 s[i] = 0;
2331 ; 2350 child_set_env(&env, &envsize, s, s + i + 1);
2332 if (s[i] == '=') 2351 }
2333 { 2352 custom_environment = ce->next;
2334 s[i] = 0; 2353 xfree(ce->s);
2335 child_set_env(&env, &envsize, s, s + i + 1); 2354 xfree(ce);
2336 } 2355 }
2337 custom_environment = ce->next;
2338 xfree(ce->s);
2339 xfree(ce);
2340 }
2341 2356
2342 /* Set SSH_CLIENT. */ 2357 /* Set SSH_CLIENT. */
2343 snprintf(buf, sizeof buf, "%.50s %d %d", 2358 snprintf(buf, sizeof buf, "%.50s %d %d",
2344 get_remote_ipaddr(), get_remote_port(), options.port); 2359 get_remote_ipaddr(), get_remote_port(), options.port);
2345 child_set_env(&env, &envsize, "SSH_CLIENT", buf); 2360 child_set_env(&env, &envsize, "SSH_CLIENT", buf);
2346 2361
2347 /* Set SSH_TTY if we have a pty. */ 2362 /* Set SSH_TTY if we have a pty. */
2348 if (ttyname) 2363 if (ttyname)
2349 child_set_env(&env, &envsize, "SSH_TTY", ttyname); 2364 child_set_env(&env, &envsize, "SSH_TTY", ttyname);
2350 2365
2351 /* Set TERM if we have a pty. */ 2366 /* Set TERM if we have a pty. */
2352 if (term) 2367 if (term)
2353 child_set_env(&env, &envsize, "TERM", term); 2368 child_set_env(&env, &envsize, "TERM", term);
2354 2369
2355 /* Set DISPLAY if we have one. */ 2370 /* Set DISPLAY if we have one. */
2356 if (display) 2371 if (display)
2357 child_set_env(&env, &envsize, "DISPLAY", display); 2372 child_set_env(&env, &envsize, "DISPLAY", display);
2358 2373
2359#ifdef KRB4 2374#ifdef KRB4
2360 { 2375 {
2361 extern char *ticket; 2376 extern char *ticket;
2362 2377
2363 if (ticket) 2378 if (ticket)
2364 child_set_env(&env, &envsize, "KRBTKFILE", ticket); 2379 child_set_env(&env, &envsize, "KRBTKFILE", ticket);
2365 } 2380 }
2366#endif /* KRB4 */ 2381#endif /* KRB4 */
2367 2382
2368#ifdef HAVE_LIBPAM 2383#ifdef HAVE_LIBPAM
2369 /* Pull in any environment variables that may have been set by PAM. */ 2384 /* Pull in any environment variables that may have been set by PAM. */
2370 { 2385 {
2371 char *equal_sign, var_name[256], var_val[256]; 2386 char *equals, var_name[512], var_val[512];
2372 long this_var; 2387 char **pam_env = pam_getenvlist((pam_handle_t *)pamh);
2373 char **pam_env = pam_getenvlist((pam_handle_t *)pamh); 2388 int i;
2374 for(this_var = 0; pam_env && pam_env[this_var]; this_var++) 2389 for(i = 0; pam_env && pam_env[i]; i++) {
2375 { 2390 equals = strstr(pam_env[i], "=");
2376 if(strlen(pam_env[this_var]) < (sizeof(var_name) - 1)) 2391 if ((strlen(pam_env[i]) < (sizeof(var_name) - 1)) && (equals != NULL))
2377 if((equal_sign = strstr(pam_env[this_var], "=")) != NULL) 2392 {
2378 { 2393 memset(var_name, '\0', sizeof(var_name));
2379 memset(var_name, 0, sizeof(var_name)); 2394 memset(var_val, '\0', sizeof(var_val));
2380 memset(var_val, 0, sizeof(var_val)); 2395 strncpy(var_name, pam_env[i], equals - pam_env[i]);
2381 strncpy(var_name, pam_env[this_var], 2396 strcpy(var_val, equals + 1);
2382 equal_sign - pam_env[this_var]); 2397 child_set_env(&env, &envsize, var_name, var_val);
2383 strcpy(var_val, equal_sign + 1); 2398 }
2384 child_set_env(&env, &envsize, var_name, var_val); 2399 }
2385 } 2400 }
2386 }
2387 }
2388#endif /* HAVE_LIBPAM */ 2401#endif /* HAVE_LIBPAM */
2389 2402
2390 /* Set XAUTHORITY to always be a local file. */ 2403 /* Set XAUTHORITY to always be a local file. */
2391 if (xauthfile) 2404 if (xauthfile)
2392 child_set_env(&env, &envsize, "XAUTHORITY", xauthfile); 2405 child_set_env(&env, &envsize, "XAUTHORITY", xauthfile);
2393 2406
2394 /* Set variable for forwarded authentication connection, if we have one. */ 2407 /* Set variable for forwarded authentication connection, if we
2395 if (auth_get_socket_name() != NULL) 2408 have one. */
2396 child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME, 2409 if (auth_get_socket_name() != NULL)
2397 auth_get_socket_name()); 2410 child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,
2398 2411 auth_get_socket_name());
2399 /* Read $HOME/.ssh/environment. */ 2412
2400 if(!options.use_login) { 2413 /* Read $HOME/.ssh/environment. */
2401 snprintf(buf, sizeof buf, "%.200s/.ssh/environment", pw->pw_dir); 2414 if (!options.use_login) {
2402 read_environment_file(&env, &envsize, buf); 2415 snprintf(buf, sizeof buf, "%.200s/.ssh/environment", pw->pw_dir);
2403 } 2416 read_environment_file(&env, &envsize, buf);
2404 2417 }
2405 /* If debugging, dump the environment to stderr. */ 2418 /* If debugging, dump the environment to stderr. */
2406 if (debug_flag) 2419 if (debug_flag) {
2407 { 2420 fprintf(stderr, "Environment:\n");
2408 fprintf(stderr, "Environment:\n"); 2421 for (i = 0; env[i]; i++)
2409 for (i = 0; env[i]; i++) 2422 fprintf(stderr, " %.200s\n", env[i]);
2410 fprintf(stderr, " %.200s\n", env[i]); 2423 }
2411 } 2424 /* Close the connection descriptors; note that this is the child,
2412 2425 and the server will still have the socket open, and it is
2413 /* Close the connection descriptors; note that this is the child, and the 2426 important that we do not shutdown it. Note that the
2414 server will still have the socket open, and it is important that we 2427 descriptors cannot be closed before building the environment,
2415 do not shutdown it. Note that the descriptors cannot be closed before 2428 as we call get_remote_ipaddr there. */
2416 building the environment, as we call get_remote_ipaddr there. */ 2429 if (packet_get_connection_in() == packet_get_connection_out())
2417 if (packet_get_connection_in() == packet_get_connection_out()) 2430 close(packet_get_connection_in());
2418 close(packet_get_connection_in()); 2431 else {
2419 else 2432 close(packet_get_connection_in());
2420 { 2433 close(packet_get_connection_out());
2421 close(packet_get_connection_in()); 2434 }
2422 close(packet_get_connection_out()); 2435 /* Close all descriptors related to channels. They will still
2423 } 2436 remain open in the parent. */
2424 /* Close all descriptors related to channels. They will still remain 2437 channel_close_all();
2425 open in the parent. */ 2438
2426 channel_close_all(); 2439 /* Close any extra file descriptors. Note that there may still be
2427 2440 descriptors left by system functions. They will be closed
2428 /* Close any extra file descriptors. Note that there may still be 2441 later. */
2429 descriptors left by system functions. They will be closed later. */ 2442 endpwent();
2430 endpwent(); 2443 endhostent();
2431 endhostent(); 2444
2432 2445 /* Close any extra open file descriptors so that we don\'t have
2433 /* Close any extra open file descriptors so that we don\'t have them 2446 them hanging around in clients. Note that we want to do this
2434 hanging around in clients. Note that we want to do this after 2447 after initgroups, because at least on Solaris 2.3 it leaves
2435 initgroups, because at least on Solaris 2.3 it leaves file descriptors 2448 file descriptors open. */
2436 open. */ 2449 for (i = 3; i < 64; i++)
2437 for (i = 3; i < 64; i++) 2450 close(i);
2438 close(i); 2451
2439 2452 /* Change current directory to the user\'s home directory. */
2440 /* Change current directory to the user\'s home directory. */ 2453 if (chdir(pw->pw_dir) < 0)
2441 if (chdir(pw->pw_dir) < 0) 2454 fprintf(stderr, "Could not chdir to home directory %s: %s\n",
2442 fprintf(stderr, "Could not chdir to home directory %s: %s\n", 2455 pw->pw_dir, strerror(errno));
2443 pw->pw_dir, strerror(errno)); 2456
2444 2457 /* Must take new environment into use so that .ssh/rc, /etc/sshrc
2445 /* Must take new environment into use so that .ssh/rc, /etc/sshrc and 2458 and xauth are run in the proper environment. */
2446 xauth are run in the proper environment. */ 2459 environ = env;
2447 environ = env; 2460
2448 2461 /* Run $HOME/.ssh/rc, /etc/sshrc, or xauth (whichever is found
2449 /* Run $HOME/.ssh/rc, /etc/sshrc, or xauth (whichever is found first 2462 first in this order). */
2450 in this order). */ 2463 if (!options.use_login) {
2451 if(!options.use_login) { 2464 if (stat(SSH_USER_RC, &st) >= 0) {
2452 if (stat(SSH_USER_RC, &st) >= 0) 2465 if (debug_flag)
2453 { 2466 fprintf(stderr, "Running /bin/sh %s\n", SSH_USER_RC);
2454 if (debug_flag) 2467
2455 fprintf(stderr, "Running /bin/sh %s\n", SSH_USER_RC); 2468 f = popen("/bin/sh " SSH_USER_RC, "w");
2456 2469 if (f) {
2457 f = popen("/bin/sh " SSH_USER_RC, "w"); 2470 if (auth_proto != NULL && auth_data != NULL)
2458 if (f) 2471 fprintf(f, "%s %s\n", auth_proto, auth_data);
2459 { 2472 pclose(f);
2460 if (auth_proto != NULL && auth_data != NULL) 2473 } else
2461 fprintf(f, "%s %s\n", auth_proto, auth_data); 2474 fprintf(stderr, "Could not run %s\n", SSH_USER_RC);
2462 pclose(f); 2475 } else if (stat(SSH_SYSTEM_RC, &st) >= 0) {
2463 } 2476 if (debug_flag)
2464 else 2477 fprintf(stderr, "Running /bin/sh %s\n", SSH_SYSTEM_RC);
2465 fprintf(stderr, "Could not run %s\n", SSH_USER_RC); 2478
2466 } 2479 f = popen("/bin/sh " SSH_SYSTEM_RC, "w");
2467 else 2480 if (f) {
2468 if (stat(SSH_SYSTEM_RC, &st) >= 0) 2481 if (auth_proto != NULL && auth_data != NULL)
2469 { 2482 fprintf(f, "%s %s\n", auth_proto, auth_data);
2470 if (debug_flag) 2483 pclose(f);
2471 fprintf(stderr, "Running /bin/sh %s\n", SSH_SYSTEM_RC); 2484 } else
2472 2485 fprintf(stderr, "Could not run %s\n", SSH_SYSTEM_RC);
2473 f = popen("/bin/sh " SSH_SYSTEM_RC, "w"); 2486 }
2474 if (f)
2475 {
2476 if (auth_proto != NULL && auth_data != NULL)
2477 fprintf(f, "%s %s\n", auth_proto, auth_data);
2478 pclose(f);
2479 }
2480 else
2481 fprintf(stderr, "Could not run %s\n", SSH_SYSTEM_RC);
2482 }
2483#ifdef XAUTH_PATH 2487#ifdef XAUTH_PATH
2484 else 2488 else {
2485 { 2489 /* Add authority data to .Xauthority if
2486 /* Add authority data to .Xauthority if appropriate. */ 2490 appropriate. */
2487 if (auth_proto != NULL && auth_data != NULL) 2491 if (auth_proto != NULL && auth_data != NULL) {
2488 { 2492 if (debug_flag)
2489 if (debug_flag) 2493 fprintf(stderr, "Running %.100s add %.100s %.100s %.100s\n",
2490 fprintf(stderr, "Running %.100s add %.100s %.100s %.100s\n", 2494 XAUTH_PATH, display, auth_proto, auth_data);
2491 XAUTH_PATH, display, auth_proto, auth_data); 2495
2492 2496 f = popen(XAUTH_PATH " -q -", "w");
2493 f = popen(XAUTH_PATH " -q -", "w"); 2497 if (f) {
2494 if (f) 2498 fprintf(f, "add %s %s %s\n", display, auth_proto, auth_data);
2495 { 2499 fclose(f);
2496 fprintf(f, "add %s %s %s\n", display, auth_proto, auth_data); 2500 } else
2497 fclose(f); 2501 fprintf(stderr, "Could not run %s -q -\n", XAUTH_PATH);
2498 } 2502 }
2499 else 2503 }
2500 fprintf(stderr, "Could not run %s -q -\n", XAUTH_PATH);
2501 }
2502 }
2503#endif /* XAUTH_PATH */ 2504#endif /* XAUTH_PATH */
2504 2505
2505 /* Get the last component of the shell name. */ 2506 /* Get the last component of the shell name. */
2506 cp = strrchr(shell, '/'); 2507 cp = strrchr(shell, '/');
2507 if (cp) 2508 if (cp)
2508 cp++; 2509 cp++;
2509 else 2510 else
2510 cp = shell; 2511 cp = shell;
2511 } 2512 }
2512 2513 /* If we have no command, execute the shell. In this case, the
2513 /* If we have no command, execute the shell. In this case, the shell name 2514 shell name to be passed in argv[0] is preceded by '-' to
2514 to be passed in argv[0] is preceded by '-' to indicate that this is 2515 indicate that this is a login shell. */
2515 a login shell. */ 2516 if (!command) {
2516 if (!command) 2517 if (!options.use_login) {
2517 { 2518 char buf[256];
2518 if(!options.use_login) { 2519
2519 char buf[256]; 2520 /* Check for mail if we have a tty and it was
2520 2521 enabled in server options. */
2521 /* Check for mail if we have a tty and it was enabled in server options. */ 2522 if (ttyname && options.check_mail) {
2522 if (ttyname && options.check_mail) { 2523 char *mailbox;
2523 char *mailbox; 2524 struct stat mailstat;
2524 struct stat mailstat; 2525 mailbox = getenv("MAIL");
2525 mailbox = getenv("MAIL"); 2526 if (mailbox != NULL) {
2526 if(mailbox != NULL) { 2527 if (stat(mailbox, &mailstat) != 0 || mailstat.st_size == 0)
2527 if(stat(mailbox, &mailstat) != 0 || mailstat.st_size == 0) { 2528 printf("No mail.\n");
2528 printf("No mail.\n"); 2529 else if (mailstat.st_mtime < mailstat.st_atime)
2529 } else if(mailstat.st_mtime < mailstat.st_atime) { 2530 printf("You have mail.\n");
2530 printf("You have mail.\n"); 2531 else
2531 } else { 2532 printf("You have new mail.\n");
2532 printf("You have new mail.\n"); 2533 }
2533 } 2534 }
2534 } 2535 /* Start the shell. Set initial character to '-'. */
2535 } 2536 buf[0] = '-';
2536 /* Start the shell. Set initial character to '-'. */ 2537 strncpy(buf + 1, cp, sizeof(buf) - 1);
2537 buf[0] = '-'; 2538 buf[sizeof(buf) - 1] = 0;
2538 strncpy(buf + 1, cp, sizeof(buf) - 1); 2539
2539 buf[sizeof(buf) - 1] = 0; 2540 /* Execute the shell. */
2540 /* Execute the shell. */ 2541 argv[0] = buf;
2541 argv[0] = buf; 2542 argv[1] = NULL;
2542 argv[1] = NULL; 2543 execve(shell, argv, env);
2543 execve(shell, argv, env); 2544
2544 /* Executing the shell failed. */ 2545 /* Executing the shell failed. */
2545 perror(shell); 2546 perror(shell);
2546 exit(1); 2547 exit(1);
2547 2548
2548 } else { 2549 } else {
2549 /* Launch login(1). */ 2550 /* Launch login(1). */
2550 2551
2551 execl(LOGIN_PROGRAM, "login", "-h", get_remote_ipaddr(), "-p", "-f", "--", pw->pw_name, NULL); 2552 execl(LOGIN_PROGRAM, "login", "-h", get_remote_ipaddr(),
2552 2553 "-p", "-f", "--", pw->pw_name, NULL);
2553 /* Login couldn't be executed, die. */ 2554
2554 2555 /* Login couldn't be executed, die. */
2555 perror("login"); 2556
2556 exit(1); 2557 perror("login");
2557 } 2558 exit(1);
2558 } 2559 }
2559 2560 }
2560 /* Execute the command using the user's shell. This uses the -c option 2561 /* Execute the command using the user's shell. This uses the -c
2561 to execute the command. */ 2562 option to execute the command. */
2562 argv[0] = (char *)cp; 2563 argv[0] = (char *) cp;
2563 argv[1] = "-c"; 2564 argv[1] = "-c";
2564 argv[2] = (char *)command; 2565 argv[2] = (char *) command;
2565 argv[3] = NULL; 2566 argv[3] = NULL;
2566 execve(shell, argv, env); 2567 execve(shell, argv, env);
2567 perror(shell); 2568 perror(shell);
2568 exit(1); 2569 exit(1);
2569} 2570}
diff --git a/tildexpand.c b/tildexpand.c
index e4b57091e..92422ee3f 100644
--- a/tildexpand.c
+++ b/tildexpand.c
@@ -1,70 +1,62 @@
1/* 1/*
2 2 * Author: Tatu Ylonen <ylo@cs.hut.fi>
3tildexpand.c 3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 4 * All rights reserved
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Created: Wed Jul 12 01:07:36 1995 ylo
6 6 */
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved
9
10Created: Wed Jul 12 01:07:36 1995 ylo
11
12*/
13 7
14#include "includes.h" 8#include "includes.h"
15RCSID("$Id: tildexpand.c,v 1.1 1999/10/27 03:42:46 damien Exp $"); 9RCSID("$Id: tildexpand.c,v 1.2 1999/11/24 13:26:23 damien Exp $");
16 10
17#include "xmalloc.h" 11#include "xmalloc.h"
18#include "ssh.h" 12#include "ssh.h"
19 13
20/* Expands tildes in the file name. Returns data allocated by xmalloc. 14/*
21 Warning: this calls getpw*. */ 15 * Expands tildes in the file name. Returns data allocated by xmalloc.
22 16 * Warning: this calls getpw*.
23char *tilde_expand_filename(const char *filename, uid_t my_uid) 17 */
18char *
19tilde_expand_filename(const char *filename, uid_t my_uid)
24{ 20{
25 const char *cp; 21 const char *cp;
26 unsigned int userlen; 22 unsigned int userlen;
27 char *expanded; 23 char *expanded;
28 struct passwd *pw; 24 struct passwd *pw;
29 char user[100]; 25 char user[100];
30 26
31 /* Return immediately if no tilde. */ 27 /* Return immediately if no tilde. */
32 if (filename[0] != '~') 28 if (filename[0] != '~')
33 return xstrdup(filename); 29 return xstrdup(filename);
34 30
35 /* Skip the tilde. */ 31 /* Skip the tilde. */
36 filename++; 32 filename++;
37 33
38 /* Find where the username ends. */ 34 /* Find where the username ends. */
39 cp = strchr(filename, '/'); 35 cp = strchr(filename, '/');
40 if (cp) 36 if (cp)
41 userlen = cp - filename; /* Have something after username. */ 37 userlen = cp - filename; /* Something after username. */
42 else 38 else
43 userlen = strlen(filename); /* Nothign after username. */ 39 userlen = strlen(filename); /* Nothing after username. */
44 if (userlen == 0) 40 if (userlen == 0)
45 pw = getpwuid(my_uid); /* Own home directory. */ 41 pw = getpwuid(my_uid); /* Own home directory. */
46 else 42 else {
47 { 43 /* Tilde refers to someone elses home directory. */
48 /* Tilde refers to someone elses home directory. */ 44 if (userlen > sizeof(user) - 1)
49 if (userlen > sizeof(user) - 1) 45 fatal("User name after tilde too long.");
50 fatal("User name after tilde too long."); 46 memcpy(user, filename, userlen);
51 memcpy(user, filename, userlen); 47 user[userlen] = 0;
52 user[userlen] = 0; 48 pw = getpwnam(user);
53 pw = getpwnam(user); 49 }
54 } 50 /* Check that we found the user. */
55 51 if (!pw)
56 /* Check that we found the user. */ 52 fatal("Unknown user %100s.", user);
57 if (!pw) 53
58 fatal("Unknown user %100s.", user); 54 /* If referring to someones home directory, return it now. */
59 55 if (!cp) { /* Only home directory specified */
60 /* If referring to someones home directory, return it now. */ 56 return xstrdup(pw->pw_dir);
61 if (!cp) 57 }
62 { /* Only home directory specified */ 58 /* Build a path combining the specified directory and path. */
63 return xstrdup(pw->pw_dir); 59 expanded = xmalloc(strlen(pw->pw_dir) + strlen(cp + 1) + 2);
64 } 60 sprintf(expanded, "%s/%s", pw->pw_dir, cp + 1);
65 61 return expanded;
66 /* Build a path combining the specified directory and path. */
67 expanded = xmalloc(strlen(pw->pw_dir) + strlen(cp + 1) + 2);
68 sprintf(expanded, "%s/%s", pw->pw_dir, cp + 1);
69 return expanded;
70} 62}
diff --git a/ttymodes.c b/ttymodes.c
index cbb7f2f64..6810ce26c 100644
--- a/ttymodes.c
+++ b/ttymodes.c
@@ -1,233 +1,229 @@
1/* 1/*
2 2 * Author: Tatu Ylonen <ylo@cs.hut.fi>
3ttymodes.c 3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 4 * All rights reserved
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Created: Tue Mar 21 15:59:15 1995 ylo
6 6 * Encoding and decoding of terminal modes in a portable way.
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Much of the format is defined in ttymodes.h; it is included multiple times
8 All rights reserved 8 * into this file with the appropriate macro definitions to generate the
9 9 * suitable code.
10Created: Tue Mar 21 15:59:15 1995 ylo 10 */
11
12Encoding and decoding of terminal modes in a portable way.
13Much of the format is defined in ttymodes.h; it is included multiple times
14into this file with the appropriate macro definitions to generate the
15suitable code.
16
17*/
18 11
19#include "includes.h" 12#include "includes.h"
20RCSID("$Id: ttymodes.c,v 1.1 1999/10/27 03:42:46 damien Exp $"); 13RCSID("$Id: ttymodes.c,v 1.2 1999/11/24 13:26:23 damien Exp $");
21 14
22#include "packet.h" 15#include "packet.h"
23#include "ssh.h" 16#include "ssh.h"
24 17
25#define TTY_OP_END 0 18#define TTY_OP_END 0
26#define TTY_OP_ISPEED 192 /* int follows */ 19#define TTY_OP_ISPEED 192 /* int follows */
27#define TTY_OP_OSPEED 193 /* int follows */ 20#define TTY_OP_OSPEED 193 /* int follows */
28 21
29/* Converts POSIX speed_t to a baud rate. The values of the constants 22/*
30 for speed_t are not themselves portable. */ 23 * Converts POSIX speed_t to a baud rate. The values of the
31 24 * constants for speed_t are not themselves portable.
32static int speed_to_baud(speed_t speed) 25 */
26static int
27speed_to_baud(speed_t speed)
33{ 28{
34 switch (speed) 29 switch (speed) {
35 { 30 case B0:
36 case B0: 31 return 0;
37 return 0; 32 case B50:
38 case B50: 33 return 50;
39 return 50; 34 case B75:
40 case B75: 35 return 75;
41 return 75; 36 case B110:
42 case B110: 37 return 110;
43 return 110; 38 case B134:
44 case B134: 39 return 134;
45 return 134; 40 case B150:
46 case B150: 41 return 150;
47 return 150; 42 case B200:
48 case B200: 43 return 200;
49 return 200; 44 case B300:
50 case B300: 45 return 300;
51 return 300; 46 case B600:
52 case B600: 47 return 600;
53 return 600; 48 case B1200:
54 case B1200: 49 return 1200;
55 return 1200; 50 case B1800:
56 case B1800: 51 return 1800;
57 return 1800; 52 case B2400:
58 case B2400: 53 return 2400;
59 return 2400; 54 case B4800:
60 case B4800: 55 return 4800;
61 return 4800; 56 case B9600:
62 case B9600: 57 return 9600;
63 return 9600;
64 58
65#ifdef B19200 59#ifdef B19200
66 case B19200: 60 case B19200:
67 return 19200; 61 return 19200;
68#else /* B19200 */ 62#else /* B19200 */
69#ifdef EXTA 63#ifdef EXTA
70 case EXTA: 64 case EXTA:
71 return 19200; 65 return 19200;
72#endif /* EXTA */ 66#endif /* EXTA */
73#endif /* B19200 */ 67#endif /* B19200 */
74 68
75#ifdef B38400 69#ifdef B38400
76 case B38400: 70 case B38400:
77 return 38400; 71 return 38400;
78#else /* B38400 */ 72#else /* B38400 */
79#ifdef EXTB 73#ifdef EXTB
80 case EXTB: 74 case EXTB:
81 return 38400; 75 return 38400;
82#endif /* EXTB */ 76#endif /* EXTB */
83#endif /* B38400 */ 77#endif /* B38400 */
84 78
85#ifdef B7200 79#ifdef B7200
86 case B7200: 80 case B7200:
87 return 7200; 81 return 7200;
88#endif /* B7200 */ 82#endif /* B7200 */
89#ifdef B14400 83#ifdef B14400
90 case B14400: 84 case B14400:
91 return 14400; 85 return 14400;
92#endif /* B14400 */ 86#endif /* B14400 */
93#ifdef B28800 87#ifdef B28800
94 case B28800: 88 case B28800:
95 return 28800; 89 return 28800;
96#endif /* B28800 */ 90#endif /* B28800 */
97#ifdef B57600 91#ifdef B57600
98 case B57600: 92 case B57600:
99 return 57600; 93 return 57600;
100#endif /* B57600 */ 94#endif /* B57600 */
101#ifdef B76800 95#ifdef B76800
102 case B76800: 96 case B76800:
103 return 76800; 97 return 76800;
104#endif /* B76800 */ 98#endif /* B76800 */
105#ifdef B115200 99#ifdef B115200
106 case B115200: 100 case B115200:
107 return 115200; 101 return 115200;
108#endif /* B115200 */ 102#endif /* B115200 */
109#ifdef B230400 103#ifdef B230400
110 case B230400: 104 case B230400:
111 return 230400; 105 return 230400;
112#endif /* B230400 */ 106#endif /* B230400 */
113 default: 107 default:
114 return 9600; 108 return 9600;
115 } 109 }
116} 110}
117 111
118/* Converts a numeric baud rate to a POSIX speed_t. */ 112/*
119 113 * Converts a numeric baud rate to a POSIX speed_t.
120static speed_t baud_to_speed(int baud) 114 */
115static speed_t
116baud_to_speed(int baud)
121{ 117{
122 switch (baud) 118 switch (baud) {
123 { 119 case 0:
124 case 0: 120 return B0;
125 return B0; 121 case 50:
126 case 50: 122 return B50;
127 return B50; 123 case 75:
128 case 75: 124 return B75;
129 return B75; 125 case 110:
130 case 110: 126 return B110;
131 return B110; 127 case 134:
132 case 134: 128 return B134;
133 return B134; 129 case 150:
134 case 150: 130 return B150;
135 return B150; 131 case 200:
136 case 200: 132 return B200;
137 return B200; 133 case 300:
138 case 300: 134 return B300;
139 return B300; 135 case 600:
140 case 600: 136 return B600;
141 return B600; 137 case 1200:
142 case 1200: 138 return B1200;
143 return B1200; 139 case 1800:
144 case 1800: 140 return B1800;
145 return B1800; 141 case 2400:
146 case 2400: 142 return B2400;
147 return B2400; 143 case 4800:
148 case 4800: 144 return B4800;
149 return B4800; 145 case 9600:
150 case 9600: 146 return B9600;
151 return B9600;
152 147
153#ifdef B19200 148#ifdef B19200
154 case 19200: 149 case 19200:
155 return B19200; 150 return B19200;
156#else /* B19200 */ 151#else /* B19200 */
157#ifdef EXTA 152#ifdef EXTA
158 case 19200: 153 case 19200:
159 return EXTA; 154 return EXTA;
160#endif /* EXTA */ 155#endif /* EXTA */
161#endif /* B19200 */ 156#endif /* B19200 */
162 157
163#ifdef B38400 158#ifdef B38400
164 case 38400: 159 case 38400:
165 return B38400; 160 return B38400;
166#else /* B38400 */ 161#else /* B38400 */
167#ifdef EXTB 162#ifdef EXTB
168 case 38400: 163 case 38400:
169 return EXTB; 164 return EXTB;
170#endif /* EXTB */ 165#endif /* EXTB */
171#endif /* B38400 */ 166#endif /* B38400 */
172 167
173#ifdef B7200 168#ifdef B7200
174 case 7200: 169 case 7200:
175 return B7200; 170 return B7200;
176#endif /* B7200 */ 171#endif /* B7200 */
177#ifdef B14400 172#ifdef B14400
178 case 14400: 173 case 14400:
179 return B14400; 174 return B14400;
180#endif /* B14400 */ 175#endif /* B14400 */
181#ifdef B28800 176#ifdef B28800
182 case 28800: 177 case 28800:
183 return B28800; 178 return B28800;
184#endif /* B28800 */ 179#endif /* B28800 */
185#ifdef B57600 180#ifdef B57600
186 case 57600: 181 case 57600:
187 return B57600; 182 return B57600;
188#endif /* B57600 */ 183#endif /* B57600 */
189#ifdef B76800 184#ifdef B76800
190 case 76800: 185 case 76800:
191 return B76800; 186 return B76800;
192#endif /* B76800 */ 187#endif /* B76800 */
193#ifdef B115200 188#ifdef B115200
194 case 115200: 189 case 115200:
195 return B115200; 190 return B115200;
196#endif /* B115200 */ 191#endif /* B115200 */
197#ifdef B230400 192#ifdef B230400
198 case 230400: 193 case 230400:
199 return B230400; 194 return B230400;
200#endif /* B230400 */ 195#endif /* B230400 */
201 default: 196 default:
202 return B9600; 197 return B9600;
203 } 198 }
204} 199}
205 200
206/* Encodes terminal modes for the terminal referenced by fd in a portable 201/*
207 manner, and appends the modes to a packet being constructed. */ 202 * Encodes terminal modes for the terminal referenced by fd
208 203 * in a portable manner, and appends the modes to a packet
209void tty_make_modes(int fd) 204 * being constructed.
205 */
206void
207tty_make_modes(int fd)
210{ 208{
211 struct termios tio; 209 struct termios tio;
212 int baud; 210 int baud;
213 211
214 /* Get the modes. */ 212 /* Get the modes. */
215 if (tcgetattr(fd, &tio) < 0) 213 if (tcgetattr(fd, &tio) < 0) {
216 { 214 packet_put_char(TTY_OP_END);
217 packet_put_char(TTY_OP_END); 215 log("tcgetattr: %.100s", strerror(errno));
218 log("tcgetattr: %.100s", strerror(errno)); 216 return;
219 return; 217 }
220 } 218 /* Store input and output baud rates. */
221 219 baud = speed_to_baud(cfgetospeed(&tio));
222 /* Store input and output baud rates. */ 220 packet_put_char(TTY_OP_OSPEED);
223 baud = speed_to_baud(cfgetospeed(&tio)); 221 packet_put_int(baud);
224 packet_put_char(TTY_OP_OSPEED); 222 baud = speed_to_baud(cfgetispeed(&tio));
225 packet_put_int(baud); 223 packet_put_char(TTY_OP_ISPEED);
226 baud = speed_to_baud(cfgetispeed(&tio)); 224 packet_put_int(baud);
227 packet_put_char(TTY_OP_ISPEED); 225
228 packet_put_int(baud); 226 /* Store values of mode flags. */
229
230 /* Store values of mode flags. */
231#define TTYCHAR(NAME, OP) \ 227#define TTYCHAR(NAME, OP) \
232 packet_put_char(OP); packet_put_char(tio.c_cc[NAME]); 228 packet_put_char(OP); packet_put_char(tio.c_cc[NAME]);
233#define TTYMODE(NAME, FIELD, OP) \ 229#define TTYMODE(NAME, FIELD, OP) \
@@ -244,48 +240,50 @@ void tty_make_modes(int fd)
244#undef SGTTYMODE 240#undef SGTTYMODE
245#undef SGTTYMODEN 241#undef SGTTYMODEN
246 242
247 /* Mark end of mode data. */ 243 /* Mark end of mode data. */
248 packet_put_char(TTY_OP_END); 244 packet_put_char(TTY_OP_END);
249} 245}
250 246
251/* Decodes terminal modes for the terminal referenced by fd in a portable 247/*
252 manner from a packet being read. */ 248 * Decodes terminal modes for the terminal referenced by fd in a portable
253 249 * manner from a packet being read.
254void tty_parse_modes(int fd, int *n_bytes_ptr) 250 */
251void
252tty_parse_modes(int fd, int *n_bytes_ptr)
255{ 253{
256 struct termios tio; 254 struct termios tio;
257 int opcode, baud; 255 int opcode, baud;
258 int n_bytes = 0; 256 int n_bytes = 0;
259 int failure = 0; 257 int failure = 0;
260 258
261 /* Get old attributes for the terminal. We will modify these flags. 259 /*
262 I am hoping that if there are any machine-specific modes, they will 260 * Get old attributes for the terminal. We will modify these
263 initially have reasonable values. */ 261 * flags. I am hoping that if there are any machine-specific
264 if (tcgetattr(fd, &tio) < 0) 262 * modes, they will initially have reasonable values.
265 failure = -1; 263 */
266 264 if (tcgetattr(fd, &tio) < 0)
267 for (;;) 265 failure = -1;
268 { 266
269 n_bytes += 1; 267 for (;;) {
270 opcode = packet_get_char(); 268 n_bytes += 1;
271 switch (opcode) 269 opcode = packet_get_char();
272 { 270 switch (opcode) {
273 case TTY_OP_END: 271 case TTY_OP_END:
274 goto set; 272 goto set;
275 273
276 case TTY_OP_ISPEED: 274 case TTY_OP_ISPEED:
277 n_bytes += 4; 275 n_bytes += 4;
278 baud = packet_get_int(); 276 baud = packet_get_int();
279 if (failure != -1 && cfsetispeed(&tio, baud_to_speed(baud)) < 0) 277 if (failure != -1 && cfsetispeed(&tio, baud_to_speed(baud)) < 0)
280 error("cfsetispeed failed for %d", baud); 278 error("cfsetispeed failed for %d", baud);
281 break; 279 break;
282 280
283 case TTY_OP_OSPEED: 281 case TTY_OP_OSPEED:
284 n_bytes += 4; 282 n_bytes += 4;
285 baud = packet_get_int(); 283 baud = packet_get_int();
286 if (failure != -1 && cfsetospeed(&tio, baud_to_speed(baud)) < 0) 284 if (failure != -1 && cfsetospeed(&tio, baud_to_speed(baud)) < 0)
287 error("cfsetospeed failed for %d", baud); 285 error("cfsetospeed failed for %d", baud);
288 break; 286 break;
289 287
290#define TTYCHAR(NAME, OP) \ 288#define TTYCHAR(NAME, OP) \
291 case OP: \ 289 case OP: \
@@ -312,48 +310,51 @@ void tty_parse_modes(int fd, int *n_bytes_ptr)
312#undef SGTTYMODE 310#undef SGTTYMODE
313#undef SGTTYMODEN 311#undef SGTTYMODEN
314 312
315 default: 313 default:
316 debug("Ignoring unsupported tty mode opcode %d (0x%x)", 314 debug("Ignoring unsupported tty mode opcode %d (0x%x)",
317 opcode, opcode); 315 opcode, opcode);
318 /* Opcodes 0 to 127 are defined to have a one-byte argument. */ 316 /*
319 if (opcode >= 0 && opcode < 128) 317 * Opcodes 0 to 127 are defined to have
320 { 318 * a one-byte argument.
321 n_bytes += 1; 319 */
322 (void)packet_get_char(); 320 if (opcode >= 0 && opcode < 128) {
323 break; 321 n_bytes += 1;
324 } 322 (void) packet_get_char();
325 else 323 break;
326 { 324 } else {
327 /* Opcodes 128 to 159 are defined to have an integer argument. */ 325 /*
328 if (opcode >= 128 && opcode < 160) 326 * Opcodes 128 to 159 are defined to have
329 { 327 * an integer argument.
330 n_bytes += 4; 328 */
331 (void)packet_get_int(); 329 if (opcode >= 128 && opcode < 160) {
332 break; 330 n_bytes += 4;
331 (void) packet_get_int();
332 break;
333 }
334 }
335 /*
336 * It is a truly undefined opcode (160 to 255).
337 * We have no idea about its arguments. So we
338 * must stop parsing. Note that some data may be
339 * left in the packet; hopefully there is nothing
340 * more coming after the mode data.
341 */
342 log("parse_tty_modes: unknown opcode %d", opcode);
343 packet_integrity_check(0, 1, SSH_CMSG_REQUEST_PTY);
344 goto set;
333 } 345 }
334 }
335 /* It is a truly undefined opcode (160 to 255). We have no idea
336 about its arguments. So we must stop parsing. Note that some
337 data may be left in the packet; hopefully there is nothing more
338 coming after the mode data. */
339 log("parse_tty_modes: unknown opcode %d", opcode);
340 packet_integrity_check(0, 1, SSH_CMSG_REQUEST_PTY);
341 goto set;
342 } 346 }
343 }
344 347
345 set: 348set:
346 if (*n_bytes_ptr != n_bytes) 349 if (*n_bytes_ptr != n_bytes) {
347 { 350 *n_bytes_ptr = n_bytes;
348 *n_bytes_ptr = n_bytes; 351 return; /* Don't process bytes passed */
349 return; /* Don't process bytes passed */ 352 }
350 } 353 if (failure == -1)
354 return; /* Packet parsed ok but tty stuff failed */
351 355
352 if (failure == -1) 356 /* Set the new modes for the terminal. */
353 return; /* Packet parsed ok but tty stuff failed */ 357 if (tcsetattr(fd, TCSANOW, &tio) < 0)
354 358 log("Setting tty modes failed: %.100s", strerror(errno));
355 /* Set the new modes for the terminal. */ 359 return;
356 if (tcsetattr(fd, TCSANOW, &tio) < 0)
357 log("Setting tty modes failed: %.100s", strerror(errno));
358 return;
359} 360}
diff --git a/ttymodes.h b/ttymodes.h
index 2a33eb78d..e9301f281 100644
--- a/ttymodes.h
+++ b/ttymodes.h
@@ -1,138 +1,140 @@
1/* 1/*
2 *
3 * ttymodes.h
4 *
5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 * SGTTY stuff contributed by Janne Snabb <snabb@niksula.hut.fi>
7 *
8 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
9 * All rights reserved
10 *
11 * Created: Tue Mar 21 15:42:09 1995 ylo
12 *
13 */
2 14
3ttymodes.h 15/* RCSID("$Id: ttymodes.h,v 1.2 1999/11/24 13:26:23 damien Exp $"); */
4
5Author: Tatu Ylonen <ylo@cs.hut.fi>
6 SGTTY stuff contributed by Janne Snabb <snabb@niksula.hut.fi>
7
8Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
9 All rights reserved
10
11Created: Tue Mar 21 15:42:09 1995 ylo
12
13*/
14
15/* RCSID("$Id: ttymodes.h,v 1.1 1999/10/27 03:42:46 damien Exp $"); */
16 16
17/* The tty mode description is a stream of bytes. The stream consists of 17/* The tty mode description is a stream of bytes. The stream consists of
18 opcode-arguments pairs. It is terminated by opcode TTY_OP_END (0). 18 * opcode-arguments pairs. It is terminated by opcode TTY_OP_END (0).
19 Opcodes 1-127 have one-byte arguments. Opcodes 128-159 have integer 19 * Opcodes 1-127 have one-byte arguments. Opcodes 128-159 have integer
20 arguments. Opcodes 160-255 are not yet defined, and cause parsing to 20 * arguments. Opcodes 160-255 are not yet defined, and cause parsing to
21 stop (they should only be used after any other data). 21 * stop (they should only be used after any other data).
22 *
23 * The client puts in the stream any modes it knows about, and the
24 * server ignores any modes it does not know about. This allows some degree
25 * of machine-independence, at least between systems that use a posix-like
26 * tty interface. The protocol can support other systems as well, but might
27 * require reimplementing as mode names would likely be different.
28 */
22 29
23 The client puts in the stream any modes it knows about, and the 30/*
24 server ignores any modes it does not know about. This allows some degree 31 * Some constants and prototypes are defined in packet.h; this file
25 of machine-independence, at least between systems that use a posix-like 32 * is only intended for including from ttymodes.h.
26 tty interface. The protocol can support other systems as well, but might 33 */
27 require reimplementing as mode names would likely be different. */
28
29/* Some constants and prototypes are defined in packet.h; this file
30 is only intended for including from ttymodes.h. */
31 34
32/* termios macro */ /* sgtty macro */ 35 /* termios macro *//* sgtty macro */
33/* name, op */ 36/* name, op */
34TTYCHAR(VINTR, 1) SGTTYCHAR(tiotc.t_intrc, 1) 37TTYCHAR(VINTR, 1) SGTTYCHAR(tiotc.t_intrc, 1)
35TTYCHAR(VQUIT, 2) SGTTYCHAR(tiotc.t_quitc, 2) 38TTYCHAR(VQUIT, 2) SGTTYCHAR(tiotc.t_quitc, 2)
36TTYCHAR(VERASE, 3) SGTTYCHAR(tio.sg_erase, 3) 39TTYCHAR(VERASE, 3) SGTTYCHAR(tio.sg_erase, 3)
37#if defined(VKILL) 40#if defined(VKILL)
38TTYCHAR(VKILL, 4) SGTTYCHAR(tio.sg_kill, 4) 41TTYCHAR(VKILL, 4) SGTTYCHAR(tio.sg_kill, 4)
39#endif /* VKILL */ 42#endif /* VKILL */
40TTYCHAR(VEOF, 5) SGTTYCHAR(tiotc.t_eofc, 5) 43TTYCHAR(VEOF, 5) SGTTYCHAR(tiotc.t_eofc, 5)
41#if defined(VEOL) 44#if defined(VEOL)
42TTYCHAR(VEOL, 6) SGTTYCHAR(tiotc.t_brkc, 6) 45TTYCHAR(VEOL, 6) SGTTYCHAR(tiotc.t_brkc, 6)
43#endif /* VEOL */ 46#endif /* VEOL */
44#ifdef VEOL2 /* n/a */ 47#ifdef VEOL2 /* n/a */
45TTYCHAR(VEOL2, 7) 48TTYCHAR(VEOL2, 7)
46#endif /* VEOL2 */ 49#endif /* VEOL2 */
47TTYCHAR(VSTART, 8) SGTTYCHAR(tiotc.t_startc, 8) 50TTYCHAR(VSTART, 8) SGTTYCHAR(tiotc.t_startc, 8)
48TTYCHAR(VSTOP, 9) SGTTYCHAR(tiotc.t_stopc, 9) 51TTYCHAR(VSTOP, 9) SGTTYCHAR(tiotc.t_stopc, 9)
49#if defined(VSUSP) 52#if defined(VSUSP)
50TTYCHAR(VSUSP, 10) SGTTYCHAR(tioltc.t_suspc, 10) 53TTYCHAR(VSUSP, 10) SGTTYCHAR(tioltc.t_suspc, 10)
51#endif /* VSUSP */ 54#endif /* VSUSP */
52#if defined(VDSUSP) 55#if defined(VDSUSP)
53TTYCHAR(VDSUSP, 11) SGTTYCHAR(tioltc.t_dsuspc, 11) 56TTYCHAR(VDSUSP, 11) SGTTYCHAR(tioltc.t_dsuspc, 11)
54#endif /* VDSUSP */ 57#endif /* VDSUSP */
55#if defined(VREPRINT) 58#if defined(VREPRINT)
56TTYCHAR(VREPRINT, 12) SGTTYCHAR(tioltc.t_rprntc, 12) 59TTYCHAR(VREPRINT, 12) SGTTYCHAR(tioltc.t_rprntc, 12)
57#endif /* VREPRINT */ 60#endif /* VREPRINT */
58#if defined(VWERASE) 61#if defined(VWERASE)
59TTYCHAR(VWERASE, 13) SGTTYCHAR(tioltc.t_werasc, 13) 62TTYCHAR(VWERASE, 13) SGTTYCHAR(tioltc.t_werasc, 13)
60#endif /* VWERASE */ 63#endif /* VWERASE */
61#if defined(VLNEXT) 64#if defined(VLNEXT)
62TTYCHAR(VLNEXT, 14) SGTTYCHAR(tioltc.t_lnextc, 14) 65TTYCHAR(VLNEXT, 14) SGTTYCHAR(tioltc.t_lnextc, 14)
63#endif /* VLNEXT */ 66#endif /* VLNEXT */
64#if defined(VFLUSH) 67#if defined(VFLUSH)
65TTYCHAR(VFLUSH, 15) SGTTYCHAR(tioltc.t_flushc, 15) 68TTYCHAR(VFLUSH, 15) SGTTYCHAR(tioltc.t_flushc, 15)
66#endif /* VFLUSH */ 69#endif /* VFLUSH */
67#ifdef VSWTCH 70#ifdef VSWTCH
68TTYCHAR(VSWTCH, 16) /* n/a */ 71TTYCHAR(VSWTCH, 16) /* n/a */
69#endif /* VSWTCH */ 72#endif /* VSWTCH */
70#if defined(VSTATUS) 73#if defined(VSTATUS)
71TTYCHAR(VSTATUS, 17) SGTTYCHAR(tiots.tc_statusc, 17) 74TTYCHAR(VSTATUS, 17) SGTTYCHAR(tiots.tc_statusc, 17)
72#endif /* VSTATUS */ 75#endif /* VSTATUS */
73#ifdef VDISCARD 76#ifdef VDISCARD
74TTYCHAR(VDISCARD, 18) /* n/a */ 77TTYCHAR(VDISCARD, 18) /* n/a */
75#endif /* VDISCARD */ 78#endif /* VDISCARD */
76 79
77/* name, field, op */ 80/* name, field, op */
78TTYMODE(IGNPAR, c_iflag, 30) /* n/a */ 81TTYMODE(IGNPAR, c_iflag, 30) /* n/a */
79TTYMODE(PARMRK, c_iflag, 31) /* n/a */ 82TTYMODE(PARMRK, c_iflag, 31) /* n/a */
80TTYMODE(INPCK, c_iflag, 32) SGTTYMODEN(ANYP, tio.sg_flags, 32) 83TTYMODE(INPCK, c_iflag, 32) SGTTYMODEN(ANYP, tio.sg_flags, 32)
81TTYMODE(ISTRIP, c_iflag, 33) SGTTYMODEN(LPASS8, tiolm, 33) 84TTYMODE(ISTRIP, c_iflag, 33) SGTTYMODEN(LPASS8, tiolm, 33)
82TTYMODE(INLCR, c_iflag, 34) /* n/a */ 85TTYMODE(INLCR, c_iflag, 34) /* n/a */
83TTYMODE(IGNCR, c_iflag, 35) /* n/a */ 86TTYMODE(IGNCR, c_iflag, 35) /* n/a */
84TTYMODE(ICRNL, c_iflag, 36) SGTTYMODE(CRMOD, tio.sg_flags, 36) 87TTYMODE(ICRNL, c_iflag, 36) SGTTYMODE(CRMOD, tio.sg_flags, 36)
85#if defined(IUCLC) 88#if defined(IUCLC)
86TTYMODE(IUCLC, c_iflag, 37) SGTTYMODE(LCASE, tio.sg_flags, 37) 89TTYMODE(IUCLC, c_iflag, 37) SGTTYMODE(LCASE, tio.sg_flags, 37)
87#endif 90#endif
88TTYMODE(IXON, c_iflag, 38) /* n/a */ 91TTYMODE(IXON, c_iflag, 38) /* n/a */
89TTYMODE(IXANY, c_iflag, 39) SGTTYMODEN(LDECCTQ, tiolm, 39) 92TTYMODE(IXANY, c_iflag, 39) SGTTYMODEN(LDECCTQ, tiolm, 39)
90TTYMODE(IXOFF, c_iflag, 40) SGTTYMODE(TANDEM, tio.sg_flags, 40) 93TTYMODE(IXOFF, c_iflag, 40) SGTTYMODE(TANDEM, tio.sg_flags, 40)
91#ifdef IMAXBEL 94#ifdef IMAXBEL
92TTYMODE(IMAXBEL,c_iflag, 41) /* n/a */ 95TTYMODE(IMAXBEL, c_iflag, 41) /* n/a */
93#endif /* IMAXBEL */ 96#endif /* IMAXBEL */
94 97
95TTYMODE(ISIG, c_lflag, 50) /* n/a */ 98TTYMODE(ISIG, c_lflag, 50) /* n/a */
96TTYMODE(ICANON, c_lflag, 51) SGTTYMODEN(CBREAK, tio.sg_flags, 51) 99TTYMODE(ICANON, c_lflag, 51) SGTTYMODEN(CBREAK, tio.sg_flags, 51)
97#ifdef XCASE 100#ifdef XCASE
98TTYMODE(XCASE, c_lflag, 52) /* n/a */ 101TTYMODE(XCASE, c_lflag, 52) /* n/a */
99#endif 102#endif
100TTYMODE(ECHO, c_lflag, 53) SGTTYMODE(ECHO, tio.sg_flags, 53) 103TTYMODE(ECHO, c_lflag, 53) SGTTYMODE(ECHO, tio.sg_flags, 53)
101TTYMODE(ECHOE, c_lflag, 54) SGTTYMODE(LCRTERA, tiolm, 54) 104TTYMODE(ECHOE, c_lflag, 54) SGTTYMODE(LCRTERA, tiolm, 54)
102TTYMODE(ECHOK, c_lflag, 55) SGTTYMODE(LCRTKIL, tiolm, 55) 105TTYMODE(ECHOK, c_lflag, 55) SGTTYMODE(LCRTKIL, tiolm, 55)
103TTYMODE(ECHONL, c_lflag, 56) /* n/a */ 106TTYMODE(ECHONL, c_lflag, 56) /* n/a */
104TTYMODE(NOFLSH, c_lflag, 57) SGTTYMODE(LNOFLSH, tiolm, 57) 107TTYMODE(NOFLSH, c_lflag, 57) SGTTYMODE(LNOFLSH, tiolm, 57)
105TTYMODE(TOSTOP, c_lflag, 58) SGTTYMODE(LTOSTOP, tiolm, 58) 108TTYMODE(TOSTOP, c_lflag, 58) SGTTYMODE(LTOSTOP, tiolm, 58)
106#ifdef IEXTEN 109#ifdef IEXTEN
107TTYMODE(IEXTEN, c_lflag, 59) /* n/a */ 110TTYMODE(IEXTEN, c_lflag, 59) /* n/a */
108#endif /* IEXTEN */ 111#endif /* IEXTEN */
109#if defined(ECHOCTL) 112#if defined(ECHOCTL)
110TTYMODE(ECHOCTL,c_lflag, 60) SGTTYMODE(LCTLECH, tiolm, 60) 113TTYMODE(ECHOCTL, c_lflag, 60) SGTTYMODE(LCTLECH, tiolm, 60)
111#endif /* ECHOCTL */ 114#endif /* ECHOCTL */
112#ifdef ECHOKE 115#ifdef ECHOKE
113TTYMODE(ECHOKE, c_lflag, 61) /* n/a */ 116TTYMODE(ECHOKE, c_lflag, 61) /* n/a */
114#endif /* ECHOKE */ 117#endif /* ECHOKE */
115#if defined(PENDIN) 118#if defined(PENDIN)
116TTYMODE(PENDIN, c_lflag, 62) SGTTYMODE(LPENDIN, tiolm, 62) 119TTYMODE(PENDIN, c_lflag, 62) SGTTYMODE(LPENDIN, tiolm, 62)
117#endif /* PENDIN */ 120#endif /* PENDIN */
118 121
119TTYMODE(OPOST, c_oflag, 70) /* n/a */ 122TTYMODE(OPOST, c_oflag, 70) /* n/a */
120#if defined(OLCUC) 123#if defined(OLCUC)
121TTYMODE(OLCUC, c_oflag, 71) SGTTYMODE(LCASE, tio.sg_flags, 71) 124TTYMODE(OLCUC, c_oflag, 71) SGTTYMODE(LCASE, tio.sg_flags, 71)
122#endif 125#endif
123TTYMODE(ONLCR, c_oflag, 72) SGTTYMODE(CRMOD, tio.sg_flags, 72) 126TTYMODE(ONLCR, c_oflag, 72) SGTTYMODE(CRMOD, tio.sg_flags, 72)
124#ifdef OCRNL 127#ifdef OCRNL
125TTYMODE(OCRNL, c_oflag, 73) /* n/a */ 128TTYMODE(OCRNL, c_oflag, 73) /* n/a */
126#endif 129#endif
127#ifdef ONOCR 130#ifdef ONOCR
128TTYMODE(ONOCR, c_oflag, 74) /* n/a */ 131TTYMODE(ONOCR, c_oflag, 74) /* n/a */
129#endif 132#endif
130#ifdef ONLRET 133#ifdef ONLRET
131TTYMODE(ONLRET, c_oflag, 75) /* n/a */ 134TTYMODE(ONLRET, c_oflag, 75) /* n/a */
132#endif 135#endif
133 136
134TTYMODE(CS7, c_cflag, 90) /* n/a */ 137TTYMODE(CS7, c_cflag, 90) /* n/a */
135TTYMODE(CS8, c_cflag, 91) SGTTYMODE(LPASS8, tiolm, 91) 138TTYMODE(CS8, c_cflag, 91) SGTTYMODE(LPASS8, tiolm, 91)
136TTYMODE(PARENB, c_cflag, 92) /* n/a */ 139TTYMODE(PARENB, c_cflag, 92) /* n/a */
137TTYMODE(PARODD, c_cflag, 93) SGTTYMODE(ODDP, tio.sg_flags, 93) 140TTYMODE(PARODD, c_cflag, 93) SGTTYMODE(ODDP, tio.sg_flags, 93)
138
diff --git a/uidswap.c b/uidswap.c
index 0eb1fd085..72c2cc6ef 100644
--- a/uidswap.c
+++ b/uidswap.c
@@ -1,32 +1,25 @@
1/* 1/*
2 2 * Author: Tatu Ylonen <ylo@cs.hut.fi>
3uidswap.c 3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 4 * All rights reserved
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Created: Sat Sep 9 01:56:14 1995 ylo
6 6 * Code for uid-swapping.
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 */
8 All rights reserved
9
10Created: Sat Sep 9 01:56:14 1995 ylo
11
12Code for uid-swapping.
13
14*/
15 8
16#include "includes.h" 9#include "includes.h"
17RCSID("$Id: uidswap.c,v 1.1 1999/10/27 03:42:46 damien Exp $"); 10RCSID("$Id: uidswap.c,v 1.2 1999/11/24 13:26:23 damien Exp $");
18 11
19#include "ssh.h" 12#include "ssh.h"
20#include "uidswap.h" 13#include "uidswap.h"
21 14
22/* Note: all these functions must work in all of the following cases: 15/*
23 16 * Note: all these functions must work in all of the following cases:
24 1. euid=0, ruid=0 17 * 1. euid=0, ruid=0
25 2. euid=0, ruid!=0 18 * 2. euid=0, ruid!=0
26 3. euid!=0, ruid!=0 19 * 3. euid!=0, ruid!=0
27 20 * Additionally, they must work regardless of whether the system has
28 Additionally, they must work regardless of whether the system has 21 * POSIX saved uids or not.
29 POSIX saved uids or not. */ 22 */
30 23
31#ifdef _POSIX_SAVED_IDS 24#ifdef _POSIX_SAVED_IDS
32/* Lets assume that posix saved ids also work with seteuid, even though that 25/* 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 $");
37/* Saved effective uid. */ 30/* Saved effective uid. */
38static uid_t saved_euid = 0; 31static uid_t saved_euid = 0;
39 32
40/* Temporarily changes to the given uid. If the effective user id is not 33/*
41 root, this does nothing. This call cannot be nested. */ 34 * Temporarily changes to the given uid. If the effective user
42 35 * id is not root, this does nothing. This call cannot be nested.
43void temporarily_use_uid(uid_t uid) 36 */
37void
38temporarily_use_uid(uid_t uid)
44{ 39{
45#ifdef SAVED_IDS_WORK_WITH_SETEUID 40#ifdef SAVED_IDS_WORK_WITH_SETEUID
41 /* Save the current euid. */
42 saved_euid = geteuid();
46 43
47 /* Save the current euid. */ 44 /* Set the effective uid to the given (unprivileged) uid. */
48 saved_euid = geteuid(); 45 if (seteuid(uid) == -1)
49 46 debug("seteuid %d: %.100s", (int) uid, strerror(errno));
50 /* Set the effective uid to the given (unprivileged) uid. */
51 if (seteuid(uid) == -1)
52 debug("seteuid %d: %.100s", (int)uid, strerror(errno));
53
54#else /* SAVED_IDS_WORK_WITH_SETUID */ 47#else /* SAVED_IDS_WORK_WITH_SETUID */
48 /* Propagate the privileged uid to all of our uids. */
49 if (setuid(geteuid()) < 0)
50 debug("setuid %d: %.100s", (int) geteuid(), strerror(errno));
55 51
56 /* Propagate the privileged uid to all of our uids. */ 52 /* Set the effective uid to the given (unprivileged) uid. */
57 if (setuid(geteuid()) < 0) 53 if (seteuid(uid) == -1)
58 debug("setuid %d: %.100s", (int)geteuid(), strerror(errno)); 54 debug("seteuid %d: %.100s", (int) uid, strerror(errno));
59
60 /* Set the effective uid to the given (unprivileged) uid. */
61 if (seteuid(uid) == -1)
62 debug("seteuid %d: %.100s", (int)uid, strerror(errno));
63
64#endif /* SAVED_IDS_WORK_WITH_SETEUID */ 55#endif /* SAVED_IDS_WORK_WITH_SETEUID */
65
66} 56}
67 57
68/* Restores to the original uid. */ 58/*
69 59 * Restores to the original uid.
70void restore_uid() 60 */
61void
62restore_uid()
71{ 63{
72#ifdef SAVED_IDS_WORK_WITH_SETEUID 64#ifdef SAVED_IDS_WORK_WITH_SETEUID
73 65 /* Set the effective uid back to the saved uid. */
74 /* Set the effective uid back to the saved uid. */ 66 if (seteuid(saved_euid) < 0)
75 if (seteuid(saved_euid) < 0) 67 debug("seteuid %d: %.100s", (int) saved_euid, strerror(errno));
76 debug("seteuid %d: %.100s", (int)saved_euid, strerror(errno));
77
78#else /* SAVED_IDS_WORK_WITH_SETEUID */ 68#else /* SAVED_IDS_WORK_WITH_SETEUID */
79 69 /* We are unable to restore the real uid to its unprivileged
80 /* We are unable to restore the real uid to its unprivileged value. */ 70 value. */
81 /* Propagate the real uid (usually more privileged) to effective uid 71 /* Propagate the real uid (usually more privileged) to effective
82 as well. */ 72 uid as well. */
83 setuid(getuid()); 73 setuid(getuid());
84
85#endif /* SAVED_IDS_WORK_WITH_SETEUID */ 74#endif /* SAVED_IDS_WORK_WITH_SETEUID */
86} 75}
87 76
88/* Permanently sets all uids to the given uid. This cannot be called while 77/*
89 temporarily_use_uid is effective. */ 78 * Permanently sets all uids to the given uid. This cannot be
90 79 * called while temporarily_use_uid is effective.
91void permanently_set_uid(uid_t uid) 80 */
81void
82permanently_set_uid(uid_t uid)
92{ 83{
93 if (setuid(uid) < 0) 84 if (setuid(uid) < 0)
94 debug("setuid %d: %.100s", (int)uid, strerror(errno)); 85 debug("setuid %d: %.100s", (int) uid, strerror(errno));
95} 86}
diff --git a/uidswap.h b/uidswap.h
index af4f924f0..4755710de 100644
--- a/uidswap.h
+++ b/uidswap.h
@@ -1,30 +1,36 @@
1/* 1/*
2 2 *
3uidswap.h 3 * uidswap.h
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Sat Sep 9 01:43:15 1995 ylo 10 * Created: Sat Sep 9 01:43:15 1995 ylo
11Last modified: Sat Sep 9 02:34:04 1995 ylo 11 * Last modified: Sat Sep 9 02:34:04 1995 ylo
12 12 *
13*/ 13 */
14 14
15#ifndef UIDSWAP_H 15#ifndef UIDSWAP_H
16#define UIDSWAP_H 16#define UIDSWAP_H
17 17
18/* Temporarily changes to the given uid. If the effective user id is not 18/*
19 root, this does nothing. This call cannot be nested. */ 19 * Temporarily changes to the given uid. If the effective user id is not
20void temporarily_use_uid(uid_t uid); 20 * root, this does nothing. This call cannot be nested.
21 */
22void temporarily_use_uid(uid_t uid);
21 23
22/* Restores the original effective user id after temporarily_use_uid(). 24/*
23 This should only be called while temporarily_use_uid is effective. */ 25 * Restores the original effective user id after temporarily_use_uid().
24void restore_uid(); 26 * This should only be called while temporarily_use_uid is effective.
27 */
28void restore_uid();
25 29
26/* Permanently sets all uids to the given uid. This cannot be called while 30/*
27 temporarily_use_uid is effective. This must also clear any saved uids. */ 31 * Permanently sets all uids to the given uid. This cannot be called while
28void permanently_set_uid(uid_t uid); 32 * temporarily_use_uid is effective. This must also clear any saved uids.
33 */
34void permanently_set_uid(uid_t uid);
29 35
30#endif /* UIDSWAP_H */ 36#endif /* UIDSWAP_H */
diff --git a/xmalloc.c b/xmalloc.c
index b536f9d19..0f1c43051 100644
--- a/xmalloc.c
+++ b/xmalloc.c
@@ -1,56 +1,53 @@
1/* 1/*
2 2 * Author: Tatu Ylonen <ylo@cs.hut.fi>
3xmalloc.c 3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 4 * All rights reserved
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Created: Mon Mar 20 21:23:10 1995 ylo
6 6 * Versions of malloc and friends that check their results, and never return
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * failure (they call fatal if they encounter an error).
8 All rights reserved 8 */
9
10Created: Mon Mar 20 21:23:10 1995 ylo
11
12Versions of malloc and friends that check their results, and never return
13failure (they call fatal if they encounter an error).
14
15*/
16 9
17#include "includes.h" 10#include "includes.h"
18RCSID("$Id: xmalloc.c,v 1.1 1999/10/27 03:42:46 damien Exp $"); 11RCSID("$Id: xmalloc.c,v 1.2 1999/11/24 13:26:23 damien Exp $");
19 12
20#include "ssh.h" 13#include "ssh.h"
21 14
22void *xmalloc(size_t size) 15void *
16xmalloc(size_t size)
23{ 17{
24 void *ptr = malloc(size); 18 void *ptr = malloc(size);
25 if (ptr == NULL) 19 if (ptr == NULL)
26 fatal("xmalloc: out of memory (allocating %d bytes)", (int)size); 20 fatal("xmalloc: out of memory (allocating %d bytes)", (int) size);
27 return ptr; 21 return ptr;
28} 22}
29 23
30void *xrealloc(void *ptr, size_t new_size) 24void *
25xrealloc(void *ptr, size_t new_size)
31{ 26{
32 void *new_ptr; 27 void *new_ptr;
33 28
34 if (ptr == NULL) 29 if (ptr == NULL)
35 fatal("xrealloc: NULL pointer given as argument"); 30 fatal("xrealloc: NULL pointer given as argument");
36 new_ptr = realloc(ptr, new_size); 31 new_ptr = realloc(ptr, new_size);
37 if (new_ptr == NULL) 32 if (new_ptr == NULL)
38 fatal("xrealloc: out of memory (new_size %d bytes)", (int)new_size); 33 fatal("xrealloc: out of memory (new_size %d bytes)", (int) new_size);
39 return new_ptr; 34 return new_ptr;
40} 35}
41 36
42void xfree(void *ptr) 37void
38xfree(void *ptr)
43{ 39{
44 if (ptr == NULL) 40 if (ptr == NULL)
45 fatal("xfree: NULL pointer given as argument"); 41 fatal("xfree: NULL pointer given as argument");
46 free(ptr); 42 free(ptr);
47} 43}
48 44
49char *xstrdup(const char *str) 45char *
46xstrdup(const char *str)
50{ 47{
51 int len = strlen(str) + 1; 48 int len = strlen(str) + 1;
52 49
53 char *cp = xmalloc(len); 50 char *cp = xmalloc(len);
54 strlcpy(cp, str, len); 51 strlcpy(cp, str, len);
55 return cp; 52 return cp;
56} 53}
diff --git a/xmalloc.h b/xmalloc.h
index 7a9610e7e..94280b118 100644
--- a/xmalloc.h
+++ b/xmalloc.h
@@ -1,34 +1,34 @@
1/* 1/*
2 2 *
3xmalloc.h 3 * xmalloc.h
4 4 *
5Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 6 *
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved 8 * All rights reserved
9 9 *
10Created: Mon Mar 20 22:09:17 1995 ylo 10 * Created: Mon Mar 20 22:09:17 1995 ylo
11 11 *
12Versions of malloc and friends that check their results, and never return 12 * Versions of malloc and friends that check their results, and never return
13failure (they call fatal if they encounter an error). 13 * failure (they call fatal if they encounter an error).
14 14 *
15*/ 15 */
16 16
17/* RCSID("$Id: xmalloc.h,v 1.1 1999/10/27 03:42:46 damien Exp $"); */ 17/* RCSID("$Id: xmalloc.h,v 1.2 1999/11/24 13:26:23 damien Exp $"); */
18 18
19#ifndef XMALLOC_H 19#ifndef XMALLOC_H
20#define XMALLOC_H 20#define XMALLOC_H
21 21
22/* Like malloc, but calls fatal() if out of memory. */ 22/* Like malloc, but calls fatal() if out of memory. */
23void *xmalloc(size_t size); 23void *xmalloc(size_t size);
24 24
25/* Like realloc, but calls fatal() if out of memory. */ 25/* Like realloc, but calls fatal() if out of memory. */
26void *xrealloc(void *ptr, size_t new_size); 26void *xrealloc(void *ptr, size_t new_size);
27 27
28/* Frees memory allocated using xmalloc or xrealloc. */ 28/* Frees memory allocated using xmalloc or xrealloc. */
29void xfree(void *ptr); 29void xfree(void *ptr);
30 30
31/* Allocates memory using xmalloc, and copies the string into that memory. */ 31/* Allocates memory using xmalloc, and copies the string into that memory. */
32char *xstrdup(const char *str); 32char *xstrdup(const char *str);
33 33
34#endif /* XMALLOC_H */ 34#endif /* XMALLOC_H */