1 /*- 2 * Copyright (c) 2003-2007 Tim Kientzle 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "archive_platform.h" 27 __FBSDID("$FreeBSD$"); 28 29 #ifdef HAVE_SYS_TYPES_H 30 #include <sys/types.h> 31 #endif 32 #ifdef HAVE_ERRNO_H 33 #include <errno.h> 34 #endif 35 #ifdef HAVE_GRP_H 36 #include <grp.h> 37 #endif 38 #ifdef HAVE_PWD_H 39 #include <pwd.h> 40 #endif 41 #ifdef HAVE_STDLIB_H 42 #include <stdlib.h> 43 #endif 44 #ifdef HAVE_STRING_H 45 #include <string.h> 46 #endif 47 48 #include "archive.h" 49 50 #if defined(_WIN32) && !defined(__CYGWIN__) 51 int 52 archive_read_disk_set_standard_lookup(struct archive *a) 53 { 54 archive_set_error(a, -1, "Standard lookups not available on Windows"); 55 return (ARCHIVE_FATAL); 56 } 57 #else /* ! (_WIN32 && !__CYGWIN__) */ 58 #define name_cache_size 127 59 60 static const char * const NO_NAME = "(noname)"; 61 62 struct name_cache { 63 struct archive *archive; 64 char *buff; 65 size_t buff_size; 66 int probes; 67 int hits; 68 size_t size; 69 struct { 70 id_t id; 71 const char *name; 72 } cache[name_cache_size]; 73 }; 74 75 static const char * lookup_gname(void *, gid_t); 76 static const char * lookup_uname(void *, uid_t); 77 static void cleanup(void *); 78 static const char * lookup_gname_helper(struct name_cache *, id_t gid); 79 static const char * lookup_uname_helper(struct name_cache *, id_t uid); 80 81 /* 82 * Installs functions that use getpwuid()/getgrgid()---along with 83 * a simple cache to accelerate such lookups---into the archive_read_disk 84 * object. This is in a separate file because getpwuid()/getgrgid() 85 * can pull in a LOT of library code (including NIS/LDAP functions, which 86 * pull in DNS resolveers, etc). This can easily top 500kB, which makes 87 * it inappropriate for some space-constrained applications. 88 * 89 * Applications that are size-sensitive may want to just use the 90 * real default functions (defined in archive_read_disk.c) that just 91 * use the uid/gid without the lookup. Or define your own custom functions 92 * if you prefer. 93 */ 94 int 95 archive_read_disk_set_standard_lookup(struct archive *a) 96 { 97 struct name_cache *ucache = malloc(sizeof(struct name_cache)); 98 struct name_cache *gcache = malloc(sizeof(struct name_cache)); 99 100 if (ucache == NULL || gcache == NULL) { 101 archive_set_error(a, ENOMEM, 102 "Can't allocate uname/gname lookup cache"); 103 free(ucache); 104 free(gcache); 105 return (ARCHIVE_FATAL); 106 } 107 108 memset(ucache, 0, sizeof(*ucache)); 109 ucache->archive = a; 110 ucache->size = name_cache_size; 111 memset(gcache, 0, sizeof(*gcache)); 112 gcache->archive = a; 113 gcache->size = name_cache_size; 114 115 archive_read_disk_set_gname_lookup(a, gcache, lookup_gname, cleanup); 116 archive_read_disk_set_uname_lookup(a, ucache, lookup_uname, cleanup); 117 118 return (ARCHIVE_OK); 119 } 120 121 static void 122 cleanup(void *data) 123 { 124 struct name_cache *cache = (struct name_cache *)data; 125 size_t i; 126 127 if (cache != NULL) { 128 for (i = 0; i < cache->size; i++) { 129 if (cache->cache[i].name != NULL && 130 cache->cache[i].name != NO_NAME) 131 free((void *)(uintptr_t)cache->cache[i].name); 132 } 133 free(cache->buff); 134 free(cache); 135 } 136 } 137 138 /* 139 * Lookup uid/gid from uname/gname, return NULL if no match. 140 */ 141 static const char * 142 lookup_name(struct name_cache *cache, 143 const char * (*lookup_fn)(struct name_cache *, id_t), id_t id) 144 { 145 const char *name; 146 int slot; 147 148 149 cache->probes++; 150 151 slot = id % cache->size; 152 if (cache->cache[slot].name != NULL) { 153 if (cache->cache[slot].id == id) { 154 cache->hits++; 155 if (cache->cache[slot].name == NO_NAME) 156 return (NULL); 157 return (cache->cache[slot].name); 158 } 159 if (cache->cache[slot].name != NO_NAME) 160 free((void *)(uintptr_t)cache->cache[slot].name); 161 cache->cache[slot].name = NULL; 162 } 163 164 name = (lookup_fn)(cache, id); 165 if (name == NULL) { 166 /* Cache and return the negative response. */ 167 cache->cache[slot].name = NO_NAME; 168 cache->cache[slot].id = id; 169 return (NULL); 170 } 171 172 cache->cache[slot].name = name; 173 cache->cache[slot].id = id; 174 return (cache->cache[slot].name); 175 } 176 177 static const char * 178 lookup_uname(void *data, uid_t uid) 179 { 180 struct name_cache *uname_cache = (struct name_cache *)data; 181 return (lookup_name(uname_cache, 182 &lookup_uname_helper, (id_t)uid)); 183 } 184 185 static const char * 186 lookup_uname_helper(struct name_cache *cache, id_t id) 187 { 188 struct passwd pwent, *result; 189 int r; 190 191 if (cache->buff_size == 0) { 192 cache->buff_size = 256; 193 cache->buff = malloc(cache->buff_size); 194 } 195 if (cache->buff == NULL) 196 return (NULL); 197 for (;;) { 198 r = getpwuid_r((uid_t)id, &pwent, 199 cache->buff, cache->buff_size, &result); 200 if (r == 0) 201 break; 202 if (r != ERANGE) 203 break; 204 /* ERANGE means our buffer was too small, but POSIX 205 * doesn't tell us how big the buffer should be, so 206 * we just double it and try again. Because the buffer 207 * is kept around in the cache object, we shouldn't 208 * have to do this very often. */ 209 cache->buff_size *= 2; 210 cache->buff = realloc(cache->buff, cache->buff_size); 211 if (cache->buff == NULL) 212 break; 213 } 214 if (r != 0) { 215 archive_set_error(cache->archive, errno, 216 "Can't lookup user for id %d", (int)id); 217 return (NULL); 218 } 219 if (result == NULL) 220 return (NULL); 221 222 return strdup(result->pw_name); 223 } 224 225 static const char * 226 lookup_gname(void *data, gid_t gid) 227 { 228 struct name_cache *gname_cache = (struct name_cache *)data; 229 return (lookup_name(gname_cache, 230 &lookup_gname_helper, (id_t)gid)); 231 } 232 233 static const char * 234 lookup_gname_helper(struct name_cache *cache, id_t id) 235 { 236 struct group grent, *result; 237 int r; 238 239 if (cache->buff_size == 0) { 240 cache->buff_size = 256; 241 cache->buff = malloc(cache->buff_size); 242 } 243 if (cache->buff == NULL) 244 return (NULL); 245 for (;;) { 246 r = getgrgid_r((gid_t)id, &grent, 247 cache->buff, cache->buff_size, &result); 248 if (r == 0) 249 break; 250 if (r != ERANGE) 251 break; 252 /* ERANGE means our buffer was too small, but POSIX 253 * doesn't tell us how big the buffer should be, so 254 * we just double it and try again. */ 255 cache->buff_size *= 2; 256 cache->buff = realloc(cache->buff, cache->buff_size); 257 if (cache->buff == NULL) 258 break; 259 } 260 if (r != 0) { 261 archive_set_error(cache->archive, errno, 262 "Can't lookup group for id %d", (int)id); 263 return (NULL); 264 } 265 if (result == NULL) 266 return (NULL); 267 268 return strdup(result->gr_name); 269 } 270 #endif /* ! (_WIN32 && !__CYGWIN__) */ 271