1/************************************************************************************
2 Copyright (C) 2014-2018 MariaDB Corporation AB
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public
15 License along with this library; if not see <http://www.gnu.org/licenses>
16 or write to the Free Software Foundation, Inc.,
17 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
18*************************************************************************************/
19#ifndef _WIN32
20#define _GNU_SOURCE 1
21#endif
22
23#include <ma_global.h>
24#include <mysql.h>
25#include <mysql/client_plugin.h>
26#include <string.h>
27#include <memory.h>
28
29#ifndef WIN32
30#include <dlfcn.h>
31#endif
32
33
34/* function prototypes */
35extern char *get_tty_password(char *opt_message, char *buff, int bufflen);
36static int auth_dialog_open(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
37static int auth_dialog_init(char *unused1,
38 size_t unused2,
39 int unused3,
40 va_list);
41
42mysql_authentication_dialog_ask_t auth_dialog_func;
43
44#ifndef PLUGIN_DYNAMIC
45struct st_mysql_client_plugin_AUTHENTICATION dialog_client_plugin=
46#else
47struct st_mysql_client_plugin_AUTHENTICATION _mysql_client_plugin_declaration_ =
48#endif
49{
50 MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
51 MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
52 "dialog",
53 "Sergei Golubchik, Georg Richter",
54 "Dialog Client Authentication Plugin",
55 {0,1,0},
56 "LGPL",
57 NULL,
58 auth_dialog_init,
59 NULL,
60 NULL,
61 auth_dialog_open
62};
63
64
65/* {{{ static char *auth_dialog_native_prompt */
66/*
67 Native dialog prompt via stdin
68
69 SYNOPSIS
70 auth_dialog_native_prompt
71 mysql connection handle
72 type input type
73 prompt prompt
74 buffer Input buffer
75 buffer_len Input buffer length
76
77 DESCRIPTION
78
79 RETURNS
80 Input buffer
81*/
82static char *auth_dialog_native_prompt(MYSQL *mysql __attribute__((unused)),
83 int type,
84 const char *prompt,
85 char *buffer,
86 int buffer_len)
87{
88 /* display prompt */
89 fprintf(stdout, "%s", prompt);
90
91 memset(buffer, 0, buffer_len);
92
93 /* for type 2 (password) don't display input */
94 if (type != 2)
95 {
96 if (fgets(buffer, buffer_len - 1, stdin))
97 {
98 /* remove trailing line break */
99 size_t length= strlen(buffer);
100 if (length && buffer[length - 1] == '\n')
101 buffer[length - 1]= 0;
102 }
103 }
104 else
105 {
106 get_tty_password((char *)"", buffer, buffer_len - 1);
107 }
108 return buffer;
109}
110/* }}} */
111
112/* {{{ static int auth_dialog_open */
113/*
114 opens dialog
115
116 SYNOPSIS
117 vio Vio
118 mysql connection handle
119
120 DESCRIPTION
121 reads prompt from server, waits for input and sends
122 input to server.
123 Note that first byte of prompt indicates if we have a
124 password which should not be echoed to stdout.
125
126 RETURN
127 CR_ERROR if an error occurs
128 CR_OK
129 CR_OK_HANDSHAKE_COMPLETE
130*/
131static int auth_dialog_open(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
132{
133 uchar *packet;
134 uchar type= 0;
135 char dialog_buffer[1024];
136 char *response;
137 int packet_length;
138 my_bool first_loop= TRUE;
139
140 do {
141 if ((packet_length= vio->read_packet(vio, &packet)) == -1)
142 /* read error */
143 return CR_ERROR;
144
145 if (packet_length > 0)
146 {
147 type= *packet;
148 packet++;
149
150 /* check for protocol packet */
151 if (!type || type == 254)
152 return CR_OK_HANDSHAKE_COMPLETE;
153
154 if ((type >> 1) == 2 &&
155 first_loop &&
156 mysql->passwd && mysql->passwd[0])
157 response= mysql->passwd;
158 else
159 response= auth_dialog_func(mysql, type >> 1,
160 (const char *)packet,
161 dialog_buffer, 1024);
162 }
163 else
164 {
165 /* in case mysql_change_user was called the client needs
166 to send packet first */
167 response= mysql->passwd;
168 }
169 if (!response ||
170 vio->write_packet(vio, (uchar *)response, (int)strlen(response) + 1))
171 return CR_ERROR;
172
173 first_loop= FALSE;
174
175 } while((type & 1) != 1);
176 return CR_OK;
177}
178/* }}} */
179
180/* {{{ static int auth_dialog_init */
181/*
182 Initialization routine
183
184 SYNOPSIS
185 auth_dialog_init
186 unused1
187 unused2
188 unused3
189 unused4
190
191 DESCRIPTION
192 Init function checks if the caller provides own dialog function.
193 The function name must be mariadb_auth_dialog or
194 mysql_authentication_dialog_ask. If the function cannot be found,
195 we will use owr own simple command line input.
196
197 RETURN
198 0 success
199*/
200static int auth_dialog_init(char *unused1 __attribute__((unused)),
201 size_t unused2 __attribute__((unused)),
202 int unused3 __attribute__((unused)),
203 va_list unused4 __attribute__((unused)))
204{
205 void *func;
206#ifdef WIN32
207 if (!(func= GetProcAddress(GetModuleHandle(NULL), "mariadb_auth_dialog")))
208 /* for MySQL users */
209 func= GetProcAddress(GetModuleHandle(NULL), "mysql_authentication_dialog_ask");
210#else
211 if (!(func= dlsym(RTLD_DEFAULT, "mariadb_auth_dialog")))
212 /* for MySQL users */
213 func= dlsym(RTLD_DEFAULT, "mysql_authentication_dialog_ask");
214#endif
215 if (func)
216 auth_dialog_func= (mysql_authentication_dialog_ask_t)func;
217 else
218 auth_dialog_func= auth_dialog_native_prompt;
219
220 return 0;
221}
222/* }}} */
223