MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
qa_auth_interface.c
1 /* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or
4  modify it under the terms of the GNU General Public License as
5  published by the Free Software Foundation; version 2 of the
6  License.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
16 
17 #include <my_global.h>
18 #include <mysql/plugin_auth.h>
19 #include <mysql/client_plugin.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 
29 #define ORDINARY_QUESTION "\2"
30 #define LAST_QUESTION "\3"
31 #define LAST_PASSWORD "\4"
32 #define PASSWORD_QUESTION "\5"
33 
34 /********************* SERVER SIDE ****************************************/
35 
36 static int qa_auth_interface (MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info)
37 {
38  unsigned char *pkt;
39  int pkt_len, err= CR_OK;
40 
41  /* send a password question */
42  if (vio->write_packet(vio, (const unsigned char *) PASSWORD_QUESTION, 1))
43  return CR_ERROR;
44 
45  /* read the answer */
46  if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)
47  return CR_ERROR;
48 
49  info->password_used= PASSWORD_USED_YES;
50 
51  /* fail if the password is wrong */
52  if (strcmp((const char *) pkt, info->auth_string))
53  return CR_ERROR;
54 
55 /* Check the contens of components of info */
56  if (strcmp(info->user_name, "qa_test_1_user")== 0)
57  {
58  if (info->user_name_length != 14)
59  err= CR_ERROR;
60  if (strcmp(info->auth_string, "qa_test_1_dest"))
61  err= CR_ERROR;
62  if (info->auth_string_length != 14)
63  err= CR_ERROR;
64 /*
65  To be set by the plugin
66  if (strcmp(info->authenticated_as, "qa_test_1_user"))
67  err= CR_ERROR;
68  if (strcmp(info->external_user, ""))
69  err= CR_ERROR;
70 */
71  if (info->password_used != PASSWORD_USED_YES)
72  err= CR_ERROR;
73  if (strcmp(info->host_or_ip, "localhost"))
74  err= CR_ERROR;
75  if (info->host_or_ip_length != 9)
76  err= CR_ERROR;
77  }
78 /* Assign values to the components of info even if not intended and watch the effect */
79  else if (strcmp(info->user_name, "qa_test_2_user")== 0)
80  {
81  /* Overwriting not intended, but with effect on USER() */
82  strcpy(info->user_name, "user_name");
83  info->user_name_length= 9;
84  /* Overwriting not intended, effect not visible */
85  strcpy((char *)info->auth_string, "auth_string");
86  info->auth_string_length= 11;
87  /* Assign with account for authorization, effect on CURRENT_USER() */
88  strcpy(info->authenticated_as, "authenticated_as");
89  /* Assign with an external account, effect on @@local.EXTERNAL_USER */
90  strcpy(info->external_user, "externaluser");
91  /*
92  Overwriting will cause a core dump
93  strcpy(info->host_or_ip, "host_or_ip");
94  info->host_or_ip_length= 10;
95  */
96  }
97 /* Invalid, means too high values for length */
98  else if (strcmp(info->user_name, "qa_test_3_user")== 0)
99  {
100 /* Original value is 14. Test runs also with higher value. Changes have no effect.*/
101  info->user_name_length= 28;
102  strcpy((char *)info->auth_string, "qa_test_3_dest");
103 /* Original value is 14. Test runs also with higher value. Changes have no effect.*/
104  info->auth_string_length= 28;
105  strcpy(info->authenticated_as, info->auth_string);
106  strcpy(info->external_user, info->auth_string);
107  }
108 /* Invalid, means too low values for length */
109  else if (strcmp(info->user_name, "qa_test_4_user")== 0)
110  {
111 /* Original value is 14. Test runs also with lower value. Changes have no effect.*/
112  info->user_name_length= 8;
113  strcpy((char *)info->auth_string, "qa_test_4_dest");
114 /* Original value is 14. Test runs also with lower value. Changes have no effect.*/
115  info->auth_string_length= 8;
116  strcpy(info->authenticated_as, info->auth_string);
117  strcpy(info->external_user, info->auth_string);
118  }
119 /* Overwrite with empty values */
120  else if (strcmp(info->user_name, "qa_test_5_user")== 0)
121  {
122 /* This assignment has no effect.*/
123  strcpy(info->user_name, "");
124  info->user_name_length= 0;
125 /* This assignment has no effect.*/
126  strcpy((char *)info->auth_string, "");
127  info->auth_string_length= 0;
128 /* This assignment caused an error or an "empty" user */
129  strcpy(info->authenticated_as, "");
130 /* This assignment has no effect.*/
131  strcpy(info->external_user, "");
132  /*
133  Overwriting will cause a core dump
134  strcpy(info->host_or_ip, "");
135  info->host_or_ip_length= 0;
136  */
137  }
138 /* Set to 'root' */
139  else if (strcmp(info->user_name, "qa_test_6_user")== 0)
140  {
141  strcpy(info->authenticated_as, "root");
142  }
143  else
144  {
145  err= CR_ERROR;
146  }
147  return err;
148 }
149 
150 static struct st_mysql_auth qa_auth_test_handler=
151 {
152  MYSQL_AUTHENTICATION_INTERFACE_VERSION,
153  "qa_auth_interface", /* requires test_plugin client's plugin */
154  qa_auth_interface
155 };
156 
157 mysql_declare_plugin(test_plugin)
158 {
159  MYSQL_AUTHENTICATION_PLUGIN,
160  &qa_auth_test_handler,
161  "qa_auth_interface",
162  "Horst Hunger",
163  "plugin API test plugin",
164  PLUGIN_LICENSE_GPL,
165  NULL,
166  NULL,
167  0x0100,
168  NULL,
169  NULL,
170  NULL,
171  0,
172 }
173 mysql_declare_plugin_end;
174 
175 /********************* CLIENT SIDE ***************************************/
176 /*
177  client plugin used for testing the plugin API
178 */
179 #include <mysql.h>
180 
197 static int test_plugin_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
198 {
199  unsigned char *pkt, cmd= 0;
200  int pkt_len, res;
201  char *reply;
202 
203  do
204  {
205  /* read the prompt */
206  pkt_len= vio->read_packet(vio, &pkt);
207  if (pkt_len < 0)
208  return CR_ERROR;
209 
210  if (pkt == 0)
211  {
212  /*
213  in mysql_change_user() the client sends the first packet, so
214  the first vio->read_packet() does nothing (pkt == 0).
215 
216  We send the "password", assuming the client knows what its doing.
217  (in other words, the dialog plugin should be only set as a default
218  authentication plugin on the client if the first question
219  asks for a password - which will be sent in cleat text, by the way)
220  */
221  reply= mysql->passwd;
222  }
223  else
224  {
225  cmd= *pkt++;
226 
227  /* is it MySQL protocol (0=OK or 254=need old password) packet ? */
228  if (cmd == 0 || cmd == 254)
229  return CR_OK_HANDSHAKE_COMPLETE; /* yes. we're done */
230 
231  /*
232  asking for a password with an empty prompt means mysql->password
233  otherwise return an error
234  */
235  if ((cmd == LAST_PASSWORD[0] || cmd == PASSWORD_QUESTION[0]) && *pkt == 0)
236  reply= mysql->passwd;
237  else
238  return CR_ERROR;
239  }
240  if (!reply)
241  return CR_ERROR;
242  /* send the reply to the server */
243  res= vio->write_packet(vio, (const unsigned char *) reply,
244  strlen(reply) + 1);
245 
246  if (res)
247  return CR_ERROR;
248 
249  /* repeat unless it was the last question */
250  } while (cmd != LAST_QUESTION[0] && cmd != PASSWORD_QUESTION[0]);
251 
252  /* the job of reading the ok/error packet is left to the server */
253  return CR_OK;
254 }
255 
256 
257 mysql_declare_client_plugin(AUTHENTICATION)
258  "qa_auth_interface",
259  "Horst Hunger",
260  "Dialog Client Authentication Plugin",
261  {0,1,0},
262  "GPL",
263  NULL,
264  NULL,
265  NULL,
266  NULL,
267  test_plugin_client
268 mysql_end_client_plugin;