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