Thread: krb_match_realm
Attached patch implements krb_match_realm for krb5, gssapi and sspi per complaint from Henry. Comments welcome. Working on documentation which will of course be ready when it's committed :) Oh, and it changes the krb username handling to be the same as the gssapi one. I've never heard of anybody actually using the other version that it used to support, and the comment clearly states that it was broken for the really complex scenarios anyway - something nobody has complained about. //Magnus Index: backend/libpq/auth.c =================================================================== RCS file: /cvsroot/pgsql/src/backend/libpq/auth.c,v retrieving revision 1.156 diff -c -r1.156 auth.c *** backend/libpq/auth.c 14 Sep 2007 15:58:02 -0000 1.156 --- backend/libpq/auth.c 1 Nov 2007 11:28:54 -0000 *************** *** 42,47 **** --- 42,48 ---- char *pg_krb_srvnam; bool pg_krb_caseins_users; char *pg_krb_server_hostname = NULL; + char *pg_krb_match_realm = NULL; #ifdef USE_PAM #ifdef HAVE_PAM_PAM_APPL_H *************** *** 103,132 **** #endif /* - * pg_an_to_ln -- return the local name corresponding to an authentication - * name - * - * XXX Assumes that the first aname component is the user name. This is NOT - * necessarily so, since an aname can actually be something out of your - * worst X.400 nightmare, like - * ORGANIZATION=U. C. Berkeley/NAME=Paul M. Aoki@CS.BERKELEY.EDU - * Note that the MIT an_to_ln code does the same thing if you don't - * provide an aname mapping database...it may be a better idea to use - * krb5_an_to_ln, except that it punts if multiple components are found, - * and we can't afford to punt. - */ - static char * - pg_an_to_ln(char *aname) - { - char *p; - - if ((p = strchr(aname, '/')) || (p = strchr(aname, '@'))) - *p = '\0'; - return aname; - } - - - /* * Various krb5 state which is not connection specfic, and a flag to * indicate whether we have initialised it yet. */ --- 104,109 ---- *************** *** 216,221 **** --- 193,199 ---- krb5_auth_context auth_context = NULL; krb5_ticket *ticket; char *kusername; + char *cp; if (get_role_line(port->user_name) == NULL) return STATUS_ERROR; *************** *** 240,247 **** * The "client" structure comes out of the ticket and is therefore * authenticated. Use it to check the username obtained from the * postmaster startup packet. - * - * I have no idea why this is considered necessary. */ #if defined(HAVE_KRB5_TICKET_ENC_PART2) retval = krb5_unparse_name(pg_krb5_context, --- 218,223 ---- *************** *** 263,269 **** return STATUS_ERROR; } ! kusername = pg_an_to_ln(kusername); if (pg_krb_caseins_users) ret = pg_strncasecmp(port->user_name, kusername, SM_DATABASE_USER); else --- 239,280 ---- return STATUS_ERROR; } ! cp = strchr(kusername, '@'); ! if (cp) ! { ! *cp = '\0'; ! cp++; ! ! if (pg_krb_match_realm != NULL && strlen(pg_krb_match_realm)) ! { ! /* Match realm against configured */ ! if (pg_krb_caseins_users) ! ret = pg_strcasecmp(pg_krb_match_realm, cp); ! else ! ret = strcmp(pg_krb_match_realm, cp); ! ! if (ret) ! { ! elog(DEBUG2, ! "krb5 realm (%s) and configured realm (%s) don't match", ! cp, pg_krb_match_realm); ! ! krb5_free_ticket(pg_krb5_context, ticket); ! krb5_auth_con_free(pg_krb5_context, auth_context); ! return STATUS_ERROR; ! } ! } ! } ! else if (pg_krb_match_realm && strlen(pg_krb_match_realm)) ! { ! elog(DEBUG2, ! "krb5 did not return realm but realm matching was requested"); ! ! krb5_free_ticket(pg_krb5_context, ticket); ! krb5_auth_con_free(pg_krb5_context, auth_context); ! return STATUS_ERROR; ! } ! if (pg_krb_caseins_users) ret = pg_strncasecmp(port->user_name, kusername, SM_DATABASE_USER); else *************** *** 509,522 **** maj_stat, min_stat); /* ! * Compare the part of the username that comes before the @ ! * sign only (ignore realm). The GSSAPI libraries won't have ! * authenticated the user if he's from an invalid realm. */ if (strchr(gbuf.value, '@')) { char *cp = strchr(gbuf.value, '@'); *cp = '\0'; } if (pg_krb_caseins_users) --- 520,561 ---- maj_stat, min_stat); /* ! * Split the username at the realm separator */ if (strchr(gbuf.value, '@')) { char *cp = strchr(gbuf.value, '@'); *cp = '\0'; + cp++; + + if (pg_krb_match_realm != NULL && strlen(pg_krb_match_realm)) + { + /* + * Match the realm part of the name first + */ + if (pg_krb_caseins_users) + ret = pg_strcasecmp(pg_krb_match_realm, cp); + else + ret = strcmp(pg_krb_match_realm, cp); + + if (ret) + { + /* GSS realm does not match */ + elog(DEBUG2, + "GSSAPI realm (%s) and configured realm (%s) don't match", + cp, pg_krb_match_realm); + gss_release_buffer(&lmin_s, &gbuf); + return STATUS_ERROR; + } + } + } + else if (pg_krb_match_realm && strlen(pg_krb_match_realm)) + { + elog(DEBUG2, + "GSSAPI did not return realm but realm matching was requested"); + + gss_release_buffer(&lmin_s, &gbuf); + return STATUS_ERROR; } if (pg_krb_caseins_users) *************** *** 792,797 **** --- 831,851 ---- free(tokenuser); + /* + * Compare realm/domain if requested. In SSPI, always compare case insensitive. + */ + if (pg_krb_match_realm && strlen(pg_krb_match_realm)) + { + if (pg_strcasecmp(pg_krb_match_realm, domainname)) + { + elog(DEBUG2, + "SSPI domain (%s) does and configured domain (%s) don't match", + domainname, pg_krb_match_realm); + + return STATUS_ERROR; + } + } + /* * We have the username (without domain/realm) in accountname, compare * to the supplied value. In SSPI, always compare case insensitive. Index: backend/utils/misc/guc.c =================================================================== RCS file: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v retrieving revision 1.423 diff -c -r1.423 guc.c *** backend/utils/misc/guc.c 26 Sep 2007 22:36:30 -0000 1.423 --- backend/utils/misc/guc.c 1 Nov 2007 11:28:54 -0000 *************** *** 2044,2049 **** --- 2044,2059 ---- }, { + {"krb_match_realm", PGC_POSTMASTER, CONN_AUTH_SECURITY, + gettext_noop("Sets realm to match Kerberos and GSSAPI users against."), + NULL, + GUC_SUPERUSER_ONLY + }, + &pg_krb_match_realm, + NULL, NULL, NULL + }, + + { {"krb_server_keyfile", PGC_POSTMASTER, CONN_AUTH_SECURITY, gettext_noop("Sets the location of the Kerberos server key file."), NULL, Index: backend/utils/misc/postgresql.conf.sample =================================================================== RCS file: /cvsroot/pgsql/src/backend/utils/misc/postgresql.conf.sample,v retrieving revision 1.231 diff -c -r1.231 postgresql.conf.sample *** backend/utils/misc/postgresql.conf.sample 26 Sep 2007 22:36:30 -0000 1.231 --- backend/utils/misc/postgresql.conf.sample 1 Nov 2007 11:28:54 -0000 *************** *** 85,90 **** --- 85,91 ---- #krb_server_hostname = '' # empty string matches any keytab entry # (change requires restart, kerberos only) #krb_caseins_users = off # (change requires restart) + #krb_match_realm = '' # (change requires restart) # - TCP Keepalives - # see 'man 7 tcp' for details Index: include/libpq/auth.h =================================================================== RCS file: /cvsroot/pgsql/src/include/libpq/auth.h,v retrieving revision 1.33 diff -c -r1.33 auth.h *** include/libpq/auth.h 5 Jan 2007 22:19:55 -0000 1.33 --- include/libpq/auth.h 1 Nov 2007 11:28:54 -0000 *************** *** 20,25 **** --- 20,26 ---- extern char *pg_krb_srvnam; extern bool pg_krb_caseins_users; extern char *pg_krb_server_hostname; + extern char *pg_krb_match_realm; extern void ClientAuthentication(Port *port);
Magnus Hagander <magnus@hagander.net> writes: > Attached patch implements krb_match_realm for krb5, gssapi and sspi per > complaint from Henry. Comments welcome. Minor gripe: "krb_match_realm" sounds like it should be a boolean: do or don't check the realm. Would just "krb_realm" be sensible? Also the elog message texts need a bit of copy-editing. regards, tom lane
Tom Lane wrote: > Magnus Hagander <magnus@hagander.net> writes: >> Attached patch implements krb_match_realm for krb5, gssapi and sspi per >> complaint from Henry. Comments welcome. > > Minor gripe: "krb_match_realm" sounds like it should be a boolean: > do or don't check the realm. Would just "krb_realm" be sensible? Yeah, probably. I'll change it to that. > Also the elog message texts need a bit of copy-editing. Probably ;-) Got any specific hints, so I don't have to go through the iteration twice? //Magnus
Magnus Hagander <magnus@hagander.net> writes: > Tom Lane wrote: >> Also the elog message texts need a bit of copy-editing. > Probably ;-) Got any specific hints, so I don't have to go through the > iteration twice? The one that caught my eye was "SSPI domain (%s) does and configured domain (%s) don't match", regards, tom lane
Tom Lane wrote: > Magnus Hagander <magnus@hagander.net> writes: >> Tom Lane wrote: >>> Also the elog message texts need a bit of copy-editing. > >> Probably ;-) Got any specific hints, so I don't have to go through the >> iteration twice? > > The one that caught my eye was > > "SSPI domain (%s) does and configured domain (%s) don't match", Wow, I need a break from the monitor, I think. I read over them all again, and missed it again :-( Will fix. //Magnus
Henry B. Hotz wrote: > Thank you very much. This helps, but I'm still evaluating how much. > > I *can* point at one problem though: you do a strchr(gbuf.value, '@') > and then error out if there isn't a Kerberos realm there. In fact that > is exactly the default username of at least one of the GSSAPI > implementations I've tested if the realm is the same as the local > default realm. Eh, so how do we then determine the difference between local realm and no realm given? > I'm not entirely sure what the intended semantics of krb_match_realm > are, but if you're trying to match the GSSAPI-authenticated name against > "value_of(PGUSER)@value_of(krb_match_realm)" then you need to construct > that string, gss_import_name() it, and then gss_compare_name() the > imported name with the authenticated name that GSSAPI already gave you. > I know the API overhead of doing that is a PITA, but that's what's going > to work. Why? (FWIW, it works perfectly fine in my test setups, so I'd really like to know why this won't work) > I also notice you have some code to do case insensitive name matching. > I assume this is to take care of the fact that Microsoft Kerberos does > case insensitive name matching (contrary to the standard and the other > Kerberos implementations out there). I suspect issues there, but it > will be 3-6 months before I will have an environment where I can easily > test this. Most likely, the way to handle this is by figuring out what > case Microsoft uses for each name inside the protocol and then > pre-mapping to that case before feeding things to (non-Microsoft) GSSAPI. Yes, it's for supporting Active Directory. It's there in the same way it's there for krb5. > I don't regard the case mapping issues as serious. We may not have the > intended level of Windows/Unix compatibility, but I don't expect other > issues. In other words I'm not even going to think about it until it's > easy for me to investigate. Note that it's turned *off* by default, so it shouldn't even affect you. >> Attached patch implements krb_match_realm for krb5, gssapi and sspi per >> complaint from Henry. Comments welcome. >> >> Working on documentation which will of course be ready when it's >> committed :) >> >> Oh, and it changes the krb username handling to be the same as the >> gssapi one. I've never heard of anybody actually using the other version >> that it used to support, and the comment clearly states that it was >> broken for the really complex scenarios anyway - something nobody has >> complained about. > > Well, *I* complained about it. ;-) Um, not sure we're talking about the same thing. I know you complained about the inability to match realm, but did you complain about the inability to use things like full X.500 names as usernames? //Magnus
Thank you very much. This helps, but I'm still evaluating how much. I *can* point at one problem though: you do a strchr(gbuf.value, '@') and then error out if there isn't a Kerberos realm there. In fact that is exactly the default username of at least one of the GSSAPI implementations I've tested if the realm is the same as the local default realm. I'm not entirely sure what the intended semantics of krb_match_realm are, but if you're trying to match the GSSAPI-authenticated name against "value_of(PGUSER)@value_of(krb_match_realm)" then you need to construct that string, gss_import_name() it, and then gss_compare_name () the imported name with the authenticated name that GSSAPI already gave you. I know the API overhead of doing that is a PITA, but that's what's going to work. I also notice you have some code to do case insensitive name matching. I assume this is to take care of the fact that Microsoft Kerberos does case insensitive name matching (contrary to the standard and the other Kerberos implementations out there). I suspect issues there, but it will be 3-6 months before I will have an environment where I can easily test this. Most likely, the way to handle this is by figuring out what case Microsoft uses for each name inside the protocol and then pre-mapping to that case before feeding things to (non-Microsoft) GSSAPI. I don't regard the case mapping issues as serious. We may not have the intended level of Windows/Unix compatibility, but I don't expect other issues. In other words I'm not even going to think about it until it's easy for me to investigate. On Nov 1, 2007, at 5:27 AM, Magnus Hagander wrote: > Attached patch implements krb_match_realm for krb5, gssapi and sspi > per > complaint from Henry. Comments welcome. > > Working on documentation which will of course be ready when it's > committed :) > > Oh, and it changes the krb username handling to be the same as the > gssapi one. I've never heard of anybody actually using the other > version > that it used to support, and the comment clearly states that it was > broken for the really complex scenarios anyway - something nobody has > complained about. Well, *I* complained about it. ;-) Sorry if I'm the only one, but I can't change the deployment environment I'm going to have to deal with. > //Magnus > Index: backend/libpq/auth.c > =================================================================== > RCS file: /cvsroot/pgsql/src/backend/libpq/auth.c,v > retrieving revision 1.156 > diff -c -r1.156 auth.c > *** backend/libpq/auth.c 14 Sep 2007 15:58:02 -0000 1.156 > --- backend/libpq/auth.c 1 Nov 2007 11:28:54 -0000 > *************** > *** 42,47 **** > --- 42,48 ---- > char *pg_krb_srvnam; > bool pg_krb_caseins_users; > char *pg_krb_server_hostname = NULL; > + char *pg_krb_match_realm = NULL; > > #ifdef USE_PAM > #ifdef HAVE_PAM_PAM_APPL_H > *************** > *** 103,132 **** > #endif > > /* > - * pg_an_to_ln -- return the local name corresponding to an > authentication > - * name > - * > - * XXX Assumes that the first aname component is the user name. > This is NOT > - * necessarily so, since an aname can actually be something > out of your > - * worst X.400 nightmare, like > - * ORGANIZATION=U. C. Berkeley/NAME=Paul M. Aoki@CS.BERKELEY.EDU > - * Note that the MIT an_to_ln code does the same thing if you > don't > - * provide an aname mapping database...it may be a better idea > to use > - * krb5_an_to_ln, except that it punts if multiple components > are found, > - * and we can't afford to punt. > - */ > - static char * > - pg_an_to_ln(char *aname) > - { > - char *p; > - > - if ((p = strchr(aname, '/')) || (p = strchr(aname, '@'))) > - *p = '\0'; > - return aname; > - } > - > - > - /* > * Various krb5 state which is not connection specfic, and a flag to > * indicate whether we have initialised it yet. > */ > --- 104,109 ---- > *************** > *** 216,221 **** > --- 193,199 ---- > krb5_auth_context auth_context = NULL; > krb5_ticket *ticket; > char *kusername; > + char *cp; > > if (get_role_line(port->user_name) == NULL) > return STATUS_ERROR; > *************** > *** 240,247 **** > * The "client" structure comes out of the ticket and is therefore > * authenticated. Use it to check the username obtained from the > * postmaster startup packet. > - * > - * I have no idea why this is considered necessary. > */ > #if defined(HAVE_KRB5_TICKET_ENC_PART2) > retval = krb5_unparse_name(pg_krb5_context, > --- 218,223 ---- > *************** > *** 263,269 **** > return STATUS_ERROR; > } > > ! kusername = pg_an_to_ln(kusername); > if (pg_krb_caseins_users) > ret = pg_strncasecmp(port->user_name, kusername, > SM_DATABASE_USER); > else > --- 239,280 ---- > return STATUS_ERROR; > } > > ! cp = strchr(kusername, '@'); > ! if (cp) > ! { > ! *cp = '\0'; > ! cp++; > ! > ! if (pg_krb_match_realm != NULL && strlen(pg_krb_match_realm)) > ! { > ! /* Match realm against configured */ > ! if (pg_krb_caseins_users) > ! ret = pg_strcasecmp(pg_krb_match_realm, cp); > ! else > ! ret = strcmp(pg_krb_match_realm, cp); > ! > ! if (ret) > ! { > ! elog(DEBUG2, > ! "krb5 realm (%s) and configured realm (%s) don't match", > ! cp, pg_krb_match_realm); > ! > ! krb5_free_ticket(pg_krb5_context, ticket); > ! krb5_auth_con_free(pg_krb5_context, auth_context); > ! return STATUS_ERROR; > ! } > ! } > ! } > ! else if (pg_krb_match_realm && strlen(pg_krb_match_realm)) I assume this case is in the existing kerb5 method. > ! { > ! elog(DEBUG2, > ! "krb5 did not return realm but realm matching was requested"); > ! > ! krb5_free_ticket(pg_krb5_context, ticket); > ! krb5_auth_con_free(pg_krb5_context, auth_context); > ! return STATUS_ERROR; > ! } > ! > if (pg_krb_caseins_users) > ret = pg_strncasecmp(port->user_name, kusername, > SM_DATABASE_USER); > else > *************** > *** 509,522 **** > maj_stat, min_stat); > > /* > ! * Compare the part of the username that comes before the @ > ! * sign only (ignore realm). The GSSAPI libraries won't have > ! * authenticated the user if he's from an invalid realm. > */ > if (strchr(gbuf.value, '@')) > { > char *cp = strchr(gbuf.value, '@'); > *cp = '\0'; > } > > if (pg_krb_caseins_users) > --- 520,561 ---- > maj_stat, min_stat); > > /* > ! * Split the username at the realm separator > */ > if (strchr(gbuf.value, '@')) > { > char *cp = strchr(gbuf.value, '@'); > *cp = '\0'; > + cp++; > + > + if (pg_krb_match_realm != NULL && strlen(pg_krb_match_realm)) > + { > + /* > + * Match the realm part of the name first > + */ > + if (pg_krb_caseins_users) > + ret = pg_strcasecmp(pg_krb_match_realm, cp); > + else > + ret = strcmp(pg_krb_match_realm, cp); > + > + if (ret) > + { > + /* GSS realm does not match */ > + elog(DEBUG2, > + "GSSAPI realm (%s) and configured realm (%s) don't match", > + cp, pg_krb_match_realm); > + gss_release_buffer(&lmin_s, &gbuf); > + return STATUS_ERROR; > + } > + } > + } > + else if (pg_krb_match_realm && strlen(pg_krb_match_realm)) > + { > + elog(DEBUG2, > + "GSSAPI did not return realm but realm matching was requested"); > + Most likely reason is that the realm is the same as the local default realm. This shouldn't be an error. > + gss_release_buffer(&lmin_s, &gbuf); > + return STATUS_ERROR; > } > > if (pg_krb_caseins_users) > *************** > *** 792,797 **** > --- 831,851 ---- > > free(tokenuser); > > + /* > + * Compare realm/domain if requested. In SSPI, always compare > case insensitive. > + */ > + if (pg_krb_match_realm && strlen(pg_krb_match_realm)) > + { > + if (pg_strcasecmp(pg_krb_match_realm, domainname)) > + { > + elog(DEBUG2, > + "SSPI domain (%s) does and configured domain (%s) don't match", > + domainname, pg_krb_match_realm); > + > + return STATUS_ERROR; > + } > + } > + > /* > * We have the username (without domain/realm) in accountname, > compare > * to the supplied value. In SSPI, always compare case insensitive. > Index: backend/utils/misc/guc.c > =================================================================== > RCS file: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v > retrieving revision 1.423 > diff -c -r1.423 guc.c > *** backend/utils/misc/guc.c 26 Sep 2007 22:36:30 -0000 1.423 > --- backend/utils/misc/guc.c 1 Nov 2007 11:28:54 -0000 > *************** > *** 2044,2049 **** > --- 2044,2059 ---- > }, > > { > + {"krb_match_realm", PGC_POSTMASTER, CONN_AUTH_SECURITY, > + gettext_noop("Sets realm to match Kerberos and GSSAPI users > against."), > + NULL, > + GUC_SUPERUSER_ONLY > + }, > + &pg_krb_match_realm, > + NULL, NULL, NULL > + }, > + > + { > {"krb_server_keyfile", PGC_POSTMASTER, CONN_AUTH_SECURITY, > gettext_noop("Sets the location of the Kerberos server key > file."), > NULL, > Index: backend/utils/misc/postgresql.conf.sample > =================================================================== > RCS file: /cvsroot/pgsql/src/backend/utils/misc/ > postgresql.conf.sample,v > retrieving revision 1.231 > diff -c -r1.231 postgresql.conf.sample > *** backend/utils/misc/postgresql.conf.sample 26 Sep 2007 22:36:30 > -0000 1.231 > --- backend/utils/misc/postgresql.conf.sample 1 Nov 2007 11:28:54 > -0000 > *************** > *** 85,90 **** > --- 85,91 ---- > #krb_server_hostname = '' # empty string matches any keytab entry > # (change requires restart, kerberos only) > #krb_caseins_users = off # (change requires restart) > + #krb_match_realm = '' # (change requires restart) > > # - TCP Keepalives - > # see 'man 7 tcp' for details > Index: include/libpq/auth.h > =================================================================== > RCS file: /cvsroot/pgsql/src/include/libpq/auth.h,v > retrieving revision 1.33 > diff -c -r1.33 auth.h > *** include/libpq/auth.h 5 Jan 2007 22:19:55 -0000 1.33 > --- include/libpq/auth.h 1 Nov 2007 11:28:54 -0000 > *************** > *** 20,25 **** > --- 20,26 ---- > extern char *pg_krb_srvnam; > extern bool pg_krb_caseins_users; > extern char *pg_krb_server_hostname; > + extern char *pg_krb_match_realm; > > extern void ClientAuthentication(Port *port); >
On Nov 1, 2007, at 1:40 PM, Magnus Hagander wrote: > Henry B. Hotz wrote: >> Thank you very much. This helps, but I'm still evaluating how much. >> >> I *can* point at one problem though: you do a strchr(gbuf.value, >> '@') >> and then error out if there isn't a Kerberos realm there. In fact >> that >> is exactly the default username of at least one of the GSSAPI >> implementations I've tested if the realm is the same as the local >> default realm. > > Eh, so how do we then determine the difference between local realm and > no realm given? Well, what I've seen is: no realm given if and only if the default local realm matches the realm for the GSSAPI username. I don't think that's guaranteed. >> I'm not entirely sure what the intended semantics of krb_match_realm >> are, but if you're trying to match the GSSAPI-authenticated name >> against >> "value_of(PGUSER)@value_of(krb_match_realm)" then you need to >> construct >> that string, gss_import_name() it, and then gss_compare_name() the >> imported name with the authenticated name that GSSAPI already gave >> you. >> I know the API overhead of doing that is a PITA, but that's what's >> going >> to work. > > Why? Because if we're using the GSSAPI then we need to use the properties defined by the GSSAPI, and not depend on observed behavior of specific implementations of specific mechanisms. Otherwise things will be non-portable or unreliable in ways that may be non-obvious. In particular gss_display_name() produces a character string intended for display to a human being. It is *NOT* intended for access control. As another example, Heimdal gss_display_name() puts '\' escapes in front of special characters in the username. I don't think it's worth writing special case code for that either. The standard defines two ways to do comparisons for access control. We should use one of them. Anything else is going to be more work and less reliable. > (FWIW, it works perfectly fine in my test setups, so I'd really > like to > know why this won't work) I may be able to flag specific failures, as I've done here, but I'm sure I can't imagine all the ways that evading the standard might cause problems. Perhaps that's not helpful or not what you want, but it's all I can do. >> I also notice you have some code to do case insensitive name >> matching. >> I assume this is to take care of the fact that Microsoft Kerberos >> does >> case insensitive name matching (contrary to the standard and the >> other >> Kerberos implementations out there). I suspect issues there, but it >> will be 3-6 months before I will have an environment where I can >> easily >> test this. Most likely, the way to handle this is by figuring out >> what >> case Microsoft uses for each name inside the protocol and then >> pre-mapping to that case before feeding things to (non-Microsoft) >> GSSAPI. > > Yes, it's for supporting Active Directory. It's there in the same way > it's there for krb5. > > >> I don't regard the case mapping issues as serious. We may not >> have the >> intended level of Windows/Unix compatibility, but I don't expect >> other >> issues. In other words I'm not even going to think about it until >> it's >> easy for me to investigate. > > Note that it's turned *off* by default, so it shouldn't even affect > you. Not my current concern. If I find a problem, then I'll be in a position to define how it ought to be done (*IF* it needs to be done differently). >>> Attached patch implements krb_match_realm for krb5, gssapi and >>> sspi per >>> complaint from Henry. Comments welcome. >>> >>> Working on documentation which will of course be ready when it's >>> committed :) >>> >>> Oh, and it changes the krb username handling to be the same as the >>> gssapi one. I've never heard of anybody actually using the other >>> version >>> that it used to support, and the comment clearly states that it was >>> broken for the really complex scenarios anyway - something nobody >>> has >>> complained about. >> >> Well, *I* complained about it. ;-) > > Um, not sure we're talking about the same thing. I know you complained > about the inability to match realm, but did you complain about the > inability to use things like full X.500 names as usernames? > > > //Magnus Well, it's not a high priority for me, but there is a GSSAPI mechanism called SPKM which uses X500-syle names (X509 certificate subject names to be precise). If we use gss_name_compare() properly then it should "just work".
Henry B. Hotz wrote: > > On Nov 1, 2007, at 1:40 PM, Magnus Hagander wrote: > >> Henry B. Hotz wrote: >>> Thank you very much. This helps, but I'm still evaluating how much. >>> >>> I *can* point at one problem though: you do a strchr(gbuf.value, '@') >>> and then error out if there isn't a Kerberos realm there. In fact that >>> is exactly the default username of at least one of the GSSAPI >>> implementations I've tested if the realm is the same as the local >>> default realm. >> >> Eh, so how do we then determine the difference between local realm and >> no realm given? > > Well, what I've seen is: no realm given if and only if the default > local realm matches the realm for the GSSAPI username. I don't think > that's guaranteed. Irrk. Very much irrk. >>> I'm not entirely sure what the intended semantics of krb_match_realm >>> are, but if you're trying to match the GSSAPI-authenticated name against >>> "value_of(PGUSER)@value_of(krb_match_realm)" then you need to construct >>> that string, gss_import_name() it, and then gss_compare_name() the >>> imported name with the authenticated name that GSSAPI already gave you. >>> I know the API overhead of doing that is a PITA, but that's what's going >>> to work. >> >> Why? > > Because if we're using the GSSAPI then we need to use the properties > defined by the GSSAPI, and not depend on observed behavior of specific > implementations of specific mechanisms. Otherwise things will be > non-portable or unreliable in ways that may be non-obvious. > > In particular gss_display_name() produces a character string intended > for display to a human being. It is *NOT* intended for access control. > As another example, Heimdal gss_display_name() puts '\' escapes in front > of special characters in the username. I don't think it's worth writing > special case code for that either. Ok. I can see that point. However, if you have those characters in your username, you may have other problems as well :-) Is there some other way to actually get the username from gss? I mean, if we *didn't* get it from the startup packet, how would we ever be able to determine what user logged in? > The standard defines two ways to do comparisons for access control. We > should use one of them. Anything else is going to be more work and less > reliable. What's the other way then? Last I checked there was no way to do case insensitive matching on gss_compare_name() but I could be on the wrong docs? Finding any kind of consistent docs for this stuff isn't exactly easy. Because we *must* have the ability to do case insensitive matching, or it *will* break on Windows. > Well, it's not a high priority for me, but there is a GSSAPI mechanism > called SPKM which uses X500-syle names (X509 certificate subject names > to be precise). If we use gss_name_compare() properly then it should > "just work". I'm unsure if PostgreSQL in general is prepared to deal with such usernames. You'd certainly have to verify that stuff before anything would "just work". //Magnus
On Nov 2, 2007, at 8:38 AM, Magnus Hagander wrote: > Henry B. Hotz wrote: >> >> On Nov 1, 2007, at 1:40 PM, Magnus Hagander wrote: >> >>> Henry B. Hotz wrote: >>>> Thank you very much. This helps, but I'm still evaluating how >>>> much. >>>> >>>> I *can* point at one problem though: you do a strchr >>>> (gbuf.value, '@') >>>> and then error out if there isn't a Kerberos realm there. In >>>> fact that >>>> is exactly the default username of at least one of the GSSAPI >>>> implementations I've tested if the realm is the same as the local >>>> default realm. >>> >>> Eh, so how do we then determine the difference between local >>> realm and >>> no realm given? >> >> Well, what I've seen is: no realm given if and only if the default >> local realm matches the realm for the GSSAPI username. I don't think >> that's guaranteed. > > Irrk. Very much irrk. > > >>>> I'm not entirely sure what the intended semantics of >>>> krb_match_realm >>>> are, but if you're trying to match the GSSAPI-authenticated name >>>> against >>>> "value_of(PGUSER)@value_of(krb_match_realm)" then you need to >>>> construct >>>> that string, gss_import_name() it, and then gss_compare_name() the >>>> imported name with the authenticated name that GSSAPI already >>>> gave you. >>>> I know the API overhead of doing that is a PITA, but that's >>>> what's going >>>> to work. >>> >>> Why? >> >> Because if we're using the GSSAPI then we need to use the properties >> defined by the GSSAPI, and not depend on observed behavior of >> specific >> implementations of specific mechanisms. Otherwise things will be >> non-portable or unreliable in ways that may be non-obvious. >> >> In particular gss_display_name() produces a character string intended >> for display to a human being. It is *NOT* intended for access >> control. >> As another example, Heimdal gss_display_name() puts '\' escapes in >> front >> of special characters in the username. I don't think it's worth >> writing >> special case code for that either. > > Ok. I can see that point. However, if you have those characters in > your > username, you may have other problems as well :-) Yeah. Not many people put spaces inside usernames. > Is there some other way to actually get the username from gss? I mean, > if we *didn't* get it from the startup packet, how would we ever be > able > to determine what user logged in? gss_export_name(), but what it returns is supposed to be an opaque binary blob. It's guaranteed to produce a unique, canonicalized name based on the specific mechanism in use. It is suitable for memcmp(). The exported name will re-import. Section 3.10 of rfc 2744 describes all this, and appears to be clearer than the Sun document I pointed you at. Certainly it's more concise. YMMV. memcmp() on exported names will only be true if everyone uses the same gss mechanism. (OK, the only one we care about is kerberos.) In contrast it's possible that gss_compare_name() would say that "uid=smith,ou=People,dc=example,dc=com" is the same as smith@EXAMPLE.COM. >> The standard defines two ways to do comparisons for access >> control. We >> should use one of them. Anything else is going to be more work >> and less >> reliable. > > What's the other way then? > > Last I checked there was no way to do case insensitive matching on > gss_compare_name() but I could be on the wrong docs? Finding any > kind of > consistent docs for this stuff isn't exactly easy. > Because we *must* have the ability to do case insensitive matching, or > it *will* break on Windows. No gss_compare_name() is case sensitive. I think the way to do it is to know what case Microsoft is going to use and pre-map everything to that case (before you do a gss_import_name()). I *think* Microsoft will use upper case for the service name so we will need to change from "postgres" to "POSTGRES" as the default name in service principals. I've seen places where they may be using lower case realm names (which makes *NO* sense to me). Absent an environment where I can actually look at all these things, my only point of reference is mod_auth_kerb, and the issues reported with it. I know an upper case "HTTP" is needed to interoperate with windows clients. An upper case realm name seems to be OK, as is a lower case server name in the second component. The actual usernames seem to be lower case, but that's not the concern of the mod_auth_kerb developers since the deployer just needs to put in whatever matches. I assume in AD you can't create both "smith" and "Smith", but can you create the latter at all? If you do, does AD remember the case for display purposes? Here at JPL usernames are lower case, and I don't think we allow anything special but hyphens in them, so I'm not likely to see a lot of the possible corner cases. I think you can upper case the service name, lower case the server name, upper case the realm name, and lower case the user name. If you can create "Smith" in AD and the user gets authenticated as "Smith@EXAMPLE.COM" at the protocol level then that won't work though. I'm actually trying to write some Kerberos principal to X500 name translation code for mod_auth_kerb right now, and I'm not happy with my options. I'm probably going to wind up doing something that I would tell you is improper, not general purpose, fragile, and shouldn't be done. |-P At least it's completely legitimate for me to assume that the only mechanism in use is the Kerberos one (since SPNEGO will have negotiated to kerberos before I need to worry about it). This is part of building up an example SAPP server (Solaris Apache Postgres Perl, you've heard of LAMP servers I assume). >> Well, it's not a high priority for me, but there is a GSSAPI >> mechanism >> called SPKM which uses X500-syle names (X509 certificate subject >> names >> to be precise). If we use gss_name_compare() properly then it should >> "just work". > > I'm unsure if PostgreSQL in general is prepared to deal with such > usernames. You'd certainly have to verify that stuff before anything > would "just work". > > //Magnus Well it might be nice if we could use the same logic and conventions to support TLS client identities as SPKM ones. Shouldn't be hard. (Famous last words.) ------------------------------------------------------------------------ The opinions expressed in this message are mine, not those of Caltech, JPL, NASA, or the US Government. Henry.B.Hotz@jpl.nasa.gov, or hbhotz@oxy.edu
On Nov 1, 2007, at 6:33 AM, Tom Lane wrote: > Magnus Hagander <magnus@hagander.net> writes: >> Tom Lane wrote: >>> Also the elog message texts need a bit of copy-editing. > >> Probably ;-) Got any specific hints, so I don't have to go through >> the >> iteration twice? > > The one that caught my eye was > > "SSPI domain (%s) does and configured domain (%s) > don't match", > > regards, tom lane s/does // I assume that's your point? ------------------------------------------------------------------------ The opinions expressed in this message are mine, not those of Caltech, JPL, NASA, or the US Government. Henry.B.Hotz@jpl.nasa.gov, or hbhotz@oxy.edu
Henry B. Hotz wrote: > > On Nov 1, 2007, at 6:33 AM, Tom Lane wrote: > >> Magnus Hagander <magnus@hagander.net> writes: >>> Tom Lane wrote: >>>> Also the elog message texts need a bit of copy-editing. >> >>> Probably ;-) Got any specific hints, so I don't have to go through the >>> iteration twice? >> >> The one that caught my eye was >> >> "SSPI domain (%s) does and configured domain (%s) don't >> match", >> >> regards, tom lane > > s/does // > > I assume that's your point? Yup, thanks. I fixed that per Toms earlier comment. I'll get back to you on the other email tomorrow, it's becoming late friday evening here now :-) //Magnus
On Fri, Nov 02, 2007 at 11:23:30AM -0700, Henry B. Hotz wrote: > >>>>I'm not entirely sure what the intended semantics of > >>>>krb_match_realm > >>>>are, but if you're trying to match the GSSAPI-authenticated name > >>>>against > >>>>"value_of(PGUSER)@value_of(krb_match_realm)" then you need to > >>>>construct > >>>>that string, gss_import_name() it, and then gss_compare_name() the > >>>>imported name with the authenticated name that GSSAPI already > >>>>gave you. > >>>>I know the API overhead of doing that is a PITA, but that's > >>>>what's going > >>>>to work. > >>> > >>>Why? > >> > >>Because if we're using the GSSAPI then we need to use the properties > >>defined by the GSSAPI, and not depend on observed behavior of > >>specific > >>implementations of specific mechanisms. Otherwise things will be > >>non-portable or unreliable in ways that may be non-obvious. > >> > >>In particular gss_display_name() produces a character string intended > >>for display to a human being. It is *NOT* intended for access > >>control. > >>As another example, Heimdal gss_display_name() puts '\' escapes in > >>front > >>of special characters in the username. I don't think it's worth > >>writing > >>special case code for that either. > > > >Ok. I can see that point. However, if you have those characters in > >your > >username, you may have other problems as well :-) > > Yeah. Not many people put spaces inside usernames. I think we can easily get away with not covering that case. > >Is there some other way to actually get the username from gss? I mean, > >if we *didn't* get it from the startup packet, how would we ever be > >able > >to determine what user logged in? > > gss_export_name(), but what it returns is supposed to be an opaque > binary blob. > > It's guaranteed to produce a unique, canonicalized name based on the > specific mechanism in use. It is suitable for memcmp(). The > exported name will re-import. Section 3.10 of rfc 2744 describes all > this, and appears to be clearer than the Sun document I pointed you > at. Certainly it's more concise. YMMV. Hmm. But it doesn't serve our purpose. > memcmp() on exported names will only be true if everyone uses the > same gss mechanism. (OK, the only one we care about is kerberos.) > In contrast it's possible that gss_compare_name() would say that > "uid=smith,ou=People,dc=example,dc=com" is the same as > smith@EXAMPLE.COM. No, memcmp()ing two separate strings (userid + match realm) with an opaque binary blob certainly won't help us at all. > >>The standard defines two ways to do comparisons for access > >>control. We > >>should use one of them. Anything else is going to be more work > >>and less > >>reliable. > > > >What's the other way then? > > > >Last I checked there was no way to do case insensitive matching on > >gss_compare_name() but I could be on the wrong docs? Finding any > >kind of > >consistent docs for this stuff isn't exactly easy. > >Because we *must* have the ability to do case insensitive matching, or > >it *will* break on Windows. > > No gss_compare_name() is case sensitive. I think the way to do it is > to know what case Microsoft is going to use and pre-map everything to > that case (before you do a gss_import_name()). I *think* Microsoft > will use upper case for the service name so we will need to change > from "postgres" to "POSTGRES" as the default name in service > principals. I've seen places where they may be using lower case > realm names (which makes *NO* sense to me). No. Microsoft will send you whatever case the user put into the login box when he logged into windows. It's case-*preserving*, but case-insensitive. However, AD itself requires uppercase service name, but that's a different thing. > Absent an environment where I can actually look at all these things, > my only point of reference is mod_auth_kerb, and the issues reported > with it. I know an upper case "HTTP" is needed to interoperate with > windows clients. An upper case realm name seems to be OK, as is a > lower case server name in the second component. The actual usernames > seem to be lower case, but that's not the concern of the > mod_auth_kerb developers since the deployer just needs to put in > whatever matches. The usernames depend on what the client puts in. It's generally a big problem because a lot of krb-aware applications can't deal with it. > I assume in AD you can't create both "smith" and "Smith", but can you > create the latter at all? If you do, does AD remember the case for > display purposes? Here at JPL usernames are lower case, and I don't > think we allow anything special but hyphens in them, so I'm not > likely to see a lot of the possible corner cases. You can and it remembers. But it has no effect on what is sent ni the kerberos packets - what's sent there is what the user typed in. Yes, that sucks bad, but that's how it is. > I think you can upper case the service name, lower case the server > name, upper case the realm name, and lower case the user name. If > you can create "Smith" in AD and the user gets authenticated as > "Smith@EXAMPLE.COM" at the protocol level then that won't work though. Which is how it is :-( From what I can tell, the least bad way to do it is still the patch that sits in the queue now (pending changes based on Stephens comments, but those are a differnt thing) //Magnus
On Nov 6, 2007, at 6:27 AM, Magnus Hagander wrote: > On Fri, Nov 02, 2007 at 11:23:30AM -0700, Henry B. Hotz wrote: >>>>>> I'm not entirely sure what the intended semantics of >>>>>> krb_match_realm >>>>>> are, but if you're trying to match the GSSAPI-authenticated name >>>>>> against >>>>>> "value_of(PGUSER)@value_of(krb_match_realm)" then you need to >>>>>> construct >>>>>> that string, gss_import_name() it, and then gss_compare_name() >>>>>> the >>>>>> imported name with the authenticated name that GSSAPI already >>>>>> gave you. >>>>>> I know the API overhead of doing that is a PITA, but that's >>>>>> what's going >>>>>> to work. >>>>> >>>>> Why? >>>> >>>> Because if we're using the GSSAPI then we need to use the >>>> properties >>>> defined by the GSSAPI, and not depend on observed behavior of >>>> specific >>>> implementations of specific mechanisms. Otherwise things will be >>>> non-portable or unreliable in ways that may be non-obvious. >>>> >>>> In particular gss_display_name() produces a character string >>>> intended >>>> for display to a human being. It is *NOT* intended for access >>>> control. >>>> As another example, Heimdal gss_display_name() puts '\' escapes in >>>> front >>>> of special characters in the username. I don't think it's worth >>>> writing >>>> special case code for that either. >>> >>> Ok. I can see that point. However, if you have those characters in >>> your >>> username, you may have other problems as well :-) >> >> Yeah. Not many people put spaces inside usernames. > > I think we can easily get away with not covering that case. *sigh* Yeah, maybe we have to live with it. >>> Is there some other way to actually get the username from gss? I >>> mean, >>> if we *didn't* get it from the startup packet, how would we ever be >>> able >>> to determine what user logged in? >> >> gss_export_name(), but what it returns is supposed to be an opaque >> binary blob. >> >> It's guaranteed to produce a unique, canonicalized name based on the >> specific mechanism in use. It is suitable for memcmp(). The >> exported name will re-import. Section 3.10 of rfc 2744 describes all >> this, and appears to be clearer than the Sun document I pointed you >> at. Certainly it's more concise. YMMV. > > Hmm. But it doesn't serve our purpose. Well, it *might* work to do a memcmp() of tolower() of the blobs. >> memcmp() on exported names will only be true if everyone uses the >> same gss mechanism. (OK, the only one we care about is kerberos.) >> In contrast it's possible that gss_compare_name() would say that >> "uid=smith,ou=People,dc=example,dc=com" is the same as >> smith@EXAMPLE.COM. > > No, memcmp()ing two separate strings (userid + match realm) with an > opaque > binary blob certainly won't help us at all. > > >>>> The standard defines two ways to do comparisons for access >>>> control. We >>>> should use one of them. Anything else is going to be more work >>>> and less >>>> reliable. >>> >>> What's the other way then? >>> >>> Last I checked there was no way to do case insensitive matching on >>> gss_compare_name() but I could be on the wrong docs? Finding any >>> kind of >>> consistent docs for this stuff isn't exactly easy. >>> Because we *must* have the ability to do case insensitive >>> matching, or >>> it *will* break on Windows. >> >> No gss_compare_name() is case sensitive. I think the way to do it is >> to know what case Microsoft is going to use and pre-map everything to >> that case (before you do a gss_import_name()). I *think* Microsoft >> will use upper case for the service name so we will need to change >> from "postgres" to "POSTGRES" as the default name in service >> principals. I've seen places where they may be using lower case >> realm names (which makes *NO* sense to me). > > No. Microsoft will send you whatever case the user put into the > login box > when he logged into windows. It's case-*preserving*, but case- > insensitive. That can't be entirely true. Maybe it's true for Microsoft's RC4 enctype, but it can't be true for the des-cbc-md5 enctype. The protocol runs with some case, and the question is what case it uses when it matters. > However, AD itself requires uppercase service name, but that's a > different > thing. OK. >> Absent an environment where I can actually look at all these things, >> my only point of reference is mod_auth_kerb, and the issues reported >> with it. I know an upper case "HTTP" is needed to interoperate with >> windows clients. An upper case realm name seems to be OK, as is a >> lower case server name in the second component. The actual usernames >> seem to be lower case, but that's not the concern of the >> mod_auth_kerb developers since the deployer just needs to put in >> whatever matches. > > The usernames depend on what the client puts in. It's generally a big > problem because a lot of krb-aware applications can't deal with it. I'd bet that the authenticated username in the service ticket is always a specific case. I'd also bet that it's whatever case the username was created with, e.g. "Smith". Without being able to inspect packets myself I'm only guessing though. >> I assume in AD you can't create both "smith" and "Smith", but can you >> create the latter at all? If you do, does AD remember the case for >> display purposes? Here at JPL usernames are lower case, and I don't >> think we allow anything special but hyphens in them, so I'm not >> likely to see a lot of the possible corner cases. > > You can and it remembers. But it has no effect on what is sent ni the > kerberos packets - what's sent there is what the user typed in. > Yes, that > sucks bad, but that's how it is. Hmmm. See above. It isn't possible to make it irrelevant everywhere, unless you only use RC4. Vista uses AES so it looses that loophole though. Expanding a bit: I can believe that the client uses the entered case in the AS_REQ. It's even possible that the DC follows suit for parts of the AS_REP. However I doubt that a non-Windows Kerberos client can do even that initial exchange unless the case of the username matches properly because the username is part of the salt used to convert passwords to keys. For a non-windows client I think you can assume the case will always match. The question is what does the DC put in the service ticket as the authenticated username. (A secondary question is if it's different if the original authentication was to a non-Windows Kerberos server.) I would bet that it puts the originally defined case in the service ticket (at least in the secondary case). I wonder if case conversion is the right way to create compatibility with GSSAPI though. If the user always comes in with a specific case then shouldn't we instead find a way to make sure the PG user is created with the corresponding case? There are several ways you can test for the existence of a user in a Kerberos service, for example kinit with a garbage password will give different errors. If you think a hook in the add user code is in scope I can investigate if there is a way to verify the existence of a username with the GSSAPI instead of the Kerberos API. It would be really easy to inspect what happens with tcpdump/snoop and Ethereal, but that's the only way I can see to really answer these questions. >> I think you can upper case the service name, lower case the server >> name, upper case the realm name, and lower case the user name. If >> you can create "Smith" in AD and the user gets authenticated as >> "Smith@EXAMPLE.COM" at the protocol level then that won't work >> though. > > Which is how it is :-( I can only > From what I can tell, the least bad way to do it is still the patch > that > sits in the queue now (pending changes based on Stephens comments, but > those are a differnt thing) > > //Magnus ------------------------------------------------------------------------ The opinions expressed in this message are mine, not those of Caltech, JPL, NASA, or the US Government. Henry.B.Hotz@jpl.nasa.gov, or hbhotz@oxy.edu
On Tue, 2007-11-06 at 18:10 -0800, Henry B. Hotz wrote: > On Nov 6, 2007, at 6:27 AM, Magnus Hagander wrote: > > On Fri, Nov 02, 2007 at 11:23:30AM -0700, Henry B. Hotz wrote: > >>>>>> I'm not entirely sure what the intended semantics of > >>>>>> krb_match_realm > >>>>>> are, but if you're trying to match the GSSAPI-authenticated name > >>>>>> against > >>>>>> "value_of(PGUSER)@value_of(krb_match_realm)" then you need to > >>>>>> construct > >>>>>> that string, gss_import_name() it, and then gss_compare_name() > >>>>>> the > >>>>>> imported name with the authenticated name that GSSAPI already > >>>>>> gave you. > >>>>>> I know the API overhead of doing that is a PITA, but that's > >>>>>> what's going > >>>>>> to work. > >>>>> > >>>>> Why? > >>>> > >>>> Because if we're using the GSSAPI then we need to use the > >>>> properties > >>>> defined by the GSSAPI, and not depend on observed behavior of > >>>> specific > >>>> implementations of specific mechanisms. Otherwise things will be > >>>> non-portable or unreliable in ways that may be non-obvious. > >>>> > >>>> In particular gss_display_name() produces a character string > >>>> intended > >>>> for display to a human being. It is *NOT* intended for access > >>>> control. > >>>> As another example, Heimdal gss_display_name() puts '\' escapes in > >>>> front > >>>> of special characters in the username. I don't think it's worth > >>>> writing > >>>> special case code for that either. > >>> > >>> Ok. I can see that point. However, if you have those characters in > >>> your > >>> username, you may have other problems as well :-) > >> > >> Yeah. Not many people put spaces inside usernames. > > > > I think we can easily get away with not covering that case. > > *sigh* Yeah, maybe we have to live with it. Yeah, that's kind of where I'm going - it's certainly not perfect, but it's the least bad one. Given this, I'll go ahead with the current version of the patch, and we can consider making better changes at a later time assuming we figure them out. It's still a lot better than what's in there now, and it *will* cover the vast majority of cases. I'll address Stephens comments separately. > >> It's guaranteed to produce a unique, canonicalized name based on the > >> specific mechanism in use. It is suitable for memcmp(). The > >> exported name will re-import. Section 3.10 of rfc 2744 describes all > >> this, and appears to be clearer than the Sun document I pointed you > >> at. Certainly it's more concise. YMMV. > > > > Hmm. But it doesn't serve our purpose. > > Well, it *might* work to do a memcmp() of tolower() of the blobs. Right, but if they're defined as blobs, that's even less safe than we did before. > >> No gss_compare_name() is case sensitive. I think the way to do it is > >> to know what case Microsoft is going to use and pre-map everything to > >> that case (before you do a gss_import_name()). I *think* Microsoft > >> will use upper case for the service name so we will need to change > >> from "postgres" to "POSTGRES" as the default name in service > >> principals. I've seen places where they may be using lower case > >> realm names (which makes *NO* sense to me). > > > > No. Microsoft will send you whatever case the user put into the > > login box > > when he logged into windows. It's case-*preserving*, but case- > > insensitive. > > That can't be entirely true. Maybe it's true for Microsoft's RC4 > enctype, but it can't be true for the des-cbc-md5 enctype. The > protocol runs with some case, and the question is what case it uses > when it matters. Haven't protocol-traced it, but our systems use des-cbc-md5. It's the only one I managed to get working with pg server running on Linux and clients running on Windows. And in this case, the case insensitive/case preserving behavior is a fact. > >> I assume in AD you can't create both "smith" and "Smith", but can > you > >> create the latter at all? If you do, does AD remember the case for > >> display purposes? Here at JPL usernames are lower case, and I don't > >> think we allow anything special but hyphens in them, so I'm not > >> likely to see a lot of the possible corner cases. > > > > You can and it remembers. But it has no effect on what is sent ni the > > kerberos packets - what's sent there is what the user typed in. > > Yes, that > > sucks bad, but that's how it is. > > Hmmm. See above. It isn't possible to make it irrelevant > everywhere, unless you only use RC4. Vista uses AES so it looses > that loophole though. > Yeah, I haven't tried Vista at all. I've only done 2000, XP and 2003. > I wonder if case conversion is the right way to create compatibility > with GSSAPI though. If the user always comes in with a specific case > then shouldn't we instead find a way to make sure the PG user is > created with the corresponding case? There are several ways you can > test for the existence of a user in a Kerberos service, for example > kinit with a garbage password will give different errors. That's why we have krb5_caseninsens_users - to let the user choose it. //Magnus
On Nov 9, 2007, at 5:24 AM, Magnus Hagander wrote: > > On Tue, 2007-11-06 at 18:10 -0800, Henry B. Hotz wrote: >> On Nov 6, 2007, at 6:27 AM, Magnus Hagander wrote: >>> On Fri, Nov 02, 2007 at 11:23:30AM -0700, Henry B. Hotz wrote: >>>>>>>> I'm not entirely sure what the intended semantics of >>>>>>>> krb_match_realm >>>>>>>> are, but if you're trying to match the GSSAPI-authenticated >>>>>>>> name >>>>>>>> against >>>>>>>> "value_of(PGUSER)@value_of(krb_match_realm)" then you need to >>>>>>>> construct >>>>>>>> that string, gss_import_name() it, and then gss_compare_name() >>>>>>>> the >>>>>>>> imported name with the authenticated name that GSSAPI already >>>>>>>> gave you. >>>>>>>> I know the API overhead of doing that is a PITA, but that's >>>>>>>> what's going >>>>>>>> to work. >>>>>>> >>>>>>> Why? >>>>>> >>>>>> Because if we're using the GSSAPI then we need to use the >>>>>> properties >>>>>> defined by the GSSAPI, and not depend on observed behavior of >>>>>> specific >>>>>> implementations of specific mechanisms. Otherwise things will be >>>>>> non-portable or unreliable in ways that may be non-obvious. >>>>>> >>>>>> In particular gss_display_name() produces a character string >>>>>> intended >>>>>> for display to a human being. It is *NOT* intended for access >>>>>> control. >>>>>> As another example, Heimdal gss_display_name() puts '\' >>>>>> escapes in >>>>>> front >>>>>> of special characters in the username. I don't think it's worth >>>>>> writing >>>>>> special case code for that either. >>>>> >>>>> Ok. I can see that point. However, if you have those characters in >>>>> your >>>>> username, you may have other problems as well :-) >>>> >>>> Yeah. Not many people put spaces inside usernames. >>> >>> I think we can easily get away with not covering that case. >> >> *sigh* Yeah, maybe we have to live with it. > > Yeah, that's kind of where I'm going - it's certainly not perfect, but > it's the least bad one. > > Given this, I'll go ahead with the current version of the patch, > and we > can consider making better changes at a later time assuming we figure > them out. It's still a lot better than what's in there now, and it > *will* cover the vast majority of cases. > > I'll address Stephens comments separately. > > >>>> It's guaranteed to produce a unique, canonicalized name based on >>>> the >>>> specific mechanism in use. It is suitable for memcmp(). The >>>> exported name will re-import. Section 3.10 of rfc 2744 >>>> describes all >>>> this, and appears to be clearer than the Sun document I pointed you >>>> at. Certainly it's more concise. YMMV. >>> >>> Hmm. But it doesn't serve our purpose. >> >> Well, it *might* work to do a memcmp() of tolower() of the blobs. > > Right, but if they're defined as blobs, that's even less safe than we > did before. > > >>>> No gss_compare_name() is case sensitive. I think the way to do >>>> it is >>>> to know what case Microsoft is going to use and pre-map >>>> everything to >>>> that case (before you do a gss_import_name()). I *think* Microsoft >>>> will use upper case for the service name so we will need to change >>>> from "postgres" to "POSTGRES" as the default name in service >>>> principals. I've seen places where they may be using lower case >>>> realm names (which makes *NO* sense to me). >>> >>> No. Microsoft will send you whatever case the user put into the >>> login box >>> when he logged into windows. It's case-*preserving*, but case- >>> insensitive. >> >> That can't be entirely true. Maybe it's true for Microsoft's RC4 >> enctype, but it can't be true for the des-cbc-md5 enctype. The >> protocol runs with some case, and the question is what case it uses >> when it matters. > > Haven't protocol-traced it, but our systems use des-cbc-md5. It's the > only one I managed to get working with pg server running on Linux and > clients running on Windows. And in this case, the case insensitive/ > case > preserving behavior is a fact. I was thinking that the case of the principal affects the protocol, but actually I guess that's only true for the string-to-key function. That would affect a user's ability to get the initial tgt, but not how service tickets are handled. Given case preservation, that would guarantee the correct case for a non-Windows client (for both Windows and Unix servers), but nowhere else. Kind of blows the SSPI/GSSAPI compatibility that's supposed to exist. I think I may start a discussion of this on an IETF list in case people want to update the GSSAPI standard. I suppose you win. Just do a gss_display_name() and do a case insensitive compare. I can't do any independent verification. *bleah* Can you leave the compare inside gssapi if it's not case insensitive though? >>>> I assume in AD you can't create both "smith" and "Smith", but can >> you >>>> create the latter at all? If you do, does AD remember the case for >>>> display purposes? Here at JPL usernames are lower case, and I >>>> don't >>>> think we allow anything special but hyphens in them, so I'm not >>>> likely to see a lot of the possible corner cases. >>> >>> You can and it remembers. But it has no effect on what is sent ni >>> the >>> kerberos packets - what's sent there is what the user typed in. >>> Yes, that >>> sucks bad, but that's how it is. >> >> Hmmm. See above. It isn't possible to make it irrelevant >> everywhere, unless you only use RC4. Vista uses AES so it looses >> that loophole though. >> > Yeah, I haven't tried Vista at all. I've only done 2000, XP and 2003. > > >> I wonder if case conversion is the right way to create compatibility >> with GSSAPI though. If the user always comes in with a specific case >> then shouldn't we instead find a way to make sure the PG user is >> created with the corresponding case? There are several ways you can >> test for the existence of a user in a Kerberos service, for example >> kinit with a garbage password will give different errors. > > That's why we have krb5_caseninsens_users - to let the user choose it. > > > //Magnus > ------------------------------------------------------------------------ The opinions expressed in this message are mine, not those of Caltech, JPL, NASA, or the US Government. Henry.B.Hotz@jpl.nasa.gov, or hbhotz@oxy.edu