usermap regexp support

Поиск
Список
Период
Сортировка
От Magnus Hagander
Тема usermap regexp support
Дата
Msg-id 49076F39.1080502@hagander.net
обсуждение исходный текст
Ответы Re: usermap regexp support  (Gianni Ciolli <gianni.ciolli@2ndquadrant.it>)
Список pgsql-hackers
The attached patch tries to implement regexp support in the usermaps
(pg_ident.conf).

The use-case will be to do things like realm-based matches in
kerberos/GSSAPI authentication (will require some further hacks on that
one to expose the realm name). For example you could have:

krb    /^(.*)@myrealm.com$    \1
krb    /^(.*)@otherrealm.com    guest

and things like that.

It will also likely be quite useful once we get SSL certificate based
authentication.

Reviews particularly appreciated - I really can't claim to *know* our
regexp code :-O

Obviously docs need to be updated as well.

//Magnus

*** a/src/backend/libpq/hba.c
--- b/src/backend/libpq/hba.c
***************
*** 27,32 ****
--- 27,33 ----

  #include "libpq/ip.h"
  #include "libpq/libpq.h"
+ #include "regex/regex.h"
  #include "storage/fd.h"
  #include "utils/flatfiles.h"
  #include "utils/guc.h"
***************
*** 1325,1344 **** parse_ident_usermap(List *line, int line_number, const char *usermap_name,
      token = lfirst(line_item);
      file_pgrole = token;

      /* Match? */
!     if (case_insensitive)
      {
!         if (strcmp(file_map, usermap_name) == 0 &&
!             pg_strcasecmp(file_pgrole, pg_role) == 0 &&
!             pg_strcasecmp(file_ident_user, ident_user) == 0)
!             *found_p = true;
      }
      else
      {
!         if (strcmp(file_map, usermap_name) == 0 &&
!             strcmp(file_pgrole, pg_role) == 0 &&
!             strcmp(file_ident_user, ident_user) == 0)
!             *found_p = true;
      }

      return;
--- 1326,1453 ----
      token = lfirst(line_item);
      file_pgrole = token;

+     if (strcmp(file_map, usermap_name) != 0)
+         /* Line does not match the map name we're looking for, so just abort */
+         return;
+
      /* Match? */
!     if (file_ident_user[0] == '/')
      {
!         /*
!          * When system username starts with a slash, treat it as a regular expression.
!          * In this case, we process the system username as a regular expression that
!          * returns exactly one match. This is replaced for $1 in the database username
!          * string, if present.
!          */
!         int            r;
!         regex_t        re;
!         regmatch_t    matches[2];
!         pg_wchar   *wstr;
!         int            wlen;
!         char       *ofs;
!         char       *regexp_pgrole;
!
!         wstr = palloc((strlen(file_ident_user+1) + 1) * sizeof(pg_wchar));
!         wlen = pg_mb2wchar_with_len(file_ident_user+1, wstr, strlen(file_ident_user+1));
!
!         /*
!          * XXX: Major room for optimization: regexps could be compiled when the file is loaded
!          * and then re-used in every connection.
!          */
!         r = pg_regcomp(&re, wstr, wlen, REG_ADVANCED);
!         if (r)
!         {
!             char errstr[100];
!
!             pg_regerror(r, &re, errstr, sizeof(errstr));
!             ereport(ERROR,
!                     (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
!                      errmsg("invalid regular expression '%s': %s", file_ident_user+1, errstr)));
!
!             pfree(wstr);
!             *error_p = true;
!             return;
!         }
!         pfree(wstr);
!
!         wstr = palloc((strlen(ident_user) + 1) * sizeof(pg_wchar));
!         wlen = pg_mb2wchar_with_len(ident_user, wstr, strlen(ident_user));
!
!         r = pg_regexec(&re, wstr, wlen, 0, NULL, 2, matches,0);
!         if (r)
!         {
!             char errstr[100];
!
!             if (r != REG_NOMATCH)
!             {
!                 /* REG_NOMATCH is not an error, everything else is */
!                 pg_regerror(r, &re, errstr, sizeof(errstr));
!                 ereport(ERROR,
!                         (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
!                          errmsg("regular expression match for '%s' failed: %s", file_ident_user+1, errstr)));
!                 *error_p = true;
!             }
!
!             pfree(wstr);
!             pg_regfree(&re);
!             return;
!         }
!         pfree(wstr);
!
!         if ((ofs = strstr(file_pgrole, "\\1")) != NULL)
!         {
!             /* substitution of the first argument requested */
!             if (matches[1].rm_so < 0)
!                 ereport(ERROR,
!                         (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
!                          errmsg("regular expression '%s' has no subexpressions as requested by backreference in
'%s'",
!                                 file_ident_user+1, file_pgrole)));
!             /* length: original length minus length of \1 plus length of match */
!             regexp_pgrole = palloc0(strlen(file_pgrole)-2+(matches[1].rm_so-matches[1].rm_so));
!             strncpy(regexp_pgrole, file_pgrole, (ofs-file_pgrole));
!             memcpy(regexp_pgrole+strlen(regexp_pgrole),
!                    ident_user+matches[1].rm_so,
!                    matches[1].rm_eo-matches[1].rm_so);
!             strcat(regexp_pgrole, ofs+2);
!         }
!         else
!         {
!             /* no substitution, so copy the match */
!             regexp_pgrole = pstrdup(file_pgrole);
!         }
!
!         pg_regfree(&re);
!
!         /* now check if the username actually matched what the user is trying to connect as */
!         if (case_insensitive)
!         {
!             if (pg_strcasecmp(regexp_pgrole, pg_role) == 0)
!                 *found_p = true;
!         }
!         else
!         {
!             if (strcmp(regexp_pgrole, pg_role) == 0)
!                 *found_p = true;
!         }
!         pfree(regexp_pgrole);
!
!         return;
      }
      else
      {
!         /* Not regular expression, so make complete match */
!         if (case_insensitive)
!         {
!             if (pg_strcasecmp(file_pgrole, pg_role) == 0 &&
!                 pg_strcasecmp(file_ident_user, ident_user) == 0)
!                 *found_p = true;
!         }
!         else
!         {
!             if (strcmp(file_pgrole, pg_role) == 0 &&
!                 strcmp(file_ident_user, ident_user) == 0)
!                 *found_p = true;
!         }
      }

      return;

В списке pgsql-hackers по дате отправления:

Предыдущее
От: Tom Lane
Дата:
Сообщение: Re: Re: [COMMITTERS] pgsql: Rework subtransaction commit protocol for hot standby.
Следующее
От: Grzegorz Jaskiewicz
Дата:
Сообщение: Re: current head fails regression tests on mac osx