1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 3*0Sstevel@tonic-gate * Use is subject to license terms. 4*0Sstevel@tonic-gate */ 5*0Sstevel@tonic-gate 6*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 7*0Sstevel@tonic-gate 8*0Sstevel@tonic-gate /* 9*0Sstevel@tonic-gate * The contents of this file are subject to the Netscape Public 10*0Sstevel@tonic-gate * License Version 1.1 (the "License"); you may not use this file 11*0Sstevel@tonic-gate * except in compliance with the License. You may obtain a copy of 12*0Sstevel@tonic-gate * the License at http://www.mozilla.org/NPL/ 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * Software distributed under the License is distributed on an "AS 15*0Sstevel@tonic-gate * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 16*0Sstevel@tonic-gate * implied. See the License for the specific language governing 17*0Sstevel@tonic-gate * rights and limitations under the License. 18*0Sstevel@tonic-gate * 19*0Sstevel@tonic-gate * The Original Code is Mozilla Communicator client code, released 20*0Sstevel@tonic-gate * March 31, 1998. 21*0Sstevel@tonic-gate * 22*0Sstevel@tonic-gate * The Initial Developer of the Original Code is Netscape 23*0Sstevel@tonic-gate * Communications Corporation. Portions created by Netscape are 24*0Sstevel@tonic-gate * Copyright (C) 1998-1999 Netscape Communications Corporation. All 25*0Sstevel@tonic-gate * Rights Reserved. 26*0Sstevel@tonic-gate * 27*0Sstevel@tonic-gate * Contributor(s): 28*0Sstevel@tonic-gate */ 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate /* 31*0Sstevel@tonic-gate * LDAP tools fileurl.c -- functions for handling file URLs. 32*0Sstevel@tonic-gate * Used by ldapmodify. 33*0Sstevel@tonic-gate */ 34*0Sstevel@tonic-gate 35*0Sstevel@tonic-gate #include "ldaptool.h" 36*0Sstevel@tonic-gate #include "fileurl.h" 37*0Sstevel@tonic-gate #include <ctype.h> /* for isalpha() */ 38*0Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD 39*0Sstevel@tonic-gate #include <locale.h> 40*0Sstevel@tonic-gate #endif /* SOLARIS_LDAP_CMD */ 41*0Sstevel@tonic-gate 42*0Sstevel@tonic-gate #ifndef SOLARIS_LDAP_CMD 43*0Sstevel@tonic-gate #define gettext(s) s 44*0Sstevel@tonic-gate #endif 45*0Sstevel@tonic-gate 46*0Sstevel@tonic-gate static int str_starts_with( const char *s, char *prefix ); 47*0Sstevel@tonic-gate static void hex_unescape( char *s ); 48*0Sstevel@tonic-gate static int unhex( char c ); 49*0Sstevel@tonic-gate static void strcpy_escaped_and_convert( char *s1, char *s2 ); 50*0Sstevel@tonic-gate static int berval_from_file( const char *path, struct berval *bvp, 51*0Sstevel@tonic-gate int reporterrs ); 52*0Sstevel@tonic-gate 53*0Sstevel@tonic-gate /* 54*0Sstevel@tonic-gate * Convert a file URL to a local path. 55*0Sstevel@tonic-gate * 56*0Sstevel@tonic-gate * If successful, LDAPTOOL_FILEURL_SUCCESS is returned and *localpathp is 57*0Sstevel@tonic-gate * set point to an allocated string. If not, an different LDAPTOOL_FILEURL_ 58*0Sstevel@tonic-gate * error code is returned. 59*0Sstevel@tonic-gate * 60*0Sstevel@tonic-gate * See RFCs 1738 and 2396 for a specification for file URLs... but 61*0Sstevel@tonic-gate * Netscape Navigator seems to be a bit more lenient in what it will 62*0Sstevel@tonic-gate * accept, especially on Windows). 63*0Sstevel@tonic-gate * 64*0Sstevel@tonic-gate * This function parses file URLs of these three forms: 65*0Sstevel@tonic-gate * 66*0Sstevel@tonic-gate * file:///path 67*0Sstevel@tonic-gate * file:/path 68*0Sstevel@tonic-gate * file://localhost/path 69*0Sstevel@tonic-gate * file://host/path (rejected with a ...NONLOCAL error) 70*0Sstevel@tonic-gate * 71*0Sstevel@tonic-gate * On Windows, we convert leading drive letters of the form C| to C: 72*0Sstevel@tonic-gate * and if a drive letter is present we strip off the slash that precedes 73*0Sstevel@tonic-gate * path. Otherwise, the leading slash is returned. 74*0Sstevel@tonic-gate * 75*0Sstevel@tonic-gate */ 76*0Sstevel@tonic-gate int 77*0Sstevel@tonic-gate ldaptool_fileurl2path( const char *fileurl, char **localpathp ) 78*0Sstevel@tonic-gate { 79*0Sstevel@tonic-gate const char *path; 80*0Sstevel@tonic-gate char *pathcopy; 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate /* 83*0Sstevel@tonic-gate * Make sure this is a file URL we can handle. 84*0Sstevel@tonic-gate */ 85*0Sstevel@tonic-gate if ( !str_starts_with( fileurl, "file:" )) { 86*0Sstevel@tonic-gate return( LDAPTOOL_FILEURL_NOTAFILEURL ); 87*0Sstevel@tonic-gate } 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate path = fileurl + 5; /* skip past "file:" scheme prefix */ 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gate if ( *path != '/' ) { 92*0Sstevel@tonic-gate return( LDAPTOOL_FILEURL_MISSINGPATH ); 93*0Sstevel@tonic-gate } 94*0Sstevel@tonic-gate 95*0Sstevel@tonic-gate ++path; /* skip past '/' at end of "file:/" */ 96*0Sstevel@tonic-gate 97*0Sstevel@tonic-gate if ( *path == '/' ) { 98*0Sstevel@tonic-gate ++path; /* remainder is now host/path or /path */ 99*0Sstevel@tonic-gate if ( *path != '/' ) { 100*0Sstevel@tonic-gate /* 101*0Sstevel@tonic-gate * Make sure it is for the local host. 102*0Sstevel@tonic-gate */ 103*0Sstevel@tonic-gate if ( str_starts_with( path, "localhost/" )) { 104*0Sstevel@tonic-gate path += 9; 105*0Sstevel@tonic-gate } else { 106*0Sstevel@tonic-gate return( LDAPTOOL_FILEURL_NONLOCAL ); 107*0Sstevel@tonic-gate } 108*0Sstevel@tonic-gate } 109*0Sstevel@tonic-gate } else { /* URL is of the form file:/path */ 110*0Sstevel@tonic-gate --path; 111*0Sstevel@tonic-gate } 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate /* 114*0Sstevel@tonic-gate * The remainder is now of the form /path. On Windows, skip past the 115*0Sstevel@tonic-gate * leading slash if a drive letter is present. 116*0Sstevel@tonic-gate */ 117*0Sstevel@tonic-gate #ifdef _WINDOWS 118*0Sstevel@tonic-gate if ( isalpha( path[1] ) && ( path[2] == '|' || path[2] == ':' )) { 119*0Sstevel@tonic-gate ++path; 120*0Sstevel@tonic-gate } 121*0Sstevel@tonic-gate #endif /* _WINDOWS */ 122*0Sstevel@tonic-gate 123*0Sstevel@tonic-gate /* 124*0Sstevel@tonic-gate * Duplicate the path so we can safely alter it. 125*0Sstevel@tonic-gate * Unescape any %HH sequences. 126*0Sstevel@tonic-gate */ 127*0Sstevel@tonic-gate if (( pathcopy = strdup( path )) == NULL ) { 128*0Sstevel@tonic-gate return( LDAPTOOL_FILEURL_NOMEMORY ); 129*0Sstevel@tonic-gate } 130*0Sstevel@tonic-gate hex_unescape( pathcopy ); 131*0Sstevel@tonic-gate 132*0Sstevel@tonic-gate #ifdef _WINDOWS 133*0Sstevel@tonic-gate /* 134*0Sstevel@tonic-gate * Convert forward slashes to backslashes for Windows. Also, 135*0Sstevel@tonic-gate * if we see a drive letter / vertical bar combination (e.g., c|) 136*0Sstevel@tonic-gate * at the beginning of the path, replace the '|' with a ':'. 137*0Sstevel@tonic-gate */ 138*0Sstevel@tonic-gate { 139*0Sstevel@tonic-gate char *p; 140*0Sstevel@tonic-gate 141*0Sstevel@tonic-gate for ( p = pathcopy; *p != '\0'; ++p ) { 142*0Sstevel@tonic-gate if ( *p == '/' ) { 143*0Sstevel@tonic-gate *p = '\\'; 144*0Sstevel@tonic-gate } 145*0Sstevel@tonic-gate } 146*0Sstevel@tonic-gate } 147*0Sstevel@tonic-gate 148*0Sstevel@tonic-gate if ( isalpha( pathcopy[0] ) && pathcopy[1] == '|' ) { 149*0Sstevel@tonic-gate pathcopy[1] = ':'; 150*0Sstevel@tonic-gate } 151*0Sstevel@tonic-gate #endif /* _WINDOWS */ 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gate *localpathp = pathcopy; 154*0Sstevel@tonic-gate return( LDAPTOOL_FILEURL_SUCCESS ); 155*0Sstevel@tonic-gate } 156*0Sstevel@tonic-gate 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate /* 159*0Sstevel@tonic-gate * Convert a local path to a file URL. 160*0Sstevel@tonic-gate * 161*0Sstevel@tonic-gate * If successful, LDAPTOOL_FILEURL_SUCCESS is returned and *urlp is 162*0Sstevel@tonic-gate * set point to an allocated string. If not, an different LDAPTOOL_FILEURL_ 163*0Sstevel@tonic-gate * error code is returned. At present, the only possible error is 164*0Sstevel@tonic-gate * LDAPTOOL_FILEURL_NOMEMORY. 165*0Sstevel@tonic-gate * 166*0Sstevel@tonic-gate * This function produces file URLs of the form file:path. 167*0Sstevel@tonic-gate * 168*0Sstevel@tonic-gate * On Windows, we convert leading drive letters to C|. 169*0Sstevel@tonic-gate * 170*0Sstevel@tonic-gate */ 171*0Sstevel@tonic-gate int 172*0Sstevel@tonic-gate ldaptool_path2fileurl( char *path, char **urlp ) 173*0Sstevel@tonic-gate { 174*0Sstevel@tonic-gate char *p, *url, *prefix ="file:"; 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gate if ( NULL == path ) { 177*0Sstevel@tonic-gate path = "/"; 178*0Sstevel@tonic-gate } 179*0Sstevel@tonic-gate 180*0Sstevel@tonic-gate /* 181*0Sstevel@tonic-gate * Allocate space for the URL, taking into account that path may 182*0Sstevel@tonic-gate * expand during the hex escaping process. 183*0Sstevel@tonic-gate */ 184*0Sstevel@tonic-gate if (( url = malloc( strlen( prefix ) + 3 * strlen( path ) + 1 )) == NULL ) { 185*0Sstevel@tonic-gate return( LDAPTOOL_FILEURL_NOMEMORY ); 186*0Sstevel@tonic-gate } 187*0Sstevel@tonic-gate 188*0Sstevel@tonic-gate strcpy( url, prefix ); 189*0Sstevel@tonic-gate p = url + strlen( prefix ); 190*0Sstevel@tonic-gate 191*0Sstevel@tonic-gate #ifdef _WINDOWS 192*0Sstevel@tonic-gate /* 193*0Sstevel@tonic-gate * On Windows, convert leading drive letters (e.g., C:) to the correct URL 194*0Sstevel@tonic-gate * syntax (e.g., C|). 195*0Sstevel@tonic-gate */ 196*0Sstevel@tonic-gate if ( isalpha( path[0] ) && path[1] == ':' ) { 197*0Sstevel@tonic-gate *p++ = path[0]; 198*0Sstevel@tonic-gate *p++ = '|'; 199*0Sstevel@tonic-gate path += 2; 200*0Sstevel@tonic-gate *p = '\0'; 201*0Sstevel@tonic-gate } 202*0Sstevel@tonic-gate #endif /* _WINDOWS */ 203*0Sstevel@tonic-gate 204*0Sstevel@tonic-gate /* 205*0Sstevel@tonic-gate * Append the path, encoding any URL-special characters using the %HH 206*0Sstevel@tonic-gate * convention. 207*0Sstevel@tonic-gate * On Windows, convert backwards slashes in the path to forward ones. 208*0Sstevel@tonic-gate */ 209*0Sstevel@tonic-gate strcpy_escaped_and_convert( p, path ); 210*0Sstevel@tonic-gate 211*0Sstevel@tonic-gate *urlp = url; 212*0Sstevel@tonic-gate return( LDAPTOOL_FILEURL_SUCCESS ); 213*0Sstevel@tonic-gate } 214*0Sstevel@tonic-gate 215*0Sstevel@tonic-gate 216*0Sstevel@tonic-gate /* 217*0Sstevel@tonic-gate * Populate *bvp from "value" of length "vlen." 218*0Sstevel@tonic-gate * 219*0Sstevel@tonic-gate * If recognize_url_syntax is non-zero, :<fileurl is recognized. 220*0Sstevel@tonic-gate * If always_try_file is recognized and no file URL was found, an 221*0Sstevel@tonic-gate * attempt is made to stat and read the value as if it were the name 222*0Sstevel@tonic-gate * of a file. 223*0Sstevel@tonic-gate * 224*0Sstevel@tonic-gate * If reporterrs is non-zero, specific error messages are printed to 225*0Sstevel@tonic-gate * stderr. 226*0Sstevel@tonic-gate * 227*0Sstevel@tonic-gate * If successful, LDAPTOOL_FILEURL_SUCCESS is returned and bvp->bv_len 228*0Sstevel@tonic-gate * and bvp->bv_val are set (the latter is set to malloc'd memory). 229*0Sstevel@tonic-gate * Upon failure, a different LDAPTOOL_FILEURL_ error code is returned. 230*0Sstevel@tonic-gate */ 231*0Sstevel@tonic-gate int 232*0Sstevel@tonic-gate ldaptool_berval_from_ldif_value( const char *value, int vlen, 233*0Sstevel@tonic-gate struct berval *bvp, int recognize_url_syntax, int always_try_file, 234*0Sstevel@tonic-gate int reporterrs ) 235*0Sstevel@tonic-gate { 236*0Sstevel@tonic-gate int rc = LDAPTOOL_FILEURL_SUCCESS; /* optimistic */ 237*0Sstevel@tonic-gate const char *url = NULL; 238*0Sstevel@tonic-gate struct stat fstats; 239*0Sstevel@tonic-gate 240*0Sstevel@tonic-gate /* recognize "attr :< url" syntax if LDIF version is >= 1 */ 241*0Sstevel@tonic-gate 242*0Sstevel@tonic-gate #ifdef notdef 243*0Sstevel@tonic-gate if ( ldaptool_verbose ) { 244*0Sstevel@tonic-gate fprintf( stderr, gettext("%s: ldaptool_berval_from_ldif_value: value: %s\n"), 245*0Sstevel@tonic-gate ldaptool_progname, value); 246*0Sstevel@tonic-gate } 247*0Sstevel@tonic-gate #endif 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate if ( recognize_url_syntax && *value == '<' ) { 250*0Sstevel@tonic-gate for ( url = value + 1; isspace( *url ); ++url ) { 251*0Sstevel@tonic-gate ; /* NULL */ 252*0Sstevel@tonic-gate } 253*0Sstevel@tonic-gate 254*0Sstevel@tonic-gate if (strlen(url) > 7 && strncasecmp(url, "file://", 7) != 0) { 255*0Sstevel@tonic-gate /* 256*0Sstevel@tonic-gate * We only support file:// URLs for now. 257*0Sstevel@tonic-gate */ 258*0Sstevel@tonic-gate url = NULL; 259*0Sstevel@tonic-gate } 260*0Sstevel@tonic-gate } 261*0Sstevel@tonic-gate 262*0Sstevel@tonic-gate if ( NULL != url ) { 263*0Sstevel@tonic-gate char *path; 264*0Sstevel@tonic-gate 265*0Sstevel@tonic-gate rc = ldaptool_fileurl2path( url, &path ); 266*0Sstevel@tonic-gate switch( rc ) { 267*0Sstevel@tonic-gate case LDAPTOOL_FILEURL_NOTAFILEURL: 268*0Sstevel@tonic-gate if ( reporterrs ) fprintf( stderr, gettext("%s: unsupported URL \"%s\";" 269*0Sstevel@tonic-gate " use a file:// URL instead.\n"), ldaptool_progname, url ); 270*0Sstevel@tonic-gate break; 271*0Sstevel@tonic-gate 272*0Sstevel@tonic-gate case LDAPTOOL_FILEURL_MISSINGPATH: 273*0Sstevel@tonic-gate if ( reporterrs ) fprintf( stderr, 274*0Sstevel@tonic-gate gettext("%s: unable to process URL \"%s\" --" 275*0Sstevel@tonic-gate " missing path.\n"), ldaptool_progname, url ); 276*0Sstevel@tonic-gate break; 277*0Sstevel@tonic-gate 278*0Sstevel@tonic-gate case LDAPTOOL_FILEURL_NONLOCAL: 279*0Sstevel@tonic-gate if ( reporterrs ) fprintf( stderr, 280*0Sstevel@tonic-gate gettext("%s: unable to process URL \"%s\" -- only" 281*0Sstevel@tonic-gate " local file:// URLs are supported.\n"), 282*0Sstevel@tonic-gate ldaptool_progname, url ); 283*0Sstevel@tonic-gate break; 284*0Sstevel@tonic-gate 285*0Sstevel@tonic-gate case LDAPTOOL_FILEURL_NOMEMORY: 286*0Sstevel@tonic-gate if ( reporterrs ) perror( "ldaptool_fileurl2path" ); 287*0Sstevel@tonic-gate break; 288*0Sstevel@tonic-gate 289*0Sstevel@tonic-gate case LDAPTOOL_FILEURL_SUCCESS: 290*0Sstevel@tonic-gate if ( stat( path, &fstats ) != 0 ) { 291*0Sstevel@tonic-gate if ( reporterrs ) perror( path ); 292*0Sstevel@tonic-gate } else if ( fstats.st_mode & S_IFDIR ) { 293*0Sstevel@tonic-gate if ( reporterrs ) fprintf( stderr, 294*0Sstevel@tonic-gate gettext("%s: %s is a directory, not a file\n"), 295*0Sstevel@tonic-gate ldaptool_progname, path ); 296*0Sstevel@tonic-gate rc = LDAPTOOL_FILEURL_FILEIOERROR; 297*0Sstevel@tonic-gate } else { 298*0Sstevel@tonic-gate rc = berval_from_file( path, bvp, reporterrs ); 299*0Sstevel@tonic-gate } 300*0Sstevel@tonic-gate free( path ); 301*0Sstevel@tonic-gate break; 302*0Sstevel@tonic-gate 303*0Sstevel@tonic-gate default: 304*0Sstevel@tonic-gate if ( reporterrs ) fprintf( stderr, 305*0Sstevel@tonic-gate gettext("%s: unable to process URL \"%s\"" 306*0Sstevel@tonic-gate " -- unknown error\n"), ldaptool_progname, url ); 307*0Sstevel@tonic-gate } 308*0Sstevel@tonic-gate } else if ( always_try_file && (stat( value, &fstats ) == 0) && 309*0Sstevel@tonic-gate !(fstats.st_mode & S_IFDIR)) { /* get value from file */ 310*0Sstevel@tonic-gate rc = berval_from_file( value, bvp, reporterrs ); 311*0Sstevel@tonic-gate } else { 312*0Sstevel@tonic-gate bvp->bv_len = vlen; 313*0Sstevel@tonic-gate if (( bvp->bv_val = (char *)malloc( vlen + 1 )) == NULL ) { 314*0Sstevel@tonic-gate if ( reporterrs ) perror( "malloc" ); 315*0Sstevel@tonic-gate rc = LDAPTOOL_FILEURL_NOMEMORY; 316*0Sstevel@tonic-gate } else { 317*0Sstevel@tonic-gate SAFEMEMCPY( bvp->bv_val, value, vlen ); 318*0Sstevel@tonic-gate bvp->bv_val[ vlen ] = '\0'; 319*0Sstevel@tonic-gate } 320*0Sstevel@tonic-gate } 321*0Sstevel@tonic-gate 322*0Sstevel@tonic-gate return( rc ); 323*0Sstevel@tonic-gate } 324*0Sstevel@tonic-gate 325*0Sstevel@tonic-gate 326*0Sstevel@tonic-gate /* 327*0Sstevel@tonic-gate * Map an LDAPTOOL_FILEURL_ error code to an LDAP error code (crude). 328*0Sstevel@tonic-gate */ 329*0Sstevel@tonic-gate int 330*0Sstevel@tonic-gate ldaptool_fileurlerr2ldaperr( int lderr ) 331*0Sstevel@tonic-gate { 332*0Sstevel@tonic-gate int rc; 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate switch( lderr ) { 335*0Sstevel@tonic-gate case LDAPTOOL_FILEURL_SUCCESS: 336*0Sstevel@tonic-gate rc = LDAP_SUCCESS; 337*0Sstevel@tonic-gate break; 338*0Sstevel@tonic-gate case LDAPTOOL_FILEURL_NOMEMORY: 339*0Sstevel@tonic-gate rc = LDAP_NO_MEMORY; 340*0Sstevel@tonic-gate break; 341*0Sstevel@tonic-gate default: 342*0Sstevel@tonic-gate rc = LDAP_PARAM_ERROR; 343*0Sstevel@tonic-gate } 344*0Sstevel@tonic-gate 345*0Sstevel@tonic-gate return( rc ); 346*0Sstevel@tonic-gate } 347*0Sstevel@tonic-gate 348*0Sstevel@tonic-gate 349*0Sstevel@tonic-gate /* 350*0Sstevel@tonic-gate * Populate *bvp with the contents of the file named by "path". 351*0Sstevel@tonic-gate * 352*0Sstevel@tonic-gate * If reporterrs is non-zero, specific error messages are printed to 353*0Sstevel@tonic-gate * stderr. 354*0Sstevel@tonic-gate * 355*0Sstevel@tonic-gate * If successful, LDAPTOOL_FILEURL_SUCCESS is returned and bvp->bv_len 356*0Sstevel@tonic-gate * and bvp->bv_val are set (the latter is set to malloc'd memory). 357*0Sstevel@tonic-gate * Upon failure, a different LDAPTOOL_FILEURL_ error code is returned. 358*0Sstevel@tonic-gate */ 359*0Sstevel@tonic-gate 360*0Sstevel@tonic-gate static int 361*0Sstevel@tonic-gate berval_from_file( const char *path, struct berval *bvp, int reporterrs ) 362*0Sstevel@tonic-gate { 363*0Sstevel@tonic-gate FILE *fp; 364*0Sstevel@tonic-gate long rlen; 365*0Sstevel@tonic-gate int eof; 366*0Sstevel@tonic-gate #if defined( XP_WIN32 ) 367*0Sstevel@tonic-gate char mode[20] = "r+b"; 368*0Sstevel@tonic-gate #else 369*0Sstevel@tonic-gate char mode[20] = "r"; 370*0Sstevel@tonic-gate #endif 371*0Sstevel@tonic-gate 372*0Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD 373*0Sstevel@tonic-gate if (( fp = fopen( path, mode )) == NULL ) { 374*0Sstevel@tonic-gate #else 375*0Sstevel@tonic-gate if (( fp = ldaptool_open_file( path, mode )) == NULL ) { 376*0Sstevel@tonic-gate #endif /* SOLARIS_LDAP_CMD */ 377*0Sstevel@tonic-gate if ( reporterrs ) perror( path ); 378*0Sstevel@tonic-gate return( LDAPTOOL_FILEURL_FILEIOERROR ); 379*0Sstevel@tonic-gate } 380*0Sstevel@tonic-gate 381*0Sstevel@tonic-gate if ( fseek( fp, 0L, SEEK_END ) != 0 ) { 382*0Sstevel@tonic-gate if ( reporterrs ) perror( path ); 383*0Sstevel@tonic-gate fclose( fp ); 384*0Sstevel@tonic-gate return( LDAPTOOL_FILEURL_FILEIOERROR ); 385*0Sstevel@tonic-gate } 386*0Sstevel@tonic-gate 387*0Sstevel@tonic-gate bvp->bv_len = ftell( fp ); 388*0Sstevel@tonic-gate 389*0Sstevel@tonic-gate if (( bvp->bv_val = (char *)malloc( bvp->bv_len + 1 )) == NULL ) { 390*0Sstevel@tonic-gate if ( reporterrs ) perror( "malloc" ); 391*0Sstevel@tonic-gate fclose( fp ); 392*0Sstevel@tonic-gate return( LDAPTOOL_FILEURL_NOMEMORY ); 393*0Sstevel@tonic-gate } 394*0Sstevel@tonic-gate 395*0Sstevel@tonic-gate if ( fseek( fp, 0L, SEEK_SET ) != 0 ) { 396*0Sstevel@tonic-gate if ( reporterrs ) perror( path ); 397*0Sstevel@tonic-gate fclose( fp ); 398*0Sstevel@tonic-gate return( LDAPTOOL_FILEURL_FILEIOERROR ); 399*0Sstevel@tonic-gate } 400*0Sstevel@tonic-gate 401*0Sstevel@tonic-gate rlen = fread( bvp->bv_val, 1, bvp->bv_len, fp ); 402*0Sstevel@tonic-gate eof = feof( fp ); 403*0Sstevel@tonic-gate fclose( fp ); 404*0Sstevel@tonic-gate 405*0Sstevel@tonic-gate if ( rlen != (long)bvp->bv_len ) { 406*0Sstevel@tonic-gate if ( reporterrs ) perror( path ); 407*0Sstevel@tonic-gate free( bvp->bv_val ); 408*0Sstevel@tonic-gate return( LDAPTOOL_FILEURL_FILEIOERROR ); 409*0Sstevel@tonic-gate } 410*0Sstevel@tonic-gate 411*0Sstevel@tonic-gate bvp->bv_val[ bvp->bv_len ] = '\0'; 412*0Sstevel@tonic-gate return( LDAPTOOL_FILEURL_SUCCESS ); 413*0Sstevel@tonic-gate } 414*0Sstevel@tonic-gate 415*0Sstevel@tonic-gate 416*0Sstevel@tonic-gate /* 417*0Sstevel@tonic-gate * Return a non-zero value if the string s begins with prefix and zero if not. 418*0Sstevel@tonic-gate */ 419*0Sstevel@tonic-gate static int 420*0Sstevel@tonic-gate str_starts_with( const char *s, char *prefix ) 421*0Sstevel@tonic-gate { 422*0Sstevel@tonic-gate size_t prefix_len; 423*0Sstevel@tonic-gate 424*0Sstevel@tonic-gate if ( s == NULL || prefix == NULL ) { 425*0Sstevel@tonic-gate return( 0 ); 426*0Sstevel@tonic-gate } 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate prefix_len = strlen( prefix ); 429*0Sstevel@tonic-gate if ( strlen( s ) < prefix_len ) { 430*0Sstevel@tonic-gate return( 0 ); 431*0Sstevel@tonic-gate } 432*0Sstevel@tonic-gate 433*0Sstevel@tonic-gate return( strncmp( s, prefix, prefix_len ) == 0 ); 434*0Sstevel@tonic-gate } 435*0Sstevel@tonic-gate 436*0Sstevel@tonic-gate 437*0Sstevel@tonic-gate /* 438*0Sstevel@tonic-gate * Remove URL hex escapes from s... done in place. The basic concept for 439*0Sstevel@tonic-gate * this routine is borrowed from the WWW library HTUnEscape() routine. 440*0Sstevel@tonic-gate * 441*0Sstevel@tonic-gate * A similar function called nsldapi_hex_unescape can be found in 442*0Sstevel@tonic-gate * ../../libraries/libldap/unescape.c 443*0Sstevel@tonic-gate */ 444*0Sstevel@tonic-gate static void 445*0Sstevel@tonic-gate hex_unescape( char *s ) 446*0Sstevel@tonic-gate { 447*0Sstevel@tonic-gate char *p; 448*0Sstevel@tonic-gate 449*0Sstevel@tonic-gate for ( p = s; *s != '\0'; ++s ) { 450*0Sstevel@tonic-gate if ( *s == '%' ) { 451*0Sstevel@tonic-gate if ( *++s != '\0' ) { 452*0Sstevel@tonic-gate *p = unhex( *s ) << 4; 453*0Sstevel@tonic-gate } 454*0Sstevel@tonic-gate if ( *++s != '\0' ) { 455*0Sstevel@tonic-gate *p++ += unhex( *s ); 456*0Sstevel@tonic-gate } 457*0Sstevel@tonic-gate } else { 458*0Sstevel@tonic-gate *p++ = *s; 459*0Sstevel@tonic-gate } 460*0Sstevel@tonic-gate } 461*0Sstevel@tonic-gate 462*0Sstevel@tonic-gate *p = '\0'; 463*0Sstevel@tonic-gate } 464*0Sstevel@tonic-gate 465*0Sstevel@tonic-gate 466*0Sstevel@tonic-gate /* 467*0Sstevel@tonic-gate * Return the integer equivalent of one hex digit (in c). 468*0Sstevel@tonic-gate * 469*0Sstevel@tonic-gate * A similar function can be found in ../../libraries/libldap/unescape.c 470*0Sstevel@tonic-gate */ 471*0Sstevel@tonic-gate static int 472*0Sstevel@tonic-gate unhex( char c ) 473*0Sstevel@tonic-gate { 474*0Sstevel@tonic-gate return( c >= '0' && c <= '9' ? c - '0' 475*0Sstevel@tonic-gate : c >= 'A' && c <= 'F' ? c - 'A' + 10 476*0Sstevel@tonic-gate : c - 'a' + 10 ); 477*0Sstevel@tonic-gate } 478*0Sstevel@tonic-gate 479*0Sstevel@tonic-gate 480*0Sstevel@tonic-gate #define HREF_CHAR_ACCEPTABLE( c ) (( c >= '-' && c <= '9' ) || \ 481*0Sstevel@tonic-gate ( c >= '@' && c <= 'Z' ) || \ 482*0Sstevel@tonic-gate ( c == '_' ) || \ 483*0Sstevel@tonic-gate ( c >= 'a' && c <= 'z' )) 484*0Sstevel@tonic-gate 485*0Sstevel@tonic-gate /* 486*0Sstevel@tonic-gate * Like strcat(), except if any URL-special characters are found in s2 487*0Sstevel@tonic-gate * they are escaped using the %HH convention and backslash characters are 488*0Sstevel@tonic-gate * converted to forward slashes on Windows. 489*0Sstevel@tonic-gate * 490*0Sstevel@tonic-gate * Maximum space needed in s1 is 3 * strlen( s2 ) + 1. 491*0Sstevel@tonic-gate * 492*0Sstevel@tonic-gate * A similar function that does not convert the slashes called 493*0Sstevel@tonic-gate * strcat_escaped() can be found in ../../libraries/libldap/tmplout.c 494*0Sstevel@tonic-gate */ 495*0Sstevel@tonic-gate static void 496*0Sstevel@tonic-gate strcpy_escaped_and_convert( char *s1, char *s2 ) 497*0Sstevel@tonic-gate { 498*0Sstevel@tonic-gate char *p, *q; 499*0Sstevel@tonic-gate char *hexdig = "0123456789ABCDEF"; 500*0Sstevel@tonic-gate 501*0Sstevel@tonic-gate p = s1 + strlen( s1 ); 502*0Sstevel@tonic-gate for ( q = s2; *q != '\0'; ++q ) { 503*0Sstevel@tonic-gate #ifdef _WINDOWS 504*0Sstevel@tonic-gate if ( *q == '\\' ) { 505*0Sstevel@tonic-gate *p++ = '/'; 506*0Sstevel@tonic-gate } else 507*0Sstevel@tonic-gate #endif /* _WINDOWS */ 508*0Sstevel@tonic-gate 509*0Sstevel@tonic-gate if ( HREF_CHAR_ACCEPTABLE( *q )) { 510*0Sstevel@tonic-gate *p++ = *q; 511*0Sstevel@tonic-gate } else { 512*0Sstevel@tonic-gate *p++ = '%'; 513*0Sstevel@tonic-gate *p++ = hexdig[ 0x0F & ((*(unsigned char*)q) >> 4) ]; 514*0Sstevel@tonic-gate *p++ = hexdig[ 0x0F & *q ]; 515*0Sstevel@tonic-gate } 516*0Sstevel@tonic-gate } 517*0Sstevel@tonic-gate 518*0Sstevel@tonic-gate *p = '\0'; 519*0Sstevel@tonic-gate } 520