1 /*- 2 * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru> 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 AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: src/lib/libc/net/nscache.c,v 1.2 2007/10/17 23:20:49 tmclaugh Exp $ 27 */ 28 29 #include "namespace.h" 30 #include <nsswitch.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include "un-namespace.h" 34 #include "nscachedcli.h" 35 #include "nscache.h" 36 37 #define NSS_CACHE_KEY_INITIAL_SIZE (256) 38 #define NSS_CACHE_KEY_SIZE_LIMIT (NSS_CACHE_KEY_INITIAL_SIZE << 4) 39 40 #define NSS_CACHE_BUFFER_INITIAL_SIZE (1024) 41 #define NSS_CACHE_BUFFER_SIZE_LIMIT (NSS_CACHE_BUFFER_INITIAL_SIZE << 8) 42 43 #define CACHED_SOCKET_PATH "/var/run/nscd" 44 45 int 46 __nss_cache_handler(void *retval __unused, void *mdata __unused, 47 va_list ap __unused) 48 { 49 return (NS_UNAVAIL); 50 } 51 52 int 53 __nss_common_cache_read(void *retval, void *mdata, va_list ap) 54 { 55 struct cached_connection_params params; 56 cached_connection connection; 57 58 char *buffer; 59 size_t buffer_size, size; 60 61 nss_cache_info const *cache_info; 62 nss_cache_data *cache_data; 63 va_list ap_new; 64 int res; 65 66 cache_data = (nss_cache_data *)mdata; 67 cache_info = cache_data->info; 68 69 memset(¶ms, 0, sizeof(struct cached_connection_params)); 70 params.socket_path = CACHED_SOCKET_PATH; 71 72 cache_data->key = (char *)malloc(NSS_CACHE_KEY_INITIAL_SIZE); 73 memset(cache_data->key, 0, NSS_CACHE_KEY_INITIAL_SIZE); 74 cache_data->key_size = NSS_CACHE_KEY_INITIAL_SIZE; 75 va_copy(ap_new, ap); 76 77 do { 78 size = cache_data->key_size; 79 res = cache_info->id_func(cache_data->key, &size, ap_new, 80 cache_info->mdata); 81 va_end(ap_new); 82 if (res == NS_RETURN) { 83 if (cache_data->key_size > NSS_CACHE_KEY_SIZE_LIMIT) 84 break; 85 86 cache_data->key_size <<= 1; 87 cache_data->key = realloc(cache_data->key, 88 cache_data->key_size); 89 memset(cache_data->key, 0, cache_data->key_size); 90 va_copy(ap_new, ap); 91 } 92 } while (res == NS_RETURN); 93 94 if (res != NS_SUCCESS) { 95 free(cache_data->key); 96 cache_data->key = NULL; 97 cache_data->key_size = 0; 98 return (res); 99 } else 100 cache_data->key_size = size; 101 102 buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE; 103 buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE); 104 memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE); 105 106 do { 107 connection = __open_cached_connection(¶ms); 108 if (connection == NULL) { 109 res = -1; 110 break; 111 } 112 res = __cached_read(connection, cache_info->entry_name, 113 cache_data->key, cache_data->key_size, buffer, 114 &buffer_size); 115 __close_cached_connection(connection); 116 if (res == -2 && buffer_size < NSS_CACHE_BUFFER_SIZE_LIMIT) { 117 buffer = (char *)realloc(buffer, buffer_size); 118 memset(buffer, 0, buffer_size); 119 } 120 } while (res == -2); 121 122 if (res == 0) { 123 if (buffer_size == 0) { 124 free(buffer); 125 free(cache_data->key); 126 cache_data->key = NULL; 127 cache_data->key_size = 0; 128 return (NS_RETURN); 129 } 130 131 va_copy(ap_new, ap); 132 res = cache_info->unmarshal_func(buffer, buffer_size, retval, 133 ap_new, cache_info->mdata); 134 va_end(ap_new); 135 136 if (res != NS_SUCCESS) { 137 free(buffer); 138 free(cache_data->key); 139 cache_data->key = NULL; 140 cache_data->key_size = 0; 141 return (res); 142 } else 143 res = 0; 144 } 145 146 if (res == 0) { 147 free(cache_data->key); 148 cache_data->key = NULL; 149 cache_data->key_size = 0; 150 } 151 152 free(buffer); 153 return (res == 0 ? NS_SUCCESS : NS_NOTFOUND); 154 } 155 156 int 157 __nss_common_cache_write(void *retval, void *mdata, va_list ap) 158 { 159 struct cached_connection_params params; 160 cached_connection connection; 161 162 char *buffer; 163 size_t buffer_size; 164 165 nss_cache_info const *cache_info; 166 nss_cache_data *cache_data; 167 va_list ap_new; 168 int res; 169 170 cache_data = (nss_cache_data *)mdata; 171 cache_info = cache_data->info; 172 173 if (cache_data->key == NULL) 174 return (NS_UNAVAIL); 175 176 memset(¶ms, 0, sizeof(struct cached_connection_params)); 177 params.socket_path = CACHED_SOCKET_PATH; 178 179 connection = __open_cached_connection(¶ms); 180 if (connection == NULL) { 181 free(cache_data->key); 182 return (NS_UNAVAIL); 183 } 184 185 buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE; 186 buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE); 187 memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE); 188 189 do { 190 size_t size; 191 192 size = buffer_size; 193 va_copy(ap_new, ap); 194 res = cache_info->marshal_func(buffer, &size, retval, ap_new, 195 cache_info->mdata); 196 va_end(ap_new); 197 198 if (res == NS_RETURN) { 199 if (buffer_size > NSS_CACHE_BUFFER_SIZE_LIMIT) 200 break; 201 202 buffer_size <<= 1; 203 buffer = (char *)realloc(buffer, buffer_size); 204 memset(buffer, 0, buffer_size); 205 } 206 } while (res == NS_RETURN); 207 208 if (res != NS_SUCCESS) { 209 __close_cached_connection(connection); 210 free(cache_data->key); 211 free(buffer); 212 return (res); 213 } 214 215 res = __cached_write(connection, cache_info->entry_name, 216 cache_data->key, cache_data->key_size, buffer, buffer_size); 217 __close_cached_connection(connection); 218 219 free(cache_data->key); 220 free(buffer); 221 222 return (res == 0 ? NS_SUCCESS : NS_UNAVAIL); 223 } 224 225 int 226 __nss_common_cache_write_negative(void *mdata) 227 { 228 struct cached_connection_params params; 229 cached_connection connection; 230 int res; 231 232 nss_cache_info const *cache_info; 233 nss_cache_data *cache_data; 234 235 cache_data = (nss_cache_data *)mdata; 236 cache_info = cache_data->info; 237 238 if (cache_data->key == NULL) 239 return (NS_UNAVAIL); 240 241 memset(¶ms, 0, sizeof(struct cached_connection_params)); 242 params.socket_path = CACHED_SOCKET_PATH; 243 244 connection = __open_cached_connection(¶ms); 245 if (connection == NULL) { 246 free(cache_data->key); 247 return (NS_UNAVAIL); 248 } 249 250 res = __cached_write(connection, cache_info->entry_name, 251 cache_data->key, cache_data->key_size, NULL, 0); 252 __close_cached_connection(connection); 253 254 free(cache_data->key); 255 return (res == 0 ? NS_SUCCESS : NS_UNAVAIL); 256 } 257 258 int 259 __nss_mp_cache_read(void *retval, void *mdata, va_list ap) 260 { 261 struct cached_connection_params params; 262 cached_mp_read_session rs; 263 264 char *buffer; 265 size_t buffer_size; 266 267 nss_cache_info const *cache_info; 268 nss_cache_data *cache_data; 269 va_list ap_new; 270 int res; 271 272 cache_data = (nss_cache_data *)mdata; 273 cache_info = cache_data->info; 274 275 if (cache_info->get_mp_ws_func() != INVALID_CACHED_MP_WRITE_SESSION) 276 return (NS_UNAVAIL); 277 278 rs = cache_info->get_mp_rs_func(); 279 if (rs == INVALID_CACHED_MP_READ_SESSION) { 280 memset(¶ms, 0, sizeof(struct cached_connection_params)); 281 params.socket_path = CACHED_SOCKET_PATH; 282 283 rs = __open_cached_mp_read_session(¶ms, 284 cache_info->entry_name); 285 if (rs == INVALID_CACHED_MP_READ_SESSION) 286 return (NS_UNAVAIL); 287 288 cache_info->set_mp_rs_func(rs); 289 } 290 291 buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE; 292 buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE); 293 memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE); 294 295 do { 296 res = __cached_mp_read(rs, buffer, &buffer_size); 297 if (res == -2 && buffer_size < NSS_CACHE_BUFFER_SIZE_LIMIT) { 298 buffer = (char *)realloc(buffer, buffer_size); 299 memset(buffer, 0, buffer_size); 300 } 301 } while (res == -2); 302 303 if (res == 0) { 304 va_copy(ap_new, ap); 305 res = cache_info->unmarshal_func(buffer, buffer_size, retval, 306 ap_new, cache_info->mdata); 307 va_end(ap_new); 308 309 if (res != NS_SUCCESS) { 310 free(buffer); 311 return (res); 312 } else 313 res = 0; 314 } else { 315 free(buffer); 316 __close_cached_mp_read_session(rs); 317 rs = INVALID_CACHED_MP_READ_SESSION; 318 cache_info->set_mp_rs_func(rs); 319 return (res == -1 ? NS_RETURN : NS_UNAVAIL); 320 } 321 322 free(buffer); 323 return (res == 0 ? NS_SUCCESS : NS_NOTFOUND); 324 } 325 326 int 327 __nss_mp_cache_write(void *retval, void *mdata, va_list ap) 328 { 329 struct cached_connection_params params; 330 cached_mp_write_session ws; 331 332 char *buffer; 333 size_t buffer_size; 334 335 nss_cache_info const *cache_info; 336 nss_cache_data *cache_data; 337 va_list ap_new; 338 int res; 339 340 cache_data = (nss_cache_data *)mdata; 341 cache_info = cache_data->info; 342 343 ws = cache_info->get_mp_ws_func(); 344 if (ws == INVALID_CACHED_MP_WRITE_SESSION) { 345 memset(¶ms, 0, sizeof(struct cached_connection_params)); 346 params.socket_path = CACHED_SOCKET_PATH; 347 348 ws = __open_cached_mp_write_session(¶ms, 349 cache_info->entry_name); 350 if (ws == INVALID_CACHED_MP_WRITE_SESSION) 351 return (NS_UNAVAIL); 352 353 cache_info->set_mp_ws_func(ws); 354 } 355 356 buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE; 357 buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE); 358 memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE); 359 360 do { 361 size_t size; 362 363 size = buffer_size; 364 va_copy(ap_new, ap); 365 res = cache_info->marshal_func(buffer, &size, retval, ap_new, 366 cache_info->mdata); 367 va_end(ap_new); 368 369 if (res == NS_RETURN) { 370 if (buffer_size > NSS_CACHE_BUFFER_SIZE_LIMIT) 371 break; 372 373 buffer_size <<= 1; 374 buffer = (char *)realloc(buffer, buffer_size); 375 memset(buffer, 0, buffer_size); 376 } 377 } while (res == NS_RETURN); 378 379 if (res != NS_SUCCESS) { 380 free(buffer); 381 return (res); 382 } 383 384 res = __cached_mp_write(ws, buffer, buffer_size); 385 386 free(buffer); 387 return (res == 0 ? NS_SUCCESS : NS_UNAVAIL); 388 } 389 390 int 391 __nss_mp_cache_write_submit(void *retval __unused, void *mdata, 392 va_list ap __unused) 393 { 394 cached_mp_write_session ws; 395 396 nss_cache_info const *cache_info; 397 nss_cache_data *cache_data; 398 399 cache_data = (nss_cache_data *)mdata; 400 cache_info = cache_data->info; 401 402 ws = cache_info->get_mp_ws_func(); 403 if (ws != INVALID_CACHED_MP_WRITE_SESSION) { 404 __close_cached_mp_write_session(ws); 405 ws = INVALID_CACHED_MP_WRITE_SESSION; 406 cache_info->set_mp_ws_func(ws); 407 } 408 return (NS_UNAVAIL); 409 } 410 411 int 412 __nss_mp_cache_end(void *retval __unused, void *mdata, va_list ap __unused) 413 { 414 cached_mp_write_session ws; 415 cached_mp_read_session rs; 416 417 nss_cache_info const *cache_info; 418 nss_cache_data *cache_data; 419 420 cache_data = (nss_cache_data *)mdata; 421 cache_info = cache_data->info; 422 423 ws = cache_info->get_mp_ws_func(); 424 if (ws != INVALID_CACHED_MP_WRITE_SESSION) { 425 __abandon_cached_mp_write_session(ws); 426 ws = INVALID_CACHED_MP_WRITE_SESSION; 427 cache_info->set_mp_ws_func(ws); 428 } 429 430 rs = cache_info->get_mp_rs_func(); 431 if (rs != INVALID_CACHED_MP_READ_SESSION) { 432 __close_cached_mp_read_session(rs); 433 rs = INVALID_CACHED_MP_READ_SESSION; 434 cache_info->set_mp_rs_func(rs); 435 } 436 437 return (NS_UNAVAIL); 438 } 439