1 /* Copyright (C) 2002 Ben Goodwin
2 This file is part of the nss-mysql library.
4 The nss-mysql library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License as published
6 by the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 The nss-mysql 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
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with the nss-mysql library; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * MySQL-specific functions; ALL MySQL calls that any other source functions
21 * need should come from here.
24 static const char rcsid[] =
25 "$Id: mysql.c,v 1.44 2004/11/13 16:25:26 cinergi Exp $";
27 #include "nss_mysql.h"
28 #include <string.h> /* strlen() */
29 #include <netinet/in.h> /* struct sockaddr_in */
31 #ifndef HAVE_SOCKLEN_T
32 typedef size_t socklen_t;
35 con_info_t ci = { nfalse };
39 * Immediately after connecting to a MySQL server, save the current
40 * socket information for later comparison purposes
43 _nss_mysql_save_socket_info (void)
45 DN ("_nss_mysql_save_socket_info")
46 socklen_t local_size = sizeof (struct sockaddr);
47 socklen_t remote_size = sizeof (struct sockaddr);
51 memset(&(ci.sock_info.local), 0, sizeof (ci.sock_info.local));
52 r = getsockname (ci.link.net.fd, &(ci.sock_info.local), &local_size);
53 if (r != RETURN_SUCCESS)
54 DFRETURN (RETURN_FAILURE)
56 memset(&(ci.sock_info.remote), 0, sizeof (ci.sock_info.remote));
57 r = getpeername (ci.link.net.fd, &(ci.sock_info.remote), &remote_size);
62 * Compare ORIG and CUR
65 _nss_mysql_is_same_sockaddr (struct sockaddr orig, struct sockaddr cur)
67 DN ("_nss_mysql_is_same_sockaddr")
70 switch (((struct sockaddr_in *)&ci.sock_info.local)->sin_family)
73 if ((*(struct sockaddr_in *) &orig).sin_port !=
74 (*(struct sockaddr_in *) &cur).sin_port)
76 if ((*(struct sockaddr_in *) &orig).sin_addr.s_addr !=
77 (*(struct sockaddr_in *) &cur).sin_addr.s_addr)
81 if (memcmp (&orig, &cur, sizeof (struct sockaddr)) != 0)
85 _nss_mysql_log (LOG_ERR, "%s: Unhandled sin_family", FUNCNAME);
93 * Check to see what current socket info is and compare to the saved
94 * socket info (from _nss_mysql_save_socket_info() above). Return
95 * NTRUE if the current socket and saved socket match.
98 _nss_mysql_validate_socket (void)
100 DN ("_nss_mysql_validate_socket")
101 socklen_t local_size = sizeof (struct sockaddr);
102 socklen_t remote_size = sizeof (struct sockaddr);
103 struct sockaddr check;
106 memset(&check, 0, sizeof (check));
107 if (getpeername (ci.link.net.fd, &check, &remote_size) != RETURN_SUCCESS)
109 if (_nss_mysql_is_same_sockaddr (ci.sock_info.remote, check) != ntrue)
112 memset(&check, 0, sizeof (check));
113 if (getsockname (ci.link.net.fd, &check, &local_size) != RETURN_SUCCESS)
115 if (_nss_mysql_is_same_sockaddr (ci.sock_info.local, check) != ntrue)
122 _nss_mysql_close_sql (MYSQL_RES **mresult, nboolean graceful)
124 DN ("_nss_mysql_close_sql")
126 _nss_mysql_close_result (mresult);
127 if (graceful && ci.valid)
129 D ("%s: calling mysql_close()", FUNCNAME);
130 mysql_close (&ci.link);
133 DSRETURN (NSS_SUCCESS)
137 _nss_mysql_set_options (sql_server_t *server)
139 DN ("_nss_mysql_set_options")
140 unsigned int timeout;
143 if (server->options.timeout)
144 timeout = (unsigned int) atoi (server->options.timeout);
146 timeout = DEF_TIMEOUT;
147 D ("%s: Setting connect timeout to %d", FUNCNAME, timeout);
148 mysql_options(&ci.link, MYSQL_OPT_CONNECT_TIMEOUT,
150 if (server->options.compress && atoi (server->options.compress))
152 D ("%s: Setting compressed protocol", FUNCNAME);
153 mysql_options(&ci.link, MYSQL_OPT_COMPRESS, 0);
155 if (server->options.initcmd && strlen (server->options.initcmd))
157 D ("%s: Setting init-command to '%s'", FUNCNAME, server->options.initcmd);
158 mysql_options(&ci.link, MYSQL_INIT_COMMAND,
159 (char *)server->options.initcmd);
165 * Validate existing connection.
166 * This does NOT run mysql_ping because that function is
167 * extraordinarily slow (~doubles time to fetch a query)
170 _nss_mysql_check_existing_connection (MYSQL_RES **mresult)
172 DN ("_nss_mysql_check_existing_connection")
173 static pid_t pid = -1;
176 if (ci.valid == nfalse || conf.valid == nfalse)
181 else if (pid == getppid ())
183 /* saved pid == ppid = we've forked; We MUST create a new connection */
184 D ("%s: fork() detected", FUNCNAME);
190 if (_nss_mysql_validate_socket () == nfalse)
192 /* Do *NOT* CLOSE_LINK - the socket is invalid! */
193 D ("%s: invalid socket detected", FUNCNAME);
194 _nss_mysql_close_sql (mresult, nfalse);
203 * Connect to a MySQL server.
206 _nss_mysql_connect_sql (MYSQL_RES **mresult)
208 DN ("_nss_mysql_connect_sql")
210 sql_server_t *server = &conf.sql.server;
215 if (_nss_mysql_check_existing_connection (mresult) == ntrue)
217 D ("%s: Using existing connection", FUNCNAME);
218 DSRETURN (NSS_SUCCESS)
221 retval = _nss_mysql_load_config ();
222 if (retval != NSS_SUCCESS)
224 _nss_mysql_log (LOG_ALERT, "Failed to load configuration");
225 DSRETURN (NSS_UNAVAIL)
228 if (mysql_init (&ci.link) == NULL)
230 _nss_mysql_log (LOG_ALERT, "mysql_init() failed");
231 DSRETURN (NSS_UNAVAIL)
234 _nss_mysql_set_options (server);
235 D ("%s: Connecting to %s", FUNCNAME, server->host);
237 port = atoi (server->port);
240 if (mysql_real_connect (&ci.link, server->host,
241 server->username[0] ? server->username : NULL,
242 server->password[0] ? server->password : NULL,
243 server->database, port,
244 server->socket[0] ? server->socket : NULL,
247 if (_nss_mysql_save_socket_info () != RETURN_SUCCESS )
249 _nss_mysql_log (LOG_ALERT, "Unable to save socket info");
250 _nss_mysql_close_sql (mresult, ntrue);
251 DSRETURN (NSS_UNAVAIL)
254 ci.link.reconnect = 0; /* Safety: We can't let MySQL assume socket is
255 still valid; see _nss_mysql_validate_socket */
256 DSRETURN (NSS_SUCCESS)
258 _nss_mysql_log (LOG_ALERT, "Connection to server '%s' failed: %s",
259 server->host, mysql_error (&ci.link));
260 DSRETURN (NSS_UNAVAIL)
264 _nss_mysql_close_result (MYSQL_RES **mresult)
266 DN ("_nss_mysql_close_result")
268 if (mresult && *mresult && ci.valid)
270 D ("%s, calling mysql_free_result()", FUNCNAME);
271 mysql_free_result (*mresult);
282 _nss_mysql_run_query (char *query, MYSQL_RES **mresult, int *attempts)
284 DN ("_nss_mysql_run_query")
289 DSRETURN (NSS_NOTFOUND)
291 D ("%s: Executing query: %s", FUNCNAME, query);
293 retval = _nss_mysql_connect_sql (mresult);
294 if (retval != NSS_SUCCESS)
297 retval = mysql_query (&ci.link, query);
298 if (retval != RETURN_SUCCESS)
303 _nss_mysql_log (LOG_ALERT,
304 "mysql_query failed: %s, trying again (%d)",
305 mysql_error (&ci.link), *attempts);
306 DSRETURN (_nss_mysql_run_query (query, mresult, attempts));
310 _nss_mysql_log (LOG_ALERT, "mysql_query failed: %s",
311 mysql_error (&ci.link));
316 if ((*mresult = mysql_store_result (&ci.link)) == NULL)
318 _nss_mysql_log (LOG_ALERT, "mysql_store_result failed: %s",
319 mysql_error (&ci.link));
320 DSRETURN (NSS_UNAVAIL);
322 DSRETURN (NSS_SUCCESS)
326 _nss_mysql_fetch_row (MYSQL_ROW *row, MYSQL_RES *mresult)
328 DN ("_nss_mysql_fetch_row")
331 if ((*row = mysql_fetch_row (mresult)) == NULL)
333 if (mysql_errno (&ci.link))
335 _nss_mysql_log (LOG_ALERT, "mysql_fetch_row() failed: %s",
336 mysql_error (&ci.link));
337 DSRETURN (NSS_UNAVAIL)
340 DSRETURN (NSS_NOTFOUND)
342 DSRETURN (NSS_SUCCESS)
346 _nss_mysql_escape_string (char *to, const char *from, MYSQL_RES **mresult)
348 DN ("_nss_mysql_escape_string")
351 if (_nss_mysql_connect_sql (mresult) != NSS_SUCCESS)
352 DSRETURN (NSS_UNAVAIL)
353 mysql_real_escape_string (&ci.link, to, from, strlen(from));
354 DSRETURN (NSS_SUCCESS)