1 /* 2 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 7 8 9 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- 10 * 11 * The contents of this file are subject to the Netscape Public License 12 * Version 1.0 (the "NPL"); you may not use this file except in 13 * compliance with the NPL. You may obtain a copy of the NPL at 14 * http://www.mozilla.org/NPL/ 15 * 16 * Software distributed under the NPL is distributed on an "AS IS" basis, 17 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL 18 * for the specific language governing rights and limitations under the 19 * NPL. 20 * 21 * The Initial Developer of this code under the NPL is Netscape 22 * Communications Corporation. Portions created by Netscape are 23 * Copyright (C) 1998 Netscape Communications Corporation. All Rights 24 * Reserved. 25 */ 26 /* 27 * Copyright (c) 1993 Regents of the University of Michigan. 28 * All rights reserved. 29 */ 30 /* 31 * getfilter.c -- optional add-on to libldap 32 */ 33 34 #if 0 35 #ifndef lint 36 static char copyright[] = "@(#) Copyright (c) 1993 Regents of the University of Michigan.\nAll rights reserved.\n"; 37 #endif 38 #endif 39 40 #include "ldap-int.h" 41 #include "regex.h" 42 #include <stdio.h> /* sprintf */ 43 44 static int break_into_words( char *str, char *delims, char ***wordsp ); 45 46 #if !defined( macintosh ) && !defined( DOS ) 47 extern char * LDAP_CALL re_comp(); 48 extern int LDAP_CALL re_exec( char *lp ); 49 #endif 50 51 #define FILT_MAX_LINE_LEN 1024 52 53 LDAPFiltDesc * 54 LDAP_CALL 55 ldap_init_getfilter( char *fname ) 56 { 57 FILE *fp; 58 char *buf; 59 ssize_t rlen, len; 60 int eof; 61 LDAPFiltDesc *lfdp; 62 63 if (( fp = fopen( fname, "rF" )) == NULL ) { 64 return( NULL ); 65 } 66 67 if ( fseek( fp, 0L, SEEK_END ) != 0 ) { /* move to end to get len */ 68 fclose( fp ); 69 return( NULL ); 70 } 71 72 len = ftell( fp ); 73 74 if ( fseek( fp, 0L, SEEK_SET ) != 0 ) { /* back to start of file */ 75 fclose( fp ); 76 return( NULL ); 77 } 78 79 if (( buf = NSLDAPI_MALLOC( (size_t)len )) == NULL ) { 80 fclose( fp ); 81 return( NULL ); 82 } 83 84 rlen = fread( buf, 1, (size_t)len, fp ); 85 eof = feof( fp ); 86 fclose( fp ); 87 88 if ( rlen != len && !eof ) { /* error: didn't get the whole file */ 89 NSLDAPI_FREE( buf ); 90 return( NULL ); 91 } 92 93 94 lfdp = ldap_init_getfilter_buf( buf, rlen ); 95 NSLDAPI_FREE( buf ); 96 97 return( lfdp ); 98 } 99 100 101 LDAPFiltDesc * 102 LDAP_CALL 103 ldap_init_getfilter_buf( char *buf, ssize_t buflen ) 104 { 105 LDAPFiltDesc *lfdp; 106 LDAPFiltList *flp, *nextflp; 107 LDAPFiltInfo *fip, *nextfip; 108 char *tag, **tok; 109 int tokcnt, i; 110 long buffer_len = (long)buflen; 111 112 if ( (buf == NULL) || (buflen < 0) || 113 ( lfdp = (LDAPFiltDesc *)NSLDAPI_CALLOC(1, sizeof( LDAPFiltDesc))) 114 == NULL ) { 115 return( NULL ); 116 } 117 118 flp = nextflp = NULL; 119 fip = NULL; 120 tag = NULL; 121 122 while ( buflen > 0 && ( tokcnt = ldap_next_line_tokens( &buf, 123 &buffer_len, &tok )) > 0 ) { 124 switch( tokcnt ) { 125 case 1: /* tag line */ 126 if ( tag != NULL ) { 127 NSLDAPI_FREE( tag ); 128 } 129 tag = tok[ 0 ]; 130 NSLDAPI_FREE( tok ); 131 break; 132 case 4: 133 case 5: /* start of filter info. list */ 134 if (( nextflp = (LDAPFiltList *)NSLDAPI_CALLOC( 1, 135 sizeof( LDAPFiltList ))) == NULL ) { 136 ldap_getfilter_free( lfdp ); 137 return( NULL ); 138 } 139 nextflp->lfl_tag = nsldapi_strdup( tag ); 140 nextflp->lfl_pattern = tok[ 0 ]; 141 if ( re_comp( nextflp->lfl_pattern ) != NULL ) { 142 char msg[256]; 143 ldap_getfilter_free( lfdp ); 144 sprintf( msg, dgettext(TEXT_DOMAIN, 145 "bad regular expresssion %s\n"), 146 nextflp->lfl_pattern ); 147 ber_err_print( msg ); 148 ldap_free_strarray( tok ); 149 return( NULL ); 150 } 151 152 nextflp->lfl_delims = tok[ 1 ]; 153 nextflp->lfl_ilist = NULL; 154 nextflp->lfl_next = NULL; 155 if ( flp == NULL ) { /* first one */ 156 lfdp->lfd_filtlist = nextflp; 157 } else { 158 flp->lfl_next = nextflp; 159 } 160 flp = nextflp; 161 fip = NULL; 162 for ( i = 2; i < 5; ++i ) { 163 tok[ i - 2 ] = tok[ i ]; 164 } 165 /* fall through */ 166 167 case 2: 168 case 3: /* filter, desc, and optional search scope */ 169 if ( nextflp != NULL ) { /* add to info list */ 170 if (( nextfip = (LDAPFiltInfo *)NSLDAPI_CALLOC( 1, 171 sizeof( LDAPFiltInfo ))) == NULL ) { 172 ldap_getfilter_free( lfdp ); 173 ldap_free_strarray( tok ); 174 return( NULL ); 175 } 176 if ( fip == NULL ) { /* first one */ 177 nextflp->lfl_ilist = nextfip; 178 } else { 179 fip->lfi_next = nextfip; 180 } 181 fip = nextfip; 182 nextfip->lfi_next = NULL; 183 nextfip->lfi_filter = tok[ 0 ]; 184 nextfip->lfi_desc = tok[ 1 ]; 185 if ( tok[ 2 ] != NULL ) { 186 if ( strcasecmp( tok[ 2 ], "subtree" ) == 0 ) { 187 nextfip->lfi_scope = LDAP_SCOPE_SUBTREE; 188 } else if ( strcasecmp( tok[ 2 ], "onelevel" ) == 0 ) { 189 nextfip->lfi_scope = LDAP_SCOPE_ONELEVEL; 190 } else if ( strcasecmp( tok[ 2 ], "base" ) == 0 ) { 191 nextfip->lfi_scope = LDAP_SCOPE_BASE; 192 } else { 193 ldap_free_strarray( tok ); 194 ldap_getfilter_free( lfdp ); 195 return( NULL ); 196 } 197 NSLDAPI_FREE( tok[ 2 ] ); 198 tok[ 2 ] = NULL; 199 } else { 200 nextfip->lfi_scope = LDAP_SCOPE_SUBTREE; /* default */ 201 } 202 nextfip->lfi_isexact = ( strchr( tok[ 0 ], '*' ) == NULL && 203 strchr( tok[ 0 ], '~' ) == NULL ); 204 NSLDAPI_FREE( tok ); 205 } 206 break; 207 208 default: 209 ldap_free_strarray( tok ); 210 ldap_getfilter_free( lfdp ); 211 return( NULL ); 212 } 213 } 214 215 if ( tag != NULL ) { 216 NSLDAPI_FREE( tag ); 217 } 218 219 return( lfdp ); 220 } 221 222 223 int 224 LDAP_CALL 225 ldap_set_filter_additions( LDAPFiltDesc *lfdp, char *prefix, char *suffix ) 226 { 227 if ( lfdp == NULL ) { 228 return( LDAP_PARAM_ERROR ); 229 } 230 231 if ( lfdp->lfd_filtprefix != NULL ) { 232 NSLDAPI_FREE( lfdp->lfd_filtprefix ); 233 } 234 lfdp->lfd_filtprefix = ( prefix == NULL ) ? NULL : nsldapi_strdup( prefix ); 235 236 if ( lfdp->lfd_filtsuffix != NULL ) { 237 NSLDAPI_FREE( lfdp->lfd_filtsuffix ); 238 } 239 lfdp->lfd_filtsuffix = ( suffix == NULL ) ? NULL : nsldapi_strdup( suffix ); 240 241 return( LDAP_SUCCESS ); 242 } 243 244 245 /* 246 * ldap_setfilteraffixes() is deprecated -- use ldap_set_filter_additions() 247 */ 248 void 249 LDAP_CALL 250 ldap_setfilteraffixes( LDAPFiltDesc *lfdp, char *prefix, char *suffix ) 251 { 252 (void)ldap_set_filter_additions( lfdp, prefix, suffix ); 253 } 254 255 256 LDAPFiltInfo * 257 LDAP_CALL 258 ldap_getfirstfilter( LDAPFiltDesc *lfdp, char *tagpat, char *value ) 259 { 260 LDAPFiltList *flp; 261 262 if ( lfdp == NULL || tagpat == NULL || value == NULL ) { 263 return( NULL ); /* punt */ 264 } 265 266 if ( lfdp->lfd_curvalcopy != NULL ) { 267 NSLDAPI_FREE( lfdp->lfd_curvalcopy ); 268 NSLDAPI_FREE( lfdp->lfd_curvalwords ); 269 } 270 271 lfdp->lfd_curval = value; 272 lfdp->lfd_curfip = NULL; 273 274 for ( flp = lfdp->lfd_filtlist; flp != NULL; flp = flp->lfl_next ) { 275 if ( re_comp( tagpat ) == NULL && re_exec( flp->lfl_tag ) == 1 276 && re_comp( flp->lfl_pattern ) == NULL 277 && re_exec( lfdp->lfd_curval ) == 1 ) { 278 lfdp->lfd_curfip = flp->lfl_ilist; 279 break; 280 } 281 } 282 283 if ( lfdp->lfd_curfip == NULL ) { 284 return( NULL ); 285 } 286 287 if (( lfdp->lfd_curvalcopy = nsldapi_strdup( value )) == NULL ) { 288 return( NULL ); 289 } 290 291 if ( break_into_words( lfdp->lfd_curvalcopy, flp->lfl_delims, 292 &lfdp->lfd_curvalwords ) < 0 ) { 293 NSLDAPI_FREE( lfdp->lfd_curvalwords ); 294 lfdp->lfd_curvalwords = NULL; 295 return( NULL ); 296 } 297 298 return( ldap_getnextfilter( lfdp )); 299 } 300 301 302 LDAPFiltInfo * 303 LDAP_CALL 304 ldap_getnextfilter( LDAPFiltDesc *lfdp ) 305 { 306 LDAPFiltInfo *fip; 307 308 if ( lfdp == NULL || ( fip = lfdp->lfd_curfip ) == NULL ) { 309 return( NULL ); 310 } 311 312 lfdp->lfd_curfip = fip->lfi_next; 313 314 ldap_build_filter( lfdp->lfd_filter, LDAP_FILT_MAXSIZ, fip->lfi_filter, 315 lfdp->lfd_filtprefix, lfdp->lfd_filtsuffix, NULL, 316 lfdp->lfd_curval, lfdp->lfd_curvalwords ); 317 lfdp->lfd_retfi.lfi_filter = lfdp->lfd_filter; 318 lfdp->lfd_retfi.lfi_desc = fip->lfi_desc; 319 lfdp->lfd_retfi.lfi_scope = fip->lfi_scope; 320 lfdp->lfd_retfi.lfi_isexact = fip->lfi_isexact; 321 322 return( &lfdp->lfd_retfi ); 323 } 324 325 326 static char* 327 filter_add_strn( char *f, char *flimit, char *v, size_t vlen ) 328 /* Copy v into f. If flimit is too small, return NULL; 329 * otherwise return (f + vlen). 330 */ 331 { 332 auto size_t flen = flimit - f; 333 if ( vlen > flen ) { /* flimit is too small */ 334 if ( flen > 0 ) SAFEMEMCPY( f, v, flen ); 335 return NULL; 336 } 337 if ( vlen > 0 ) SAFEMEMCPY( f, v, vlen ); 338 return f + vlen; 339 } 340 341 static char* 342 filter_add_value( char *f, char *flimit, char *v, int escape_all ) 343 /* Copy v into f, but with parentheses escaped. But only escape * and \ 344 * if escape_all is non-zero so that either "*" or "\2a" can be used in 345 * v, with different meanings. 346 * If flimit is too small, return NULL; otherwise 347 * return (f + the number of bytes copied). 348 */ 349 { 350 auto char x[4]; 351 auto size_t slen; 352 while ( f && *v ) { 353 switch ( *v ) { 354 case '*': 355 if ( escape_all ) { 356 f = filter_add_strn( f, flimit, "\\2a", 3 ); 357 v++; 358 } else { 359 if ( f < flimit ) { 360 *f++ = *v++; 361 } else { 362 f = NULL; /* overflow */ 363 } 364 } 365 break; 366 367 case '(': 368 case ')': 369 sprintf( x, "\\%02x", (unsigned)*v ); 370 f = filter_add_strn( f, flimit, x, 3 ); 371 v++; 372 break; 373 374 case '\\': 375 if ( escape_all ) { 376 f = filter_add_strn( f, flimit, "\\5c", 3 ); 377 v++; 378 } else { 379 slen = (ldap_utf8isxdigit( v+1 ) && 380 ldap_utf8isxdigit( v+2 )) ? 3 : (v[1] ? 2 : 1); 381 f = filter_add_strn( f, flimit, v, slen ); 382 v += slen; 383 } 384 break; 385 386 default: 387 if ( f < flimit ) { 388 *f++ = *v++; 389 } else { 390 f = NULL; /* overflow */ 391 } 392 break; 393 } 394 } 395 return f; 396 } 397 398 int 399 LDAP_CALL 400 ldap_create_filter( char *filtbuf, unsigned long buflen, char *pattern, 401 char *prefix, char *suffix, char *attr, char *value, char **valwords ) 402 { 403 char *p, *f, *flimit; 404 int i, wordcount, wordnum, endwordnum, escape_all; 405 406 /* 407 * there is some confusion on what to create for a filter if 408 * attr or value are null pointers. For now we just leave them 409 * as TO BE DEALT with 410 */ 411 412 if ( filtbuf == NULL || buflen == 0 || pattern == NULL ){ 413 return( LDAP_PARAM_ERROR ); 414 } 415 416 if ( valwords == NULL ) { 417 wordcount = 0; 418 } else { 419 for ( wordcount = 0; valwords[ wordcount ] != NULL; ++wordcount ) { 420 ; 421 } 422 } 423 424 f = filtbuf; 425 flimit = filtbuf + buflen - 1; 426 427 if ( prefix != NULL ) { 428 f = filter_add_strn( f, flimit, prefix, strlen( prefix )); 429 } 430 431 for ( p = pattern; f != NULL && *p != '\0'; ++p ) { 432 if ( *p == '%' ) { 433 ++p; 434 if ( *p == 'v' || *p == 'e' ) { 435 escape_all = ( *p == 'e' ); 436 if ( ldap_utf8isdigit( p+1 )) { 437 ++p; 438 wordnum = *p - '1'; 439 if ( *(p+1) == '-' ) { 440 ++p; 441 if ( ldap_utf8isdigit( p+1 )) { 442 ++p; 443 endwordnum = *p - '1'; /* e.g., "%v2-4" */ 444 if ( endwordnum > wordcount - 1 ) { 445 endwordnum = wordcount - 1; 446 } 447 } else { 448 endwordnum = wordcount - 1; /* e.g., "%v2-" */ 449 } 450 } else { 451 endwordnum = wordnum; /* e.g., "%v2" */ 452 } 453 454 if ( wordcount > 0 ) { 455 for ( i = wordnum; i <= endwordnum; ++i ) { 456 if ( i > wordnum ) { /* add blank btw words */ 457 f = filter_add_strn( f, flimit, " ", 1 ); 458 if ( f == NULL ) break; 459 } 460 f = filter_add_value( f, flimit, valwords[ i ], 461 escape_all ); 462 if ( f == NULL ) break; 463 } 464 } 465 } else if ( *(p+1) == '$' ) { 466 ++p; 467 if ( wordcount > 0 ) { 468 wordnum = wordcount - 1; 469 f = filter_add_value( f, flimit, 470 valwords[ wordnum ], escape_all ); 471 } 472 } else if ( value != NULL ) { 473 f = filter_add_value( f, flimit, value, escape_all ); 474 } 475 } else if ( *p == 'a' && attr != NULL ) { 476 f = filter_add_strn( f, flimit, attr, strlen( attr )); 477 } else { 478 *f++ = *p; 479 } 480 } else { 481 *f++ = *p; 482 } 483 if ( f > flimit ) { /* overflow */ 484 f = NULL; 485 } 486 } 487 488 if ( suffix != NULL && f != NULL) { 489 f = filter_add_strn( f, flimit, suffix, strlen( suffix )); 490 } 491 492 if ( f == NULL ) { 493 *flimit = '\0'; 494 return( LDAP_SIZELIMIT_EXCEEDED ); 495 } 496 *f = '\0'; 497 return( LDAP_SUCCESS ); 498 } 499 500 501 /* 502 * ldap_build_filter() is deprecated -- use ldap_create_filter() instead 503 */ 504 void 505 LDAP_CALL 506 ldap_build_filter( char *filtbuf, size_t buflen, char *pattern, 507 char *prefix, char *suffix, char *attr, char *value, char **valwords ) 508 { 509 (void)ldap_create_filter( filtbuf, buflen, pattern, prefix, suffix, attr, 510 value, valwords ); 511 } 512 513 514 static int 515 break_into_words( char *str, char *delims, char ***wordsp ) 516 { 517 char *word, **words; 518 int count; 519 char *lasts; 520 521 if (( words = (char **)NSLDAPI_CALLOC( 1, sizeof( char * ))) == NULL ) { 522 return( -1 ); 523 } 524 count = 0; 525 words[ count ] = NULL; 526 527 word = ldap_utf8strtok_r( str, delims, &lasts ); 528 while ( word != NULL ) { 529 if (( words = (char **)NSLDAPI_REALLOC( words, 530 ( count + 2 ) * sizeof( char * ))) == NULL ) { 531 return( -1 ); 532 } 533 534 words[ count ] = word; 535 words[ ++count ] = NULL; 536 word = ldap_utf8strtok_r( NULL, delims, &lasts ); 537 } 538 539 *wordsp = words; 540 return( count ); 541 } 542