[svn-inject] Installing original source of libnss-mysql-bg
[manu/libnss-mysql-bg.git] / src / lookup.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    You should have received a copy of the GNU General Public License
14    along with the nss-mysql library; if not, write to the Free Software
15    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16  */
17
18 static const char rcsid[] =
19     "$Id: lookup.c,v 1.28 2004/11/13 18:09:49 cinergi Exp $ ";
20
21 #include "nss_mysql.h"
22 #include <stdio.h>      /* snprintf () */
23 #include <string.h>     /* strcpy () */
24
25 extern conf_t conf;
26
27 /*
28  * Take query from config, such as "SELECT x FROM foo WHERE bar = '%s'"
29  * and replace "%s" with appropriate data
30  * ltype = BYNAME, BYNUM, or BYNONE
31  * name = username if this is a BYNAME
32  * num = uid/gid if this is a BYNUM
33  * qin = query in config to use
34  * qout = string to send to MySQL server (after format string processing)
35  * mresult = Current MySQL result (if any)
36  * caller = calling function's name
37  */
38 static NSS_STATUS
39 _nss_mysql_build_query (lookup_t ltype, const char *name, unsigned int num,
40                         char *qin, char *qout, MYSQL_RES **mresult,
41                         const char *caller)
42 {
43   DN ("_nss_mysql_build_query")
44   char clean_name[MAX_NAME_SIZE * 2 + 1];
45   int retVal;
46
47   DENTER
48
49   /* Verify existence of input query, lest we crash */
50   if (!qin || !qin[0])
51     {
52      _nss_mysql_log (LOG_CRIT, "%s has no valid query in config", caller);
53      DSRETURN (NSS_UNAVAIL)
54     }
55
56   switch (ltype)
57     {
58     case BYNAME: /* This lookup key is a name/string */
59       if (!name || !name[0])
60         DSRETURN (NSS_NOTFOUND)
61       D ("%s: BYNAME, name = '%s'", FUNCNAME, name);
62       if (strlen (name) >= MAX_NAME_SIZE)
63         {
64           _nss_mysql_log (LOG_CRIT, "%s: name '%s' too long (MAX = %d)",
65                           FUNCNAME, name, MAX_NAME_SIZE);
66           DSRETURN (NSS_UNAVAIL)
67         }
68       if (_nss_mysql_escape_string (clean_name, name, mresult) != NSS_SUCCESS)
69         DSRETURN (NSS_UNAVAIL)
70       retVal = snprintf (qout, MAX_QUERY_SIZE, qin, clean_name);
71       if (retVal < 1 || retVal >= MAX_QUERY_SIZE)
72         {
73           _nss_mysql_log (LOG_CRIT, "%s: snprintf error: %d", FUNCNAME, retVal);
74           DSRETURN (NSS_UNAVAIL)
75         }
76       /* New lookup, reset any existing queries */
77       _nss_mysql_reset_ent (mresult);
78       break;
79     case BYNUM: /* This lookup key is a uid/gid/number */
80       D ("%s: BYNUM, num = '%u'", FUNCNAME, num);
81       retVal = snprintf (qout, MAX_QUERY_SIZE, qin, num);
82       if (retVal < 1 || retVal >= MAX_QUERY_SIZE)
83         {
84           _nss_mysql_log (LOG_CRIT, "%s: snprintf error: %d", FUNCNAME, retVal);
85           DSRETURN (NSS_UNAVAIL)
86         }
87       /* New lookup, reset any existing queries */
88       _nss_mysql_reset_ent (mresult);
89       break;
90     case BYNONE: /* This query has no key (e.g. a getpwent) */
91       D ("%s: BYNONE creating initial query", FUNCNAME);
92       strcpy (qout, qin);
93       break;
94     default:
95       _nss_mysql_log (LOG_ERR, "%s: default case reached - should never happen",
96                       FUNCNAME);
97       DSRETURN (NSS_UNAVAIL)
98     }
99   DSRETURN (NSS_SUCCESS)
100 }
101
102 /*
103  * The high-level function that does the actual lookup
104  * Gets the query built and sent to the MySQL server, as well as
105  * loads the result & buffer with the appropriate return data
106  *
107  * ltype = BYNAME, BYNUM, or BYNONE
108  * name = name if BYNAME
109  * num = uid/gid if BYNUM
110  * q = unformatted query from config to use / build from
111  * restricted = restrict this query to euid = 0?
112  * result = NSS API result
113  * buffer = NSS API buffer
114  * buflen = NSS API length of buffer
115  * errnop = NSS API errno pointer
116  * load_func = pointer to function to load result/buffer with
117  * mresult = current MySQL result set
118  * caller = name of calling function
119  */
120 NSS_STATUS
121 _nss_mysql_lookup (lookup_t ltype, const char *name, unsigned int num,
122                    char *q, nboolean restricted, void *result,
123                    char *buffer, size_t buflen, int *errnop,
124                    NSS_STATUS (*load_func)(void *, char *, size_t,
125                                            MYSQL_RES *, int *),
126                    MYSQL_RES **mresult, const char *caller)
127 {
128   DN ("_nss_mysql_lookup")
129   char query[MAX_QUERY_SIZE];            /* Query to send to MySQL */
130   int retVal;
131   int attempts = MAX_QUERY_ATTEMPTS;    /* Attempt # (countdown) */
132   static uid_t euid = -1;               /* Last known euid for change detect */
133   uid_t cur_euid;                       /* CURRENT euid */
134
135   DENTER
136
137   cur_euid = geteuid ();
138   D ("%s: restricted = %d, cur_euid = %u", FUNCNAME, restricted, cur_euid);
139   if (restricted == ntrue && cur_euid != 0)
140     DSRETURN (NSS_NOTFOUND)
141
142    /* Make sure euid hasn't changed, thus changing our access abilities */
143   if (euid == -1)
144     euid = cur_euid;
145   else if (euid != cur_euid)
146     {
147       D ("%s:, euid changed: %u -> %u", FUNCNAME, euid, cur_euid);
148       /* Close MySQL and config to force reload of config and reconnect */
149       _nss_mysql_close_sql (mresult, ntrue);
150       conf.valid = nfalse;
151       euid = cur_euid;
152     }
153
154   /* Required in case link & config were reset due to euid change */
155   if (_nss_mysql_init () != NSS_SUCCESS)
156     DSRETURN (NSS_UNAVAIL)
157
158   /* BYNONE indicates *ent; don't create/run the query since we already did */
159   if (!(ltype == BYNONE && mresult && *mresult))
160     {
161       /* Create query string using config & args */
162       retVal = _nss_mysql_build_query (ltype, name, num, q, query, mresult,
163                                        caller);
164       if (retVal != NSS_SUCCESS)
165         DSRETURN (retVal)
166       retVal = _nss_mysql_run_query (query, mresult, &attempts);
167       if (retVal != NSS_SUCCESS)
168         DSRETURN (retVal)
169     }
170
171   /* Take result of query and load RESULT & BUFFER */
172   retVal = load_func (result, buffer, buflen, *mresult, errnop);
173
174   /* BYNONE indicates *ent; don't kill the result here, endent does that */
175   if (ltype != BYNONE)
176     _nss_mysql_close_result (mresult);
177
178   DSRETURN (retVal)
179 }
180