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