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