26
|
1 #include "includes.h" |
|
2 #include "session.h" |
|
3 #include "dbutil.h" |
|
4 #include "kex.h" |
|
5 #include "ssh.h" |
|
6 #include "packet.h" |
|
7 #include "tcpfwd-direct.h" |
|
8 #include "tcpfwd-remote.h" |
|
9 #include "channel.h" |
|
10 #include "random.h" |
33
|
11 #include "service.h" |
26
|
12 |
|
13 static void cli_remoteclosed(); |
|
14 static void cli_sessionloop(); |
33
|
15 static void cli_session_init(); |
26
|
16 |
|
17 struct clientsession cli_ses; /* GLOBAL */ |
|
18 |
|
19 static const packettype cli_packettypes[] = { |
|
20 /* TYPE, AUTHREQUIRED, FUNCTION */ |
|
21 {SSH_MSG_KEXINIT, recv_msg_kexinit}, |
|
22 {SSH_MSG_KEXDH_REPLY, recv_msg_kexdh_reply}, // client |
|
23 {SSH_MSG_NEWKEYS, recv_msg_newkeys}, |
|
24 {SSH_MSG_CHANNEL_DATA, recv_msg_channel_data}, |
|
25 {SSH_MSG_CHANNEL_WINDOW_ADJUST, recv_msg_channel_window_adjust}, |
|
26 {SSH_MSG_GLOBAL_REQUEST, recv_msg_global_request_remotetcp}, |
|
27 {SSH_MSG_CHANNEL_REQUEST, recv_msg_channel_request}, |
|
28 {SSH_MSG_CHANNEL_OPEN, recv_msg_channel_open}, |
|
29 {SSH_MSG_CHANNEL_EOF, recv_msg_channel_eof}, |
|
30 {SSH_MSG_CHANNEL_CLOSE, recv_msg_channel_close}, |
|
31 {SSH_MSG_CHANNEL_OPEN_CONFIRMATION, recv_msg_channel_open_confirmation}, |
|
32 {SSH_MSG_CHANNEL_OPEN_FAILURE, recv_msg_channel_open_failure}, |
33
|
33 {SSH_MSG_USERAUTH_FAILURE, recv_msg_userauth_failure}, |
|
34 {SSH_MSG_USERAUTH_SUCCESS, recv_msg_userauth_success}, |
26
|
35 {0, 0} /* End */ |
|
36 }; |
|
37 |
|
38 static const struct ChanType *cli_chantypes[] = { |
|
39 // &clichansess, |
|
40 /* &chan_tcpdirect etc, though need to only allow if we've requested |
|
41 * that forwarding */ |
|
42 NULL /* Null termination */ |
|
43 }; |
33
|
44 |
26
|
45 void cli_session(int sock, char* remotehost) { |
|
46 |
|
47 crypto_init(); |
|
48 common_session_init(sock, remotehost); |
|
49 |
|
50 chaninitialise(cli_chantypes); |
|
51 |
|
52 |
33
|
53 /* Set up cli_ses vars */ |
|
54 cli_session_init(); |
26
|
55 |
|
56 /* Ready to go */ |
|
57 sessinitdone = 1; |
|
58 |
|
59 /* Exchange identification */ |
|
60 session_identification(); |
|
61 |
|
62 seedrandom(); |
|
63 |
|
64 send_msg_kexinit(); |
|
65 |
|
66 /* XXX here we do stuff differently */ |
|
67 |
|
68 session_loop(cli_sessionloop); |
|
69 |
|
70 /* Not reached */ |
|
71 |
33
|
72 } |
26
|
73 |
33
|
74 static void cli_session_init() { |
|
75 |
|
76 cli_ses.state = STATE_NOTHING; |
|
77 cli_ses.kex_state = KEX_NOTHING; |
|
78 |
|
79 /* For printing "remote host closed" for the user */ |
|
80 ses.remoteclosed = cli_remoteclosed; |
|
81 ses.buf_match_algo = cli_buf_match_algo; |
|
82 |
|
83 /* packet handlers */ |
|
84 ses.packettypes = cli_packettypes; |
26
|
85 } |
|
86 |
33
|
87 /* This function drives the progress of the session - it initiates KEX, |
|
88 * service, userauth and channel requests */ |
26
|
89 static void cli_sessionloop() { |
|
90 |
33
|
91 TRACE(("enter cli_sessionloop")); |
|
92 |
|
93 if (cli_ses.kex_state == KEX_NOTHING && ses.kexstate.recvkexinit) { |
|
94 cli_ses.state = KEXINIT_RCVD; |
|
95 } |
|
96 |
|
97 if (cli_ses.state == KEXINIT_RCVD) { |
|
98 |
|
99 /* We initiate the KEXDH. If DH wasn't the correct type, the KEXINIT |
|
100 * negotiation would have failed. */ |
|
101 send_msg_kexdh_init(); |
|
102 cli_ses.kex_state = KEXDH_INIT_SENT; |
|
103 TRACE(("leave cli_sessionloop: done with KEXINIT_RCVD")); |
|
104 return; |
|
105 } |
|
106 |
|
107 /* A KEX has finished, so we should go back to our KEX_NOTHING state */ |
|
108 if (cli_ses.kex_state != KEX_NOTHING && ses.kexstate.recvkexinit == 0 |
|
109 && ses.kexstate.sentkexinit == 0) { |
|
110 cli_ses.kex_state = KEX_NOTHING; |
|
111 } |
|
112 |
|
113 /* We shouldn't do anything else if a KEX is in progress */ |
|
114 if (cli_ses.kex_state != KEX_NOTHING) { |
|
115 TRACE(("leave cli_sessionloop: kex_state != KEX_NOTHING")); |
|
116 return; |
|
117 } |
|
118 |
|
119 /* We should exit if we haven't donefirstkex: we shouldn't reach here |
|
120 * in normal operation */ |
|
121 if (ses.kexstate.donefirstkex == 0) { |
|
122 TRACE(("XXX XXX might be bad! leave cli_sessionloop: haven't donefirstkex")); |
|
123 } |
|
124 |
26
|
125 switch (cli_ses.state) { |
|
126 |
33
|
127 case STATE_NOTHING: |
|
128 /* We've got the transport layer sorted, we now need to request |
|
129 * userauth */ |
|
130 send_msg_service_request(SSH_SERVICE_USERAUTH); |
|
131 cli_ses.state = SERVICE_AUTH_REQ_SENT; |
|
132 return; |
26
|
133 |
33
|
134 /* userauth code */ |
|
135 case SERVICE_AUTH_ACCEPT_RCVD: |
|
136 cli_get_user(); |
|
137 cli_auth_getmethods(); |
|
138 cli_ses.state = USERAUTH_METHODS_SENT; |
|
139 return; |
|
140 |
|
141 case USERAUTH_FAIL_RCVD: |
|
142 cli_auth_try(); |
|
143 return; |
|
144 |
|
145 /* XXX more here needed */ |
|
146 |
|
147 |
|
148 default: |
|
149 break; |
26
|
150 } |
|
151 |
|
152 |
|
153 } |
|
154 |
|
155 /* called when the remote side closes the connection */ |
|
156 static void cli_remoteclosed() { |
|
157 |
|
158 /* XXX TODO perhaps print a friendlier message if we get this but have |
|
159 * already sent/received disconnect message(s) ??? */ |
|
160 close(ses.sock); |
|
161 ses.sock = -1; |
33
|
162 dropbear_exit("remote closed the connection"); |
26
|
163 } |