Merge lp:~sergei.glushchenko/percona-pam-for-mysql/two-plugins into lp:percona-pam-for-mysql

Proposed by Sergei Glushchenko
Status: Merged
Approved by: Laurynas Biveinis
Approved revision: 23
Merged at revision: 23
Proposed branch: lp:~sergei.glushchenko/percona-pam-for-mysql/two-plugins
Merge into: lp:percona-pam-for-mysql
Diff against target: 729 lines (+410/-205)
7 files modified
CMakeLists.txt (+5/-2)
src/Makefile.am (+6/-2)
src/auth_mapping.h (+1/-2)
src/auth_pam.c (+175/-0)
src/auth_pam_common.c (+21/-199)
src/auth_pam_common.h (+71/-0)
src/auth_pam_compat.c (+131/-0)
To merge this branch: bzr merge lp:~sergei.glushchenko/percona-pam-for-mysql/two-plugins
Reviewer Review Type Date Requested Status
Laurynas Biveinis (community) Approve
Review via email: mp+92716@code.launchpad.net

Description of the change

Full-featured PAM auth server plugin was split into two parts.
First one is generic PAM conversation function, second one performs
client-specific message sending and receiving.
(auth_pam_common.c and auth_pam.c) modules. Oracle-compatible
server-side plugin was implemented (auth_pam_compat.c).
Both plugins use auth_pam_common.c. All client-specific behavior
localized in auth_pam.c and auth_pam_compat.c.

auth_pam_compat plugin do not support dialog with client and the only
way to specify password with *mysql* client is using -p option.

Example:
mysql -u test -p111

or
mysql -u test -p
Enter password:

Besides there is no visible difference between case when -p option
used and when it not. So password_used is always set to
PASSWORD_USED_NO_MENTION.

To post a comment you must log in.
Revision history for this message
Laurynas Biveinis (laurynas-biveinis) wrote :

LGTM, thank you.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2012-02-09 16:25:22 +0000
3+++ CMakeLists.txt 2012-02-13 06:42:18 +0000
4@@ -19,9 +19,12 @@
5 CHECK_SYMBOL_EXISTS(getpwnam_r "pwd.h" HAVE_GETPWNAM_R)
6 CHECK_SYMBOL_EXISTS(getgrgid_r "grp.h" HAVE_GETGRGID_R)
7 IF(HAVE_PAM AND HAVE_MYSQLCLIENT AND HAVE_GETPWNAM_R AND HAVE_GETGRGID_R)
8- SET(AUTH_PAM_SOURCES
9- src/auth_pam.c src/lib_auth_pam_client.c src/lib_auth_pam_client.h
10+ SET(AUTH_PAM_COMMON_SOURCES
11+ src/auth_pam_common.c src/lib_auth_pam_client.c src/lib_auth_pam_client.h
12 src/auth_mapping.h src/auth_mapping.c)
13+ SET(AUTH_PAM_SOURCES ${AUTH_PAM_COMMON_SOURCES} src/auth_pam.c)
14+ SET(AUTH_PAM_COMPAT_SOURCES ${AUTH_PAM_COMMON_SOURCES} src/auth_pam_compat.c)
15 MYSQL_ADD_PLUGIN(auth_pam ${AUTH_PAM_SOURCES} LINK_LIBRARIES pam)
16+ MYSQL_ADD_PLUGIN(auth_pam_compat ${AUTH_PAM_COMPAT_SOURCES} LINK_LIBRARIES pam)
17 MYSQL_ADD_PLUGIN(dialog src/dialog.c LINK_LIBRARIES mysqlclient)
18 ENDIF(HAVE_PAM AND HAVE_MYSQLCLIENT AND HAVE_GETPWNAM_R AND HAVE_GETGRGID_R)
19
20=== modified file 'src/Makefile.am'
21--- src/Makefile.am 2012-02-10 04:21:32 +0000
22+++ src/Makefile.am 2012-02-13 06:42:18 +0000
23@@ -16,14 +16,18 @@
24
25 plugindir = @PLUGINDIR@
26
27-plugin_LTLIBRARIES = auth_pam.la test_auth_pam_client.la dialog.la
28+plugin_LTLIBRARIES = auth_pam.la auth_pam_compat.la test_auth_pam_client.la dialog.la
29 plugin_CPPFLAGS = -DMYSQL_DYNAMIC_PLUGIN
30 plugin_LDFLAGS = -module -avoid-version -shared
31
32-auth_pam_la_SOURCES = auth_pam.c lib_auth_pam_client.h lib_auth_pam_client.c auth_mapping.c
33+auth_pam_la_SOURCES = auth_pam_common.c auth_pam.c lib_auth_pam_client.h lib_auth_pam_client.c auth_mapping.c
34 auth_pam_la_CPPFLAGS = $(plugin_CPPFLAGS)
35 auth_pam_la_LDFLAGS = $(plugin_LDFLAGS) $(AUTH_PAM_LIBS)
36
37+auth_pam_compat_la_SOURCES = auth_pam_common.c auth_pam_compat.c lib_auth_pam_client.h lib_auth_pam_client.c auth_mapping.c
38+auth_pam_compat_la_CPPFLAGS = $(plugin_CPPFLAGS)
39+auth_pam_compat_la_LDFLAGS = $(plugin_LDFLAGS) $(AUTH_PAM_LIBS)
40+
41 test_auth_pam_client_la_SOURCES = test_auth_pam_client.c \
42 lib_auth_pam_client.h lib_auth_pam_client.c
43 test_auth_pam_client_la_LDFLAGS = $(plugin_LDFLAGS)
44
45=== modified file 'src/auth_mapping.h'
46--- src/auth_mapping.h 2012-02-09 16:25:22 +0000
47+++ src/auth_mapping.h 2012-02-13 06:42:18 +0000
48@@ -20,9 +20,8 @@
49 /**
50 @file
51
52- PAM authentication for MySQL, common definitions for side plugins.
53+ PAM authentication for MySQL, interface for user mapping.
54
55- For the general description, see the top comment in auth_pam.c.
56 */
57
58 #ifdef __cplusplus
59
60=== added file 'src/auth_pam.c'
61--- src/auth_pam.c 1970-01-01 00:00:00 +0000
62+++ src/auth_pam.c 2012-02-13 06:42:18 +0000
63@@ -0,0 +1,175 @@
64+/*
65+(C) 2012 Percona Inc.
66+
67+This program is free software; you can redistribute it and/or modify
68+it under the terms of the GNU General Public License as published by
69+the Free Software Foundation; version 2 of the License.
70+
71+This program is distributed in the hope that it will be useful,
72+but WITHOUT ANY WARRANTY; without even the implied warranty of
73+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
74+GNU General Public License for more details.
75+
76+You should have received a copy of the GNU General Public License
77+along with this program; if not, write to the Free Software
78+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
79+*/
80+
81+/**
82+ @file
83+
84+ PAM authentication for MySQL, server-side plugin for the
85+ production use.
86+
87+ A general-purpose PAM authentication plugin for MySQL. Acts as a mediator
88+ between the MySQL server, the MySQL client, and the PAM backend. Dialog plugin
89+ used as client plugin.
90+
91+ The server plugin requests authentication from the PAM backend, forwards any
92+ requests and messages from the PAM backend over the wire to the client (in
93+ cleartext) and reads back any replies for the backend.
94+
95+ This plugin does not encrypt the communication channel in any way. If this is
96+ required, a SSL connection should be used.
97+
98+ To install this plugin, copy the .so file to the plugin directory and do
99+
100+ INSTALL PLUGIN auth_pam SONAME 'auth_pam.so';
101+
102+ To use this plugin for one particular user, specify it at user's creation time
103+ (TODO: tested with localhost only):
104+
105+ CREATE USER 'username'@'hostname' IDENTIFIED WITH auth_pam;
106+
107+ Alternatively UPDATE the mysql.user table to set the plugin value for an
108+ existing user.
109+
110+ Also it is possible to use this plugin to authenticate anonymous users:
111+
112+ CREATE USER ''@'hostname' IDENTIFIED WITH auth_pam;
113+
114+*/
115+
116+#ifdef HAVE_CONFIG_H
117+#include "config.h"
118+#endif
119+
120+#include "auth_pam_common.h"
121+
122+/** The maximum length of buffered PAM messages, i.e. any messages up to the
123+ next PAM reply-requiring message. 10K should be more than enough by order
124+ of magnitude. */
125+enum { max_pam_buffered_msg_len = 10240 };
126+
127+struct pam_msg_buf {
128+ unsigned char buf[max_pam_buffered_msg_len];
129+ unsigned char* ptr;
130+};
131+
132+static char pam_msg_style_to_char (int pam_msg_style)
133+{
134+ /* Magic byte for the dialog plugin, '\2' is defined as ORDINARY_QUESTION
135+ and '\4' as PASSWORD_QUESTION there. */
136+ return (pam_msg_style == PAM_PROMPT_ECHO_ON) ? '\2' : '\4';
137+}
138+
139+int auth_pam_client_talk_init(void **talk_data)
140+{
141+ struct pam_msg_buf *msg_buf= calloc(1, sizeof(struct pam_msg_buf));
142+ *talk_data= (void*)msg_buf;
143+ if (msg_buf != NULL)
144+ {
145+ msg_buf->ptr= msg_buf->buf + 1;
146+ return PAM_SUCCESS;
147+ }
148+ return PAM_BUF_ERR;
149+}
150+
151+void auth_pam_client_talk_finalize(void *talk_data)
152+{
153+ free(talk_data);
154+}
155+
156+int auth_pam_talk_perform(const struct pam_message *msg,
157+ struct pam_response *resp,
158+ struct pam_conv_data *data,
159+ void *talk_data)
160+{
161+ struct pam_msg_buf *msg_buf= (struct pam_msg_buf*)talk_data;
162+
163+ /* Append the PAM message or prompt to the unsent message buffer */
164+ if (msg->msg)
165+ {
166+ unsigned char *last_buf_pos = msg_buf->buf + max_pam_buffered_msg_len - 1;
167+ if (msg_buf->ptr + strlen(msg->msg) >= last_buf_pos)
168+ {
169+ /* Cannot happen: the PAM message buffer too small. */
170+ MY_ASSERT_UNREACHABLE();
171+ return PAM_CONV_ERR;
172+ }
173+ memcpy(msg_buf->ptr, msg->msg, strlen(msg->msg));
174+ msg_buf->ptr+= strlen(msg->msg);
175+ *(msg_buf->ptr)++= '\n';
176+ }
177+
178+ if (msg->msg_style == PAM_PROMPT_ECHO_OFF
179+ || msg->msg_style == PAM_PROMPT_ECHO_ON)
180+ {
181+ int pkt_len;
182+ unsigned char *pkt;
183+
184+ msg_buf->buf[0]= pam_msg_style_to_char(msg->msg_style);
185+
186+ /* Write the message. */
187+ if (data->vio->write_packet(data->vio, msg_buf->buf,
188+ msg_buf->ptr - msg_buf->buf - 1))
189+ return PAM_CONV_ERR;
190+
191+ /* Read the answer */
192+ if ((pkt_len= data->vio->read_packet(data->vio, &pkt))
193+ < 0)
194+ return PAM_CONV_ERR;
195+
196+ resp->resp= malloc(pkt_len + 1);
197+ if (resp->resp == NULL)
198+ return PAM_BUF_ERR;
199+
200+ strncpy(resp->resp, (char *)pkt, pkt_len);
201+ resp->resp[pkt_len]= '\0';
202+
203+ if (msg->msg_style == PAM_PROMPT_ECHO_OFF)
204+ data->info->password_used= PASSWORD_USED_YES;
205+
206+ msg_buf->ptr= msg_buf->buf + 1;
207+ }
208+
209+ return PAM_SUCCESS;
210+}
211+
212+static struct st_mysql_auth pam_auth_handler=
213+{
214+ MYSQL_AUTHENTICATION_INTERFACE_VERSION,
215+ "dialog",
216+ &authenticate_user_with_pam_server
217+};
218+
219+mysql_declare_plugin(auth_pam)
220+{
221+ MYSQL_AUTHENTICATION_PLUGIN,
222+ &pam_auth_handler,
223+ "auth_pam",
224+ "Percona, Inc.",
225+ "PAM authentication plugin",
226+ PLUGIN_LICENSE_GPL,
227+ NULL,
228+ NULL,
229+ 0x0001,
230+ NULL,
231+ NULL,
232+ NULL
233+#if MYSQL_PLUGIN_INTERFACE_VERSION >= 0x103
234+ ,
235+ 0
236+#endif
237+}
238+mysql_declare_plugin_end;
239
240=== renamed file 'src/auth_pam.c' => 'src/auth_pam_common.c'
241--- src/auth_pam.c 2012-02-09 16:25:22 +0000
242+++ src/auth_pam_common.c 2012-02-13 06:42:18 +0000
243@@ -15,69 +15,11 @@
244 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
245 */
246
247-/**
248- @file
249-
250- PAM authentication for MySQL, server- and client-side plugins for the
251- production use.
252-
253- A general-purpose PAM authentication plugin for MySQL. Acts as a mediator
254- between the MySQL server, the MySQL client, and the PAM backend. Consists of
255- both the server and the client plugin.
256-
257- The server plugin requests authentication from the PAM backend, forwards any
258- requests and messages from the PAM backend over the wire to the client (in
259- cleartext) and reads back any replies for the backend.
260-
261- The client plugin inputs from the TTY any requested info/passwords as
262- requested and sends them back over the wire to the server.
263-
264- This plugin does not encrypt the communication channel in any way. If this is
265- required, a SSL connection should be used.
266-
267- To install this plugin, copy the .so file to the plugin directory and do
268-
269- INSTALL PLUGIN auth_pam SONAME 'auth_pam.so';
270-
271- To use this plugin for one particular user, specify it at user's creation time
272- (TODO: tested with localhost only):
273-
274- CREATE USER 'username'@'hostname' IDENTIFIED WITH auth_pam;
275-
276- Alternatively UPDATE the mysql.user table to set the plugin value for an
277- existing user.
278-
279- Also it is possible to use this plugin to authenticate anonymous users:
280-
281- CREATE USER ''@'hostname' IDENTIFIED WITH auth_pam;
282-
283-*/
284 #ifdef HAVE_CONFIG_H
285 #include "config.h"
286 #endif
287
288-#include <assert.h>
289-
290-#include <security/pam_appl.h>
291-#include <security/pam_modules.h>
292-#include <security/pam_misc.h>
293-
294-/* Define these macros ourselves, so we don't have to include my_global.h and
295-can compile against unconfigured MySQL source tree. */
296-#define STDCALL
297-
298-#define MY_ASSERT_UNREACHABLE() assert(0)
299-
300-#include <mysql/plugin.h>
301-#include <mysql/plugin_auth.h>
302-#include <mysql/client_plugin.h>
303-
304-#ifdef HAVE_GETPASS
305-#include <unistd.h> /* getpass() */
306-#else
307-#error "Please add support for echo-less input for your platform"
308-#endif
309-
310+#include "auth_pam_common.h"
311 #include "auth_mapping.h"
312
313 /* The server plugin */
314@@ -99,37 +41,10 @@
315 }
316 }
317
318-static char pam_msg_style_to_char (int pam_msg_style)
319-{
320- /* Do not use any of MySQL client-server protocol reserved values, i.e. \0 */
321- switch (pam_msg_style)
322- {
323- case PAM_PROMPT_ECHO_OFF: return '\2';
324- case PAM_PROMPT_ECHO_ON: return '\3';
325- case PAM_ERROR_MSG: return '\4';
326- case PAM_TEXT_INFO: return '\5';
327- default:
328- MY_ASSERT_UNREACHABLE();
329- return '\1';
330- }
331-}
332-
333-/** The maximum length of buffered PAM messages, i.e. any messages up to the
334- next PAM reply-requiring message. 10K should be more than enough by order
335- of magnitude. */
336-enum { max_pam_buffered_msg_len = 10240 };
337-
338 /** The maximum length of service name. It shouldn't be too long as it's
339 filename in pam.d directory also */
340 enum { max_pam_service_name_len = 64 };
341
342-struct pam_conv_data {
343- MYSQL_PLUGIN_VIO *vio;
344- MYSQL_SERVER_AUTH_INFO *info;
345- unsigned char buf[max_pam_buffered_msg_len];
346- unsigned char* ptr;
347-};
348-
349 static void free_pam_response (struct pam_response ** resp, int n)
350 {
351 int i;
352@@ -145,6 +60,8 @@
353 struct pam_response ** resp, void *appdata_ptr)
354 {
355 int i;
356+ int error;
357+ void *talk_data;
358 struct pam_conv_data *data= (struct pam_conv_data *)appdata_ptr;
359
360 if (data == NULL)
361@@ -157,80 +74,39 @@
362 if (*resp == NULL)
363 return PAM_BUF_ERR;
364
365+ error= auth_pam_client_talk_init(&talk_data);
366+ if (error != PAM_SUCCESS)
367+ {
368+ free_pam_response(resp, 0);
369+ return error;
370+ }
371+
372 for (i = 0; i < num_msg; i++)
373 {
374 if (!valid_pam_msg_style(msg[i]->msg_style))
375 {
376+ auth_pam_client_talk_finalize(talk_data);
377 free_pam_response(resp, i);
378 return PAM_CONV_ERR;
379 }
380
381- /* Append the PAM message or prompt to the unsent message buffer */
382- if (msg[i]->msg)
383- {
384- unsigned char *last_buf_pos = data->buf + max_pam_buffered_msg_len - 1;
385- if (data->ptr + strlen(msg[i]->msg) >= last_buf_pos)
386- {
387- free_pam_response(resp, i);
388- /* Cannot happen: the PAM message buffer too small. */
389- MY_ASSERT_UNREACHABLE();
390- return PAM_CONV_ERR;
391- }
392- memcpy(data->ptr, msg[i]->msg, strlen(msg[i]->msg));
393- data->ptr+= strlen(msg[i]->msg);
394- *(data->ptr)++= '\n';
395- }
396-
397- if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF
398- || msg[i]->msg_style == PAM_PROMPT_ECHO_ON)
399- {
400- int pkt_len;
401- unsigned char *pkt;
402-
403- /* Magic byte for the dialog plugin, '\2' is defined as ORDINARY_QUESTION
404- and '\4' as PASSWORD_QUESTION there. */
405- data->buf[0]= (msg[i]->msg_style == PAM_PROMPT_ECHO_ON ? '\2' : '\4');
406-
407- /* Write the message. */
408- if (data->vio->write_packet(data->vio, data->buf,
409- data->ptr - data->buf - 1))
410- {
411- free_pam_response(resp, i);
412- return PAM_CONV_ERR;
413- }
414-
415- /* Read the answer */
416- if ((pkt_len= data->vio->read_packet(data->vio, &pkt))
417- < 0)
418- {
419- free_pam_response(resp, i);
420- return PAM_CONV_ERR;
421- }
422-
423- (*resp)[i].resp= malloc(pkt_len + 1);
424- if ((*resp)[i].resp == NULL)
425- {
426- free_pam_response(resp, i);
427- return PAM_BUF_ERR;
428- }
429-
430- strncpy((*resp)[i].resp, (char *)pkt, pkt_len);
431- (*resp)[i].resp[pkt_len]= '\0';
432-
433- if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF)
434- data->info->password_used= PASSWORD_USED_YES;
435-
436- data->ptr= data->buf + 1;
437+ error= auth_pam_talk_perform(msg[i], resp[i], data, talk_data);
438+ if (error != PAM_SUCCESS)
439+ {
440+ auth_pam_client_talk_finalize(talk_data);
441+ free_pam_response(resp, i);
442+ return error;
443 }
444 }
445+ auth_pam_client_talk_finalize(talk_data);
446 return PAM_SUCCESS;
447 }
448
449-static int authenticate_user_with_pam_server (MYSQL_PLUGIN_VIO *vio,
450- MYSQL_SERVER_AUTH_INFO *info)
451+int authenticate_user_with_pam_server (MYSQL_PLUGIN_VIO *vio,
452+ MYSQL_SERVER_AUTH_INFO *info)
453 {
454 pam_handle_t *pam_handle;
455- struct pam_conv_data data= { vio, info, "", data.buf+1 };
456+ struct pam_conv_data data= { vio, info };
457 struct pam_conv conv_func_info= { &vio_server_conv, &data };
458 int error;
459 char *pam_mapped_user_name;
460@@ -312,57 +188,3 @@
461
462 return CR_OK;
463 }
464-
465-static struct st_mysql_auth pam_auth_handler=
466-{
467- MYSQL_AUTHENTICATION_INTERFACE_VERSION,
468- "dialog",
469- &authenticate_user_with_pam_server
470-};
471-
472-static struct st_mysql_auth test_pam_auth_handler=
473-{
474- MYSQL_AUTHENTICATION_INTERFACE_VERSION,
475- "auth_pam_test",
476- &authenticate_user_with_pam_server
477-};
478-
479-mysql_declare_plugin(auth_pam)
480-{
481- MYSQL_AUTHENTICATION_PLUGIN,
482- &pam_auth_handler,
483- "auth_pam",
484- "Percona, Inc.",
485- "PAM authentication plugin",
486- PLUGIN_LICENSE_GPL,
487- NULL,
488- NULL,
489- 0x0001,
490- NULL,
491- NULL,
492- NULL
493-#if MYSQL_PLUGIN_INTERFACE_VERSION >= 0x103
494- ,
495- 0
496-#endif
497-},
498-{
499- MYSQL_AUTHENTICATION_PLUGIN,
500- &test_pam_auth_handler,
501- "test_auth_pam_server",
502- "Percona, Inc.",
503- "PAM authentication plugin that requests the test version of the"
504- " client-side plugin. DO NOT USE IN PRODUCTION.",
505- PLUGIN_LICENSE_GPL,
506- NULL,
507- NULL,
508- 0x0001,
509- NULL,
510- NULL,
511- NULL
512-#if MYSQL_PLUGIN_INTERFACE_VERSION >= 0x103
513- ,
514- 0
515-#endif
516-}
517-mysql_declare_plugin_end;
518
519=== added file 'src/auth_pam_common.h'
520--- src/auth_pam_common.h 1970-01-01 00:00:00 +0000
521+++ src/auth_pam_common.h 2012-02-13 06:42:18 +0000
522@@ -0,0 +1,71 @@
523+#ifndef AUTH_PAM_COMMON_INCLUDED
524+#define AUTH_PAM_COMMON_INCLUDED
525+/*
526+ (C) 2012 Percona Inc.
527+
528+ This program is free software; you can redistribute it and/or modify
529+ it under the terms of the GNU General Public License as published by
530+ the Free Software Foundation; version 2 of the License.
531+
532+ This program is distributed in the hope that it will be useful,
533+ but WITHOUT ANY WARRANTY; without even the implied warranty of
534+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
535+ GNU General Public License for more details.
536+
537+ You should have received a copy of the GNU General Public License
538+ along with this program; if not, write to the Free Software
539+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
540+*/
541+
542+/**
543+ @file
544+
545+ PAM authentication for MySQL, common definitions for side plugins.
546+
547+ For the general description, see the top comment in auth_pam_common.c.
548+*/
549+
550+/* Define these macros ourselves, so we don't have to include my_global.h and
551+can compile against unconfigured MySQL source tree. */
552+#define STDCALL
553+
554+#include <security/pam_appl.h>
555+#include <security/pam_modules.h>
556+#include <security/pam_misc.h>
557+
558+#include <mysql/plugin.h>
559+#include <mysql/plugin_auth.h>
560+#include <mysql/client_plugin.h>
561+
562+#include <assert.h>
563+
564+#define MY_ASSERT_UNREACHABLE() assert(0)
565+
566+#ifdef __cplusplus
567+extern "C" {
568+#endif
569+
570+struct pam_conv_data {
571+ MYSQL_PLUGIN_VIO *vio;
572+ MYSQL_SERVER_AUTH_INFO *info;
573+};
574+
575+/** Define following three functions for your specific client plugin */
576+
577+int auth_pam_client_talk_init(void **talk_data);
578+
579+int auth_pam_talk_perform(const struct pam_message *msg,
580+ struct pam_response *resp,
581+ struct pam_conv_data *data,
582+ void *talk_data);
583+
584+void auth_pam_client_talk_finalize(void *talk_data);
585+
586+int authenticate_user_with_pam_server (MYSQL_PLUGIN_VIO *vio,
587+ MYSQL_SERVER_AUTH_INFO *info);
588+
589+#ifdef __cplusplus
590+}
591+#endif
592+
593+#endif
594
595=== added file 'src/auth_pam_compat.c'
596--- src/auth_pam_compat.c 1970-01-01 00:00:00 +0000
597+++ src/auth_pam_compat.c 2012-02-13 06:42:18 +0000
598@@ -0,0 +1,131 @@
599+/*
600+(C) 2012 Percona Inc.
601+
602+This program is free software; you can redistribute it and/or modify
603+it under the terms of the GNU General Public License as published by
604+the Free Software Foundation; version 2 of the License.
605+
606+This program is distributed in the hope that it will be useful,
607+but WITHOUT ANY WARRANTY; without even the implied warranty of
608+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
609+GNU General Public License for more details.
610+
611+You should have received a copy of the GNU General Public License
612+along with this program; if not, write to the Free Software
613+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
614+*/
615+
616+/**
617+ @file
618+
619+ PAM authentication for MySQL, server-side plugin for the
620+ production use.
621+
622+ Oracle MySQL-compatible plugin. Acts as a mediator
623+ between the MySQL server, the MySQL client, and the PAM backend.
624+
625+ The server plugin requests authentication from the PAM backend, and reads one
626+ phrase from client plugin. mysql_clear_password plugin used as client plugin.
627+
628+ This plugin does not encrypt the communication channel in any way. If this is
629+ required, a SSL connection should be used.
630+
631+ To install this plugin, copy the .so file to the plugin directory and do
632+
633+ INSTALL PLUGIN auth_pam SONAME 'auth_pam_compat.so';
634+
635+ To use this plugin for one particular user, specify it at user's creation time
636+ (TODO: tested with localhost only):
637+
638+ CREATE USER 'username'@'hostname' IDENTIFIED WITH auth_pam_compat;
639+
640+ Alternatively UPDATE the mysql.user table to set the plugin value for an
641+ existing user.
642+
643+ Also it is possible to use this plugin to authenticate anonymous users:
644+
645+ CREATE USER ''@'hostname' IDENTIFIED WITH auth_pam_compat;
646+
647+*/
648+
649+#ifdef HAVE_CONFIG_H
650+#include "config.h"
651+#endif
652+
653+#include "auth_pam_common.h"
654+
655+int auth_pam_client_talk_init(void **talk_data)
656+{
657+ int *num_talks= calloc(1, sizeof(int));
658+ *talk_data= (void*)num_talks;
659+ return (num_talks != NULL) ? PAM_SUCCESS : PAM_BUF_ERR;
660+}
661+
662+void auth_pam_client_talk_finalize(void *talk_data)
663+{
664+ free(talk_data);
665+}
666+
667+int auth_pam_talk_perform(const struct pam_message *msg,
668+ struct pam_response *resp,
669+ struct pam_conv_data *data,
670+ void *talk_data)
671+{
672+ int pkt_len;
673+ unsigned char *pkt;
674+ int *num_talks= (int*)talk_data;
675+
676+ if (msg->msg_style == PAM_PROMPT_ECHO_OFF
677+ || msg->msg_style == PAM_PROMPT_ECHO_ON)
678+ {
679+ /* mysql_clear_password plugin has support for only single phrase */
680+ if (*num_talks > 1)
681+ return PAM_CONV_ERR;
682+
683+ /* Read the answer */
684+ if ((pkt_len= data->vio->read_packet(data->vio, &pkt))
685+ < 0)
686+ return PAM_CONV_ERR;
687+
688+ resp->resp= malloc(pkt_len + 1);
689+ if (resp->resp == NULL)
690+ return PAM_BUF_ERR;
691+
692+ strncpy(resp->resp, (char *)pkt, pkt_len);
693+ resp->resp[pkt_len]= '\0';
694+
695+ /* we could only guess whether password was used or not */
696+ data->info->password_used= PASSWORD_USED_NO_MENTION;
697+ ++(*num_talks);
698+ }
699+
700+ return PAM_SUCCESS;
701+}
702+
703+static struct st_mysql_auth pam_auth_handler=
704+{
705+ MYSQL_AUTHENTICATION_INTERFACE_VERSION,
706+ "mysql_clear_password",
707+ &authenticate_user_with_pam_server
708+};
709+
710+mysql_declare_plugin(auth_pam)
711+{
712+ MYSQL_AUTHENTICATION_PLUGIN,
713+ &pam_auth_handler,
714+ "auth_pam_compat",
715+ "Percona, Inc.",
716+ "PAM authentication plugin",
717+ PLUGIN_LICENSE_GPL,
718+ NULL,
719+ NULL,
720+ 0x0001,
721+ NULL,
722+ NULL,
723+ NULL
724+#if MYSQL_PLUGIN_INTERFACE_VERSION >= 0x103
725+ ,
726+ 0
727+#endif
728+}
729+mysql_declare_plugin_end;

Subscribers

People subscribed via source and target branches