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.46 2005/09/04 03:34:02 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 const unsigned int def_timeout = DEF_TIMEOUT;
144 mysql_options(&ci.link, MYSQL_OPT_CONNECT_TIMEOUT,
145 (const char *) &def_timeout);
146 mysql_options(&ci.link, MYSQL_READ_DEFAULT_GROUP, "libnss-mysql");
152 * Validate existing connection.
153 * This does NOT run mysql_ping because that function is
154 * extraordinarily slow (~doubles time to fetch a query)
157 _nss_mysql_check_existing_connection (MYSQL_RES **mresult)
159 DN ("_nss_mysql_check_existing_connection")
160 static pid_t pid = -1;
163 if (ci.valid == nfalse || conf.valid == nfalse)
168 else if (pid == getppid ())
170 /* saved pid == ppid = we've forked; We MUST create a new connection */
171 D ("%s: fork() detected", FUNCNAME);
177 if (_nss_mysql_validate_socket () == nfalse)
179 /* Do *NOT* CLOSE_LINK - the socket is invalid! */
180 D ("%s: invalid socket detected", FUNCNAME);
181 _nss_mysql_close_sql (mresult, nfalse);
190 * Connect to a MySQL server.
193 _nss_mysql_connect_sql (MYSQL_RES **mresult)
195 DN ("_nss_mysql_connect_sql")
197 sql_server_t *server = &conf.sql.server;
202 if (_nss_mysql_check_existing_connection (mresult) == ntrue)
204 D ("%s: Using existing connection", FUNCNAME);
205 DSRETURN (NSS_SUCCESS)
208 retval = _nss_mysql_load_config ();
209 if (retval != NSS_SUCCESS)
211 _nss_mysql_log (LOG_ALERT, "Failed to load configuration");
212 DSRETURN (NSS_UNAVAIL)
215 if (mysql_init (&ci.link) == NULL)
217 _nss_mysql_log (LOG_ALERT, "mysql_init() failed");
218 DSRETURN (NSS_UNAVAIL)
221 _nss_mysql_set_options (server);
222 D ("%s: Connecting to %s", FUNCNAME, server->host);
224 port = atoi (server->port);
227 if (mysql_real_connect (&ci.link, server->host,
228 server->username[0] ? server->username : NULL,
229 server->password[0] ? server->password : NULL,
230 server->database, port,
231 server->socket[0] ? server->socket : NULL,
234 if (_nss_mysql_save_socket_info () != RETURN_SUCCESS )
236 _nss_mysql_log (LOG_ALERT, "Unable to save socket info");
237 _nss_mysql_close_sql (mresult, ntrue);
238 DSRETURN (NSS_UNAVAIL)
241 ci.link.reconnect = 0; /* Safety: We can't let MySQL assume socket is
242 still valid; see _nss_mysql_validate_socket */
243 DSRETURN (NSS_SUCCESS)
245 _nss_mysql_log (LOG_ALERT, "Connection to server '%s' failed: %s",
246 server->host, mysql_error (&ci.link));
247 DSRETURN (NSS_UNAVAIL)
251 _nss_mysql_close_result (MYSQL_RES **mresult)
253 DN ("_nss_mysql_close_result")
255 if (mresult && *mresult && ci.valid)
257 D ("%s, calling mysql_free_result()", FUNCNAME);
258 mysql_free_result (*mresult);
269 _nss_mysql_run_query (char *query, MYSQL_RES **mresult, int *attempts)
271 DN ("_nss_mysql_run_query")
276 DSRETURN (NSS_NOTFOUND)
278 D ("%s: Executing query: %s", FUNCNAME, query);
280 retval = _nss_mysql_connect_sql (mresult);
281 if (retval != NSS_SUCCESS)
284 retval = mysql_query (&ci.link, query);
285 if (retval != RETURN_SUCCESS)
290 _nss_mysql_log (LOG_ALERT,
291 "mysql_query failed: %s, trying again (%d)",
292 mysql_error (&ci.link), *attempts);
293 DSRETURN (_nss_mysql_run_query (query, mresult, attempts));
297 _nss_mysql_log (LOG_ALERT, "mysql_query failed: %s",
298 mysql_error (&ci.link));
303 if ((*mresult = mysql_store_result (&ci.link)) == NULL)
305 _nss_mysql_log (LOG_ALERT, "mysql_store_result failed: %s",
306 mysql_error (&ci.link));
307 DSRETURN (NSS_UNAVAIL);
309 DSRETURN (NSS_SUCCESS)
313 _nss_mysql_fetch_row (MYSQL_ROW *row, MYSQL_RES *mresult)
315 DN ("_nss_mysql_fetch_row")
318 if ((*row = mysql_fetch_row (mresult)) == NULL)
320 if (mysql_errno (&ci.link))
322 _nss_mysql_log (LOG_ALERT, "mysql_fetch_row() failed: %s",
323 mysql_error (&ci.link));
324 DSRETURN (NSS_UNAVAIL)
327 DSRETURN (NSS_NOTFOUND)
329 DSRETURN (NSS_SUCCESS)
333 _nss_mysql_escape_string (char *to, const char *from, MYSQL_RES **mresult)
335 DN ("_nss_mysql_escape_string")
338 if (_nss_mysql_connect_sql (mresult) != NSS_SUCCESS)
339 DSRETURN (NSS_UNAVAIL)
340 mysql_real_escape_string (&ci.link, to, from, strlen(from));
341 DSRETURN (NSS_SUCCESS)