Skip Menu |

This queue is for tickets about the DBD-Pg CPAN distribution.

Report information
The Basics
Id: 11266
Status: resolved
Priority: 0/
Queue: DBD-Pg

People
Owner: Nobody in particular
Requestors: sgifford [...] suspectclass.com
Cc:
AdminCc:

Bug Information
Severity: Critical
Broken in: 1.32
Fixed in: 1.40



Subject: Username and Password quoting bug in dbdimp.c
Hello, I was testing out some code for escaping Postgres connection strings today, and found that DBD::Pg doesn't quote usernames or passwords properly when creating a connection string. This makes it impossible to connect to a database with a username or password containing a single quote or a backslash. It also seems to open up a security hole if a username or password are under user control. In the process of testing, I created a user with a password of: \scott's"place"\ and found that DBD::Pg couldn't connect as that user. Some investigation showed that in dbdimp.c, usernames and passwords are not escaped at all. In an application where the database username or password are under user control (this is true in my application, where we take a Postgres username and password from a Web form to authenticate and later execute SQL statements), this lets a user set any database parameter. For example, look at the connection string that's used if I enter a password of: s3cr3t host=127.0.0.1 port=6543 env DBI_TRACE=9 perl -Iblib/lib -Iblib/arch -MDBI -e' $dbh = DBI->connect("DBI:Pg:dbname=vahrs", "sgifford", "s3cr3t host=127.0.0.1 port=6543") or die "connect error: $DBI::errstr\n" ' 2>&1 |grep conn_str pg_db_login: conn_str = >dbname=vahrs user=sgifford password=s3c3rt host=127.0.0.1 port=6\ 543< In this case, a user could cause authentication to happen against a database of their choosing, which would let them access our application without a valid username and password. The attached patch escapes single quotes and backslashes with a backslash; this works, and seems to be The Right Thing to Do according to: http://www.postgresql.org/docs/7.2/static/libpq-connect.html
diff -u DBD-Pg-1.32/dbdimp.c DBD-Pg-1.32-sg/dbdimp.c --- DBD-Pg-1.32/dbdimp.c Tue Feb 3 14:50:22 2004 +++ DBD-Pg-1.32-sg/dbdimp.c Thu Jan 27 02:43:18 2005 @@ -36,6 +36,25 @@ #include "large_object.c" #include "prescan_stmt.c" +char * +_strcat_esc(dest,s) + char *dest, *s; +{ + char *d = dest; + + while (*d) + d++; + + while (*s) { + if (*s == '\'' || *s == '\\') + *(d++)='\\'; + *(d++)=*(s++); + } + *d='\0'; + + return dest; +} + void dbd_init (dbistate) dbistate_t *dbistate; @@ -142,7 +161,7 @@ /* DBD-Pg syntax: 'dbname=dbname;host=host;port=port' */ /* pgsql syntax: 'dbname=dbname host=host port=port user=uid password=pwd' */ - conn_str = (char *)safemalloc(strlen(dbname) + strlen(uid) + strlen(pwd) + 16 + 1); + conn_str = (char *)safemalloc(strlen(dbname) + 2*strlen(uid) + 2*strlen(pwd) + 16 + 4 + 1); if (! conn_str) return 0; @@ -162,11 +181,13 @@ *dest = '\0'; if (strlen(uid)) { - strcat(conn_str, " user="); - strcat(conn_str, uid); + strcat(conn_str, " user='"); + _strcat_esc(conn_str,uid); + strcat(conn_str,"'"); if (strlen(pwd)) { - strcat(conn_str, " password="); - strcat(conn_str, pwd); + strcat(conn_str, " password='"); + _strcat_esc(conn_str, pwd); + strcat(conn_str,"'"); } }