10Sstevel@tonic-gate /* 2*871Scasper * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 30Sstevel@tonic-gate * Use is subject to license terms. 40Sstevel@tonic-gate */ 50Sstevel@tonic-gate 60Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 70Sstevel@tonic-gate 80Sstevel@tonic-gate /* 90Sstevel@tonic-gate * The contents of this file are subject to the Netscape Public 100Sstevel@tonic-gate * License Version 1.1 (the "License"); you may not use this file 110Sstevel@tonic-gate * except in compliance with the License. You may obtain a copy of 120Sstevel@tonic-gate * the License at http://www.mozilla.org/NPL/ 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * Software distributed under the License is distributed on an "AS 150Sstevel@tonic-gate * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 160Sstevel@tonic-gate * implied. See the License for the specific language governing 170Sstevel@tonic-gate * rights and limitations under the License. 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * The Original Code is Mozilla Communicator client code, released 200Sstevel@tonic-gate * March 31, 1998. 210Sstevel@tonic-gate * 220Sstevel@tonic-gate * The Initial Developer of the Original Code is Netscape 230Sstevel@tonic-gate * Communications Corporation. Portions created by Netscape are 240Sstevel@tonic-gate * Copyright (C) 1998-1999 Netscape Communications Corporation. All 250Sstevel@tonic-gate * Rights Reserved. 260Sstevel@tonic-gate * 270Sstevel@tonic-gate * Contributor(s): 280Sstevel@tonic-gate */ 290Sstevel@tonic-gate 300Sstevel@tonic-gate /* 310Sstevel@tonic-gate * LDAP tools fileurl.c -- functions for handling file URLs. 320Sstevel@tonic-gate * Used by ldapmodify. 330Sstevel@tonic-gate */ 340Sstevel@tonic-gate 350Sstevel@tonic-gate #include "ldaptool.h" 360Sstevel@tonic-gate #include "fileurl.h" 370Sstevel@tonic-gate #include <ctype.h> /* for isalpha() */ 380Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD 390Sstevel@tonic-gate #include <locale.h> 400Sstevel@tonic-gate #endif /* SOLARIS_LDAP_CMD */ 410Sstevel@tonic-gate 420Sstevel@tonic-gate #ifndef SOLARIS_LDAP_CMD 430Sstevel@tonic-gate #define gettext(s) s 440Sstevel@tonic-gate #endif 450Sstevel@tonic-gate 460Sstevel@tonic-gate static int str_starts_with( const char *s, char *prefix ); 470Sstevel@tonic-gate static void hex_unescape( char *s ); 480Sstevel@tonic-gate static int unhex( char c ); 490Sstevel@tonic-gate static void strcpy_escaped_and_convert( char *s1, char *s2 ); 500Sstevel@tonic-gate static int berval_from_file( const char *path, struct berval *bvp, 510Sstevel@tonic-gate int reporterrs ); 520Sstevel@tonic-gate 530Sstevel@tonic-gate /* 540Sstevel@tonic-gate * Convert a file URL to a local path. 550Sstevel@tonic-gate * 560Sstevel@tonic-gate * If successful, LDAPTOOL_FILEURL_SUCCESS is returned and *localpathp is 570Sstevel@tonic-gate * set point to an allocated string. If not, an different LDAPTOOL_FILEURL_ 580Sstevel@tonic-gate * error code is returned. 590Sstevel@tonic-gate * 600Sstevel@tonic-gate * See RFCs 1738 and 2396 for a specification for file URLs... but 610Sstevel@tonic-gate * Netscape Navigator seems to be a bit more lenient in what it will 620Sstevel@tonic-gate * accept, especially on Windows). 630Sstevel@tonic-gate * 640Sstevel@tonic-gate * This function parses file URLs of these three forms: 650Sstevel@tonic-gate * 660Sstevel@tonic-gate * file:///path 670Sstevel@tonic-gate * file:/path 680Sstevel@tonic-gate * file://localhost/path 690Sstevel@tonic-gate * file://host/path (rejected with a ...NONLOCAL error) 700Sstevel@tonic-gate * 710Sstevel@tonic-gate * On Windows, we convert leading drive letters of the form C| to C: 720Sstevel@tonic-gate * and if a drive letter is present we strip off the slash that precedes 730Sstevel@tonic-gate * path. Otherwise, the leading slash is returned. 740Sstevel@tonic-gate * 750Sstevel@tonic-gate */ 760Sstevel@tonic-gate int 770Sstevel@tonic-gate ldaptool_fileurl2path( const char *fileurl, char **localpathp ) 780Sstevel@tonic-gate { 790Sstevel@tonic-gate const char *path; 800Sstevel@tonic-gate char *pathcopy; 810Sstevel@tonic-gate 820Sstevel@tonic-gate /* 830Sstevel@tonic-gate * Make sure this is a file URL we can handle. 840Sstevel@tonic-gate */ 850Sstevel@tonic-gate if ( !str_starts_with( fileurl, "file:" )) { 860Sstevel@tonic-gate return( LDAPTOOL_FILEURL_NOTAFILEURL ); 870Sstevel@tonic-gate } 880Sstevel@tonic-gate 890Sstevel@tonic-gate path = fileurl + 5; /* skip past "file:" scheme prefix */ 900Sstevel@tonic-gate 910Sstevel@tonic-gate if ( *path != '/' ) { 920Sstevel@tonic-gate return( LDAPTOOL_FILEURL_MISSINGPATH ); 930Sstevel@tonic-gate } 940Sstevel@tonic-gate 950Sstevel@tonic-gate ++path; /* skip past '/' at end of "file:/" */ 960Sstevel@tonic-gate 970Sstevel@tonic-gate if ( *path == '/' ) { 980Sstevel@tonic-gate ++path; /* remainder is now host/path or /path */ 990Sstevel@tonic-gate if ( *path != '/' ) { 1000Sstevel@tonic-gate /* 1010Sstevel@tonic-gate * Make sure it is for the local host. 1020Sstevel@tonic-gate */ 1030Sstevel@tonic-gate if ( str_starts_with( path, "localhost/" )) { 1040Sstevel@tonic-gate path += 9; 1050Sstevel@tonic-gate } else { 1060Sstevel@tonic-gate return( LDAPTOOL_FILEURL_NONLOCAL ); 1070Sstevel@tonic-gate } 1080Sstevel@tonic-gate } 1090Sstevel@tonic-gate } else { /* URL is of the form file:/path */ 1100Sstevel@tonic-gate --path; 1110Sstevel@tonic-gate } 1120Sstevel@tonic-gate 1130Sstevel@tonic-gate /* 1140Sstevel@tonic-gate * The remainder is now of the form /path. On Windows, skip past the 1150Sstevel@tonic-gate * leading slash if a drive letter is present. 1160Sstevel@tonic-gate */ 1170Sstevel@tonic-gate #ifdef _WINDOWS 1180Sstevel@tonic-gate if ( isalpha( path[1] ) && ( path[2] == '|' || path[2] == ':' )) { 1190Sstevel@tonic-gate ++path; 1200Sstevel@tonic-gate } 1210Sstevel@tonic-gate #endif /* _WINDOWS */ 1220Sstevel@tonic-gate 1230Sstevel@tonic-gate /* 1240Sstevel@tonic-gate * Duplicate the path so we can safely alter it. 1250Sstevel@tonic-gate * Unescape any %HH sequences. 1260Sstevel@tonic-gate */ 1270Sstevel@tonic-gate if (( pathcopy = strdup( path )) == NULL ) { 1280Sstevel@tonic-gate return( LDAPTOOL_FILEURL_NOMEMORY ); 1290Sstevel@tonic-gate } 1300Sstevel@tonic-gate hex_unescape( pathcopy ); 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate #ifdef _WINDOWS 1330Sstevel@tonic-gate /* 1340Sstevel@tonic-gate * Convert forward slashes to backslashes for Windows. Also, 1350Sstevel@tonic-gate * if we see a drive letter / vertical bar combination (e.g., c|) 1360Sstevel@tonic-gate * at the beginning of the path, replace the '|' with a ':'. 1370Sstevel@tonic-gate */ 1380Sstevel@tonic-gate { 1390Sstevel@tonic-gate char *p; 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate for ( p = pathcopy; *p != '\0'; ++p ) { 1420Sstevel@tonic-gate if ( *p == '/' ) { 1430Sstevel@tonic-gate *p = '\\'; 1440Sstevel@tonic-gate } 1450Sstevel@tonic-gate } 1460Sstevel@tonic-gate } 1470Sstevel@tonic-gate 1480Sstevel@tonic-gate if ( isalpha( pathcopy[0] ) && pathcopy[1] == '|' ) { 1490Sstevel@tonic-gate pathcopy[1] = ':'; 1500Sstevel@tonic-gate } 1510Sstevel@tonic-gate #endif /* _WINDOWS */ 1520Sstevel@tonic-gate 1530Sstevel@tonic-gate *localpathp = pathcopy; 1540Sstevel@tonic-gate return( LDAPTOOL_FILEURL_SUCCESS ); 1550Sstevel@tonic-gate } 1560Sstevel@tonic-gate 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate /* 1590Sstevel@tonic-gate * Convert a local path to a file URL. 1600Sstevel@tonic-gate * 1610Sstevel@tonic-gate * If successful, LDAPTOOL_FILEURL_SUCCESS is returned and *urlp is 1620Sstevel@tonic-gate * set point to an allocated string. If not, an different LDAPTOOL_FILEURL_ 1630Sstevel@tonic-gate * error code is returned. At present, the only possible error is 1640Sstevel@tonic-gate * LDAPTOOL_FILEURL_NOMEMORY. 1650Sstevel@tonic-gate * 1660Sstevel@tonic-gate * This function produces file URLs of the form file:path. 1670Sstevel@tonic-gate * 1680Sstevel@tonic-gate * On Windows, we convert leading drive letters to C|. 1690Sstevel@tonic-gate * 1700Sstevel@tonic-gate */ 1710Sstevel@tonic-gate int 1720Sstevel@tonic-gate ldaptool_path2fileurl( char *path, char **urlp ) 1730Sstevel@tonic-gate { 1740Sstevel@tonic-gate char *p, *url, *prefix ="file:"; 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate if ( NULL == path ) { 1770Sstevel@tonic-gate path = "/"; 1780Sstevel@tonic-gate } 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate /* 1810Sstevel@tonic-gate * Allocate space for the URL, taking into account that path may 1820Sstevel@tonic-gate * expand during the hex escaping process. 1830Sstevel@tonic-gate */ 1840Sstevel@tonic-gate if (( url = malloc( strlen( prefix ) + 3 * strlen( path ) + 1 )) == NULL ) { 1850Sstevel@tonic-gate return( LDAPTOOL_FILEURL_NOMEMORY ); 1860Sstevel@tonic-gate } 1870Sstevel@tonic-gate 1880Sstevel@tonic-gate strcpy( url, prefix ); 1890Sstevel@tonic-gate p = url + strlen( prefix ); 1900Sstevel@tonic-gate 1910Sstevel@tonic-gate #ifdef _WINDOWS 1920Sstevel@tonic-gate /* 1930Sstevel@tonic-gate * On Windows, convert leading drive letters (e.g., C:) to the correct URL 1940Sstevel@tonic-gate * syntax (e.g., C|). 1950Sstevel@tonic-gate */ 1960Sstevel@tonic-gate if ( isalpha( path[0] ) && path[1] == ':' ) { 1970Sstevel@tonic-gate *p++ = path[0]; 1980Sstevel@tonic-gate *p++ = '|'; 1990Sstevel@tonic-gate path += 2; 2000Sstevel@tonic-gate *p = '\0'; 2010Sstevel@tonic-gate } 2020Sstevel@tonic-gate #endif /* _WINDOWS */ 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate /* 2050Sstevel@tonic-gate * Append the path, encoding any URL-special characters using the %HH 2060Sstevel@tonic-gate * convention. 2070Sstevel@tonic-gate * On Windows, convert backwards slashes in the path to forward ones. 2080Sstevel@tonic-gate */ 2090Sstevel@tonic-gate strcpy_escaped_and_convert( p, path ); 2100Sstevel@tonic-gate 2110Sstevel@tonic-gate *urlp = url; 2120Sstevel@tonic-gate return( LDAPTOOL_FILEURL_SUCCESS ); 2130Sstevel@tonic-gate } 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate 2160Sstevel@tonic-gate /* 2170Sstevel@tonic-gate * Populate *bvp from "value" of length "vlen." 2180Sstevel@tonic-gate * 2190Sstevel@tonic-gate * If recognize_url_syntax is non-zero, :<fileurl is recognized. 2200Sstevel@tonic-gate * If always_try_file is recognized and no file URL was found, an 2210Sstevel@tonic-gate * attempt is made to stat and read the value as if it were the name 2220Sstevel@tonic-gate * of a file. 2230Sstevel@tonic-gate * 2240Sstevel@tonic-gate * If reporterrs is non-zero, specific error messages are printed to 2250Sstevel@tonic-gate * stderr. 2260Sstevel@tonic-gate * 2270Sstevel@tonic-gate * If successful, LDAPTOOL_FILEURL_SUCCESS is returned and bvp->bv_len 2280Sstevel@tonic-gate * and bvp->bv_val are set (the latter is set to malloc'd memory). 2290Sstevel@tonic-gate * Upon failure, a different LDAPTOOL_FILEURL_ error code is returned. 2300Sstevel@tonic-gate */ 2310Sstevel@tonic-gate int 2320Sstevel@tonic-gate ldaptool_berval_from_ldif_value( const char *value, int vlen, 2330Sstevel@tonic-gate struct berval *bvp, int recognize_url_syntax, int always_try_file, 2340Sstevel@tonic-gate int reporterrs ) 2350Sstevel@tonic-gate { 2360Sstevel@tonic-gate int rc = LDAPTOOL_FILEURL_SUCCESS; /* optimistic */ 2370Sstevel@tonic-gate const char *url = NULL; 2380Sstevel@tonic-gate struct stat fstats; 2390Sstevel@tonic-gate 2400Sstevel@tonic-gate /* recognize "attr :< url" syntax if LDIF version is >= 1 */ 2410Sstevel@tonic-gate 2420Sstevel@tonic-gate #ifdef notdef 2430Sstevel@tonic-gate if ( ldaptool_verbose ) { 2440Sstevel@tonic-gate fprintf( stderr, gettext("%s: ldaptool_berval_from_ldif_value: value: %s\n"), 2450Sstevel@tonic-gate ldaptool_progname, value); 2460Sstevel@tonic-gate } 2470Sstevel@tonic-gate #endif 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate if ( recognize_url_syntax && *value == '<' ) { 2500Sstevel@tonic-gate for ( url = value + 1; isspace( *url ); ++url ) { 2510Sstevel@tonic-gate ; /* NULL */ 2520Sstevel@tonic-gate } 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate if (strlen(url) > 7 && strncasecmp(url, "file://", 7) != 0) { 2550Sstevel@tonic-gate /* 2560Sstevel@tonic-gate * We only support file:// URLs for now. 2570Sstevel@tonic-gate */ 2580Sstevel@tonic-gate url = NULL; 2590Sstevel@tonic-gate } 2600Sstevel@tonic-gate } 2610Sstevel@tonic-gate 2620Sstevel@tonic-gate if ( NULL != url ) { 2630Sstevel@tonic-gate char *path; 2640Sstevel@tonic-gate 2650Sstevel@tonic-gate rc = ldaptool_fileurl2path( url, &path ); 2660Sstevel@tonic-gate switch( rc ) { 2670Sstevel@tonic-gate case LDAPTOOL_FILEURL_NOTAFILEURL: 2680Sstevel@tonic-gate if ( reporterrs ) fprintf( stderr, gettext("%s: unsupported URL \"%s\";" 2690Sstevel@tonic-gate " use a file:// URL instead.\n"), ldaptool_progname, url ); 2700Sstevel@tonic-gate break; 2710Sstevel@tonic-gate 2720Sstevel@tonic-gate case LDAPTOOL_FILEURL_MISSINGPATH: 2730Sstevel@tonic-gate if ( reporterrs ) fprintf( stderr, 2740Sstevel@tonic-gate gettext("%s: unable to process URL \"%s\" --" 2750Sstevel@tonic-gate " missing path.\n"), ldaptool_progname, url ); 2760Sstevel@tonic-gate break; 2770Sstevel@tonic-gate 2780Sstevel@tonic-gate case LDAPTOOL_FILEURL_NONLOCAL: 2790Sstevel@tonic-gate if ( reporterrs ) fprintf( stderr, 2800Sstevel@tonic-gate gettext("%s: unable to process URL \"%s\" -- only" 2810Sstevel@tonic-gate " local file:// URLs are supported.\n"), 2820Sstevel@tonic-gate ldaptool_progname, url ); 2830Sstevel@tonic-gate break; 2840Sstevel@tonic-gate 2850Sstevel@tonic-gate case LDAPTOOL_FILEURL_NOMEMORY: 2860Sstevel@tonic-gate if ( reporterrs ) perror( "ldaptool_fileurl2path" ); 2870Sstevel@tonic-gate break; 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate case LDAPTOOL_FILEURL_SUCCESS: 2900Sstevel@tonic-gate if ( stat( path, &fstats ) != 0 ) { 2910Sstevel@tonic-gate if ( reporterrs ) perror( path ); 292*871Scasper } else if (S_ISDIR(fstats.st_mode)) { 2930Sstevel@tonic-gate if ( reporterrs ) fprintf( stderr, 2940Sstevel@tonic-gate gettext("%s: %s is a directory, not a file\n"), 2950Sstevel@tonic-gate ldaptool_progname, path ); 2960Sstevel@tonic-gate rc = LDAPTOOL_FILEURL_FILEIOERROR; 2970Sstevel@tonic-gate } else { 2980Sstevel@tonic-gate rc = berval_from_file( path, bvp, reporterrs ); 2990Sstevel@tonic-gate } 3000Sstevel@tonic-gate free( path ); 3010Sstevel@tonic-gate break; 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate default: 3040Sstevel@tonic-gate if ( reporterrs ) fprintf( stderr, 3050Sstevel@tonic-gate gettext("%s: unable to process URL \"%s\"" 3060Sstevel@tonic-gate " -- unknown error\n"), ldaptool_progname, url ); 3070Sstevel@tonic-gate } 3080Sstevel@tonic-gate } else if ( always_try_file && (stat( value, &fstats ) == 0) && 309*871Scasper !S_ISDIR(fstats.st_mode)) { /* get value from file */ 3100Sstevel@tonic-gate rc = berval_from_file( value, bvp, reporterrs ); 3110Sstevel@tonic-gate } else { 3120Sstevel@tonic-gate bvp->bv_len = vlen; 3130Sstevel@tonic-gate if (( bvp->bv_val = (char *)malloc( vlen + 1 )) == NULL ) { 3140Sstevel@tonic-gate if ( reporterrs ) perror( "malloc" ); 3150Sstevel@tonic-gate rc = LDAPTOOL_FILEURL_NOMEMORY; 3160Sstevel@tonic-gate } else { 3170Sstevel@tonic-gate SAFEMEMCPY( bvp->bv_val, value, vlen ); 3180Sstevel@tonic-gate bvp->bv_val[ vlen ] = '\0'; 3190Sstevel@tonic-gate } 3200Sstevel@tonic-gate } 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate return( rc ); 3230Sstevel@tonic-gate } 3240Sstevel@tonic-gate 3250Sstevel@tonic-gate 3260Sstevel@tonic-gate /* 3270Sstevel@tonic-gate * Map an LDAPTOOL_FILEURL_ error code to an LDAP error code (crude). 3280Sstevel@tonic-gate */ 3290Sstevel@tonic-gate int 3300Sstevel@tonic-gate ldaptool_fileurlerr2ldaperr( int lderr ) 3310Sstevel@tonic-gate { 3320Sstevel@tonic-gate int rc; 3330Sstevel@tonic-gate 3340Sstevel@tonic-gate switch( lderr ) { 3350Sstevel@tonic-gate case LDAPTOOL_FILEURL_SUCCESS: 3360Sstevel@tonic-gate rc = LDAP_SUCCESS; 3370Sstevel@tonic-gate break; 3380Sstevel@tonic-gate case LDAPTOOL_FILEURL_NOMEMORY: 3390Sstevel@tonic-gate rc = LDAP_NO_MEMORY; 3400Sstevel@tonic-gate break; 3410Sstevel@tonic-gate default: 3420Sstevel@tonic-gate rc = LDAP_PARAM_ERROR; 3430Sstevel@tonic-gate } 3440Sstevel@tonic-gate 3450Sstevel@tonic-gate return( rc ); 3460Sstevel@tonic-gate } 3470Sstevel@tonic-gate 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate /* 3500Sstevel@tonic-gate * Populate *bvp with the contents of the file named by "path". 3510Sstevel@tonic-gate * 3520Sstevel@tonic-gate * If reporterrs is non-zero, specific error messages are printed to 3530Sstevel@tonic-gate * stderr. 3540Sstevel@tonic-gate * 3550Sstevel@tonic-gate * If successful, LDAPTOOL_FILEURL_SUCCESS is returned and bvp->bv_len 3560Sstevel@tonic-gate * and bvp->bv_val are set (the latter is set to malloc'd memory). 3570Sstevel@tonic-gate * Upon failure, a different LDAPTOOL_FILEURL_ error code is returned. 3580Sstevel@tonic-gate */ 3590Sstevel@tonic-gate 3600Sstevel@tonic-gate static int 3610Sstevel@tonic-gate berval_from_file( const char *path, struct berval *bvp, int reporterrs ) 3620Sstevel@tonic-gate { 3630Sstevel@tonic-gate FILE *fp; 3640Sstevel@tonic-gate long rlen; 3650Sstevel@tonic-gate int eof; 3660Sstevel@tonic-gate #if defined( XP_WIN32 ) 3670Sstevel@tonic-gate char mode[20] = "r+b"; 3680Sstevel@tonic-gate #else 3690Sstevel@tonic-gate char mode[20] = "r"; 3700Sstevel@tonic-gate #endif 3710Sstevel@tonic-gate 3720Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD 3730Sstevel@tonic-gate if (( fp = fopen( path, mode )) == NULL ) { 3740Sstevel@tonic-gate #else 3750Sstevel@tonic-gate if (( fp = ldaptool_open_file( path, mode )) == NULL ) { 3760Sstevel@tonic-gate #endif /* SOLARIS_LDAP_CMD */ 3770Sstevel@tonic-gate if ( reporterrs ) perror( path ); 3780Sstevel@tonic-gate return( LDAPTOOL_FILEURL_FILEIOERROR ); 3790Sstevel@tonic-gate } 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate if ( fseek( fp, 0L, SEEK_END ) != 0 ) { 3820Sstevel@tonic-gate if ( reporterrs ) perror( path ); 3830Sstevel@tonic-gate fclose( fp ); 3840Sstevel@tonic-gate return( LDAPTOOL_FILEURL_FILEIOERROR ); 3850Sstevel@tonic-gate } 3860Sstevel@tonic-gate 3870Sstevel@tonic-gate bvp->bv_len = ftell( fp ); 3880Sstevel@tonic-gate 3890Sstevel@tonic-gate if (( bvp->bv_val = (char *)malloc( bvp->bv_len + 1 )) == NULL ) { 3900Sstevel@tonic-gate if ( reporterrs ) perror( "malloc" ); 3910Sstevel@tonic-gate fclose( fp ); 3920Sstevel@tonic-gate return( LDAPTOOL_FILEURL_NOMEMORY ); 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate if ( fseek( fp, 0L, SEEK_SET ) != 0 ) { 3960Sstevel@tonic-gate if ( reporterrs ) perror( path ); 3970Sstevel@tonic-gate fclose( fp ); 3980Sstevel@tonic-gate return( LDAPTOOL_FILEURL_FILEIOERROR ); 3990Sstevel@tonic-gate } 4000Sstevel@tonic-gate 4010Sstevel@tonic-gate rlen = fread( bvp->bv_val, 1, bvp->bv_len, fp ); 4020Sstevel@tonic-gate eof = feof( fp ); 4030Sstevel@tonic-gate fclose( fp ); 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate if ( rlen != (long)bvp->bv_len ) { 4060Sstevel@tonic-gate if ( reporterrs ) perror( path ); 4070Sstevel@tonic-gate free( bvp->bv_val ); 4080Sstevel@tonic-gate return( LDAPTOOL_FILEURL_FILEIOERROR ); 4090Sstevel@tonic-gate } 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate bvp->bv_val[ bvp->bv_len ] = '\0'; 4120Sstevel@tonic-gate return( LDAPTOOL_FILEURL_SUCCESS ); 4130Sstevel@tonic-gate } 4140Sstevel@tonic-gate 4150Sstevel@tonic-gate 4160Sstevel@tonic-gate /* 4170Sstevel@tonic-gate * Return a non-zero value if the string s begins with prefix and zero if not. 4180Sstevel@tonic-gate */ 4190Sstevel@tonic-gate static int 4200Sstevel@tonic-gate str_starts_with( const char *s, char *prefix ) 4210Sstevel@tonic-gate { 4220Sstevel@tonic-gate size_t prefix_len; 4230Sstevel@tonic-gate 4240Sstevel@tonic-gate if ( s == NULL || prefix == NULL ) { 4250Sstevel@tonic-gate return( 0 ); 4260Sstevel@tonic-gate } 4270Sstevel@tonic-gate 4280Sstevel@tonic-gate prefix_len = strlen( prefix ); 4290Sstevel@tonic-gate if ( strlen( s ) < prefix_len ) { 4300Sstevel@tonic-gate return( 0 ); 4310Sstevel@tonic-gate } 4320Sstevel@tonic-gate 4330Sstevel@tonic-gate return( strncmp( s, prefix, prefix_len ) == 0 ); 4340Sstevel@tonic-gate } 4350Sstevel@tonic-gate 4360Sstevel@tonic-gate 4370Sstevel@tonic-gate /* 4380Sstevel@tonic-gate * Remove URL hex escapes from s... done in place. The basic concept for 4390Sstevel@tonic-gate * this routine is borrowed from the WWW library HTUnEscape() routine. 4400Sstevel@tonic-gate * 4410Sstevel@tonic-gate * A similar function called nsldapi_hex_unescape can be found in 4420Sstevel@tonic-gate * ../../libraries/libldap/unescape.c 4430Sstevel@tonic-gate */ 4440Sstevel@tonic-gate static void 4450Sstevel@tonic-gate hex_unescape( char *s ) 4460Sstevel@tonic-gate { 4470Sstevel@tonic-gate char *p; 4480Sstevel@tonic-gate 4490Sstevel@tonic-gate for ( p = s; *s != '\0'; ++s ) { 4500Sstevel@tonic-gate if ( *s == '%' ) { 4510Sstevel@tonic-gate if ( *++s != '\0' ) { 4520Sstevel@tonic-gate *p = unhex( *s ) << 4; 4530Sstevel@tonic-gate } 4540Sstevel@tonic-gate if ( *++s != '\0' ) { 4550Sstevel@tonic-gate *p++ += unhex( *s ); 4560Sstevel@tonic-gate } 4570Sstevel@tonic-gate } else { 4580Sstevel@tonic-gate *p++ = *s; 4590Sstevel@tonic-gate } 4600Sstevel@tonic-gate } 4610Sstevel@tonic-gate 4620Sstevel@tonic-gate *p = '\0'; 4630Sstevel@tonic-gate } 4640Sstevel@tonic-gate 4650Sstevel@tonic-gate 4660Sstevel@tonic-gate /* 4670Sstevel@tonic-gate * Return the integer equivalent of one hex digit (in c). 4680Sstevel@tonic-gate * 4690Sstevel@tonic-gate * A similar function can be found in ../../libraries/libldap/unescape.c 4700Sstevel@tonic-gate */ 4710Sstevel@tonic-gate static int 4720Sstevel@tonic-gate unhex( char c ) 4730Sstevel@tonic-gate { 4740Sstevel@tonic-gate return( c >= '0' && c <= '9' ? c - '0' 4750Sstevel@tonic-gate : c >= 'A' && c <= 'F' ? c - 'A' + 10 4760Sstevel@tonic-gate : c - 'a' + 10 ); 4770Sstevel@tonic-gate } 4780Sstevel@tonic-gate 4790Sstevel@tonic-gate 4800Sstevel@tonic-gate #define HREF_CHAR_ACCEPTABLE( c ) (( c >= '-' && c <= '9' ) || \ 4810Sstevel@tonic-gate ( c >= '@' && c <= 'Z' ) || \ 4820Sstevel@tonic-gate ( c == '_' ) || \ 4830Sstevel@tonic-gate ( c >= 'a' && c <= 'z' )) 4840Sstevel@tonic-gate 4850Sstevel@tonic-gate /* 4860Sstevel@tonic-gate * Like strcat(), except if any URL-special characters are found in s2 4870Sstevel@tonic-gate * they are escaped using the %HH convention and backslash characters are 4880Sstevel@tonic-gate * converted to forward slashes on Windows. 4890Sstevel@tonic-gate * 4900Sstevel@tonic-gate * Maximum space needed in s1 is 3 * strlen( s2 ) + 1. 4910Sstevel@tonic-gate * 4920Sstevel@tonic-gate * A similar function that does not convert the slashes called 4930Sstevel@tonic-gate * strcat_escaped() can be found in ../../libraries/libldap/tmplout.c 4940Sstevel@tonic-gate */ 4950Sstevel@tonic-gate static void 4960Sstevel@tonic-gate strcpy_escaped_and_convert( char *s1, char *s2 ) 4970Sstevel@tonic-gate { 4980Sstevel@tonic-gate char *p, *q; 4990Sstevel@tonic-gate char *hexdig = "0123456789ABCDEF"; 5000Sstevel@tonic-gate 5010Sstevel@tonic-gate p = s1 + strlen( s1 ); 5020Sstevel@tonic-gate for ( q = s2; *q != '\0'; ++q ) { 5030Sstevel@tonic-gate #ifdef _WINDOWS 5040Sstevel@tonic-gate if ( *q == '\\' ) { 5050Sstevel@tonic-gate *p++ = '/'; 5060Sstevel@tonic-gate } else 5070Sstevel@tonic-gate #endif /* _WINDOWS */ 5080Sstevel@tonic-gate 5090Sstevel@tonic-gate if ( HREF_CHAR_ACCEPTABLE( *q )) { 5100Sstevel@tonic-gate *p++ = *q; 5110Sstevel@tonic-gate } else { 5120Sstevel@tonic-gate *p++ = '%'; 5130Sstevel@tonic-gate *p++ = hexdig[ 0x0F & ((*(unsigned char*)q) >> 4) ]; 5140Sstevel@tonic-gate *p++ = hexdig[ 0x0F & *q ]; 5150Sstevel@tonic-gate } 5160Sstevel@tonic-gate } 5170Sstevel@tonic-gate 5180Sstevel@tonic-gate *p = '\0'; 5190Sstevel@tonic-gate } 520