[svn-inject] Installing original source of libnss-mysql-bg
[manu/libnss-mysql-bg.git] / src / nss_main.c
1 /* Copyright (C) 2002 Ben Goodwin
2    This file is part of the nss-mysql library.
3
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.
8
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.
13
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
17  */
18
19 /*
20  * Global variables and miscellaneous support routines
21  */
22
23 static const char rcsid[] =
24     "$Id: nss_main.c,v 1.31 2004/11/13 18:10:32 cinergi Exp $";
25
26 #include "nss_mysql.h"
27 #include <stdio.h>      /* fprintf() */
28 #include <stdarg.h>     /* va_start() */
29 #include <sys/stat.h>   /* umask() */
30
31 /* 
32  * GNU source only defines RTLD_DEFAULT if __USE_GNU is set
33  */
34 #ifndef __USE_GNU
35 #define __USE_GNU
36 #include <dlfcn.h>
37 #undef __USE_GNU
38 #endif
39
40 pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
41 pthread_once_t _nss_mysql_once_control = {PTHREAD_ONCE_INIT};
42 static int _nss_mysql_locked_by_atfork = 0;
43
44 #define MAX_MSG_SIZE 1024
45
46 /*
47  * Debugs to either a file, stderr, or syslog, depending on the environ var
48  * LIBNSS_MYSQL_DEBUG
49  * none or 0 = file (DEBUG_FILE, defined in nss_mysql.h)
50  *         1 = stderr
51  *         2 = syslog (facility defined at configure, priority DEBUG)
52  */
53 #ifdef DEBUG
54 void
55 _nss_mysql_debug (char *fmt, ...)
56 {
57   va_list ap;
58   char msg[MAX_MSG_SIZE];
59   FILE *fh;
60   char *env;
61   int type = 0;
62   mode_t old_mask;
63
64   va_start (ap, fmt);
65   vsnprintf (msg, MAX_MSG_SIZE, fmt, ap);
66   env = getenv ("LIBNSS_MYSQL_DEBUG");
67   if (env)
68     type = atoi (env);
69   
70   if (type <= 1)
71     {
72       if (type == 0)
73         {
74           old_mask = umask (000);
75           fh = fopen (DEBUG_FILE, "a");
76           umask (old_mask);
77         }
78       else
79         fh = stderr;
80       if (fh)
81         {
82           fprintf (fh, "[%d]: %s\n", getpid(), msg);
83           if (type == 0)
84             fclose (fh);
85         }
86     }
87   else
88     {
89       _nss_mysql_log (LOG_DEBUG, "%s", msg);
90     }
91   va_end (ap);
92 }
93 #endif
94
95 /*
96  *                          THREADING NOTES
97  *
98  * libnss-mysql is *not* to be linked against any threading library.
99  * Instead, check for pthread functions in the current namespace
100  * by using dlsym() and RTLD_DEFAULT.  This way we don't litter every
101  * application with a thread library (since libnss-mysql would be linked
102  * against it and so many applications would dlopen libnss-mysql).
103  * Applications often misbehave when a thread environment is unexpected
104  *
105  * libnss-mysql is *not* to be linked against the threaded version
106  * of MySQL for the same reasons.  libnss-mysql is not coded in such
107  * a way that a threaded MySQL library is needed, anyway.
108  *
109  * libnss-mysql locks just prior to calling _nss_mysql_lookup() and
110  * unlocks when done with it and all data handled by it.  Since the lock
111  * occurs so early on and lasts so long, libnss-mysql doesn't perform
112  * that well in a heavily threaded application (e.g. a threaded radius
113  * server).  Use of "nscd" is highly recommended.
114  */
115
116 /*
117  * Before fork() processing begins, the prepare fork handler is called
118  */
119 static void
120 _nss_mysql_atfork_prepare (void)
121 {
122   DN ("_nss_mysql_atfork_prepare")
123   int (*trylock)();
124
125   DENTER
126   trylock = (int (*)(int))dlsym (RTLD_DEFAULT, "pthread_mutex_trylock");
127   if (trylock)
128     if ((*trylock) (&lock) == 0)
129       _nss_mysql_locked_by_atfork = 1;
130   DEXIT
131 }
132
133 /*
134  * The parent fork handler is called after fork() processing finishes
135  * in the parent process
136  */
137 static void
138 _nss_mysql_atfork_parent (void)
139 {
140   DN ("_nss_mysql_atfork_parent")
141   DENTER
142   if (_nss_mysql_locked_by_atfork)
143     {
144       _nss_mysql_locked_by_atfork = 0;
145       UNLOCK;
146     }
147   DEXIT
148 }
149
150 /*
151  * The child fork handler is called after fork() processing finishes in the
152  * child process.
153  */
154 static void
155 _nss_mysql_atfork_child (void)
156 {
157   DN ("_nss_mysql_atfork_child")
158   DENTER
159   /* Don't close the link; just set it to invalid so we'll open a new one */
160   _nss_mysql_close_sql (NULL, nfalse);
161   if (_nss_mysql_locked_by_atfork)
162     {
163       _nss_mysql_locked_by_atfork = 0;
164       UNLOCK;
165     }
166   DEXIT
167 }
168
169 /* Setup pthread_atfork if current namespace contains pthreads. */
170 static void
171 _nss_mysql_pthread_once_init (void)
172 {
173   DN ("_nss_mysql_atfork_once_init")
174   int (*pthread_atfork)();
175
176   DENTER
177   pthread_atfork = (int (*)(int))dlsym (RTLD_DEFAULT, "pthread_atfork");
178   if (pthread_atfork)
179     (*pthread_atfork) (_nss_mysql_atfork_prepare, _nss_mysql_atfork_parent,
180                        _nss_mysql_atfork_child);
181   DEXIT
182 }
183
184 /*
185  * Prevent the "dead store removal" problem present with stock memset()
186  */
187 static void *
188 _nss_mysql_safe_memset (void *s, int c, size_t n)
189 {
190   DN ("_nss_mysql_safe_memset")
191   volatile char *p = s;
192
193   DENTER
194   if (p)
195     {
196       while (n--)
197         *p++ = c;
198     }
199   DPRETURN (s)
200 }
201
202 /*
203  * Make an attempt to close the link when the process exits
204  * Set in _nss_mysql_init() below
205  */
206 static void
207 _nss_mysql_atexit_handler (void)
208 {
209   DN ("_nss_mysql_atexit_handler")
210   extern conf_t conf;
211
212   DENTER
213   _nss_mysql_close_sql (NULL, ntrue);
214   _nss_mysql_safe_memset (conf.sql.server.password, 0,
215                           sizeof (conf.sql.server.password));
216   DEXIT
217 }
218
219 /*
220  * Setup pthread_once if it's available in the current namespace
221  * Load config file(s)
222  */
223 NSS_STATUS
224 _nss_mysql_init (void)
225 {
226   DN ("_nss_mysql_init")
227   int (*pthread_once)();
228   static int atexit_isset = nfalse;
229
230   DENTER
231   pthread_once = (int (*)(int))dlsym (RTLD_DEFAULT, "pthread_once");
232   if (pthread_once)
233     (*pthread_once) (&_nss_mysql_once_control, _nss_mysql_pthread_once_init);
234   if (atexit_isset == nfalse)
235     {
236       if (atexit(_nss_mysql_atexit_handler) == RETURN_SUCCESS)
237         atexit_isset = ntrue;
238     }
239   DSRETURN (_nss_mysql_load_config ())
240 }
241
242 /*
243  * Syslog a message at PRIORITY.
244  * Do *NOT* openlog/closelog as you'll mess up calling programs that
245  * are syslogging their own stuff.
246  */
247 void
248 _nss_mysql_log (int priority, char *fmt, ...)
249 {
250   DN ("_nss_mysql_log")
251   va_list ap;
252   char msg[MAX_MSG_SIZE];
253
254   va_start (ap, fmt);
255   vsnprintf (msg, MAX_MSG_SIZE, fmt, ap);
256   syslog (priority, "%s: %s", PACKAGE, msg);
257   va_end (ap);
258 }
259
260 #ifdef HAVE_NSS_COMMON_H
261 NSS_STATUS
262 _nss_mysql_default_destr (nss_backend_t *be, void *args)
263 {
264   DN ("_nss_mysql_default_destr")
265   DENTER
266   if (be)
267     {
268       free (be);
269       be = NULL;
270     }
271   /* Closing link & freeing memory unnecessary due to link w/ '-znodelete' */
272   DSRETURN (NSS_SUCCESS)
273
274 }
275 #endif
276
277 /*
278  * SET/END ent's call this.  While the definition of endent is to close
279  * the "file", we need to keep the MySQL link persistent, so we just
280  * clear any lingering MySQL result set.
281  */
282 void
283 _nss_mysql_reset_ent (MYSQL_RES **mresult)
284 {
285   DN ("_nss_mysql_reset_ent")
286   DENTER
287   _nss_mysql_close_result (mresult);
288   DEXIT
289 }
290