1 /* Copyright (c) 2011, 2021, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
22
23 #include "handshake.h"
24
25 #include <mysql.h> // for MYSQL structure
26
27
28 /// Client-side context for authentication handshake
29
30 class Handshake_client: public Handshake
31 {
32 /**
33 Name of the server's service for which we authenticate.
34
35 The service name is sent by server in the initial packet. If no
36 service name is used, this member is @c NULL.
37 */
38 SEC_WCHAR *m_service_name;
39
40 /// Buffer for storing service name obtained from server.
41 SEC_WCHAR m_service_name_buf[MAX_SERVICE_NAME_LENGTH];
42
43 Connection &m_con;
44
45 public:
46
47 Handshake_client(Connection &con, const char *target, size_t len);
48 ~Handshake_client();
49
50 Blob first_packet();
51 Blob process_data(const Blob&);
52
53 Blob read_packet();
54 int write_packet(Blob &data);
55 };
56
57
58 /**
59 Create authentication handshake context for client.
60
61 @param con connection for communication with the peer
62 @param target name of the target service with which we will authenticate
63 (can be NULL if not used)
64
65 Some security packages (like Kerberos) require providing explicit name
66 of the service with which a client wants to authenticate. The server-side
67 authentication plugin sends this name in the greeting packet
68 (see @c win_auth_handshake_{server,client}() functions).
69 */
70
Handshake_client(Connection & con,const char * target,size_t len)71 Handshake_client::Handshake_client(Connection &con,
72 const char *target, size_t len)
73 : Handshake(SSP_NAME, CLIENT), m_service_name(NULL), m_con(con)
74 {
75 if (!target || 0 == len)
76 return;
77
78 // Convert received UPN to internal WCHAR representation.
79
80 m_service_name= utf8_to_wchar(target, &len);
81
82 if (m_service_name)
83 DBUG_PRINT("info", ("Using target service: %S\n", m_service_name));
84 else
85 {
86 /*
87 Note: we ignore errors here - m_target will be NULL, the target name
88 will not be used and system will fall-back to NTLM authentication. But
89 we leave trace in error log.
90 */
91 ERROR_LOG(WARNING, ("Could not decode UPN sent by the server"
92 "; target service name will not be used"
93 " and Kerberos authentication will not work"));
94 }
95 }
96
97
~Handshake_client()98 Handshake_client::~Handshake_client()
99 {
100 if (m_service_name)
101 free(m_service_name);
102 }
103
104
read_packet()105 Blob Handshake_client::read_packet()
106 {
107 /*
108 We do a fake read in the first round because first
109 packet from the server containing UPN must be read
110 before the handshake context is created and the packet
111 processing loop starts. We return an empty blob here
112 and process_data() function will ignore it.
113 */
114 if (m_round == 1)
115 return Blob();
116
117 // Otherwise we read packet from the connection.
118
119 Blob packet= m_con.read();
120 m_error= m_con.error();
121 if (!m_error && packet.is_null())
122 m_error= true; // (no specific error code assigned)
123
124 if (m_error)
125 return Blob();
126
127 DBUG_PRINT("dump", ("Got the following bytes"));
128 DBUG_DUMP("dump", packet.ptr(), packet.len());
129 return packet;
130 }
131
132
133
write_packet(Blob & data)134 int Handshake_client::write_packet(Blob &data)
135 {
136 /*
137 Length of the first data payload send by client authentication plugin is
138 limited to 255 bytes (because it is wrapped inside client authentication
139 packet and is length-encoded with 1 byte for the length).
140
141 If the data payload is longer than 254 bytes, then it is sent in two parts:
142 first part of length 255 will be embedded in the authentication packet,
143 second part will be sent in the following packet. Byte 255 of the first
144 part contains information about the total length of the payload. It is a
145 number of blocks of size 512 bytes which is sufficient to store the
146 combined packets.
147
148 Server's logic for reading first client's payload is as follows
149 (see Handshake_server::read_packet()):
150 1. Read data from the authentication packet, if it is shorter than 255 bytes
151 then that is all data sent by client.
152 2. If there is 255 bytes of data in the authentication packet, read another
153 packet and append it to the data, skipping byte 255 of the first packet
154 which can be used to allocate buffer of appropriate size.
155 */
156
157 size_t len2= 0; // length of the second part of first data payload
158 byte saved_byte; // for saving byte 255 in which data length is stored
159
160 if (m_round == 1 && data.len() > 254)
161 {
162 len2= data.len() - 254;
163 DBUG_PRINT("info", ("Splitting first packet of length %lu"
164 ", %lu bytes will be sent in a second part",
165 data.len(), len2));
166 /*
167 Store in byte 255 the number of 512b blocks that are needed to
168 keep all the data.
169 */
170 unsigned block_count= data.len()/512 + ((data.len() % 512) ? 1 : 0);
171
172 #if !defined(NDEBUG) && defined(WINAUTH_USE_DBUG_LIB)
173
174 /*
175 For testing purposes, use wrong block count to see how server
176 handles this.
177 */
178 DBUG_EXECUTE_IF("winauth_first_packet_test",{
179 block_count= data.len() == 601 ? 0 :
180 data.len() == 602 ? 1 :
181 block_count;
182 });
183
184 #endif
185
186 assert(block_count < (unsigned)0x100);
187 saved_byte= data[254];
188 data[254] = block_count;
189
190 data.trim(255);
191 }
192
193 DBUG_PRINT("dump", ("Sending the following data"));
194 DBUG_DUMP("dump", data.ptr(), data.len());
195 int ret= m_con.write(data);
196
197 if (ret)
198 return ret;
199
200 // Write second part if it is present.
201 if (len2)
202 {
203 data[254]= saved_byte;
204 Blob data2(data.ptr() + 254, len2);
205 DBUG_PRINT("info", ("Sending second part of data"));
206 DBUG_DUMP("info", data2.ptr(), data2.len());
207 ret= m_con.write(data2);
208 }
209
210 return ret;
211 }
212
213
214 /**
215 Process data sent by server.
216
217 @param[in] data blob with data from server
218
219 This method analyses data sent by server during authentication handshake.
220 If client should continue packet exchange, this method returns data to
221 be sent to the server next. If no more data needs to be exchanged, an
222 empty blob is returned and @c is_complete() is @c true. In case of error
223 an empty blob is returned and @c error() gives non-zero error code.
224
225 When invoked for the first time (in the first round of the handshake)
226 there is no data from the server (data blob is null) and the intial
227 packet is generated without an input.
228
229 @return Data to be sent to the server next or null blob if no more data
230 needs to be exchanged or in case of error.
231 */
232
process_data(const Blob & data)233 Blob Handshake_client::process_data(const Blob &data)
234 {
235 #if !defined(NDEBUG) && defined(WINAUTH_USE_DBUG_LIB)
236 /*
237 Code for testing the logic for sending the first client payload.
238
239 A fake data of length given by environment variable TEST_PACKET_LENGTH
240 (or default 255 bytes) is sent to the server. First 2 bytes of the
241 payload contain its total length (LSB first). The length of test data
242 is limited to 2048 bytes.
243
244 Upon receiving test data, server will check that data is correct and
245 refuse connection. If server detects data errors it will crash on
246 assertion.
247
248 This code is executed if debug flag "winauth_first_packet_test" is
249 set, e.g. using client option:
250
251 --debug="d,winauth_first_packet_test"
252
253 The same debug flag must be enabled in the server, e.g. using
254 statement:
255
256 SET GLOBAL debug= '+d,winauth_first_packet_test';
257 */
258
259 static byte test_buf[2048];
260
261 if (m_round == 1
262 && DBUG_EVALUATE_IF("winauth_first_packet_test", true, false))
263 {
264 const char *env= getenv("TEST_PACKET_LENGTH");
265 size_t len= env ? atoi(env) : 0;
266 if (!len)
267 len= 255;
268 if (len > sizeof(test_buf))
269 len= sizeof(test_buf);
270
271 // Store data length in first 2 bytes.
272 byte *ptr= test_buf;
273 *ptr++= len & 0xFF;
274 *ptr++= len >> 8;
275
276 // Fill remaining bytes with known values.
277 for (byte b= 0; ptr < test_buf + len; ++ptr, ++b)
278 *ptr= b;
279
280 return Blob(test_buf, len);
281 };
282
283 #endif
284
285 Security_buffer input(data);
286 SECURITY_STATUS ret;
287
288 m_output.mem_free();
289
290 ret= InitializeSecurityContextW(
291 &m_cred,
292 m_round == 1 ? NULL : &m_sctx, // partial context
293 m_service_name, // service name
294 ASC_REQ_ALLOCATE_MEMORY, // requested attributes
295 0, // reserved
296 SECURITY_NETWORK_DREP, // data representation
297 m_round == 1 ? NULL : &input, // input data
298 0, // reserved
299 &m_sctx, // context
300 &m_output, // output data
301 &m_atts, // attributes
302 &m_expire); // expire date
303
304 if (process_result(ret))
305 {
306 DBUG_PRINT("error",
307 ("InitializeSecurityContext() failed with error %X", ret));
308 return Blob();
309 }
310
311 return m_output.as_blob();
312 }
313
314
315 /**********************************************************************/
316
317
318 /**
319 Perform authentication handshake from client side.
320
321 @param[in] vio pointer to @c MYSQL_PLUGIN_VIO instance to be used
322 for communication with the server
323 @param[in] mysql pointer to a MySQL connection for which we authenticate
324
325 After reading the initial packet from server, containing its UPN to be
326 used as service name, client starts packet exchange by sending the first
327 packet in this exchange. While handshake is not yet completed, client
328 reads packets sent by the server and process them, possibly generating new
329 data to be sent to the server.
330
331 This function reports errors.
332
333 @return 0 on success.
334 */
335
win_auth_handshake_client(MYSQL_PLUGIN_VIO * vio,MYSQL * mysql)336 int win_auth_handshake_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
337 {
338 DBUG_ENTER("win_auth_handshake_client");
339
340 /*
341 Check if we should enable logging.
342 */
343 {
344 const char *opt= getenv("AUTHENTICATION_WIN_LOG");
345 int opt_val= opt ? atoi(opt) : 0;
346 if (opt && !opt_val)
347 {
348 if (!_strnicmp("on", opt, 2)) opt_val= 2;
349 if (!_strnicmp("yes", opt, 3)) opt_val= 2;
350 if (!_strnicmp("true", opt, 4)) opt_val= 2;
351 if (!_strnicmp("debug", opt, 5)) opt_val= 4;
352 if (!_strnicmp("dbug", opt, 4)) opt_val= 4;
353 }
354 set_log_level(opt_val);
355 }
356
357 ERROR_LOG(INFO, ("Authentication handshake for account %s", mysql->user));
358
359 // Create connection object.
360
361 Connection con(vio);
362 assert(!con.error());
363
364 // Read initial packet from server containing service name.
365
366 Blob service_name= con.read();
367
368 if (con.error() || service_name.is_null())
369 {
370 ERROR_LOG(ERROR, ("Error reading initial packet"));
371 DBUG_RETURN(CR_ERROR);
372 }
373 DBUG_PRINT("info", ("Got initial packet of length %d", service_name.len()));
374
375 // Create authentication handshake context using the given service name.
376
377 Handshake_client hndshk(con,
378 service_name[0] ? (char *)service_name.ptr() : NULL,
379 service_name.len());
380 if (hndshk.error())
381 {
382 ERROR_LOG(ERROR, ("Could not create authentication handshake context"));
383 DBUG_RETURN(CR_ERROR);
384 }
385
386 assert(!hndshk.error());
387
388 /*
389 Read and process packets from server until handshake is complete.
390 Note that the first read from server is dummy
391 (see Handshake_client::read_packet()) as we already have read the
392 first packet to establish service name.
393 */
394 if (hndshk.packet_processing_loop())
395 DBUG_RETURN(CR_ERROR);
396
397 assert(!hndshk.error() && hndshk.is_complete());
398
399 DBUG_RETURN(CR_OK);
400 }
401