Mercurial > dropbear
comparison common-session.c @ 4:fe6bca95afa7
Makefile.in contains updated files required
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Tue, 01 Jun 2004 02:46:09 +0000 |
parents | |
children | ab00ef513e97 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 4:fe6bca95afa7 |
---|---|
1 /* | |
2 * Dropbear - a SSH2 server | |
3 * | |
4 * Copyright (c) 2002,2003 Matt Johnston | |
5 * All rights reserved. | |
6 * | |
7 * Permission is hereby granted, free of charge, to any person obtaining a copy | |
8 * of this software and associated documentation files (the "Software"), to deal | |
9 * in the Software without restriction, including without limitation the rights | |
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
11 * copies of the Software, and to permit persons to whom the Software is | |
12 * furnished to do so, subject to the following conditions: | |
13 * | |
14 * The above copyright notice and this permission notice shall be included in | |
15 * all copies or substantial portions of the Software. | |
16 * | |
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
23 * SOFTWARE. */ | |
24 | |
25 #include "includes.h" | |
26 #include "session.h" | |
27 #include "dbutil.h" | |
28 #include "packet.h" | |
29 #include "algo.h" | |
30 #include "buffer.h" | |
31 #include "dss.h" | |
32 #include "ssh.h" | |
33 #include "random.h" | |
34 #include "kex.h" | |
35 #include "channel.h" | |
36 #include "atomicio.h" | |
37 | |
38 struct sshsession ses; | |
39 | |
40 /* need to know if the session struct has been initialised, this way isn't the | |
41 * cleanest, but works OK */ | |
42 int sessinitdone = 0; | |
43 | |
44 /* this is set when we get SIGINT or SIGTERM, the handler is in main.c */ | |
45 int exitflag = 0; | |
46 | |
47 static int ident_readln(int fd, char* buf, int count); | |
48 | |
49 | |
50 void(*session_remoteclosed)() = NULL; | |
51 | |
52 | |
53 /* called only at the start of a session, set up initial state */ | |
54 void common_session_init(int sock, runopts *opts) { | |
55 | |
56 TRACE(("enter session_init")); | |
57 | |
58 ses.remoteaddr = NULL; | |
59 ses.remotehost = NULL; | |
60 | |
61 ses.sock = sock; | |
62 ses.maxfd = sock; | |
63 | |
64 ses.opts = opts; | |
65 | |
66 ses.connecttimeout = 0; | |
67 | |
68 kexinitialise(); /* initialise the kex state */ | |
69 chaninitialise(); /* initialise the channel state */ | |
70 | |
71 ses.writepayload = buf_new(MAX_TRANS_PAYLOAD_LEN); | |
72 ses.transseq = 0; | |
73 | |
74 ses.readbuf = NULL; | |
75 ses.decryptreadbuf = NULL; | |
76 ses.payload = NULL; | |
77 ses.recvseq = 0; | |
78 | |
79 ses.expecting = SSH_MSG_KEXINIT; | |
80 ses.dataallowed = 0; /* don't send data yet, we'll wait until after kex */ | |
81 ses.ignorenext = 0; | |
82 | |
83 /* set all the algos to none */ | |
84 ses.keys = (struct key_context*)m_malloc(sizeof(struct key_context)); | |
85 ses.newkeys = NULL; | |
86 ses.keys->recv_algo_crypt = &dropbear_nocipher; | |
87 ses.keys->trans_algo_crypt = &dropbear_nocipher; | |
88 | |
89 ses.keys->recv_algo_mac = &dropbear_nohash; | |
90 ses.keys->trans_algo_mac = &dropbear_nohash; | |
91 | |
92 ses.keys->algo_kex = -1; | |
93 ses.keys->algo_hostkey = -1; | |
94 ses.keys->recv_algo_comp = DROPBEAR_COMP_NONE; | |
95 ses.keys->trans_algo_comp = DROPBEAR_COMP_NONE; | |
96 | |
97 #ifndef DISABLE_ZLIB | |
98 ses.keys->recv_zstream = NULL; | |
99 ses.keys->trans_zstream = NULL; | |
100 #endif | |
101 | |
102 /* key exchange buffers */ | |
103 ses.session_id = NULL; | |
104 ses.kexhashbuf = NULL; | |
105 ses.transkexinit = NULL; | |
106 ses.dh_K = NULL; | |
107 ses.remoteident = NULL; | |
108 | |
109 | |
110 TRACE(("leave session_init")); | |
111 } | |
112 | |
113 /* clean up a session on exit */ | |
114 void common_session_cleanup() { | |
115 | |
116 TRACE(("enter session_cleanup")); | |
117 | |
118 /* we can't cleanup if we don't know the session state */ | |
119 if (!sessinitdone) { | |
120 TRACE(("leave session_cleanup: !sessinitdone")); | |
121 return; | |
122 } | |
123 | |
124 m_free(ses.session_id); | |
125 freerunopts(ses.opts); | |
126 m_burn(ses.keys, sizeof(struct key_context)); | |
127 m_free(ses.keys); | |
128 | |
129 chancleanup(); | |
130 | |
131 TRACE(("leave session_cleanup")); | |
132 } | |
133 | |
134 /* Check all timeouts which are required. Currently these are the time for | |
135 * user authentication, and the automatic rekeying. */ | |
136 void checktimeouts() { | |
137 | |
138 struct timeval tv; | |
139 long secs; | |
140 | |
141 if (gettimeofday(&tv, 0) < 0) { | |
142 dropbear_exit("Error getting time"); | |
143 } | |
144 | |
145 secs = tv.tv_sec; | |
146 | |
147 if (ses.connecttimeout != 0 && secs > ses.connecttimeout) { | |
148 dropbear_close("Timeout before auth"); | |
149 } | |
150 | |
151 /* we can't rekey if we haven't done remote ident exchange yet */ | |
152 if (ses.remoteident == NULL) { | |
153 return; | |
154 } | |
155 | |
156 if (!ses.kexstate.sentkexinit | |
157 && (secs - ses.kexstate.lastkextime >= KEX_REKEY_TIMEOUT | |
158 || ses.kexstate.datarecv+ses.kexstate.datatrans >= KEX_REKEY_DATA)){ | |
159 TRACE(("rekeying after timeout or max data reached")); | |
160 send_msg_kexinit(); | |
161 } | |
162 } | |
163 void session_identification() { | |
164 | |
165 /* max length of 255 chars */ | |
166 char linebuf[256]; | |
167 int len = 0; | |
168 char done = 0; | |
169 | |
170 /* write our version string, this blocks */ | |
171 if (atomicio(write, ses.sock, LOCAL_IDENT "\r\n", | |
172 strlen(LOCAL_IDENT "\r\n")) == DROPBEAR_FAILURE) { | |
173 dropbear_exit("Error writing ident string"); | |
174 } | |
175 | |
176 len = ident_readln(ses.sock, linebuf, 256); | |
177 if (len >= 4 && memcmp(linebuf, "SSH-", 4) == 0) { | |
178 /* start of line matches */ | |
179 done = 1; | |
180 } | |
181 | |
182 if (!done) { | |
183 dropbear_exit("Failed to get client version"); | |
184 } else { | |
185 /* linebuf is already null terminated */ | |
186 ses.remoteident = m_malloc(len); | |
187 memcpy(ses.remoteident, linebuf, len); | |
188 } | |
189 | |
190 TRACE(("remoteident: %s", ses.remoteident)); | |
191 | |
192 } | |
193 | |
194 /* returns the length including null-terminating zero on success, | |
195 * or -1 on failure */ | |
196 static int ident_readln(int fd, char* buf, int count) { | |
197 | |
198 char in; | |
199 int pos = 0; | |
200 int num = 0; | |
201 fd_set fds; | |
202 struct timeval timeout; | |
203 | |
204 TRACE(("enter ident_readln")); | |
205 | |
206 if (count < 1) { | |
207 return -1; | |
208 } | |
209 | |
210 FD_ZERO(&fds); | |
211 | |
212 /* select since it's a non-blocking fd */ | |
213 | |
214 /* leave space to null-terminate */ | |
215 while (pos < count-1) { | |
216 | |
217 FD_SET(fd, &fds); | |
218 | |
219 timeout.tv_sec = 1; | |
220 timeout.tv_usec = 0; | |
221 if (select(fd+1, &fds, NULL, NULL, &timeout) < 0) { | |
222 if (errno == EINTR) { | |
223 continue; | |
224 } | |
225 TRACE(("leave ident_readln: select error")); | |
226 return -1; | |
227 } | |
228 | |
229 checktimeouts(); | |
230 | |
231 /* Have to go one byte at a time, since we don't want to read past | |
232 * the end, and have to somehow shove bytes back into the normal | |
233 * packet reader */ | |
234 if (FD_ISSET(fd, &fds)) { | |
235 num = read(fd, &in, 1); | |
236 /* a "\n" is a newline, "\r" we want to read in and keep going | |
237 * so that it won't be read as part of the next line */ | |
238 if (num < 0) { | |
239 /* error */ | |
240 if (errno == EINTR) { | |
241 continue; /* not a real error */ | |
242 } | |
243 TRACE(("leave ident_readln: read error")); | |
244 return -1; | |
245 } | |
246 if (num == 0) { | |
247 /* EOF */ | |
248 TRACE(("leave ident_readln: EOF")); | |
249 return -1; | |
250 } | |
251 if (in == '\n') { | |
252 /* end of ident string */ | |
253 break; | |
254 } | |
255 /* we don't want to include '\r's */ | |
256 if (in != '\r') { | |
257 buf[pos] = in; | |
258 pos++; | |
259 } | |
260 } | |
261 } | |
262 | |
263 buf[pos] = '\0'; | |
264 TRACE(("leave ident_readln: return %d", pos+1)); | |
265 return pos+1; | |
266 } | |
267 |