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, void *mdata, va_list ap) 47 { 48 return (NS_UNAVAIL); 49 } 50 51 int 52 __nss_common_cache_read(void *retval, void *mdata, va_list ap) 53 { 54 struct cached_connection_params params; 55 cached_connection connection; 56 57 char *buffer; 58 size_t buffer_size, size; 59 60 nss_cache_info const *cache_info; 61 nss_cache_data *cache_data; 62 va_list ap_new; 63 int res; 64 65 cache_data = (nss_cache_data *)mdata; 66 cache_info = cache_data->info; 67 68 memset(¶ms, 0, sizeof(struct cached_connection_params)); 69 params.socket_path = CACHED_SOCKET_PATH; 70 71 cache_data->key = (char *)malloc(NSS_CACHE_KEY_INITIAL_SIZE); 72 memset(cache_data->key, 0, NSS_CACHE_KEY_INITIAL_SIZE); 73 cache_data->key_size = NSS_CACHE_KEY_INITIAL_SIZE; 74 va_copy(ap_new, ap); 75 76 do { 77 size = cache_data->key_size; 78 res = cache_info->id_func(cache_data->key, &size, ap_new, 79 cache_info->mdata); 80 va_end(ap_new); 81 if (res == NS_RETURN) { 82 if (cache_data->key_size > NSS_CACHE_KEY_SIZE_LIMIT) 83 break; 84 85 cache_data->key_size <<= 1; 86 cache_data->key = realloc(cache_data->key, 87 cache_data->key_size); 88 memset(cache_data->key, 0, cache_data->key_size); 89 va_copy(ap_new, ap); 90 } 91 } while (res == NS_RETURN); 92 93 if (res != NS_SUCCESS) { 94 free(cache_data->key); 95 cache_data->key = NULL; 96 cache_data->key_size = 0; 97 return (res); 98 } else 99 cache_data->key_size = size; 100 101 buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE; 102 buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE); 103 memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE); 104 105 do { 106 connection = __open_cached_connection(¶ms); 107 if (connection == NULL) { 108 res = -1; 109 break; 110 } 111 res = __cached_read(connection, cache_info->entry_name, 112 cache_data->key, cache_data->key_size, buffer, 113 &buffer_size); 114 __close_cached_connection(connection); 115 if (res == -2 && buffer_size < NSS_CACHE_BUFFER_SIZE_LIMIT) { 116 buffer = (char *)realloc(buffer, buffer_size); 117 memset(buffer, 0, buffer_size); 118 } 119 } while (res == -2); 120 121 if (res == 0) { 122 if (buffer_size == 0) { 123 free(buffer); 124 free(cache_data->key); 125 cache_data->key = NULL; 126 cache_data->key_size = 0; 127 return (NS_RETURN); 128 } 129 130 va_copy(ap_new, ap); 131 res = cache_info->unmarshal_func(buffer, buffer_size, retval, 132 ap_new, cache_info->mdata); 133 va_end(ap_new); 134 135 if (res != NS_SUCCESS) { 136 free(buffer); 137 free(cache_data->key); 138 cache_data->key = NULL; 139 cache_data->key_size = 0; 140 return (res); 141 } else 142 res = 0; 143 } 144 145 if (res == 0) { 146 free(cache_data->key); 147 cache_data->key = NULL; 148 cache_data->key_size = 0; 149 } 150 151 free(buffer); 152 return (res == 0 ? NS_SUCCESS : NS_NOTFOUND); 153 } 154 155 int 156 __nss_common_cache_write(void *retval, void *mdata, va_list ap) 157 { 158 struct cached_connection_params params; 159 cached_connection connection; 160 161 char *buffer; 162 size_t buffer_size; 163 164 nss_cache_info const *cache_info; 165 nss_cache_data *cache_data; 166 va_list ap_new; 167 int res; 168 169 cache_data = (nss_cache_data *)mdata; 170 cache_info = cache_data->info; 171 172 if (cache_data->key == NULL) 173 return (NS_UNAVAIL); 174 175 memset(¶ms, 0, sizeof(struct cached_connection_params)); 176 params.socket_path = CACHED_SOCKET_PATH; 177 178 connection = __open_cached_connection(¶ms); 179 if (connection == NULL) { 180 free(cache_data->key); 181 return (NS_UNAVAIL); 182 } 183 184 buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE; 185 buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE); 186 memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE); 187 188 do { 189 size_t size; 190 191 size = buffer_size; 192 va_copy(ap_new, ap); 193 res = cache_info->marshal_func(buffer, &size, retval, ap_new, 194 cache_info->mdata); 195 va_end(ap_new); 196 197 if (res == NS_RETURN) { 198 if (buffer_size > NSS_CACHE_BUFFER_SIZE_LIMIT) 199 break; 200 201 buffer_size <<= 1; 202 buffer = (char *)realloc(buffer, buffer_size); 203 memset(buffer, 0, buffer_size); 204 } 205 } while (res == NS_RETURN); 206 207 if (res != NS_SUCCESS) { 208 __close_cached_connection(connection); 209 free(cache_data->key); 210 free(buffer); 211 return (res); 212 } 213 214 res = __cached_write(connection, cache_info->entry_name, 215 cache_data->key, cache_data->key_size, buffer, buffer_size); 216 __close_cached_connection(connection); 217 218 free(cache_data->key); 219 free(buffer); 220 221 return (res == 0 ? NS_SUCCESS : NS_UNAVAIL); 222 } 223 224 int 225 __nss_common_cache_write_negative(void *mdata) 226 { 227 struct cached_connection_params params; 228 cached_connection connection; 229 int res; 230 231 nss_cache_info const *cache_info; 232 nss_cache_data *cache_data; 233 234 cache_data = (nss_cache_data *)mdata; 235 cache_info = cache_data->info; 236 237 if (cache_data->key == NULL) 238 return (NS_UNAVAIL); 239 240 memset(¶ms, 0, sizeof(struct cached_connection_params)); 241 params.socket_path = CACHED_SOCKET_PATH; 242 243 connection = __open_cached_connection(¶ms); 244 if (connection == NULL) { 245 free(cache_data->key); 246 return (NS_UNAVAIL); 247 } 248 249 res = __cached_write(connection, cache_info->entry_name, 250 cache_data->key, cache_data->key_size, NULL, 0); 251 __close_cached_connection(connection); 252 253 free(cache_data->key); 254 return (res == 0 ? NS_SUCCESS : NS_UNAVAIL); 255 } 256 257 int 258 __nss_mp_cache_read(void *retval, void *mdata, va_list ap) 259 { 260 struct cached_connection_params params; 261 cached_mp_read_session rs; 262 263 char *buffer; 264 size_t buffer_size; 265 266 nss_cache_info const *cache_info; 267 nss_cache_data *cache_data; 268 va_list ap_new; 269 int res; 270 271 cache_data = (nss_cache_data *)mdata; 272 cache_info = cache_data->info; 273 274 if (cache_info->get_mp_ws_func() != INVALID_CACHED_MP_WRITE_SESSION) 275 return (NS_UNAVAIL); 276 277 rs = cache_info->get_mp_rs_func(); 278 if (rs == INVALID_CACHED_MP_READ_SESSION) { 279 memset(¶ms, 0, sizeof(struct cached_connection_params)); 280 params.socket_path = CACHED_SOCKET_PATH; 281 282 rs = __open_cached_mp_read_session(¶ms, 283 cache_info->entry_name); 284 if (rs == INVALID_CACHED_MP_READ_SESSION) 285 return (NS_UNAVAIL); 286 287 cache_info->set_mp_rs_func(rs); 288 } 289 290 buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE; 291 buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE); 292 memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE); 293 294 do { 295 res = __cached_mp_read(rs, buffer, &buffer_size); 296 if (res == -2 && buffer_size < NSS_CACHE_BUFFER_SIZE_LIMIT) { 297 buffer = (char *)realloc(buffer, buffer_size); 298 memset(buffer, 0, buffer_size); 299 } 300 } while (res == -2); 301 302 if (res == 0) { 303 va_copy(ap_new, ap); 304 res = cache_info->unmarshal_func(buffer, buffer_size, retval, 305 ap_new, cache_info->mdata); 306 va_end(ap_new); 307 308 if (res != NS_SUCCESS) { 309 free(buffer); 310 return (res); 311 } else 312 res = 0; 313 } else { 314 free(buffer); 315 __close_cached_mp_read_session(rs); 316 rs = INVALID_CACHED_MP_READ_SESSION; 317 cache_info->set_mp_rs_func(rs); 318 return (res == -1 ? NS_RETURN : NS_UNAVAIL); 319 } 320 321 free(buffer); 322 return (res == 0 ? NS_SUCCESS : NS_NOTFOUND); 323 } 324 325 int 326 __nss_mp_cache_write(void *retval, void *mdata, va_list ap) 327 { 328 struct cached_connection_params params; 329 cached_mp_write_session ws; 330 331 char *buffer; 332 size_t buffer_size; 333 334 nss_cache_info const *cache_info; 335 nss_cache_data *cache_data; 336 va_list ap_new; 337 int res; 338 339 cache_data = (nss_cache_data *)mdata; 340 cache_info = cache_data->info; 341 342 ws = cache_info->get_mp_ws_func(); 343 if (ws == INVALID_CACHED_MP_WRITE_SESSION) { 344 memset(¶ms, 0, sizeof(struct cached_connection_params)); 345 params.socket_path = CACHED_SOCKET_PATH; 346 347 ws = __open_cached_mp_write_session(¶ms, 348 cache_info->entry_name); 349 if (ws == INVALID_CACHED_MP_WRITE_SESSION) 350 return (NS_UNAVAIL); 351 352 cache_info->set_mp_ws_func(ws); 353 } 354 355 buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE; 356 buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE); 357 memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE); 358 359 do { 360 size_t size; 361 362 size = buffer_size; 363 va_copy(ap_new, ap); 364 res = cache_info->marshal_func(buffer, &size, retval, ap_new, 365 cache_info->mdata); 366 va_end(ap_new); 367 368 if (res == NS_RETURN) { 369 if (buffer_size > NSS_CACHE_BUFFER_SIZE_LIMIT) 370 break; 371 372 buffer_size <<= 1; 373 buffer = (char *)realloc(buffer, buffer_size); 374 memset(buffer, 0, buffer_size); 375 } 376 } while (res == NS_RETURN); 377 378 if (res != NS_SUCCESS) { 379 free(buffer); 380 return (res); 381 } 382 383 res = __cached_mp_write(ws, buffer, buffer_size); 384 385 free(buffer); 386 return (res == 0 ? NS_SUCCESS : NS_UNAVAIL); 387 } 388 389 int 390 __nss_mp_cache_write_submit(void *retval, void *mdata, va_list ap) 391 { 392 cached_mp_write_session ws; 393 394 nss_cache_info const *cache_info; 395 nss_cache_data *cache_data; 396 397 cache_data = (nss_cache_data *)mdata; 398 cache_info = cache_data->info; 399 400 ws = cache_info->get_mp_ws_func(); 401 if (ws != INVALID_CACHED_MP_WRITE_SESSION) { 402 __close_cached_mp_write_session(ws); 403 ws = INVALID_CACHED_MP_WRITE_SESSION; 404 cache_info->set_mp_ws_func(ws); 405 } 406 return (NS_UNAVAIL); 407 } 408 409 int 410 __nss_mp_cache_end(void *retval, void *mdata, va_list ap) 411 { 412 cached_mp_write_session ws; 413 cached_mp_read_session rs; 414 415 nss_cache_info const *cache_info; 416 nss_cache_data *cache_data; 417 418 cache_data = (nss_cache_data *)mdata; 419 cache_info = cache_data->info; 420 421 ws = cache_info->get_mp_ws_func(); 422 if (ws != INVALID_CACHED_MP_WRITE_SESSION) { 423 __abandon_cached_mp_write_session(ws); 424 ws = INVALID_CACHED_MP_WRITE_SESSION; 425 cache_info->set_mp_ws_func(ws); 426 } 427 428 rs = cache_info->get_mp_rs_func(); 429 if (rs != INVALID_CACHED_MP_READ_SESSION) { 430 __close_cached_mp_read_session(rs); 431 rs = INVALID_CACHED_MP_READ_SESSION; 432 cache_info->set_mp_rs_func(rs); 433 } 434 435 return (NS_UNAVAIL); 436 } 437