8
8
* Author: Andreas Pflug <pgadmin@pse-consulting.de>
9
9
*
10
10
* 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 $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
@@ -60,43 +60,47 @@ typedef struct
60
60
*/
61
61
62
62
/*
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.
65
67
*/
66
68
static char *
67
- absClusterPath (text * arg , bool logAllowed )
69
+ convert_and_check_filename (text * arg , bool logAllowed )
68
70
{
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' ;
72
76
73
- filename = palloc (len + 1 );
74
- memcpy (filename , VARDATA (arg ), len );
75
- filename [len ] = 0 ;
77
+ canonicalize_path (filename ); /* filename can change length here */
76
78
77
- if (strstr (filename , ".." ) != NULL )
79
+ /* Disallow ".." in the path */
80
+ if (path_contains_parent_reference (filename ))
78
81
ereport (ERROR ,
79
82
(errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
80
- (errmsg ("No .. allowed in filenames " ))));
83
+ (errmsg ("reference to parent directory (\"..\") not allowed " ))));
81
84
82
85
if (is_absolute_path (filename ))
83
86
{
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 ))
85
94
return filename ;
86
- if (strncmp (filename , DataDir , dlen ))
87
- ereport (ERROR ,
88
- (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
89
- (errmsg ("Absolute path not allowed" ))));
90
95
91
- return filename ;
96
+ ereport (ERROR ,
97
+ (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
98
+ (errmsg ("absolute path not allowed" ))));
99
+ return NULL ; /* keep compiler quiet */
92
100
}
93
101
else
94
102
{
95
- char * absname = palloc (dlen + len + 2 );
96
-
97
- sprintf (absname , "%s/%s" , DataDir , filename );
98
- pfree (filename );
99
- return absname ;
103
+ return filename ;
100
104
}
101
105
}
102
106
@@ -129,29 +133,28 @@ pg_file_write(PG_FUNCTION_ARGS)
129
133
130
134
requireSuperuser ();
131
135
132
- filename = absClusterPath (PG_GETARG_TEXT_P (0 ), false);
136
+ filename = convert_and_check_filename (PG_GETARG_TEXT_P (0 ), false);
133
137
data = PG_GETARG_TEXT_P (1 );
134
138
135
- if (PG_ARGISNULL ( 2 ) || !PG_GETARG_BOOL (2 ))
139
+ if (!PG_GETARG_BOOL (2 ))
136
140
{
137
141
struct stat fst ;
138
142
139
143
if (stat (filename , & fst ) >= 0 )
140
144
ereport (ERROR ,
141
145
(ERRCODE_DUPLICATE_FILE ,
142
- errmsg ("file %s exists" , filename )));
146
+ errmsg ("file \"%s\" exists" , filename )));
143
147
144
148
f = fopen (filename , "wb" );
145
149
}
146
150
else
147
151
f = fopen (filename , "ab" );
148
152
149
153
if (!f )
150
- {
151
154
ereport (ERROR ,
152
155
(errcode_for_file_access (),
153
- errmsg ("could open file %s for writing: %m" , filename )));
154
- }
156
+ errmsg ("could not open file \"%s\" for writing: %m" ,
157
+ filename )));
155
158
156
159
if (VARSIZE (data ) != 0 )
157
160
{
@@ -160,7 +163,7 @@ pg_file_write(PG_FUNCTION_ARGS)
160
163
if (count != VARSIZE (data ) - VARHDRSZ )
161
164
ereport (ERROR ,
162
165
(errcode_for_file_access (),
163
- errmsg ("error writing file %s : %m" , filename )));
166
+ errmsg ("could not write file \"%s\" : %m" , filename )));
164
167
}
165
168
fclose (f );
166
169
@@ -181,18 +184,18 @@ pg_file_rename(PG_FUNCTION_ARGS)
181
184
if (PG_ARGISNULL (0 ) || PG_ARGISNULL (1 ))
182
185
PG_RETURN_NULL ();
183
186
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);
186
189
if (PG_ARGISNULL (2 ))
187
190
fn3 = 0 ;
188
191
else
189
- fn3 = absClusterPath (PG_GETARG_TEXT_P (2 ), false);
192
+ fn3 = convert_and_check_filename (PG_GETARG_TEXT_P (2 ), false);
190
193
191
194
if (access (fn1 , W_OK ) < 0 )
192
195
{
193
196
ereport (WARNING ,
194
197
(errcode_for_file_access (),
195
- errmsg ("file %s not accessible: %m" , fn1 )));
198
+ errmsg ("file \"%s\" is not accessible: %m" , fn1 )));
196
199
197
200
PG_RETURN_BOOL (false);
198
201
}
@@ -201,18 +204,18 @@ pg_file_rename(PG_FUNCTION_ARGS)
201
204
{
202
205
ereport (WARNING ,
203
206
(errcode_for_file_access (),
204
- errmsg ("file %s not accessible: %m" , fn2 )));
207
+ errmsg ("file \"%s\" is not accessible: %m" , fn2 )));
205
208
206
209
PG_RETURN_BOOL (false);
207
210
}
208
211
209
-
210
212
rc = access (fn3 ? fn3 : fn2 , 2 );
211
213
if (rc >= 0 || errno != ENOENT )
212
214
{
213
215
ereport (ERROR ,
214
216
(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 )));
216
219
}
217
220
218
221
if (fn3 )
@@ -221,37 +224,37 @@ pg_file_rename(PG_FUNCTION_ARGS)
221
224
{
222
225
ereport (ERROR ,
223
226
(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 )));
225
229
}
226
230
if (rename (fn1 , fn2 ) != 0 )
227
231
{
228
232
ereport (WARNING ,
229
233
(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 )));
231
236
232
237
if (rename (fn3 , fn2 ) != 0 )
233
238
{
234
239
ereport (ERROR ,
235
240
(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 )));
237
243
}
238
244
else
239
245
{
240
246
ereport (ERROR ,
241
247
(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 )));
244
250
}
245
251
}
246
252
}
247
253
else if (rename (fn1 , fn2 ) != 0 )
248
254
{
249
- ereport (WARNING ,
250
- (errcode_for_file_access (),
251
- errmsg ("renaming %s to %s %m" , fn1 , fn2 )));
252
255
ereport (ERROR ,
253
256
(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 )));
255
258
}
256
259
257
260
PG_RETURN_BOOL (true);
@@ -265,7 +268,7 @@ pg_file_unlink(PG_FUNCTION_ARGS)
265
268
266
269
requireSuperuser ();
267
270
268
- filename = absClusterPath (PG_GETARG_TEXT_P (0 ), false);
271
+ filename = convert_and_check_filename (PG_GETARG_TEXT_P (0 ), false);
269
272
270
273
if (access (filename , W_OK ) < 0 )
271
274
{
@@ -274,15 +277,14 @@ pg_file_unlink(PG_FUNCTION_ARGS)
274
277
else
275
278
ereport (ERROR ,
276
279
(errcode_for_file_access (),
277
- errmsg ("file %s not accessible: %m" , filename )));
278
-
280
+ errmsg ("file \"%s\" is not accessible: %m" , filename )));
279
281
}
280
282
281
283
if (unlink (filename ) < 0 )
282
284
{
283
285
ereport (WARNING ,
284
286
(errcode_for_file_access (),
285
- errmsg ("could not unlink file %s : %m" , filename )));
287
+ errmsg ("could not unlink file \"%s\" : %m" , filename )));
286
288
287
289
PG_RETURN_BOOL (false);
288
290
}
@@ -316,13 +318,7 @@ pg_logdir_ls(PG_FUNCTION_ARGS)
316
318
oldcontext = MemoryContextSwitchTo (funcctx -> multi_call_memory_ctx );
317
319
318
320
fctx = 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
+
326
322
tupdesc = CreateTemplateTupleDesc (2 , false);
327
323
TupleDescInitEntry (tupdesc , (AttrNumber ) 1 , "starttime" ,
328
324
TIMESTAMPOID , -1 , 0 );
@@ -331,12 +327,14 @@ pg_logdir_ls(PG_FUNCTION_ARGS)
331
327
332
328
funcctx -> attinmeta = TupleDescGetAttInMetadata (tupdesc );
333
329
330
+ fctx -> location = pstrdup (Log_directory );
334
331
fctx -> dirdesc = AllocateDir (fctx -> location );
335
332
336
333
if (!fctx -> dirdesc )
337
334
ereport (ERROR ,
338
335
(errcode_for_file_access (),
339
- errmsg ("%s is not browsable: %m" , fctx -> location )));
336
+ errmsg ("could not read directory \"%s\": %m" ,
337
+ fctx -> location )));
340
338
341
339
funcctx -> user_fctx = fctx ;
342
340
MemoryContextSwitchTo (oldcontext );
0 commit comments