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