1 /*
2 (C) 2012, 2013 Percona LLC and/or its affiliates
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the 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 Street, Fifth Floor, Boston, MA  02110-1301, USA
16 */
17 
18 /**
19  @file
20 
21  PAM authentication for MySQL, server-side plugin for the
22  production use.
23 
24  Oracle MySQL-compatible plugin.  Acts as a mediator
25  between the MySQL server, the MySQL client, and the PAM backend.
26 
27  The server plugin requests authentication from the PAM backend, and reads one
28  phrase from client plugin. mysql_clear_password plugin used as client plugin.
29 
30  This plugin does not encrypt the communication channel in any way.  If this is
31  required, a SSL connection should be used.
32 
33  To install this plugin, copy the .so file to the plugin directory and do
34 
35  INSTALL PLUGIN auth_pam SONAME 'auth_pam_compat.so';
36 
37  To use this plugin for one particular user, specify it at user's creation time
38  (TODO: tested with localhost only):
39 
40  CREATE USER 'username'@'hostname' IDENTIFIED WITH auth_pam_compat;
41 
42  Alternatively UPDATE the mysql.user table to set the plugin value for an
43  existing user.
44 
45  Also it is possible to use this plugin to authenticate anonymous users:
46 
47  CREATE USER ''@'hostname' IDENTIFIED WITH auth_pam_compat;
48 
49 */
50 
51 #ifdef HAVE_CONFIG_H
52 #include "config.h"
53 #endif
54 
55 #include <string.h>
56 #include "auth_pam_common.h"
57 
auth_pam_client_talk_init(void ** talk_data)58 int auth_pam_client_talk_init(void **talk_data)
59 {
60   int *num_talks= calloc(1, sizeof(int));
61   *talk_data= (void*)num_talks;
62   return (num_talks != NULL) ? PAM_SUCCESS : PAM_BUF_ERR;
63 }
64 
auth_pam_client_talk_finalize(void * talk_data)65 void auth_pam_client_talk_finalize(void *talk_data)
66 {
67   free(talk_data);
68 }
69 
auth_pam_talk_perform(const struct pam_message * msg,struct pam_response * resp,struct pam_conv_data * data,void * talk_data)70 int auth_pam_talk_perform(const struct pam_message *msg,
71                           struct pam_response *resp,
72                           struct pam_conv_data *data,
73                           void *talk_data)
74 {
75   int pkt_len;
76   unsigned char *pkt;
77   int *num_talks= (int*)talk_data;
78 
79   if (msg->msg_style == PAM_PROMPT_ECHO_OFF
80       || msg->msg_style == PAM_PROMPT_ECHO_ON)
81   {
82     /* mysql_clear_password plugin has support for only single phrase */
83     if (*num_talks > 1)
84       return PAM_CONV_ERR;
85 
86     /* Read the answer */
87     if ((pkt_len= data->vio->read_packet(data->vio, &pkt))
88         < 0)
89       return PAM_CONV_ERR;
90 
91     resp->resp= malloc(pkt_len + 1);
92     if (resp->resp == NULL)
93       return PAM_BUF_ERR;
94 
95     strncpy(resp->resp, (char *)pkt, pkt_len);
96     resp->resp[pkt_len]= '\0';
97 
98     /**
99       we could only guess whether password was used or not
100       normally we would set PASSWORD_USED_NO_MENTION but
101       because of http://bugs.mysql.com/bug.php?id=72536
102       we set PASSWORD_USED_YES.
103     */
104     data->info->password_used= PASSWORD_USED_YES;
105     ++(*num_talks);
106   }
107 
108   return PAM_SUCCESS;
109 }
110 
111 static struct st_mysql_auth pam_auth_handler=
112 {
113   MYSQL_AUTHENTICATION_INTERFACE_VERSION,
114   "mysql_clear_password",
115   &authenticate_user_with_pam_server
116 };
117 
mysql_declare_plugin(auth_pam)118 mysql_declare_plugin(auth_pam)
119 {
120   MYSQL_AUTHENTICATION_PLUGIN,
121   &pam_auth_handler,
122   "auth_pam_compat",
123   "Percona, Inc.",
124   "PAM authentication plugin",
125   PLUGIN_LICENSE_GPL,
126   NULL,
127   NULL,
128   0x0001,
129   NULL,
130   NULL,
131   NULL
132 #if MYSQL_PLUGIN_INTERFACE_VERSION >= 0x103
133   ,
134   0
135 #endif
136 }
137 mysql_declare_plugin_end;
138