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