mirror of
https://github.com/postgres/postgres.git
synced 2025-07-08 11:42:09 +03:00
Allow only superuser to do backend copy.
This commit is contained in:
@ -6,99 +6,92 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.10 1996/10/23 07:39:53 scrappy Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.11 1996/11/02 02:01:47 bryanh Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include <postgres.h>
|
||||||
|
|
||||||
#include "catalog/pg_attribute.h"
|
#include <catalog/pg_attribute.h>
|
||||||
#include "access/attnum.h"
|
#include <access/attnum.h>
|
||||||
#include "nodes/pg_list.h"
|
#include <nodes/pg_list.h>
|
||||||
#include "access/tupdesc.h"
|
#include <access/tupdesc.h>
|
||||||
#include "storage/fd.h"
|
#include <storage/fd.h>
|
||||||
#include "catalog/pg_am.h"
|
#include <catalog/pg_am.h>
|
||||||
#include "catalog/pg_class.h"
|
#include <catalog/pg_class.h>
|
||||||
#include "nodes/nodes.h"
|
#include <nodes/nodes.h>
|
||||||
#include "rewrite/prs2lock.h"
|
#include <rewrite/prs2lock.h>
|
||||||
#include "access/skey.h"
|
#include <access/skey.h>
|
||||||
#include "access/strat.h"
|
#include <access/strat.h>
|
||||||
#include "utils/rel.h"
|
#include <utils/rel.h>
|
||||||
|
|
||||||
#include "storage/block.h"
|
#include <storage/block.h>
|
||||||
#include "storage/off.h"
|
#include <storage/off.h>
|
||||||
#include "storage/itemptr.h"
|
#include <storage/itemptr.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "utils/nabstime.h"
|
#include <utils/nabstime.h>
|
||||||
#include "access/htup.h"
|
#include <access/htup.h>
|
||||||
|
|
||||||
#include "utils/tqual.h"
|
#include <utils/tqual.h>
|
||||||
#include "storage/buf.h"
|
#include <storage/buf.h>
|
||||||
#include "access/relscan.h"
|
#include <access/relscan.h>
|
||||||
#include "access/heapam.h"
|
#include <access/heapam.h>
|
||||||
|
|
||||||
#include "access/itup.h"
|
#include <access/itup.h>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "tcop/dest.h"
|
#include <tcop/dest.h>
|
||||||
|
|
||||||
#include "fmgr.h"
|
#include <fmgr.h>
|
||||||
|
|
||||||
#include "utils/palloc.h"
|
#include <utils/palloc.h>
|
||||||
|
|
||||||
#include "miscadmin.h"
|
#include <miscadmin.h>
|
||||||
|
|
||||||
#include "utils/geo-decls.h"
|
#include <utils/geo-decls.h>
|
||||||
#include "utils/builtins.h"
|
#include <utils/builtins.h>
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include "access/funcindex.h"
|
#include <access/funcindex.h>
|
||||||
|
|
||||||
#include "catalog/pg_index.h"
|
#include <catalog/pg_index.h>
|
||||||
|
|
||||||
#include "utils/syscache.h"
|
#include <utils/syscache.h>
|
||||||
|
|
||||||
#include "nodes/params.h"
|
#include <nodes/params.h>
|
||||||
#include "access/sdir.h"
|
#include <access/sdir.h>
|
||||||
#include "executor/hashjoin.h"
|
#include <executor/hashjoin.h>
|
||||||
#include "nodes/primnodes.h"
|
#include <nodes/primnodes.h>
|
||||||
#include "nodes/memnodes.h"
|
#include <nodes/memnodes.h>
|
||||||
#include "executor/tuptable.h"
|
#include <executor/tuptable.h>
|
||||||
#include "nodes/execnodes.h"
|
#include <nodes/execnodes.h>
|
||||||
|
|
||||||
#include "utils/memutils.h"
|
#include <utils/memutils.h>
|
||||||
|
|
||||||
#include "nodes/plannodes.h"
|
#include <nodes/plannodes.h>
|
||||||
#include "nodes/parsenodes.h"
|
#include <nodes/parsenodes.h>
|
||||||
#include "executor/execdesc.h"
|
#include <executor/execdesc.h>
|
||||||
#include "executor/executor.h"
|
#include <executor/executor.h>
|
||||||
|
|
||||||
#include "storage/ipc.h"
|
#include <storage/ipc.h>
|
||||||
#include "storage/bufmgr.h"
|
#include <storage/bufmgr.h>
|
||||||
#include "access/transam.h"
|
#include <access/transam.h>
|
||||||
|
|
||||||
#include "catalog/index.h"
|
#include <catalog/index.h>
|
||||||
|
|
||||||
#include "access/genam.h"
|
#include <access/genam.h>
|
||||||
|
|
||||||
#include "catalog/pg_type.h"
|
#include <catalog/pg_type.h>
|
||||||
|
|
||||||
|
#include <catalog/catname.h>
|
||||||
|
|
||||||
#include "catalog/catname.h"
|
|
||||||
|
|
||||||
#define ISOCTAL(c) (((c) >= '0') && ((c) <= '7'))
|
#define ISOCTAL(c) (((c) >= '0') && ((c) <= '7'))
|
||||||
#define VALUE(c) ((c) - '0')
|
#define VALUE(c) ((c) - '0')
|
||||||
|
|
||||||
/*
|
|
||||||
* New copy code.
|
|
||||||
*
|
|
||||||
* This code "knows" the following about tuples:
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
static bool reading_from_input = false;
|
|
||||||
|
|
||||||
/* non-export function prototypes */
|
/* non-export function prototypes */
|
||||||
static void CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim);
|
static void CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim);
|
||||||
@ -116,53 +109,104 @@ static int CountTuples(Relation relation);
|
|||||||
|
|
||||||
extern FILE *Pfout, *Pfin;
|
extern FILE *Pfout, *Pfin;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DoCopy executes a the SQL COPY statement.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe, char *filename,
|
DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
|
||||||
char *delim)
|
char *filename, char *delim) {
|
||||||
{
|
/*----------------------------------------------------------------------------
|
||||||
|
Either unload or reload contents of class <relname>, depending on <from>.
|
||||||
|
|
||||||
|
If <pipe> is false, transfer is between the class and the file named
|
||||||
|
<filename>. Otherwise, transfer is between the class and our regular
|
||||||
|
input/output stream. The latter could be either stdin/stdout or a
|
||||||
|
socket, depending on whether we're running under Postmaster control.
|
||||||
|
|
||||||
|
Iff <binary>, unload or reload in the binary format, as opposed to the
|
||||||
|
more wasteful but more robust and portable text format.
|
||||||
|
|
||||||
|
If in the text format, delimit columns with delimiter <delim>.
|
||||||
|
|
||||||
|
When loading in the text format from an input stream (as opposed to
|
||||||
|
a file), recognize a "." on a line by itself as EOF. Also recognize
|
||||||
|
a stream EOF. When unloading in the text format to an output stream,
|
||||||
|
write a "." on a line by itself at the end of the data.
|
||||||
|
|
||||||
|
Iff <oids>, unload or reload the format that includes OID information.
|
||||||
|
|
||||||
|
Do not allow a Postgres user without superuser privilege to read from
|
||||||
|
or write to a file.
|
||||||
|
|
||||||
|
Do not allow the copy if user doesn't have proper permission to access
|
||||||
|
the class.
|
||||||
|
----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
Relation rel;
|
Relation rel;
|
||||||
reading_from_input = pipe;
|
extern char *UserName; /* defined in global.c */
|
||||||
|
const AclMode required_access = from ? ACL_WR : ACL_RD;
|
||||||
|
|
||||||
rel = heap_openr(relname);
|
rel = heap_openr(relname);
|
||||||
if (rel == NULL) elog(WARN, "Copy: class %s does not exist.", relname);
|
if (rel == NULL) elog(WARN, "COPY command failed. Class %s "
|
||||||
|
"does not exist.", relname);
|
||||||
|
|
||||||
if (from) {
|
if (!pg_aclcheck(relname, UserName, required_access))
|
||||||
if (pipe && IsUnderPostmaster) ReceiveCopyBegin();
|
elog(WARN, "%s %s", relname, ACL_NO_PRIV_WARNING);
|
||||||
|
/* Above should not return */
|
||||||
|
else if (!superuser() && !pipe)
|
||||||
|
elog(WARN, "You must have Postgres superuser privilege to do a COPY "
|
||||||
|
"directly to or from a file. Anyone can COPY to stdout or "
|
||||||
|
"from stdin. Psql's \\copy command also works for anyone.");
|
||||||
|
/* Above should not return. */
|
||||||
|
else {
|
||||||
|
if (from) { /* copy from file to database */
|
||||||
|
if (pipe) {
|
||||||
if (IsUnderPostmaster) {
|
if (IsUnderPostmaster) {
|
||||||
fp = pipe ? Pfin : fopen(filename, "r");
|
ReceiveCopyBegin();
|
||||||
}else {
|
fp = Pfin;
|
||||||
fp = pipe ? stdin : fopen(filename, "r");
|
} else fp = stdin;
|
||||||
}
|
} else {
|
||||||
if (fp == NULL) {
|
fp = fopen(filename, "r");
|
||||||
elog(WARN, "COPY: file %s could not be open for reading", filename);
|
if (fp == NULL)
|
||||||
|
elog(WARN, "COPY command, running in backend with "
|
||||||
|
"effective uid %d, could not open file '%s' for ",
|
||||||
|
"reading. Errno = %s (%d).",
|
||||||
|
geteuid(), filename, strerror(errno), errno);
|
||||||
|
/* Above should not return */
|
||||||
}
|
}
|
||||||
CopyFrom(rel, binary, oids, fp, delim);
|
CopyFrom(rel, binary, oids, fp, delim);
|
||||||
}else {
|
} else { /* copy from database to file */
|
||||||
|
if (pipe) {
|
||||||
mode_t oumask = umask((mode_t) 0);
|
|
||||||
|
|
||||||
if (pipe && IsUnderPostmaster) SendCopyBegin();
|
|
||||||
if (IsUnderPostmaster) {
|
if (IsUnderPostmaster) {
|
||||||
fp = pipe ? Pfout : fopen(filename, "w");
|
SendCopyBegin();
|
||||||
|
fp = Pfout;
|
||||||
}else {
|
} else fp = stdout;
|
||||||
fp = pipe ? stdout : fopen(filename, "w");
|
} else {
|
||||||
}
|
mode_t oumask; /* Pre-existing umask value */
|
||||||
|
(void) umask((mode_t) 0);
|
||||||
|
fp = fopen(filename, "w");
|
||||||
(void) umask(oumask);
|
(void) umask(oumask);
|
||||||
if (fp == NULL) {
|
if (fp == NULL)
|
||||||
elog(WARN, "COPY: file %s could not be open for writing", filename);
|
elog(WARN, "COPY command, running in backend with "
|
||||||
|
"effective uid %d, could not open file '%s' for ",
|
||||||
|
"writing. Errno = %s (%d).",
|
||||||
|
geteuid(), filename, strerror(errno), errno);
|
||||||
|
/* Above should not return */
|
||||||
}
|
}
|
||||||
CopyTo(rel, binary, oids, fp, delim);
|
CopyTo(rel, binary, oids, fp, delim);
|
||||||
}
|
}
|
||||||
if (!pipe) {
|
if (!pipe) fclose(fp);
|
||||||
fclose(fp);
|
else if (!from && !binary) {
|
||||||
}else if (!from && !binary) {
|
|
||||||
fputs("\\.\n", fp);
|
fputs("\\.\n", fp);
|
||||||
if (IsUnderPostmaster) fflush(Pfout);
|
if (IsUnderPostmaster) fflush(Pfout);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
|
CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
|
||||||
{
|
{
|
||||||
@ -176,8 +220,14 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
|
|||||||
Oid out_func_oid;
|
Oid out_func_oid;
|
||||||
Oid *elements;
|
Oid *elements;
|
||||||
Datum value;
|
Datum value;
|
||||||
bool isnull = (bool) true;
|
bool isnull; /* The attribute we are copying is null */
|
||||||
char *nulls = NULL;
|
char *nulls;
|
||||||
|
/* <nulls> is a (dynamically allocated) array with one character
|
||||||
|
per attribute in the instance being copied. nulls[I-1] is
|
||||||
|
'n' if Attribute Number I is null, and ' ' otherwise.
|
||||||
|
|
||||||
|
<nulls> is meaningful only if we are doing a binary copy.
|
||||||
|
*/
|
||||||
char *string;
|
char *string;
|
||||||
int32 ntuples;
|
int32 ntuples;
|
||||||
TupleDesc tupDesc;
|
TupleDesc tupDesc;
|
||||||
@ -196,6 +246,7 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
|
|||||||
fmgr_info(out_func_oid, &out_functions[i], &dummy);
|
fmgr_info(out_func_oid, &out_functions[i], &dummy);
|
||||||
elements[i] = GetTypeElement(attr[i]->atttypid);
|
elements[i] = GetTypeElement(attr[i]->atttypid);
|
||||||
}
|
}
|
||||||
|
nulls = NULL; /* meaningless, but compiler doesn't know that */
|
||||||
}else {
|
}else {
|
||||||
elements = NULL;
|
elements = NULL;
|
||||||
out_functions = NULL;
|
out_functions = NULL;
|
||||||
@ -608,6 +659,8 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
|
|||||||
heap_close(rel);
|
heap_close(rel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static Oid
|
static Oid
|
||||||
GetOutputFunction(Oid type)
|
GetOutputFunction(Oid type)
|
||||||
{
|
{
|
||||||
@ -879,7 +932,7 @@ CopyAttributeOut(FILE *fp, char *string, char *delim)
|
|||||||
if (len && (string[0] == '{') && (string[len-1] == '}'))
|
if (len && (string[0] == '{') && (string[len-1] == '}'))
|
||||||
is_array = true;
|
is_array = true;
|
||||||
|
|
||||||
for ( ; (c = *string) != 0; string++) {
|
for ( ; (c = *string) != '\0'; string++) {
|
||||||
if (c == delim[0] || c == '\n' ||
|
if (c == delim[0] || c == '\n' ||
|
||||||
(c == '\\' && !is_array))
|
(c == '\\' && !is_array))
|
||||||
fputc('\\', fp);
|
fputc('\\', fp);
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.3 1996/10/31 09:07:41 bryanh Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.4 1996/11/02 02:01:48 bryanh Exp $
|
||||||
*
|
*
|
||||||
* DESCRIPTION
|
* DESCRIPTION
|
||||||
* The "DefineFoo" routines take the parse tree and pick out the
|
* The "DefineFoo" routines take the parse tree and pick out the
|
||||||
@ -34,19 +34,16 @@
|
|||||||
*/
|
*/
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#include <postgres.h>
|
#include <postgres.h>
|
||||||
|
|
||||||
#include <access/heapam.h>
|
#include <access/heapam.h>
|
||||||
#include <access/htup.h>
|
|
||||||
#include <utils/tqual.h>
|
#include <utils/tqual.h>
|
||||||
#include <catalog/catname.h>
|
#include <catalog/catname.h>
|
||||||
#include <catalog/pg_aggregate.h>
|
#include <catalog/pg_aggregate.h>
|
||||||
#include <catalog/pg_operator.h>
|
#include <catalog/pg_operator.h>
|
||||||
#include <catalog/pg_proc.h>
|
#include <catalog/pg_proc.h>
|
||||||
#include <catalog/pg_type.h>
|
#include <catalog/pg_type.h>
|
||||||
#include <catalog/pg_user.h> /* superuser() uses this */
|
|
||||||
#include <utils/syscache.h>
|
#include <utils/syscache.h>
|
||||||
#include <nodes/pg_list.h>
|
#include <nodes/pg_list.h>
|
||||||
#include <nodes/parsenodes.h>
|
#include <nodes/parsenodes.h>
|
||||||
@ -66,24 +63,6 @@ static int defGetTypeLength(DefElem *def);
|
|||||||
#define DEFAULT_TYPDELIM ','
|
#define DEFAULT_TYPDELIM ','
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
superuser(void) {
|
|
||||||
/*--------------------------------------------------------------------------
|
|
||||||
The Postgres user running this command has Postgres superuser
|
|
||||||
privileges.
|
|
||||||
--------------------------------------------------------------------------*/
|
|
||||||
HeapTuple utup;
|
|
||||||
char *userName;
|
|
||||||
|
|
||||||
userName = GetPgUserName();
|
|
||||||
utup = SearchSysCacheTuple(USENAME, PointerGetDatum(userName),
|
|
||||||
0,0,0);
|
|
||||||
Assert(utup != NULL);
|
|
||||||
return ((Form_pg_user)GETSTRUCT(utup))->usesuper;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
case_translate_language_name(const char *input, char *output) {
|
case_translate_language_name(const char *input, char *output) {
|
||||||
/*-------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------
|
||||||
|
Reference in New Issue
Block a user