88 * Author: Andreas Pflug <pgadmin@pse-consulting.de>
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/contrib/adminpack/adminpack.c,v 1.7 2006/10/20 00:59:03 tgl Exp $
11+ * $PostgreSQL: pgsql/contrib/adminpack/adminpack.c,v 1.8 2006/11/06 03:06:40 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -60,43 +60,47 @@ typedef struct
6060 */
6161
6262/*
63- * Return an absolute path. Argument may be absolute or
64- * relative to the DataDir.
63+ * Convert a "text" filename argument to C string, and check it's allowable.
64+ *
65+ * Filename may be absolute or relative to the DataDir, but we only allow
66+ * absolute paths that match DataDir or Log_directory.
6567 */
6668static char *
67- absClusterPath (text * arg ,bool logAllowed )
69+ convert_and_check_filename (text * arg ,bool logAllowed )
6870{
69- char * filename ;
70- int len = VARSIZE (arg )- VARHDRSZ ;
71- int dlen = strlen (DataDir );
71+ int input_len = VARSIZE (arg )- VARHDRSZ ;
72+ char * filename = palloc (input_len + 1 );
73+
74+ memcpy (filename ,VARDATA (arg ),input_len );
75+ filename [input_len ]= '\0' ;
7276
73- filename = palloc (len + 1 );
74- memcpy (filename ,VARDATA (arg ),len );
75- filename [len ]= 0 ;
77+ canonicalize_path (filename );/* filename can change length here */
7678
77- if (strstr (filename ,".." )!= NULL )
79+ /* Disallow ".." in the path */
80+ if (path_contains_parent_reference (filename ))
7881ereport (ERROR ,
7982(errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
80- (errmsg ("No .. allowed in filenames " ))));
83+ (errmsg ("reference to parent directory (\"..\") not allowed " ))));
8184
8285if (is_absolute_path (filename ))
8386{
84- if (logAllowed && !strncmp (filename ,Log_directory ,strlen (Log_directory )))
87+ /* Allow absolute references within DataDir */
88+ if (path_is_prefix_of_path (DataDir ,filename ))
89+ return filename ;
90+ /* The log directory might be outside our datadir, but allow it */
91+ if (logAllowed &&
92+ is_absolute_path (Log_directory )&&
93+ path_is_prefix_of_path (Log_directory ,filename ))
8594return filename ;
86- if (strncmp (filename ,DataDir ,dlen ))
87- ereport (ERROR ,
88- (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
89- (errmsg ("Absolute path not allowed" ))));
9095
91- return filename ;
96+ ereport (ERROR ,
97+ (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
98+ (errmsg ("absolute path not allowed" ))));
99+ return NULL ;/* keep compiler quiet */
92100}
93101else
94102{
95- char * absname = palloc (dlen + len + 2 );
96-
97- sprintf (absname ,"%s/%s" ,DataDir ,filename );
98- pfree (filename );
99- return absname ;
103+ return filename ;
100104}
101105}
102106
@@ -129,29 +133,28 @@ pg_file_write(PG_FUNCTION_ARGS)
129133
130134requireSuperuser ();
131135
132- filename = absClusterPath (PG_GETARG_TEXT_P (0 ), false);
136+ filename = convert_and_check_filename (PG_GETARG_TEXT_P (0 ), false);
133137data = PG_GETARG_TEXT_P (1 );
134138
135- if (PG_ARGISNULL ( 2 ) || !PG_GETARG_BOOL (2 ))
139+ if (!PG_GETARG_BOOL (2 ))
136140{
137141struct stat fst ;
138142
139143if (stat (filename ,& fst ) >=0 )
140144ereport (ERROR ,
141145(ERRCODE_DUPLICATE_FILE ,
142- errmsg ("file%s exists" ,filename )));
146+ errmsg ("file\"%s\" exists" ,filename )));
143147
144148f = fopen (filename ,"wb" );
145149}
146150else
147151f = fopen (filename ,"ab" );
148152
149153if (!f )
150- {
151154ereport (ERROR ,
152155(errcode_for_file_access (),
153- errmsg ("could open file%s for writing: %m" ,filename )));
154- }
156+ errmsg ("couldnot open file\"%s\" for writing: %m" ,
157+ filename )));
155158
156159if (VARSIZE (data )!= 0 )
157160{
@@ -160,7 +163,7 @@ pg_file_write(PG_FUNCTION_ARGS)
160163if (count != VARSIZE (data )- VARHDRSZ )
161164ereport (ERROR ,
162165(errcode_for_file_access (),
163- errmsg ("error writing file%s : %m" ,filename )));
166+ errmsg ("could not write file\"%s\" : %m" ,filename )));
164167}
165168fclose (f );
166169
@@ -181,18 +184,18 @@ pg_file_rename(PG_FUNCTION_ARGS)
181184if (PG_ARGISNULL (0 )|| PG_ARGISNULL (1 ))
182185PG_RETURN_NULL ();
183186
184- fn1 = absClusterPath (PG_GETARG_TEXT_P (0 ), false);
185- fn2 = absClusterPath (PG_GETARG_TEXT_P (1 ), false);
187+ fn1 = convert_and_check_filename (PG_GETARG_TEXT_P (0 ), false);
188+ fn2 = convert_and_check_filename (PG_GETARG_TEXT_P (1 ), false);
186189if (PG_ARGISNULL (2 ))
187190fn3 = 0 ;
188191else
189- fn3 = absClusterPath (PG_GETARG_TEXT_P (2 ), false);
192+ fn3 = convert_and_check_filename (PG_GETARG_TEXT_P (2 ), false);
190193
191194if (access (fn1 ,W_OK )< 0 )
192195{
193196ereport (WARNING ,
194197(errcode_for_file_access (),
195- errmsg ("file%s not accessible: %m" ,fn1 )));
198+ errmsg ("file\"%s\" is not accessible: %m" ,fn1 )));
196199
197200PG_RETURN_BOOL (false);
198201}
@@ -201,18 +204,18 @@ pg_file_rename(PG_FUNCTION_ARGS)
201204{
202205ereport (WARNING ,
203206(errcode_for_file_access (),
204- errmsg ("file%s not accessible: %m" ,fn2 )));
207+ errmsg ("file\"%s\" is not accessible: %m" ,fn2 )));
205208
206209PG_RETURN_BOOL (false);
207210}
208211
209-
210212rc = access (fn3 ?fn3 :fn2 ,2 );
211213if (rc >=0 || errno != ENOENT )
212214{
213215ereport (ERROR ,
214216(ERRCODE_DUPLICATE_FILE ,
215- errmsg ("cannot rename to target file %s" ,fn3 ?fn3 :fn2 )));
217+ errmsg ("cannot rename to target file \"%s\"" ,
218+ fn3 ?fn3 :fn2 )));
216219}
217220
218221if (fn3 )
@@ -221,37 +224,37 @@ pg_file_rename(PG_FUNCTION_ARGS)
221224{
222225ereport (ERROR ,
223226(errcode_for_file_access (),
224- errmsg ("could not rename %s to %s: %m" ,fn2 ,fn3 )));
227+ errmsg ("could not rename \"%s\" to \"%s\": %m" ,
228+ fn2 ,fn3 )));
225229}
226230if (rename (fn1 ,fn2 )!= 0 )
227231{
228232ereport (WARNING ,
229233(errcode_for_file_access (),
230- errmsg ("could not rename %s to %s: %m" ,fn1 ,fn2 )));
234+ errmsg ("could not rename \"%s\" to \"%s\": %m" ,
235+ fn1 ,fn2 )));
231236
232237if (rename (fn3 ,fn2 )!= 0 )
233238{
234239ereport (ERROR ,
235240(errcode_for_file_access (),
236- errmsg ("could not rename %s back to %s: %m" ,fn3 ,fn2 )));
241+ errmsg ("could not rename \"%s\" back to \"%s\": %m" ,
242+ fn3 ,fn2 )));
237243}
238244else
239245{
240246ereport (ERROR ,
241247(ERRCODE_UNDEFINED_FILE ,
242- errmsg ("renaming%s to%s was reverted" ,fn2 , fn3 )));
243-
248+ errmsg ("renaming\"%s\" to\"%s\" was reverted" ,
249+ fn2 , fn3 )));
244250}
245251}
246252}
247253else if (rename (fn1 ,fn2 )!= 0 )
248254{
249- ereport (WARNING ,
250- (errcode_for_file_access (),
251- errmsg ("renaming %s to %s %m" ,fn1 ,fn2 )));
252255ereport (ERROR ,
253256(errcode_for_file_access (),
254- errmsg ("could not rename%s to%s : %m" ,fn1 ,fn2 )));
257+ errmsg ("could not rename\"%s\" to\"%s\" : %m" ,fn1 ,fn2 )));
255258}
256259
257260PG_RETURN_BOOL (true);
@@ -265,7 +268,7 @@ pg_file_unlink(PG_FUNCTION_ARGS)
265268
266269requireSuperuser ();
267270
268- filename = absClusterPath (PG_GETARG_TEXT_P (0 ), false);
271+ filename = convert_and_check_filename (PG_GETARG_TEXT_P (0 ), false);
269272
270273if (access (filename ,W_OK )< 0 )
271274{
@@ -274,15 +277,14 @@ pg_file_unlink(PG_FUNCTION_ARGS)
274277else
275278ereport (ERROR ,
276279(errcode_for_file_access (),
277- errmsg ("file %s not accessible: %m" ,filename )));
278-
280+ errmsg ("file \"%s\" is not accessible: %m" ,filename )));
279281}
280282
281283if (unlink (filename )< 0 )
282284{
283285ereport (WARNING ,
284286(errcode_for_file_access (),
285- errmsg ("could not unlink file%s : %m" ,filename )));
287+ errmsg ("could not unlink file\"%s\" : %m" ,filename )));
286288
287289PG_RETURN_BOOL (false);
288290}
@@ -316,13 +318,7 @@ pg_logdir_ls(PG_FUNCTION_ARGS)
316318oldcontext = MemoryContextSwitchTo (funcctx -> multi_call_memory_ctx );
317319
318320fctx = palloc (sizeof (directory_fctx ));
319- if (is_absolute_path (Log_directory ))
320- fctx -> location = pstrdup (Log_directory );
321- else
322- {
323- fctx -> location = palloc (strlen (DataDir )+ strlen (Log_directory )+ 2 );
324- sprintf (fctx -> location ,"%s/%s" ,DataDir ,Log_directory );
325- }
321+
326322tupdesc = CreateTemplateTupleDesc (2 , false);
327323TupleDescInitEntry (tupdesc , (AttrNumber )1 ,"starttime" ,
328324TIMESTAMPOID ,-1 ,0 );
@@ -331,12 +327,14 @@ pg_logdir_ls(PG_FUNCTION_ARGS)
331327
332328funcctx -> attinmeta = TupleDescGetAttInMetadata (tupdesc );
333329
330+ fctx -> location = pstrdup (Log_directory );
334331fctx -> dirdesc = AllocateDir (fctx -> location );
335332
336333if (!fctx -> dirdesc )
337334ereport (ERROR ,
338335(errcode_for_file_access (),
339- errmsg ("%s is not browsable: %m" ,fctx -> location )));
336+ errmsg ("could not read directory \"%s\": %m" ,
337+ fctx -> location )));
340338
341339funcctx -> user_fctx = fctx ;
342340MemoryContextSwitchTo (oldcontext );