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