xref: /titanic_53/usr/src/cmd/ldap/common/fileurl.c (revision 4bc0a2ef2b7ba50a7a717e7ddbf31472ad28e358)
17c478bd9Sstevel@tonic-gate /*
2*4bc0a2efScasper  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
77c478bd9Sstevel@tonic-gate 
87c478bd9Sstevel@tonic-gate /*
97c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the Netscape Public
107c478bd9Sstevel@tonic-gate  * License Version 1.1 (the "License"); you may not use this file
117c478bd9Sstevel@tonic-gate  * except in compliance with the License. You may obtain a copy of
127c478bd9Sstevel@tonic-gate  * the License at http://www.mozilla.org/NPL/
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * Software distributed under the License is distributed on an "AS
157c478bd9Sstevel@tonic-gate  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
167c478bd9Sstevel@tonic-gate  * implied. See the License for the specific language governing
177c478bd9Sstevel@tonic-gate  * rights and limitations under the License.
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * The Original Code is Mozilla Communicator client code, released
207c478bd9Sstevel@tonic-gate  * March 31, 1998.
217c478bd9Sstevel@tonic-gate  *
227c478bd9Sstevel@tonic-gate  * The Initial Developer of the Original Code is Netscape
237c478bd9Sstevel@tonic-gate  * Communications Corporation. Portions created by Netscape are
247c478bd9Sstevel@tonic-gate  * Copyright (C) 1998-1999 Netscape Communications Corporation. All
257c478bd9Sstevel@tonic-gate  * Rights Reserved.
267c478bd9Sstevel@tonic-gate  *
277c478bd9Sstevel@tonic-gate  * Contributor(s):
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate  *  LDAP tools fileurl.c -- functions for handling file URLs.
327c478bd9Sstevel@tonic-gate  *  Used by ldapmodify.
337c478bd9Sstevel@tonic-gate  */
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #include "ldaptool.h"
367c478bd9Sstevel@tonic-gate #include "fileurl.h"
377c478bd9Sstevel@tonic-gate #include <ctype.h>	/* for isalpha() */
387c478bd9Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
397c478bd9Sstevel@tonic-gate #include <locale.h>
407c478bd9Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate #ifndef SOLARIS_LDAP_CMD
437c478bd9Sstevel@tonic-gate #define gettext(s) s
447c478bd9Sstevel@tonic-gate #endif
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate static int str_starts_with( const char *s, char *prefix );
477c478bd9Sstevel@tonic-gate static void hex_unescape( char *s );
487c478bd9Sstevel@tonic-gate static int unhex( char c );
497c478bd9Sstevel@tonic-gate static void strcpy_escaped_and_convert( char *s1, char *s2 );
507c478bd9Sstevel@tonic-gate static int berval_from_file( const char *path, struct berval *bvp,
517c478bd9Sstevel@tonic-gate 	int reporterrs );
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate /*
547c478bd9Sstevel@tonic-gate  * Convert a file URL to a local path.
557c478bd9Sstevel@tonic-gate  *
567c478bd9Sstevel@tonic-gate  * If successful, LDAPTOOL_FILEURL_SUCCESS is returned and *localpathp is
577c478bd9Sstevel@tonic-gate  * set point to an allocated string.  If not, an different LDAPTOOL_FILEURL_
587c478bd9Sstevel@tonic-gate  * error code is returned.
597c478bd9Sstevel@tonic-gate  *
607c478bd9Sstevel@tonic-gate  * See RFCs 1738 and 2396 for a specification for file URLs... but
617c478bd9Sstevel@tonic-gate  * Netscape Navigator seems to be a bit more lenient in what it will
627c478bd9Sstevel@tonic-gate  * accept, especially on Windows).
637c478bd9Sstevel@tonic-gate  *
647c478bd9Sstevel@tonic-gate  * This function parses file URLs of these three forms:
657c478bd9Sstevel@tonic-gate  *
667c478bd9Sstevel@tonic-gate  *    file:///path
677c478bd9Sstevel@tonic-gate  *    file:/path
687c478bd9Sstevel@tonic-gate  *    file://localhost/path
697c478bd9Sstevel@tonic-gate  *    file://host/path		(rejected with a ...NONLOCAL error)
707c478bd9Sstevel@tonic-gate  *
717c478bd9Sstevel@tonic-gate  * On Windows, we convert leading drive letters of the form C| to C:
727c478bd9Sstevel@tonic-gate  * and if a drive letter is present we strip off the slash that precedes
737c478bd9Sstevel@tonic-gate  * path.  Otherwise, the leading slash is returned.
747c478bd9Sstevel@tonic-gate  *
757c478bd9Sstevel@tonic-gate  */
767c478bd9Sstevel@tonic-gate int
777c478bd9Sstevel@tonic-gate ldaptool_fileurl2path( const char *fileurl, char **localpathp )
787c478bd9Sstevel@tonic-gate {
797c478bd9Sstevel@tonic-gate     const char	*path;
807c478bd9Sstevel@tonic-gate     char	*pathcopy;
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate     /*
837c478bd9Sstevel@tonic-gate      * Make sure this is a file URL we can handle.
847c478bd9Sstevel@tonic-gate      */
857c478bd9Sstevel@tonic-gate     if ( !str_starts_with( fileurl, "file:" )) {
867c478bd9Sstevel@tonic-gate 	return( LDAPTOOL_FILEURL_NOTAFILEURL );
877c478bd9Sstevel@tonic-gate     }
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate     path = fileurl + 5;		/* skip past "file:" scheme prefix */
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate     if ( *path != '/' ) {
927c478bd9Sstevel@tonic-gate 	return( LDAPTOOL_FILEURL_MISSINGPATH );
937c478bd9Sstevel@tonic-gate     }
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate     ++path;			/* skip past '/' at end of "file:/" */
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate     if ( *path == '/' ) {
987c478bd9Sstevel@tonic-gate 	++path;			/* remainder is now host/path or /path */
997c478bd9Sstevel@tonic-gate 	if ( *path != '/' ) {
1007c478bd9Sstevel@tonic-gate 	    /*
1017c478bd9Sstevel@tonic-gate 	     * Make sure it is for the local host.
1027c478bd9Sstevel@tonic-gate 	     */
1037c478bd9Sstevel@tonic-gate 	    if ( str_starts_with( path, "localhost/" )) {
1047c478bd9Sstevel@tonic-gate 		path += 9;
1057c478bd9Sstevel@tonic-gate 	    } else {
1067c478bd9Sstevel@tonic-gate 		return( LDAPTOOL_FILEURL_NONLOCAL );
1077c478bd9Sstevel@tonic-gate 	    }
1087c478bd9Sstevel@tonic-gate 	}
1097c478bd9Sstevel@tonic-gate     } else {		/* URL is of the form file:/path */
1107c478bd9Sstevel@tonic-gate 	--path;
1117c478bd9Sstevel@tonic-gate     }
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate     /*
1147c478bd9Sstevel@tonic-gate      * The remainder is now of the form /path.  On Windows, skip past the
1157c478bd9Sstevel@tonic-gate      * leading slash if a drive letter is present.
1167c478bd9Sstevel@tonic-gate      */
1177c478bd9Sstevel@tonic-gate #ifdef _WINDOWS
1187c478bd9Sstevel@tonic-gate     if ( isalpha( path[1] ) && ( path[2] == '|' || path[2] == ':' )) {
1197c478bd9Sstevel@tonic-gate 	++path;
1207c478bd9Sstevel@tonic-gate     }
1217c478bd9Sstevel@tonic-gate #endif /* _WINDOWS */
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate     /*
1247c478bd9Sstevel@tonic-gate      * Duplicate the path so we can safely alter it.
1257c478bd9Sstevel@tonic-gate      * Unescape any %HH sequences.
1267c478bd9Sstevel@tonic-gate      */
1277c478bd9Sstevel@tonic-gate     if (( pathcopy = strdup( path )) == NULL ) {
1287c478bd9Sstevel@tonic-gate 	return( LDAPTOOL_FILEURL_NOMEMORY );
1297c478bd9Sstevel@tonic-gate     }
1307c478bd9Sstevel@tonic-gate     hex_unescape( pathcopy );
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate #ifdef _WINDOWS
1337c478bd9Sstevel@tonic-gate     /*
1347c478bd9Sstevel@tonic-gate      * Convert forward slashes to backslashes for Windows.  Also,
1357c478bd9Sstevel@tonic-gate      * if we see a drive letter / vertical bar combination (e.g., c|)
1367c478bd9Sstevel@tonic-gate      * at the beginning of the path, replace the '|' with a ':'.
1377c478bd9Sstevel@tonic-gate      */
1387c478bd9Sstevel@tonic-gate     {
1397c478bd9Sstevel@tonic-gate 	char	*p;
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 	for ( p = pathcopy; *p != '\0'; ++p ) {
1427c478bd9Sstevel@tonic-gate 	    if ( *p == '/' ) {
1437c478bd9Sstevel@tonic-gate 		*p = '\\';
1447c478bd9Sstevel@tonic-gate 	    }
1457c478bd9Sstevel@tonic-gate 	}
1467c478bd9Sstevel@tonic-gate     }
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate     if ( isalpha( pathcopy[0] ) && pathcopy[1] == '|' ) {
1497c478bd9Sstevel@tonic-gate 	pathcopy[1] = ':';
1507c478bd9Sstevel@tonic-gate     }
1517c478bd9Sstevel@tonic-gate #endif /* _WINDOWS */
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate     *localpathp = pathcopy;
1547c478bd9Sstevel@tonic-gate     return( LDAPTOOL_FILEURL_SUCCESS );
1557c478bd9Sstevel@tonic-gate }
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate /*
1597c478bd9Sstevel@tonic-gate  * Convert a local path to a file URL.
1607c478bd9Sstevel@tonic-gate  *
1617c478bd9Sstevel@tonic-gate  * If successful, LDAPTOOL_FILEURL_SUCCESS is returned and *urlp is
1627c478bd9Sstevel@tonic-gate  * set point to an allocated string.  If not, an different LDAPTOOL_FILEURL_
1637c478bd9Sstevel@tonic-gate  * error code is returned.  At present, the only possible error is
1647c478bd9Sstevel@tonic-gate  * LDAPTOOL_FILEURL_NOMEMORY.
1657c478bd9Sstevel@tonic-gate  *
1667c478bd9Sstevel@tonic-gate  * This function produces file URLs of the form file:path.
1677c478bd9Sstevel@tonic-gate  *
1687c478bd9Sstevel@tonic-gate  * On Windows, we convert leading drive letters to C|.
1697c478bd9Sstevel@tonic-gate  *
1707c478bd9Sstevel@tonic-gate  */
1717c478bd9Sstevel@tonic-gate int
1727c478bd9Sstevel@tonic-gate ldaptool_path2fileurl( char *path, char **urlp )
1737c478bd9Sstevel@tonic-gate {
1747c478bd9Sstevel@tonic-gate     char	*p, *url, *prefix ="file:";
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate     if ( NULL == path ) {
1777c478bd9Sstevel@tonic-gate 	path = "/";
1787c478bd9Sstevel@tonic-gate     }
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate     /*
1817c478bd9Sstevel@tonic-gate      * Allocate space for the URL, taking into account that path may
1827c478bd9Sstevel@tonic-gate      * expand during the hex escaping process.
1837c478bd9Sstevel@tonic-gate      */
1847c478bd9Sstevel@tonic-gate     if (( url = malloc( strlen( prefix ) + 3 * strlen( path ) + 1 )) == NULL ) {
1857c478bd9Sstevel@tonic-gate 	return( LDAPTOOL_FILEURL_NOMEMORY );
1867c478bd9Sstevel@tonic-gate     }
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate     strcpy( url, prefix );
1897c478bd9Sstevel@tonic-gate     p = url + strlen( prefix );
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate #ifdef _WINDOWS
1927c478bd9Sstevel@tonic-gate     /*
1937c478bd9Sstevel@tonic-gate      * On Windows, convert leading drive letters (e.g., C:) to the correct URL
1947c478bd9Sstevel@tonic-gate      * syntax (e.g., C|).
1957c478bd9Sstevel@tonic-gate      */
1967c478bd9Sstevel@tonic-gate     if ( isalpha( path[0] ) && path[1] == ':' ) {
1977c478bd9Sstevel@tonic-gate 	*p++ = path[0];
1987c478bd9Sstevel@tonic-gate 	*p++ = '|';
1997c478bd9Sstevel@tonic-gate 	path += 2;
2007c478bd9Sstevel@tonic-gate 	*p = '\0';
2017c478bd9Sstevel@tonic-gate     }
2027c478bd9Sstevel@tonic-gate #endif /* _WINDOWS */
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate     /*
2057c478bd9Sstevel@tonic-gate      * Append the path, encoding any URL-special characters using the %HH
2067c478bd9Sstevel@tonic-gate      * convention.
2077c478bd9Sstevel@tonic-gate      * On Windows, convert backwards slashes in the path to forward ones.
2087c478bd9Sstevel@tonic-gate      */
2097c478bd9Sstevel@tonic-gate     strcpy_escaped_and_convert( p, path );
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate     *urlp = url;
2127c478bd9Sstevel@tonic-gate     return( LDAPTOOL_FILEURL_SUCCESS );
2137c478bd9Sstevel@tonic-gate }
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate /*
2177c478bd9Sstevel@tonic-gate  * Populate *bvp from "value" of length "vlen."
2187c478bd9Sstevel@tonic-gate  *
2197c478bd9Sstevel@tonic-gate  * If recognize_url_syntax is non-zero, :<fileurl is recognized.
2207c478bd9Sstevel@tonic-gate  * If always_try_file is recognized and no file URL was found, an
2217c478bd9Sstevel@tonic-gate  * attempt is made to stat and read the value as if it were the name
2227c478bd9Sstevel@tonic-gate  * of a file.
2237c478bd9Sstevel@tonic-gate  *
2247c478bd9Sstevel@tonic-gate  * If reporterrs is non-zero, specific error messages are printed to
2257c478bd9Sstevel@tonic-gate  * stderr.
2267c478bd9Sstevel@tonic-gate  *
2277c478bd9Sstevel@tonic-gate  * If successful, LDAPTOOL_FILEURL_SUCCESS is returned and bvp->bv_len
2287c478bd9Sstevel@tonic-gate  * and bvp->bv_val are set (the latter is set to malloc'd memory).
2297c478bd9Sstevel@tonic-gate  * Upon failure, a different LDAPTOOL_FILEURL_ error code is returned.
2307c478bd9Sstevel@tonic-gate  */
2317c478bd9Sstevel@tonic-gate int
2327c478bd9Sstevel@tonic-gate ldaptool_berval_from_ldif_value( const char *value, int vlen,
2337c478bd9Sstevel@tonic-gate 	struct berval *bvp, int recognize_url_syntax, int always_try_file,
2347c478bd9Sstevel@tonic-gate 	int reporterrs )
2357c478bd9Sstevel@tonic-gate {
2367c478bd9Sstevel@tonic-gate     int	rc = LDAPTOOL_FILEURL_SUCCESS;	/* optimistic */
2377c478bd9Sstevel@tonic-gate     const char	*url = NULL;
2387c478bd9Sstevel@tonic-gate     struct stat	fstats;
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate     /* recognize "attr :< url" syntax if LDIF version is >= 1 */
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate #ifdef notdef
2437c478bd9Sstevel@tonic-gate     if ( ldaptool_verbose ) {
2447c478bd9Sstevel@tonic-gate 	fprintf( stderr, gettext("%s: ldaptool_berval_from_ldif_value: value: %s\n"),
2457c478bd9Sstevel@tonic-gate 	    ldaptool_progname, value);
2467c478bd9Sstevel@tonic-gate     }
2477c478bd9Sstevel@tonic-gate #endif
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate     if ( recognize_url_syntax && *value == '<' ) {
2507c478bd9Sstevel@tonic-gate         for ( url = value + 1; isspace( *url ); ++url ) {
2517c478bd9Sstevel@tonic-gate 	    ;	/* NULL */
2527c478bd9Sstevel@tonic-gate 	}
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 	if (strlen(url) > 7 && strncasecmp(url, "file://", 7) != 0) {
2557c478bd9Sstevel@tonic-gate 	    /*
2567c478bd9Sstevel@tonic-gate 	     * We only support file:// URLs for now.
2577c478bd9Sstevel@tonic-gate 	     */
2587c478bd9Sstevel@tonic-gate 	    url = NULL;
2597c478bd9Sstevel@tonic-gate 	}
2607c478bd9Sstevel@tonic-gate     }
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate     if ( NULL != url ) {
2637c478bd9Sstevel@tonic-gate 	char		*path;
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 	rc = ldaptool_fileurl2path( url, &path );
2667c478bd9Sstevel@tonic-gate 	switch( rc ) {
2677c478bd9Sstevel@tonic-gate 	case LDAPTOOL_FILEURL_NOTAFILEURL:
2687c478bd9Sstevel@tonic-gate 	    if ( reporterrs ) fprintf( stderr, gettext("%s: unsupported URL \"%s\";"
2697c478bd9Sstevel@tonic-gate 				       " use a file:// URL instead.\n"), ldaptool_progname, url );
2707c478bd9Sstevel@tonic-gate 	    break;
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	case LDAPTOOL_FILEURL_MISSINGPATH:
2737c478bd9Sstevel@tonic-gate 	    if ( reporterrs ) fprintf( stderr,
2747c478bd9Sstevel@tonic-gate 				       gettext("%s: unable to process URL \"%s\" --"
2757c478bd9Sstevel@tonic-gate 				       " missing path.\n"), ldaptool_progname, url );
2767c478bd9Sstevel@tonic-gate 	    break;
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 	case LDAPTOOL_FILEURL_NONLOCAL:
2797c478bd9Sstevel@tonic-gate 	    if ( reporterrs ) fprintf( stderr,
2807c478bd9Sstevel@tonic-gate 				       gettext("%s: unable to process URL \"%s\" -- only"
2817c478bd9Sstevel@tonic-gate 				       " local file:// URLs are supported.\n"),
2827c478bd9Sstevel@tonic-gate 				       ldaptool_progname, url );
2837c478bd9Sstevel@tonic-gate 	    break;
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	case LDAPTOOL_FILEURL_NOMEMORY:
2867c478bd9Sstevel@tonic-gate 	    if ( reporterrs ) perror( "ldaptool_fileurl2path" );
2877c478bd9Sstevel@tonic-gate 	    break;
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	case LDAPTOOL_FILEURL_SUCCESS:
2907c478bd9Sstevel@tonic-gate 	    if ( stat( path, &fstats ) != 0 ) {
2917c478bd9Sstevel@tonic-gate 		if ( reporterrs ) perror( path );
292*4bc0a2efScasper 	    } else if (S_ISDIR(fstats.st_mode)) {
2937c478bd9Sstevel@tonic-gate 		if ( reporterrs ) fprintf( stderr,
2947c478bd9Sstevel@tonic-gate 					   gettext("%s: %s is a directory, not a file\n"),
2957c478bd9Sstevel@tonic-gate 					   ldaptool_progname, path );
2967c478bd9Sstevel@tonic-gate 		rc = LDAPTOOL_FILEURL_FILEIOERROR;
2977c478bd9Sstevel@tonic-gate 	    } else {
2987c478bd9Sstevel@tonic-gate 		rc = berval_from_file( path, bvp, reporterrs );
2997c478bd9Sstevel@tonic-gate 	    }
3007c478bd9Sstevel@tonic-gate 	    free( path );
3017c478bd9Sstevel@tonic-gate 	    break;
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	default:
3047c478bd9Sstevel@tonic-gate 	    if ( reporterrs ) fprintf( stderr,
3057c478bd9Sstevel@tonic-gate 				       gettext("%s: unable to process URL \"%s\""
3067c478bd9Sstevel@tonic-gate 				       " -- unknown error\n"), ldaptool_progname, url );
3077c478bd9Sstevel@tonic-gate 	}
3087c478bd9Sstevel@tonic-gate     } else if ( always_try_file && (stat( value, &fstats ) == 0) &&
309*4bc0a2efScasper 		!S_ISDIR(fstats.st_mode)) {	/* get value from file */
3107c478bd9Sstevel@tonic-gate 	rc = berval_from_file( value, bvp, reporterrs );
3117c478bd9Sstevel@tonic-gate     } else {
3127c478bd9Sstevel@tonic-gate 	bvp->bv_len = vlen;
3137c478bd9Sstevel@tonic-gate 	if (( bvp->bv_val = (char *)malloc( vlen + 1 )) == NULL ) {
3147c478bd9Sstevel@tonic-gate 	    if ( reporterrs ) perror( "malloc" );
3157c478bd9Sstevel@tonic-gate 	    rc = LDAPTOOL_FILEURL_NOMEMORY;
3167c478bd9Sstevel@tonic-gate 	} else {
3177c478bd9Sstevel@tonic-gate 	    SAFEMEMCPY( bvp->bv_val, value, vlen );
3187c478bd9Sstevel@tonic-gate 	    bvp->bv_val[ vlen ] = '\0';
3197c478bd9Sstevel@tonic-gate 	}
3207c478bd9Sstevel@tonic-gate     }
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate     return( rc );
3237c478bd9Sstevel@tonic-gate }
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate /*
3277c478bd9Sstevel@tonic-gate  * Map an LDAPTOOL_FILEURL_ error code to an LDAP error code (crude).
3287c478bd9Sstevel@tonic-gate  */
3297c478bd9Sstevel@tonic-gate int
3307c478bd9Sstevel@tonic-gate ldaptool_fileurlerr2ldaperr( int lderr )
3317c478bd9Sstevel@tonic-gate {
3327c478bd9Sstevel@tonic-gate     int		rc;
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate     switch( lderr ) {
3357c478bd9Sstevel@tonic-gate     case LDAPTOOL_FILEURL_SUCCESS:
3367c478bd9Sstevel@tonic-gate 	rc = LDAP_SUCCESS;
3377c478bd9Sstevel@tonic-gate 	break;
3387c478bd9Sstevel@tonic-gate     case LDAPTOOL_FILEURL_NOMEMORY:
3397c478bd9Sstevel@tonic-gate 	rc = LDAP_NO_MEMORY;
3407c478bd9Sstevel@tonic-gate 	break;
3417c478bd9Sstevel@tonic-gate     default:
3427c478bd9Sstevel@tonic-gate 	rc = LDAP_PARAM_ERROR;
3437c478bd9Sstevel@tonic-gate     }
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate     return( rc );
3467c478bd9Sstevel@tonic-gate }
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate /*
3507c478bd9Sstevel@tonic-gate  * Populate *bvp with the contents of the file named by "path".
3517c478bd9Sstevel@tonic-gate  *
3527c478bd9Sstevel@tonic-gate  * If reporterrs is non-zero, specific error messages are printed to
3537c478bd9Sstevel@tonic-gate  * stderr.
3547c478bd9Sstevel@tonic-gate  *
3557c478bd9Sstevel@tonic-gate  * If successful, LDAPTOOL_FILEURL_SUCCESS is returned and bvp->bv_len
3567c478bd9Sstevel@tonic-gate  * and bvp->bv_val are set (the latter is set to malloc'd memory).
3577c478bd9Sstevel@tonic-gate  * Upon failure, a different LDAPTOOL_FILEURL_ error code is returned.
3587c478bd9Sstevel@tonic-gate  */
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate static int
3617c478bd9Sstevel@tonic-gate berval_from_file( const char *path, struct berval *bvp, int reporterrs )
3627c478bd9Sstevel@tonic-gate {
3637c478bd9Sstevel@tonic-gate     FILE	*fp;
3647c478bd9Sstevel@tonic-gate     long	rlen;
3657c478bd9Sstevel@tonic-gate     int		eof;
3667c478bd9Sstevel@tonic-gate #if defined( XP_WIN32 )
3677c478bd9Sstevel@tonic-gate     char	mode[20] = "r+b";
3687c478bd9Sstevel@tonic-gate #else
3697c478bd9Sstevel@tonic-gate     char	mode[20] = "r";
3707c478bd9Sstevel@tonic-gate #endif
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
3737c478bd9Sstevel@tonic-gate     if (( fp = fopen( path, mode )) == NULL ) {
3747c478bd9Sstevel@tonic-gate #else
3757c478bd9Sstevel@tonic-gate     if (( fp = ldaptool_open_file( path, mode )) == NULL ) {
3767c478bd9Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
3777c478bd9Sstevel@tonic-gate 	if ( reporterrs ) perror( path );
3787c478bd9Sstevel@tonic-gate 	return( LDAPTOOL_FILEURL_FILEIOERROR );
3797c478bd9Sstevel@tonic-gate     }
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate     if ( fseek( fp, 0L, SEEK_END ) != 0 ) {
3827c478bd9Sstevel@tonic-gate 	if ( reporterrs ) perror( path );
3837c478bd9Sstevel@tonic-gate 	fclose( fp );
3847c478bd9Sstevel@tonic-gate 	return( LDAPTOOL_FILEURL_FILEIOERROR );
3857c478bd9Sstevel@tonic-gate     }
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate     bvp->bv_len = ftell( fp );
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate     if (( bvp->bv_val = (char *)malloc( bvp->bv_len + 1 )) == NULL ) {
3907c478bd9Sstevel@tonic-gate 	if ( reporterrs ) perror( "malloc" );
3917c478bd9Sstevel@tonic-gate 	fclose( fp );
3927c478bd9Sstevel@tonic-gate 	return( LDAPTOOL_FILEURL_NOMEMORY );
3937c478bd9Sstevel@tonic-gate     }
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate     if ( fseek( fp, 0L, SEEK_SET ) != 0 ) {
3967c478bd9Sstevel@tonic-gate 	if ( reporterrs ) perror( path );
3977c478bd9Sstevel@tonic-gate 	fclose( fp );
3987c478bd9Sstevel@tonic-gate 	return( LDAPTOOL_FILEURL_FILEIOERROR );
3997c478bd9Sstevel@tonic-gate     }
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate     rlen = fread( bvp->bv_val, 1, bvp->bv_len, fp );
4027c478bd9Sstevel@tonic-gate     eof = feof( fp );
4037c478bd9Sstevel@tonic-gate     fclose( fp );
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate     if ( rlen != (long)bvp->bv_len ) {
4067c478bd9Sstevel@tonic-gate 	if ( reporterrs ) perror( path );
4077c478bd9Sstevel@tonic-gate 	free( bvp->bv_val );
4087c478bd9Sstevel@tonic-gate 	return( LDAPTOOL_FILEURL_FILEIOERROR );
4097c478bd9Sstevel@tonic-gate     }
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate     bvp->bv_val[ bvp->bv_len ] = '\0';
4127c478bd9Sstevel@tonic-gate     return( LDAPTOOL_FILEURL_SUCCESS );
4137c478bd9Sstevel@tonic-gate }
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate /*
4177c478bd9Sstevel@tonic-gate  * Return a non-zero value if the string s begins with prefix and zero if not.
4187c478bd9Sstevel@tonic-gate  */
4197c478bd9Sstevel@tonic-gate static int
4207c478bd9Sstevel@tonic-gate str_starts_with( const char *s, char *prefix )
4217c478bd9Sstevel@tonic-gate {
4227c478bd9Sstevel@tonic-gate     size_t	prefix_len;
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate     if ( s == NULL || prefix == NULL ) {
4257c478bd9Sstevel@tonic-gate 	return( 0 );
4267c478bd9Sstevel@tonic-gate     }
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate     prefix_len = strlen( prefix );
4297c478bd9Sstevel@tonic-gate     if ( strlen( s ) < prefix_len ) {
4307c478bd9Sstevel@tonic-gate 	return( 0 );
4317c478bd9Sstevel@tonic-gate     }
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate     return( strncmp( s, prefix, prefix_len ) == 0 );
4347c478bd9Sstevel@tonic-gate }
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate /*
4387c478bd9Sstevel@tonic-gate  * Remove URL hex escapes from s... done in place.  The basic concept for
4397c478bd9Sstevel@tonic-gate  * this routine is borrowed from the WWW library HTUnEscape() routine.
4407c478bd9Sstevel@tonic-gate  *
4417c478bd9Sstevel@tonic-gate  * A similar function called nsldapi_hex_unescape can be found in
4427c478bd9Sstevel@tonic-gate  * ../../libraries/libldap/unescape.c
4437c478bd9Sstevel@tonic-gate  */
4447c478bd9Sstevel@tonic-gate static void
4457c478bd9Sstevel@tonic-gate hex_unescape( char *s )
4467c478bd9Sstevel@tonic-gate {
4477c478bd9Sstevel@tonic-gate 	char	*p;
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	for ( p = s; *s != '\0'; ++s ) {
4507c478bd9Sstevel@tonic-gate 		if ( *s == '%' ) {
4517c478bd9Sstevel@tonic-gate 			if ( *++s != '\0' ) {
4527c478bd9Sstevel@tonic-gate 				*p = unhex( *s ) << 4;
4537c478bd9Sstevel@tonic-gate 			}
4547c478bd9Sstevel@tonic-gate 			if ( *++s != '\0' ) {
4557c478bd9Sstevel@tonic-gate 				*p++ += unhex( *s );
4567c478bd9Sstevel@tonic-gate 			}
4577c478bd9Sstevel@tonic-gate 		} else {
4587c478bd9Sstevel@tonic-gate 			*p++ = *s;
4597c478bd9Sstevel@tonic-gate 		}
4607c478bd9Sstevel@tonic-gate 	}
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 	*p = '\0';
4637c478bd9Sstevel@tonic-gate }
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate /*
4677c478bd9Sstevel@tonic-gate  * Return the integer equivalent of one hex digit (in c).
4687c478bd9Sstevel@tonic-gate  *
4697c478bd9Sstevel@tonic-gate  * A similar function can be found in ../../libraries/libldap/unescape.c
4707c478bd9Sstevel@tonic-gate  */
4717c478bd9Sstevel@tonic-gate static int
4727c478bd9Sstevel@tonic-gate unhex( char c )
4737c478bd9Sstevel@tonic-gate {
4747c478bd9Sstevel@tonic-gate 	return( c >= '0' && c <= '9' ? c - '0'
4757c478bd9Sstevel@tonic-gate 	    : c >= 'A' && c <= 'F' ? c - 'A' + 10
4767c478bd9Sstevel@tonic-gate 	    : c - 'a' + 10 );
4777c478bd9Sstevel@tonic-gate }
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate #define HREF_CHAR_ACCEPTABLE( c )	(( c >= '-' && c <= '9' ) ||	\
4817c478bd9Sstevel@tonic-gate 					 ( c >= '@' && c <= 'Z' ) ||	\
4827c478bd9Sstevel@tonic-gate 					 ( c == '_' ) ||		\
4837c478bd9Sstevel@tonic-gate 					 ( c >= 'a' && c <= 'z' ))
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate /*
4867c478bd9Sstevel@tonic-gate  * Like strcat(), except if any URL-special characters are found in s2
4877c478bd9Sstevel@tonic-gate  * they are escaped using the %HH convention and backslash characters are
4887c478bd9Sstevel@tonic-gate  * converted to forward slashes on Windows.
4897c478bd9Sstevel@tonic-gate  *
4907c478bd9Sstevel@tonic-gate  * Maximum space needed in s1 is 3 * strlen( s2 ) + 1.
4917c478bd9Sstevel@tonic-gate  *
4927c478bd9Sstevel@tonic-gate  * A similar function that does not convert the slashes called
4937c478bd9Sstevel@tonic-gate  * strcat_escaped() can be found in ../../libraries/libldap/tmplout.c
4947c478bd9Sstevel@tonic-gate  */
4957c478bd9Sstevel@tonic-gate static void
4967c478bd9Sstevel@tonic-gate strcpy_escaped_and_convert( char *s1, char *s2 )
4977c478bd9Sstevel@tonic-gate {
4987c478bd9Sstevel@tonic-gate     char	*p, *q;
4997c478bd9Sstevel@tonic-gate     char	*hexdig = "0123456789ABCDEF";
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate     p = s1 + strlen( s1 );
5027c478bd9Sstevel@tonic-gate     for ( q = s2; *q != '\0'; ++q ) {
5037c478bd9Sstevel@tonic-gate #ifdef _WINDOWS
5047c478bd9Sstevel@tonic-gate 	if ( *q == '\\' ) {
5057c478bd9Sstevel@tonic-gate                 *p++ = '/';
5067c478bd9Sstevel@tonic-gate 	} else
5077c478bd9Sstevel@tonic-gate #endif /* _WINDOWS */
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	if ( HREF_CHAR_ACCEPTABLE( *q )) {
5107c478bd9Sstevel@tonic-gate 	    *p++ = *q;
5117c478bd9Sstevel@tonic-gate 	} else {
5127c478bd9Sstevel@tonic-gate 	    *p++ = '%';
5137c478bd9Sstevel@tonic-gate 	    *p++ = hexdig[ 0x0F & ((*(unsigned char*)q) >> 4) ];
5147c478bd9Sstevel@tonic-gate 	    *p++ = hexdig[ 0x0F & *q ];
5157c478bd9Sstevel@tonic-gate 	}
5167c478bd9Sstevel@tonic-gate     }
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate     *p = '\0';
5197c478bd9Sstevel@tonic-gate }
520