|
10 | 10 | *
|
11 | 11 | *
|
12 | 12 | * IDENTIFICATION
|
13 |
| - * $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.175 2008/11/20 20:45:30 momjian Exp $ |
| 13 | + * $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.176 2008/11/28 14:26:58 mha Exp $ |
14 | 14 | *
|
15 | 15 | *-------------------------------------------------------------------------
|
16 | 16 | */
|
|
27 | 27 |
|
28 | 28 | #include"libpq/ip.h"
|
29 | 29 | #include"libpq/libpq.h"
|
| 30 | +#include"regex/regex.h" |
30 | 31 | #include"storage/fd.h"
|
31 | 32 | #include"utils/flatfiles.h"
|
32 | 33 | #include"utils/guc.h"
|
@@ -1403,20 +1404,128 @@ parse_ident_usermap(List *line, int line_number, const char *usermap_name,
|
1403 | 1404 | token=lfirst(line_item);
|
1404 | 1405 | file_pgrole=token;
|
1405 | 1406 |
|
| 1407 | +if (strcmp(file_map,usermap_name)!=0) |
| 1408 | +/* Line does not match the map name we're looking for, so just abort */ |
| 1409 | +return; |
| 1410 | + |
1406 | 1411 | /* Match? */
|
1407 |
| -if (case_insensitive) |
| 1412 | +if (file_ident_user[0]=='/') |
1408 | 1413 | {
|
1409 |
| -if (strcmp(file_map,usermap_name)==0&& |
1410 |
| -pg_strcasecmp(file_pgrole,pg_role)==0&& |
1411 |
| -pg_strcasecmp(file_ident_user,ident_user)==0) |
1412 |
| -*found_p= true; |
| 1414 | +/* |
| 1415 | + * When system username starts with a slash, treat it as a regular expression. |
| 1416 | + * In this case, we process the system username as a regular expression that |
| 1417 | + * returns exactly one match. This is replaced for \1 in the database username |
| 1418 | + * string, if present. |
| 1419 | + */ |
| 1420 | +intr; |
| 1421 | +regex_tre; |
| 1422 | +regmatch_tmatches[2]; |
| 1423 | +pg_wchar*wstr; |
| 1424 | +intwlen; |
| 1425 | +char*ofs; |
| 1426 | +char*regexp_pgrole; |
| 1427 | + |
| 1428 | +wstr=palloc((strlen(file_ident_user+1)+1)*sizeof(pg_wchar)); |
| 1429 | +wlen=pg_mb2wchar_with_len(file_ident_user+1,wstr,strlen(file_ident_user+1)); |
| 1430 | + |
| 1431 | +/* |
| 1432 | + * XXX: Major room for optimization: regexps could be compiled when the file is loaded |
| 1433 | + * and then re-used in every connection. |
| 1434 | + */ |
| 1435 | +r=pg_regcomp(&re,wstr,wlen,REG_ADVANCED); |
| 1436 | +if (r) |
| 1437 | +{ |
| 1438 | +charerrstr[100]; |
| 1439 | + |
| 1440 | +pg_regerror(r,&re,errstr,sizeof(errstr)); |
| 1441 | +ereport(ERROR, |
| 1442 | +(errcode(ERRCODE_INVALID_REGULAR_EXPRESSION), |
| 1443 | +errmsg("invalid regular expression '%s': %s",file_ident_user+1,errstr))); |
| 1444 | + |
| 1445 | +pfree(wstr); |
| 1446 | +*error_p= true; |
| 1447 | +return; |
| 1448 | +} |
| 1449 | +pfree(wstr); |
| 1450 | + |
| 1451 | +wstr=palloc((strlen(ident_user)+1)*sizeof(pg_wchar)); |
| 1452 | +wlen=pg_mb2wchar_with_len(ident_user,wstr,strlen(ident_user)); |
| 1453 | + |
| 1454 | +r=pg_regexec(&re,wstr,wlen,0,NULL,2,matches,0); |
| 1455 | +if (r) |
| 1456 | +{ |
| 1457 | +charerrstr[100]; |
| 1458 | + |
| 1459 | +if (r!=REG_NOMATCH) |
| 1460 | +{ |
| 1461 | +/* REG_NOMATCH is not an error, everything else is */ |
| 1462 | +pg_regerror(r,&re,errstr,sizeof(errstr)); |
| 1463 | +ereport(ERROR, |
| 1464 | +(errcode(ERRCODE_INVALID_REGULAR_EXPRESSION), |
| 1465 | +errmsg("regular expression match for '%s' failed: %s",file_ident_user+1,errstr))); |
| 1466 | +*error_p= true; |
| 1467 | +} |
| 1468 | + |
| 1469 | +pfree(wstr); |
| 1470 | +pg_regfree(&re); |
| 1471 | +return; |
| 1472 | +} |
| 1473 | +pfree(wstr); |
| 1474 | + |
| 1475 | +if ((ofs=strstr(file_pgrole,"\\1"))!=NULL) |
| 1476 | +{ |
| 1477 | +/* substitution of the first argument requested */ |
| 1478 | +if (matches[1].rm_so<0) |
| 1479 | +ereport(ERROR, |
| 1480 | +(errcode(ERRCODE_INVALID_REGULAR_EXPRESSION), |
| 1481 | +errmsg("regular expression '%s' has no subexpressions as requested by backreference in '%s'", |
| 1482 | +file_ident_user+1,file_pgrole))); |
| 1483 | +/* length: original length minus length of \1 plus length of match plus null terminator */ |
| 1484 | +regexp_pgrole=palloc0(strlen(file_pgrole)-2+ (matches[1].rm_eo-matches[1].rm_so)+1); |
| 1485 | +strncpy(regexp_pgrole,file_pgrole, (ofs-file_pgrole)); |
| 1486 | +memcpy(regexp_pgrole+strlen(regexp_pgrole), |
| 1487 | +ident_user+matches[1].rm_so, |
| 1488 | +matches[1].rm_eo-matches[1].rm_so); |
| 1489 | +strcat(regexp_pgrole,ofs+2); |
| 1490 | +} |
| 1491 | +else |
| 1492 | +{ |
| 1493 | +/* no substitution, so copy the match */ |
| 1494 | +regexp_pgrole=pstrdup(file_pgrole); |
| 1495 | +} |
| 1496 | + |
| 1497 | +pg_regfree(&re); |
| 1498 | + |
| 1499 | +/* now check if the username actually matched what the user is trying to connect as */ |
| 1500 | +if (case_insensitive) |
| 1501 | +{ |
| 1502 | +if (pg_strcasecmp(regexp_pgrole,pg_role)==0) |
| 1503 | +*found_p= true; |
| 1504 | +} |
| 1505 | +else |
| 1506 | +{ |
| 1507 | +if (strcmp(regexp_pgrole,pg_role)==0) |
| 1508 | +*found_p= true; |
| 1509 | +} |
| 1510 | +pfree(regexp_pgrole); |
| 1511 | + |
| 1512 | +return; |
1413 | 1513 | }
|
1414 | 1514 | else
|
1415 | 1515 | {
|
1416 |
| -if (strcmp(file_map,usermap_name)==0&& |
1417 |
| -strcmp(file_pgrole,pg_role)==0&& |
1418 |
| -strcmp(file_ident_user,ident_user)==0) |
1419 |
| -*found_p= true; |
| 1516 | +/* Not regular expression, so make complete match */ |
| 1517 | +if (case_insensitive) |
| 1518 | +{ |
| 1519 | +if (pg_strcasecmp(file_pgrole,pg_role)==0&& |
| 1520 | +pg_strcasecmp(file_ident_user,ident_user)==0) |
| 1521 | +*found_p= true; |
| 1522 | +} |
| 1523 | +else |
| 1524 | +{ |
| 1525 | +if (strcmp(file_pgrole,pg_role)==0&& |
| 1526 | +strcmp(file_ident_user,ident_user)==0) |
| 1527 | +*found_p= true; |
| 1528 | +} |
1420 | 1529 | }
|
1421 | 1530 |
|
1422 | 1531 | return;
|
|