xref: /titanic_53/usr/src/cmd/ldap/common/fileurl.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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