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
19 static const char rcsid[] =
20 "$Id: nss_support.c,v 1.39 2004/11/13 16:25:26 cinergi Exp $";
22 #include "nss_mysql.h"
23 #include <string.h> /* memset() */
24 #include <pwd.h> /* struct passwd */
26 #include <shadow.h> /* struct spwd */
28 #include <grp.h> /* struct group */
32 /* Alignment code adapted from padl.com's nss_ldap */
34 #define alignof(ptr) __alignof__(ptr)
36 #define alignof(ptr) (sizeof(char *))
39 #define align(ptr, blen, TYPE) \
42 ptr += alignof(TYPE) - 1; \
43 ptr -= ((ptr - (char *)NULL) % alignof(TYPE)); \
44 blen -= (ptr - qtr); \
48 #if defined(__FreeBSD__)
112 _nss_mysql_load_passwd (void *result, char *buffer, size_t buflen,
113 MYSQL_RES *mresult, int *errnop)
115 DN ("_nss_mysql_load_passwd")
118 struct passwd *pw = (struct passwd *)result;
119 size_t offsets[NUM_PW_ELEMENTS];
120 unsigned long *lengths;
121 unsigned int num_fields;
124 retVal = _nss_mysql_fetch_row (&row, mresult);
125 if (retVal != NSS_SUCCESS)
127 num_fields = _nss_mysql_num_fields (mresult);
128 if (num_fields != NUM_PW_ELEMENTS)
130 _nss_mysql_log (LOG_ALERT,
131 "mysql_fetch_row() found %u rows (expecting %u).",
132 num_fields, NUM_PW_ELEMENTS);
133 DSRETURN (NSS_UNAVAIL)
136 /* Make sure we have enough room in 'buffer' for all our data */
137 lengths = (unsigned long *) _nss_mysql_fetch_lengths (mresult);
138 offsets[ROW_PW_NAME] = 0;
139 for (i = 1; i < NUM_PW_ELEMENTS; i++)
140 offsets[i] = offsets[i - 1] + lengths[i - 1] + 1;
141 if (offsets[NUM_PW_ELEMENTS - 1] > buflen)
144 /* Clear out buffer and copy in data */
145 memset (buffer, 0, buflen);
146 pw->pw_name = memcpy (buffer + offsets[ROW_PW_NAME], row[ROW_PW_NAME],
147 lengths[ROW_PW_NAME]);
148 pw->pw_passwd = memcpy (buffer + offsets[ROW_PW_PASSWD], row[ROW_PW_PASSWD],
149 lengths[ROW_PW_PASSWD]);
150 pw->pw_uid = atoi (row[ROW_PW_UID]);
151 pw->pw_gid = atoi (row[ROW_PW_GID]);
152 pw->pw_gecos = memcpy (buffer + offsets[ROW_PW_GECOS], row[ROW_PW_GECOS],
153 lengths[ROW_PW_GECOS]);
154 pw->pw_dir = memcpy (buffer + offsets[ROW_PW_DIR], row[ROW_PW_DIR],
155 lengths[ROW_PW_DIR]);
156 pw->pw_shell = memcpy (buffer + offsets[ROW_PW_SHELL], row[ROW_PW_SHELL],
157 lengths[ROW_PW_SHELL]);
158 #if defined(__FreeBSD__)
159 pw->pw_change = atoi (row[ROW_PW_CHANGE]);
160 pw->pw_class = memcpy (buffer + offsets[ROW_PW_CLASS], row[ROW_PW_CLASS],
161 lengths[ROW_PW_CLASS]);
162 pw->pw_change = atoi (row[ROW_PW_EXPIRE]);
166 pw->pw_age = memcpy (buffer + offsets[ROW_PW_AGE], row[ROW_PW_AGE],
167 lengths[ROW_PW_AGE]);
168 pw->pw_comment = memcpy (buffer + offsets[ROW_PW_COMMENT],
169 row[ROW_PW_COMMENT], lengths[ROW_PW_COMMENT]);
172 DSRETURN (NSS_SUCCESS)
177 _nss_mysql_load_shadow (void *result, char *buffer, size_t buflen,
178 MYSQL_RES *mresult, int *errnop)
180 DN ("_nss_mysql_load_shadow")
183 struct spwd *sp = (struct spwd *)result;
184 size_t offsets[NUM_SP_ELEMENTS];
185 unsigned long *lengths;
186 unsigned int num_fields;
189 retVal = _nss_mysql_fetch_row (&row, mresult);
190 if (retVal != NSS_SUCCESS)
192 num_fields = _nss_mysql_num_fields (mresult);
193 if (num_fields != NUM_SP_ELEMENTS)
195 _nss_mysql_log (LOG_ALERT,
196 "mysql_fetch_row() found %u rows (expecting %u).",
197 num_fields, NUM_SP_ELEMENTS);
198 DSRETURN (NSS_UNAVAIL)
201 /* Make sure we have enough room in 'buffer' for all our data */
202 lengths = (unsigned long *) _nss_mysql_fetch_lengths (mresult);
203 offsets[ROW_SP_NAMP] = 0;
204 offsets[ROW_SP_PWDP] = offsets[ROW_SP_NAMP] + lengths[ROW_SP_NAMP] + 1;
205 if (offsets[ROW_SP_PWDP] + lengths[ROW_SP_PWDP] + 1 > buflen)
208 /* Clear out buffer and copy in data */
209 memset (buffer, 0, buflen);
210 sp->sp_namp = memcpy (buffer + offsets[ROW_SP_NAMP], row[ROW_SP_NAMP],
211 lengths[ROW_SP_NAMP]);
212 sp->sp_pwdp = memcpy (buffer + offsets[ROW_SP_PWDP], row[ROW_SP_PWDP],
213 lengths[ROW_SP_PWDP]);
214 sp->sp_lstchg = atol (row[ROW_SP_LSTCHG]);
215 sp->sp_min = atol (row[ROW_SP_MIN]);
216 sp->sp_max = atol (row[ROW_SP_MAX]);
217 sp->sp_warn = atol (row[ROW_SP_WARN]);
218 sp->sp_inact = atol (row[ROW_SP_INACT]);
219 sp->sp_expire = atol (row[ROW_SP_EXPIRE]);
220 sp->sp_flag = (unsigned long) atol (row[ROW_SP_FLAG]);
221 DSRETURN (NSS_SUCCESS)
226 _nss_mysql_load_memsbygid (void *result, char *buffer, size_t buflen,
227 MYSQL_RES *mresult, int *errnop)
229 DN ("_nss_mysql_load_memsbygid")
232 struct group *gr = (struct group *)result;
234 unsigned long num_rows, i;
235 unsigned long *lengths;
236 size_t strings_offset;
239 num_rows = _nss_mysql_num_rows (mresult);
240 align (buffer, buflen, char *);
242 /* Return empty/NULL group list if no members */
245 gr->gr_mem = (char **) (uintptr_t)buffer;
246 DSRETURN (NSS_SUCCESS)
249 members = (char **)buffer;
250 strings_offset = (num_rows + 1) * sizeof (char *);
251 /* Allow room for NUM_ROWS + 1 pointers */
252 if (strings_offset > buflen)
255 buflen -= strings_offset;
257 /* Load the first one */
258 retVal = _nss_mysql_fetch_row (&row, mresult);
259 if (retVal != NSS_SUCCESS)
261 lengths = (unsigned long *) _nss_mysql_fetch_lengths (mresult);
262 if (lengths[0] + 1 > buflen)
265 members[0] = buffer + strings_offset;
266 strncpy (members[0], row[0], lengths[0]);
267 buflen -= lengths[0] + 1;
270 for (i = 1; i < num_rows; i++)
272 /* Set pointer to one byte after the last string loaded */
273 members[i] = members[i - 1] + lengths[0] + 1;
275 retVal = _nss_mysql_fetch_row (&row, mresult);
276 if (retVal != NSS_SUCCESS)
278 lengths = (unsigned long *) _nss_mysql_fetch_lengths (mresult);
279 if (lengths[0] + 1 > buflen)
281 strncpy (members[i], row[0], lengths[0]);
282 buflen -= lengths[0] + 1;
285 /* Set the last pointer to NULL to terminate the pointer-list */
286 members[num_rows] = NULL;
288 /* Set gr->gr_mem to point to start of our pointer-list */
289 gr->gr_mem = (char **) (uintptr_t)buffer;
291 DSRETURN (NSS_SUCCESS)
295 _nss_mysql_load_group (void *result, char *buffer, size_t buflen,
296 MYSQL_RES *mresult, int *errnop)
298 DN ("_nss_mysql_load_group")
300 MYSQL_RES *mresult_grmem = NULL;
302 struct group *gr = (struct group *)result;
303 size_t offsets[NUM_GR_ELEMENTS];
304 unsigned long *lengths;
305 unsigned int num_fields;
308 retVal = _nss_mysql_fetch_row (&row, mresult);
309 if (retVal != NSS_SUCCESS)
311 num_fields = _nss_mysql_num_fields (mresult);
312 if (num_fields != NUM_GR_ELEMENTS - 1) /* gr_mem not part of this query */
314 _nss_mysql_log (LOG_ALERT,
315 "mysql_fetch_row() found %u rows (expecting %u).",
316 num_fields, NUM_GR_ELEMENTS - 1);
317 DSRETURN (NSS_UNAVAIL)
321 * Make sure we have enough room in 'buffer' for all our data
322 * (not including gr_mem - that's dealt with later
324 lengths = (unsigned long *) _nss_mysql_fetch_lengths (mresult);
325 offsets[ROW_GR_NAME] = 0;
326 offsets[ROW_GR_PASSWD] = offsets[ROW_GR_NAME] + lengths[ROW_GR_NAME] + 1;
327 offsets[ROW_GR_MEM] = offsets[ROW_GR_PASSWD] + lengths[ROW_GR_PASSWD] + 1;
328 if (offsets[ROW_GR_MEM] + 1 > buflen)
331 /* Clear out buffer and copy in data (except gr_mem) */
332 memset (buffer, 0, buflen);
333 gr->gr_name = memcpy (buffer + offsets[ROW_GR_NAME], row[ROW_GR_NAME],
334 lengths[ROW_GR_NAME]);
335 gr->gr_passwd = memcpy (buffer + offsets[ROW_GR_PASSWD], row[ROW_GR_PASSWD],
336 lengths[ROW_GR_PASSWD]);
337 gr->gr_gid = atoi (row[ROW_GR_GID]);
340 retVal = _nss_mysql_lookup (BYNUM, NULL, gr->gr_gid,
341 conf.sql.query.memsbygid, nfalse, result,
342 buffer + offsets[ROW_GR_MEM],
343 buflen - offsets[ROW_GR_MEM],
344 errnop, _nss_mysql_load_memsbygid,
345 &mresult_grmem, FUNCNAME);
351 _nss_mysql_load_gidsbymem (void *result, char *buffer, size_t buflen,
352 MYSQL_RES *mresult, int *errnop)
354 DN ("_nss_mysql_load_gidsbymem")
356 unsigned long num_rows, i;
357 group_info_t *gi = (group_info_t *)result;
363 num_rows = _nss_mysql_num_rows (mresult);
365 /* Nothing to load = success */
367 DSRETURN (NSS_SUCCESS)
369 /* If we need more room and we're allowed to alloc it, alloc it */
370 if (num_rows + *gi->start > *gi->size)
372 long int newsize = *gi->size;
374 if (gi->limit <= 0) /* Allocate as much as we need */
375 newsize = num_rows + *gi->start;
376 else if (*gi->size != gi->limit) /* Allocate to limit */
379 if (newsize != *gi->size) /* If we've got more room, do it */
381 gid_t *groups = *gi->groupsp;
384 newgroups = realloc (groups, newsize * sizeof (*groups));
385 if (newgroups != NULL)
387 *gi->groupsp = groups = newgroups;
393 groups = *gi->groupsp;
394 for (i = *gi->start; i < *gi->size; i++)
396 retVal = _nss_mysql_fetch_row (&row, mresult);
397 if (retVal != NSS_SUCCESS)
400 if ((long int)gid != gi->group && (long int)gid != groups[0])
401 groups[(*gi->start)++] = gid;
404 DSRETURN (NSS_SUCCESS)
407 /* Thanks to Clement Laforet for most of this */
408 #if defined(__FreeBSD__)
410 NSS_METHOD_PROTOTYPE(__nss_compat_getpwnam_r);
411 NSS_METHOD_PROTOTYPE(__nss_compat_getpwuid_r);
412 NSS_METHOD_PROTOTYPE(__nss_compat_getpwent_r);
413 NSS_METHOD_PROTOTYPE(__nss_compat_setpwent);
414 NSS_METHOD_PROTOTYPE(__nss_compat_endpwent);
415 NSS_METHOD_PROTOTYPE(__nss_compat_getgrnam_r);
416 NSS_METHOD_PROTOTYPE(__nss_compat_getgrgid_r);
417 NSS_METHOD_PROTOTYPE(__nss_compat_getgrent_r);
418 NSS_METHOD_PROTOTYPE(__nss_compat_setgrent);
419 NSS_METHOD_PROTOTYPE(__nss_compat_endgrent);
421 NSS_STATUS _nss_mysql_getpwnam_r (const char *, struct passwd *, char *,
423 NSS_STATUS _nss_mysql_getpwuid_r (uid_t, struct passwd *, char *,
425 NSS_STATUS _nss_mysql_getpwent_r (struct passwd *, char *, size_t, int *);
426 NSS_STATUS _nss_mysql_setpwent (void);
427 NSS_STATUS _nss_mysql_endpwent (void);
429 NSS_STATUS _nss_mysql_getgrnam_r (const char *, struct group *, char *,
431 NSS_STATUS _nss_mysql_getgrgid_r (gid_t, struct group *, char *,
433 NSS_STATUS _nss_mysql_getgrent_r (struct group *, char *, size_t, int *);
434 NSS_STATUS _nss_mysql_setgrent (void);
435 NSS_STATUS _nss_mysql_endgrent (void);
437 static ns_mtab methods[] = {
438 { NSDB_PASSWD, "getpwnam_r", __nss_compat_getpwnam_r, _nss_mysql_getpwnam_r },
439 { NSDB_PASSWD, "getpwuid_r", __nss_compat_getpwuid_r, _nss_mysql_getpwuid_r },
440 { NSDB_PASSWD, "getpwent_r", __nss_compat_getpwent_r, _nss_mysql_getpwent_r },
441 { NSDB_PASSWD, "endpwent", __nss_compat_setpwent, _nss_mysql_setpwent },
442 { NSDB_PASSWD, "setpwent", __nss_compat_endpwent, _nss_mysql_endpwent },
443 { NSDB_GROUP, "getgrnam_r", __nss_compat_getgrnam_r, _nss_mysql_getgrnam_r },
444 { NSDB_GROUP, "getgrgid_r", __nss_compat_getgrgid_r, _nss_mysql_getgrgid_r },
445 { NSDB_GROUP, "getgrent_r", __nss_compat_getgrent_r, _nss_mysql_getgrent_r },
446 { NSDB_GROUP, "endgrent", __nss_compat_setgrent, _nss_mysql_setgrent },
447 { NSDB_GROUP, "setgrent", __nss_compat_endgrent, _nss_mysql_endgrent },
451 nss_module_register (const char *name, unsigned int *size,
452 nss_module_unregister_fn *unregister)
454 *size = sizeof (methods) / sizeof (methods[0]);
459 #endif /* defined(__FreeBSD__) */