Last active
March 6, 2016 00:59
-
-
Save clausecker/9f84b8be7591897f8473 to your computer and use it in GitHub Desktop.
Caching functions for the group and passwd database
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /*- | |
| * Copyright (c) 2016 Robert Clausecker. All rights reserved. | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions | |
| * are met: | |
| * 1. Redistributions of source code must retain the above copyright | |
| * notice, this list of conditions and the following disclaimer. | |
| * 2. Redistributions in binary form must reproduce the above copyright | |
| * notice, this list of conditions and the following disclaimer in the | |
| * documentation and/or other materials provided with the distribution. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| * SUCH DAMAGE. | |
| */ | |
| #define _XOPEN_SOURCE 700 | |
| #include <errno.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <sys/types.h> | |
| #include <grp.h> | |
| #include "perm.h" | |
| static size_t grpcachesize = 0; | |
| static struct grentry { | |
| char *groupname; | |
| gid_t groupid; | |
| } *grpcache = NULL; | |
| static void clear_grpcache(struct grentry**, size_t*); | |
| static int sort_by_groupid(const void*, const void*); | |
| /* | |
| * Load group to gid mappings from the group database and save them | |
| * for future quick lookups. This function returns 0 on success, -1 on | |
| * failure. errno is set to indicate the source of failure. Failure of | |
| * this function should not be considered to be a hard failure and does | |
| * not make calls to gid_to_group() fail. Such calls may be (depending | |
| * on the implementation of getgrgid()) much slower though. | |
| */ | |
| extern int | |
| fill_grpcache() | |
| { | |
| struct grentry *cache = NULL, *newcache; | |
| struct group *group; | |
| size_t i = 0, n = 0; | |
| int saved_errno = errno; | |
| errno = 0; | |
| clear_grpcache(&grpcache, &grpcachesize); | |
| while ((group = getgrent()) != NULL) { | |
| if (i + 1 > n) { | |
| /* approximate golden ratio in allocation scheme */ | |
| n = n > 0 ? (n * 13) / 8 : 64; | |
| newcache = realloc(cache, n * sizeof *cache); | |
| if (newcache == NULL) { | |
| clear_grpcache(&cache, &i); | |
| return (-1); | |
| } | |
| cache = newcache; | |
| } | |
| cache[i].groupid = group->gr_gid; | |
| cache[i].groupname = strdup(group->gr_name); | |
| if (cache[i++].groupname == NULL) { | |
| clear_grpcache(&cache, &i); | |
| return (-1); | |
| } | |
| } | |
| if (errno != 0) { | |
| clear_grpcache(&cache, &i); | |
| return (-1); | |
| } | |
| /* ignore error when closing passwd database */ | |
| endgrent(); | |
| /* reclaim some memory */ | |
| newcache = realloc(cache, i * sizeof *cache); | |
| if (newcache != NULL) | |
| cache = newcache; | |
| qsort(cache, i, sizeof *cache, &sort_by_groupid); | |
| grpcache = cache; | |
| grpcachesize = i; | |
| errno = saved_errno; | |
| return (0); | |
| } | |
| /* | |
| * Lookup a group name from a gid. It's unspecified which group is | |
| * returned if multiple group entries exist for a given gid. Calling | |
| * gid_to_group(() without a succesful call to fill_grpcache() | |
| * beforehand is not an error, in this case an attempt is made to lookup | |
| * the desired information using getgrgid(). NULL is returned if the | |
| * gid could not be found or if an error occured. Check errno to tell | |
| * these two cases apart. The string returned by this function is only | |
| * valid until the next call to this function or fill_grpcache(). | |
| * No attempt is made to keep data up to date. | |
| */ | |
| extern const char* | |
| gid_to_group(gid_t groupid) | |
| { | |
| struct group *group; | |
| struct grentry *match, key; | |
| if (grpcache == NULL) { | |
| group = getgrgid(groupid); | |
| if (group == NULL) | |
| return (NULL); | |
| else | |
| return (group->gr_name); | |
| } | |
| key.groupid = groupid; | |
| match = bsearch(&key, grpcache, grpcachesize, sizeof *grpcache, &sort_by_groupid); | |
| if (match == NULL) | |
| return (NULL); | |
| else | |
| return (match->groupname); | |
| } | |
| /* | |
| * Clear out a grp cache and free() its contents. | |
| */ | |
| static void | |
| clear_grpcache(struct grentry **cachevar, size_t *cachesizevar) | |
| { | |
| size_t i, n = *cachesizevar; | |
| struct grentry *cache = *cachevar; | |
| *cachesizevar = 0; | |
| *cachevar = NULL; | |
| if (cache == NULL) | |
| return; | |
| for (i = 0; i < n; i++) | |
| free(cache[i].groupname); | |
| free(cache); | |
| } | |
| /* | |
| * Sort struct grentry by groupid. | |
| */ | |
| static int | |
| sort_by_groupid(const void *a, const void *b) | |
| { | |
| return (((const struct grentry*)a)->groupid - ((const struct grentry*)b)->groupid); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /*- | |
| * Copyright (c) 2014, 2016 Robert Clausecker. All rights reserved. | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions | |
| * are met: | |
| * 1. Redistributions of source code must retain the above copyright | |
| * notice, this list of conditions and the following disclaimer. | |
| * 2. Redistributions in binary form must reproduce the above copyright | |
| * notice, this list of conditions and the following disclaimer in the | |
| * documentation and/or other materials provided with the distribution. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| * SUCH DAMAGE. | |
| */ | |
| /* | |
| * perm.h - utility functions for permissions. | |
| */ | |
| #ifndef PERM_H | |
| #define PERM_H | |
| #include <pwd.h> | |
| #include <grp.h> | |
| extern int fill_pwdcache(void); | |
| extern const char *uid_to_user(uid_t); | |
| extern int fill_grpcache(void); | |
| extern const char *gid_to_group(gid_t); | |
| #endif /* PERM_H */ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /*- | |
| * Copyright (c) 2016 Robert Clausecker. All rights reserved. | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions | |
| * are met: | |
| * 1. Redistributions of source code must retain the above copyright | |
| * notice, this list of conditions and the following disclaimer. | |
| * 2. Redistributions in binary form must reproduce the above copyright | |
| * notice, this list of conditions and the following disclaimer in the | |
| * documentation and/or other materials provided with the distribution. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| * SUCH DAMAGE. | |
| */ | |
| #define _XOPEN_SOURCE 700 | |
| #include <errno.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <sys/types.h> | |
| #include <pwd.h> | |
| #include "perm.h" | |
| static size_t pwdcachesize = 0; | |
| static struct pwentry { | |
| char *username; | |
| uid_t userid; | |
| } *pwdcache = NULL; | |
| static void clear_pwdcache(struct pwentry**, size_t*); | |
| static int sort_by_userid(const void*, const void*); | |
| /* | |
| * Load user name to uid mappings from the passwd database and save them | |
| * for future quick lookups. This function returns 0 on success, -1 on | |
| * failure. errno is set to indicate the source of failure. Failure of | |
| * this function should not be considered to be a hard failure and does | |
| * not make calls to uid_to_user() fail. Such calls may be (depending | |
| * on the implementation of getpwuid()) much slower though. | |
| */ | |
| extern int | |
| fill_pwdcache() | |
| { | |
| struct pwentry *cache = NULL, *newcache; | |
| struct passwd *passwd; | |
| size_t i = 0, n = 0; | |
| int saved_errno = errno; | |
| errno = 0; | |
| clear_pwdcache(&pwdcache, &pwdcachesize); | |
| while ((passwd = getpwent()) != NULL) { | |
| if (i + 1 > n) { | |
| /* approximate golden ratio in allocation scheme */ | |
| n = n > 0 ? (n * 13) / 8 : 64; | |
| newcache = realloc(cache, n * sizeof *cache); | |
| if (newcache == NULL) { | |
| clear_pwdcache(&cache, &i); | |
| return (-1); | |
| } | |
| cache = newcache; | |
| } | |
| cache[i].userid = passwd->pw_uid; | |
| cache[i].username = strdup(passwd->pw_name); | |
| if (cache[i++].username == NULL) { | |
| clear_pwdcache(&cache, &i); | |
| return (-1); | |
| } | |
| } | |
| if (errno != 0) { | |
| clear_pwdcache(&cache, &i); | |
| return (-1); | |
| } | |
| /* ignore error when closing passwd database */ | |
| endpwent(); | |
| /* reclaim some memory */ | |
| newcache = realloc(cache, i * sizeof *cache); | |
| if (newcache != NULL) | |
| cache = newcache; | |
| qsort(cache, i, sizeof *cache, &sort_by_userid); | |
| pwdcache = cache; | |
| pwdcachesize = i; | |
| errno = saved_errno; | |
| return (0); | |
| } | |
| /* | |
| * Lookup a user name from a uid. It's unspecified which user name is | |
| * returned if multiple passwd entries exist for a given uid. Calling | |
| * uid_to_user() without a succesful call to fill_pwdcache() beforehand | |
| * is not an error, in this case an attempt is made to lookup the | |
| * desired information using getpwuid(). NULL is returned if the uid | |
| * could not be found or if an error occured. Check errno to tell these | |
| * two cases apart. The string returned by this function is only | |
| * valid until the next call to this function or fill_pwdcache(). | |
| * No attempt is made to keep data up to date. | |
| */ | |
| extern const char* | |
| uid_to_user(uid_t userid) | |
| { | |
| struct passwd *passwd; | |
| struct pwentry *match, key; | |
| if (pwdcache == NULL) { | |
| passwd = getpwuid(userid); | |
| if (passwd == NULL) | |
| return (NULL); | |
| else | |
| return (passwd->pw_name); | |
| } | |
| key.userid = userid; | |
| match = bsearch(&key, pwdcache, pwdcachesize, sizeof *pwdcache, &sort_by_userid); | |
| if (match == NULL) | |
| return (NULL); | |
| else | |
| return (match->username); | |
| } | |
| /* | |
| * Clear out a pwd cache and free() its contents. | |
| */ | |
| static void | |
| clear_pwdcache(struct pwentry **cachevar, size_t *cachesizevar) | |
| { | |
| size_t i, n = *cachesizevar; | |
| struct pwentry *cache = *cachevar; | |
| *cachesizevar = 0; | |
| *cachevar = NULL; | |
| if (cache == NULL) | |
| return; | |
| for (i = 0; i < n; i++) | |
| free(cache[i].username); | |
| free(cache); | |
| } | |
| /* | |
| * Sort struct pwentry by userid. | |
| */ | |
| static int | |
| sort_by_userid(const void *a, const void *b) | |
| { | |
| return (((const struct pwentry*)a)->userid - ((const struct pwentry*)b)->userid); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment