Re: [patch] fix dblink security hole - Mailing list pgsql-hackers
From | Joe Conway |
---|---|
Subject | Re: [patch] fix dblink security hole |
Date | |
Msg-id | 48D70252.4050108@joeconway.com Whole thread Raw |
In response to | Re: [patch] fix dblink security hole (Tom Lane <tgl@sss.pgh.pa.us>) |
Responses |
Re: [patch] fix dblink security hole
Re: [patch] fix dblink security hole |
List | pgsql-hackers |
Tom Lane wrote: > Yeah. We could make one further refinement: callers that don't care > about acquiring an error string can pass NULL for the errmsg parameter. > That tells PQconninfoParse to throw away the errmsg string anyway. > With that, the minimal case isn't much uglier than your original: > just need a NULL arg tacked onto the call. True > BTW, the usual method for doing this is just to give the caller back the > errorBuf.data, not incur an additional strdup that could fail. OK, was entirely sure that was safe. New patch attached. Joe Index: contrib/dblink/dblink.c =================================================================== RCS file: /opt/src/cvs/pgsql/contrib/dblink/dblink.c,v retrieving revision 1.74 diff -c -r1.74 dblink.c *** contrib/dblink/dblink.c 3 Jul 2008 03:56:57 -0000 1.74 --- contrib/dblink/dblink.c 22 Sep 2008 02:09:39 -0000 *************** *** 93,98 **** --- 93,99 ---- static HeapTuple get_tuple_of_interest(Oid relid, int2vector *pkattnums, int16 pknumatts, char **src_pkattvals); static Oid get_relid_from_relname(text *relname_text); static char *generate_relation_name(Oid relid); + static void dblink_connstr_check(const char *connstr); static void dblink_security_check(PGconn *conn, remoteConn *rconn); static void dblink_res_error(const char *conname, PGresult *res, const char *dblink_context_msg, bool fail); *************** *** 165,170 **** --- 166,172 ---- else \ { \ connstr = conname_or_str; \ + dblink_connstr_check(connstr); \ conn = PQconnectdb(connstr); \ if (PQstatus(conn) == CONNECTION_BAD) \ { \ *************** *** 229,234 **** --- 231,239 ---- if (connname) rconn = (remoteConn *) palloc(sizeof(remoteConn)); + + /* check password in connection string if not superuser */ + dblink_connstr_check(connstr); conn = PQconnectdb(connstr); MemoryContextSwitchTo(oldcontext); *************** *** 246,252 **** errdetail("%s", msg))); } ! /* check password used if not superuser */ dblink_security_check(conn, rconn); if (connname) --- 251,257 ---- errdetail("%s", msg))); } ! /* check password actually used if not superuser */ dblink_security_check(conn, rconn); if (connname) *************** *** 2252,2257 **** --- 2257,2293 ---- } static void + dblink_connstr_check(const char *connstr) + { + if (!superuser()) + { + PQconninfoOption *options; + PQconninfoOption *option; + bool conn_used_password = false; + + options = PQconninfoParse(connstr, NULL); + for (option = options; option->keyword != NULL; option++) + { + if (strcmp(option->keyword, "password") == 0) + { + if (option->val != NULL && option->val[0] != '\0') + { + conn_used_password = true; + break; + } + } + } + PQconninfoFree(options); + + if (!conn_used_password) + ereport(ERROR, + (errcode(ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED), + errmsg("password is required"), + errdetail("Non-superuser must provide a password in the connection string."))); + } + } + + static void dblink_res_error(const char *conname, PGresult *res, const char *dblink_context_msg, bool fail) { int level; Index: doc/src/sgml/libpq.sgml =================================================================== RCS file: /opt/src/cvs/pgsql/doc/src/sgml/libpq.sgml,v retrieving revision 1.263 diff -c -r1.263 libpq.sgml *** doc/src/sgml/libpq.sgml 19 Sep 2008 20:06:13 -0000 1.263 --- doc/src/sgml/libpq.sgml 22 Sep 2008 02:08:50 -0000 *************** *** 625,630 **** --- 625,661 ---- </varlistentry> <varlistentry> + <term><function>PQconninfoParse</function><indexterm><primary>PQconninfoParse</></></term> + <listitem> + <para> + Returns parsed connection options from the provided connection string. + + <synopsis> + PQconninfoOption *PQconninfoParse(const char *conninfo, char **errmsg); + </synopsis> + + <para> + Returns a connection options array. This can be used to determine + the <function>PQconnectdb</function> options in the provided + connection string. The return value points to an array of + <structname>PQconninfoOption</structname> structures, which ends + with an entry having a null <structfield>keyword</> pointer. The + null pointer is returned if an error occurs. In this case, + <literal>errmsg</literal> contains the error message. Passing + <literal>NULL</literal> for <literal>errmsg</literal> tells + <function>PQconninfoParse</function> to throw away the error message. + </para> + + <para> + After processing the options array, free it by passing it to + <function>PQconninfoFree</function>. If this is not done, a small amount of memory + is leaked for each call to <function>PQconndefaults</function>. + </para> + + </listitem> + </varlistentry> + + <varlistentry> <term><function>PQfinish</function><indexterm><primary>PQfinish</></></term> <listitem> <para> Index: src/interfaces/libpq/exports.txt =================================================================== RCS file: /opt/src/cvs/pgsql/src/interfaces/libpq/exports.txt,v retrieving revision 1.21 diff -c -r1.21 exports.txt *** src/interfaces/libpq/exports.txt 19 Sep 2008 20:06:13 -0000 1.21 --- src/interfaces/libpq/exports.txt 21 Sep 2008 23:32:56 -0000 *************** *** 151,153 **** --- 151,154 ---- PQresultInstanceData 149 PQresultSetInstanceData 150 PQfireResultCreateEvents 151 + PQconninfoParse 152 Index: src/interfaces/libpq/fe-connect.c =================================================================== RCS file: /opt/src/cvs/pgsql/src/interfaces/libpq/fe-connect.c,v retrieving revision 1.360 diff -c -r1.360 fe-connect.c *** src/interfaces/libpq/fe-connect.c 17 Sep 2008 04:31:08 -0000 1.360 --- src/interfaces/libpq/fe-connect.c 22 Sep 2008 02:01:33 -0000 *************** *** 3101,3106 **** --- 3101,3129 ---- return 0; } + /* + * PQconninfoParse + * + * Parse a string like PQconnectdb() would do and return the + * working connection options array. + * + * NOTE: the returned array is dynamically allocated and should + * be freed when no longer needed via PQconninfoFree(). + */ + PQconninfoOption * + PQconninfoParse(const char *conninfo, char **errmsg) + { + PQExpBufferData errorBuf; + bool password_from_string; + PQconninfoOption *connOptions; + + initPQExpBuffer(&errorBuf); + connOptions = conninfo_parse(conninfo, &errorBuf, &password_from_string); + if (!connOptions && errmsg) + *errmsg = errorBuf.data; + termPQExpBuffer(&errorBuf); + return connOptions; + } /* * Conninfo parser routine Index: src/interfaces/libpq/libpq-fe.h =================================================================== RCS file: /opt/src/cvs/pgsql/src/interfaces/libpq/libpq-fe.h,v retrieving revision 1.143 diff -c -r1.143 libpq-fe.h *** src/interfaces/libpq/libpq-fe.h 17 Sep 2008 04:31:08 -0000 1.143 --- src/interfaces/libpq/libpq-fe.h 22 Sep 2008 01:45:24 -0000 *************** *** 243,248 **** --- 243,251 ---- /* get info about connection options known to PQconnectdb */ extern PQconninfoOption *PQconndefaults(void); + /* parse connection options in same way as PQconnectdb */ + extern PQconninfoOption *PQconninfoParse(const char *conninfo, char **errmsg); + /* free the data structure returned by PQconndefaults() */ extern void PQconninfoFree(PQconninfoOption *connOptions);
pgsql-hackers by date: