Closed
Bug 394071
Opened 17 years ago
Closed 17 years ago
LDAP SASL bind fails when the given hostname is numeric IPv6 address
Categories
(Directory :: LDAP C SDK, defect)
Tracking
(Not tracked)
RESOLVED
FIXED
People
(Reporter: nhosoi, Assigned: mcs)
Details
Attachments
(2 files, 2 obsolete files)
6.14 KB,
patch
|
Details | Diff | Splinter Review | |
1.53 KB,
text/plain
|
Details |
Sample error case: $ ./ldapsearch -h [3ffe:1111:2222:1000::11] -p <port> -o "mech=GSSAPI" -s sub -b "ou=TestPeople,o=sasl.com" "(uid=testuser1)" Bind Error: Local error Bind Error: additional info: SASL(-1): generic failure: GSSAPI Error: An invalid name was supplied (Hostname cannot be canonicalized) When binding, LDAP tools call nsldapi_sasl_open via ldap_sasl_interactive_bind_ext_s. In the function, it calls the sasl client init function sasl_client_new. nsldapi_sasl_open passes the "host" as users type, but sasl_client_new expects serverRQDN (as attached below). Note that sasl_client_new handles correctly if the host is numeric IPv4 address. [mozilla/directory/c-sdk/ldap/libldap/saslio.c] int nsldapi_sasl_open( LDAP *ld, LDAPConn *lconn, sasl_conn_t **ctx, sasl_ssf_t ssf ) { int saslrc; char *host = NULL; [...] if ( 0 != ldap_get_option( ld, LDAP_OPT_HOST_NAME, &host ) ) { LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, NULL ); return( LDAP_LOCAL_ERROR ); } saslrc = sasl_client_new( "ldap", host, NULL, NULL, /* iplocalport, ipremoteport - use defaults */ NULL, 0, ctx ); ldap_memfree(host); [...] [cyrus-sasl/lib/client.c] /* initialize a client exchange based on the specified mechanism * service -- registered name of the service using SASL (e.g. "imap") * serverFQDN -- the fully qualified domain name of the server * iplocalport -- client IPv4/IPv6 domain literal string with port * (if NULL, then mechanisms requiring IPaddr are disabled) * ipremoteport -- server IPv4/IPv6 domain literal string with port * (if NULL, then mechanisms requiring IPaddr are disabled) * prompt_supp -- list of client interactions supported * may also include sasl_getopt_t context & call * NULL prompt_supp = user/pass via SASL_INTERACT only * NULL proc = interaction supported via SASL_INTERACT * secflags -- security flags (see above) * in/out: * pconn -- connection negotiation structure * pointer to NULL => allocate new * non-NULL => recycle storage and go for next available mech * * Returns: * SASL_OK -- success * SASL_NOMECH -- no mechanism meets requested properties * SASL_NOMEM -- not enough memory */ I also tried the OpenLDAP client. It does not support the numeric IPv6 address correctly either: $ ldapsearch -h [3ffe:1111:2222:1000::11] -p 11111 -Y "mech=GSSAPI" -s sub -b "ou=TestPeople,o=sasl.com" "(uid=testuser1)" SASL/GSSAPI authentication started ldap_sasl_interactive_bind_s: Local error (-2) additional info: SASL(-1): generic failure: GSSAPI Error: An invalid name was supplied (Cannot determine realm for numeric host address) To get FQDN from a numeric IPv6 address, we may need to use getaddrinfo & getnameinfo.
Assignee | ||
Comment 1•17 years ago
|
||
Interesting. This may be a silly question, but is it important to support SASL with IP addresses (if a fully qualified domain name is needed by SASL, I assume most LDAP SASL applications will know to pass one in). Adding reverse DNS lookups inside libldap is a little messy. Maybe the LDAP tools should do a reverse lookup when needed. Also, I do not understand why this already works for IPv4 but not for IPv6. Is lack of IPv6 support a limitation of the Cyrus SASL library? Can that be fixed?
Reporter | ||
Comment 2•17 years ago
|
||
(In reply to comment #1) > Interesting. This may be a silly question, but is it important to support SASL > with IP addresses (if a fully qualified domain name is needed by SASL, I assume > most LDAP SASL applications will know to pass one in). Adding reverse DNS > lookups inside libldap is a little messy. Maybe the LDAP tools should do a > reverse lookup when needed. Hi Mark! Actually, I am asking the same question to myself. :) And I have to agree with you that introducing reverse DNS lookup for IPv6 in the generic form looks pretty tough. Regarding the importance, besides for our QA effort :), only a case I could think of is for the Directory Server administrators to check the IPv6 configuration. When some network problem occurs, it might help them to troubleshoot. Other than that... :) > Also, I do not understand why this already works for IPv4 but not for IPv6. Is > lack of IPv6 support a limitation of the Cyrus SASL library? Can that be > fixed? We could file a bug to Cyrus SASL. Based upon this spec "serverFQDN -- the fully qualified domain name of the server" for the second argument of sasl_client_new, working for IPv4 would be a bonus, I guess, though...
Reporter | ||
Comment 3•17 years ago
|
||
Files: configure.in config/autoconf.mk.in ldap/clients/tools/Makefile.in ldap/clients/tools/common.c (configure is also modified, but not attached here) Fix Description: As Mark suggested, I'm proposing to add the conversion function just to tools/common.c. It's called from ldaptool_ldap_init and used only if the given host name is IPv6 numeric address. If the conversion fails, the ldap client utilities do the operation with the use-passed host name. The function is made from 3 parts: 1. check if the given host name looks like IPv6 numeric address or not 2. if it is, try Here's the sample usage: $ ./ldapsearch -h '3ffe:1111:2222:3333::ff' -v -D "cn=Directory Manager" -w password -b "cn=config" -s base "(objectclass=*)" dn [...] ldap_init( hostA.full.domain.com, 389 ) filter pattern: (objectclass=*) returning: dn configure.in: added getaddrinfo and getnameinfo to AC_CHECK_FUNCS config/autoconf.mk.in: added macros HAVE_GETADDRINFO and HAVE_GETNAMEINFO
Attachment #280836 -
Flags: review?(mcs)
Reporter | ||
Comment 4•17 years ago
|
||
Oope, this part was not completed. The function is made from 3 parts: 1. check if the given host name looks like IPv6 numeric address or not 2. if it is, try getaddrinfo + getnameinfo if available 3. if they are not or they failed, try NSPR functions, which are a bit old handling IPv6 addresses, but for this case, they return the expected result -- FQDN.
Comment 5•17 years ago
|
||
If you are looking for two colons, I don't think this will work: hostp = strchr( numaddr, ':' ); if ( hostp ) { hostp = strchr( numaddr, ':' ); /* should use (hostp+1) instead of numaddr here? */ if ( hostp ) Do you need to see if len(numaddr) >= blen here, before doing strcpy into buf? } else { isIPv6Numeric = 1; strcpy( buf, numaddr ); } You should use type size_t for string lengths and buffer sizes and structure sizes. See man strlen, man strncpy, man getaddrinfo, and man getnameinfo. All of the length/size parameters and return values (including sizeof) are size_t. For example, size_t hlen = sizeof(hname); or size_t slen = 0;
Reporter | ||
Comment 6•17 years ago
|
||
Thank you for reviewing my proposal, Rich. I fixed the 3 places you pointed out.
Attachment #280836 -
Attachment is obsolete: true
Attachment #280907 -
Flags: review?(richm)
Attachment #280836 -
Flags: review?(mcs)
Comment 7•17 years ago
|
||
(In reply to comment #6) > Created an attachment (id=280907) [details] > revised diff of common.c > > Thank you for reviewing my proposal, Rich. > I fixed the 3 places you pointed out. Ok. Looks good.
Assignee | ||
Comment 8•17 years ago
|
||
Do you need to check against blen before this strcpy() as well: if ( workp ) { /* [address] form */ strncpy( buf, hostp, workp - hostp ); buf[workp - hostp] = '\0'; } else { strcpy( buf, hostp ); ^^^^^^^^^^^^^^^^^^^^^ } ? The parsing is messy. Can you avoid that by letting getnameinfo() tell you if it is a numeric IPv6 address or not (I have not thought about this problem a lot, so maybe this is a bad suggestion).
Reporter | ||
Comment 9•17 years ago
|
||
Thank you, Mark! *shame shame* ... :( Regarding letting getnameinfo handle the address, I need to remove '[' and ']' from the string, but other than that, it works fine. On the system with no getnameinfo and getaddrinfo, it converts all input into FQDN. I thought we did not want to do it. I don't see any harm, but it may be redundant if we do IPv4 address -> FQDN and use it.
Reporter | ||
Comment 10•17 years ago
|
||
The parse code is a little messy, but to make the impact to the code minimized, I'd like to keep it until we don't have to support platforms without getaddrinfo and getnameinfo...
Attachment #280907 -
Attachment is obsolete: true
Attachment #280907 -
Flags: review?(richm)
Comment 11•17 years ago
|
||
(In reply to comment #10) > Created an attachment (id=280970) [details] > 2nd revised diff of common.c > > The parse code is a little messy, but to make the impact to the code minimized, > I'd like to keep it until we don't have to support platforms without > getaddrinfo and getnameinfo... > Ok.
Reporter | ||
Comment 12•17 years ago
|
||
Reviewed by Rich and Mark (Thank you very much!). Checked in into HEAD.
Reporter | ||
Updated•17 years ago
|
Status: NEW → RESOLVED
Closed: 17 years ago
Resolution: --- → FIXED
Comment 13•15 years ago
|
||
Hi, Noriko: I have hit a similar problem as you. But it seems I can't use your fix, because your fix is in "clients/tools/common.c" which is probably used by the utility "ldapsearch". My case is related to the dynamic library "libldap60.so". :-( And, another scenario I hit is that when the Kerberos authentication server is configured with IPv6 address, SASL binding will fail. Have you ever met the same problem as mine? By the way, I am not sure if this is a MozLDAP defect or Cyrus SASL library defect.
Reporter | ||
Comment 14•15 years ago
|
||
Hi Xu, I agree with you that it should be taken care in Cyrus SASL. Since we were urgent to support the ldap client utilities, I put the fix into the command line code. Luckily, we haven't run into the problem in the library level. Could it be possible for you to do something similar as we did in your application?
Comment 15•15 years ago
|
||
If the passed-in LDAP server is an IPv6 address, we used a similar strategy as you. The difference is that we did a preliminary simple binding to find the server's attribute "dnsHostName", which usually is an FQDN. Then we use this FQDN to do SASL binding. That way, we walked around this problem. And this walk-around is done in the application level, beyond MozLDAP libraries. Anyway, I think probably Cyrus SASL library need a fix to handle hard-coded IPv6 address of LDAP server. My problem is a little bit more serious. As you know, SASL binding is done in conjunction with Kerberos authentication server. But when the Kerberos authentication server is configured with hard-coded IPv6 address, the binding breaks. Another scenario is Kerberos authentication server is configured with hostname, and the option "Prefer IPv6 address over IPv4 address" in DNS server settings in our printer is ticked, so that DNS server will resolve the Kerberos hostname to IPv6 address, then SASL binding will break as well. It should be a Cyrus SASL defect, right? Need your confirmation.
Reporter | ||
Comment 16•15 years ago
|
||
I think you should ask the question of the Cyrus SASL community. http://cyrusimap.web.cmu.edu/lists.html
Comment 17•15 years ago
|
||
I didn't find a place to report a bug in Cyrus mailist, is it here: cyrus-bugzilla@lists.andrew.cmu.edu?
Comment 18•15 years ago
|
||
Hi, Noriko: Want to ask a silly question. In your fix, you called getaddrinfo( buf, NULL, &hints, &ainfo ) and then rc = getnameinfo( saddr, slen, buf, (socklen_t)blen, NULL, 0, NI_NAMEREQD ) to convert the IPv6 address to an FQDN. But, isn't it enough by calling just the latter, i.e. getnameinfo() with the IPv6 address in buf? I just don't understand why you call getaddrinfo() when buf already stores an IPv6 address. Sorry for my dumb, Xu Qiang
Comment 19•15 years ago
|
||
(In reply to comment #17) > I didn't find a place to report a bug in Cyrus mailist, is it here: > cyrus-bugzilla@lists.andrew.cmu.edu? There is a bugzilla instance for Cyrus SASL bugs at http://bugzilla.andrew.cmu.edu/
Reporter | ||
Comment 20•15 years ago
|
||
(In reply to comment #18) > Hi, Noriko: > > Want to ask a silly question. > > In your fix, you called getaddrinfo( buf, NULL, &hints, &ainfo ) and then rc = > getnameinfo( saddr, slen, buf, (socklen_t)blen, NULL, 0, NI_NAMEREQD ) to > convert the IPv6 address to an FQDN. > > But, isn't it enough by calling just the latter, i.e. getnameinfo() with the > IPv6 address in buf? > > I just don't understand why you call getaddrinfo() when buf already stores an > IPv6 address. > > Sorry for my dumb, > Xu Qiang I called getaddrinfo to convert the numeric address in "char *" into sockaddr. I also thought by calling getaddrinfo, we could guarantee the input string is valid. If not, it returns an error...
Comment 21•15 years ago
|
||
(In reply to comment #20) > I called getaddrinfo to convert the numeric address in "char *" into sockaddr. > I also thought by calling getaddrinfo, we could guarantee the input string is > valid. If not, it returns an error... Just realized that the func getnameinfo() can't take a "char *" type as input directly. The source must be a "const struct sockaddr *" type. My negligence. Thanks for your clarification, Noriko!
Comment 22•15 years ago
|
||
Hi, Noriko: Another thing to seek your help. Although my SASL binding is successful, there is some minor defect. Please look at the following trace I captured. As you can see, the Malformed Packet is in the 2nd round of binding interaction with the server: ======================================== 32 17.839052 13.198.98.107 13.198.98.35 LDAP bindRequest(1) "<ROOT>" sasl 33 17.917608 13.198.98.35 13.198.98.107 LDAP bindResponse(1) saslBindInProgress 35 17.919333 13.198.98.107 13.198.98.35 LDAP bindRequest(2) "<ROOT>" [Malformed Packet] 36 17.919637 13.198.98.35 13.198.98.107 LDAP bindResponse(2) saslBindInProgress 37 17.920316 13.198.98.107 13.198.98.35 LDAP bindRequest(3) "<ROOT>" sasl 38 17.920691 13.198.98.35 13.198.98.107 LDAP bindResponse(3) success ======================================== I am not sure if packet 35 is normal or not? After all, it says the packet is malformed. In contrast, a trace captured with OpenLDAP ldapsearch utility does not have this malformat packet: ======================================== 22 24.805633 13.198.98.35 13.198.98.190 LDAP bindResponse(1) saslBindInProgress 28 26.616093 13.198.98.190 13.198.98.35 LDAP bindRequest(2) "<ROOT>" sasl 29 26.616459 13.198.98.35 13.198.98.190 LDAP bindResponse(2) saslBindInProgress 31 26.616705 13.198.98.190 13.198.98.35 LDAP bindRequest(3) "<ROOT>" sasl 32 26.633134 13.198.98.35 13.198.98.190 LDAP bindResponse(3) success ======================================== When I compare the content of packet 35 in MozLDAP trace and packet 29 in OpenLDAP trace, it is noted that the MozLDAP packet has extra bytes "04 00" after "mechanism: GSSAPI". These extra bytes are interpreted as "<MISSING> credentials" by WireShark. In contrast, although the OpenLDAP packet doesn't have any credential information as well, it doesn't have these extra bytes. That's why packet 35 in MozLDAP trace is marked as Malformed Packet, while packet 29 in OpenLDAP trace is not. In your SASL binding with MozLDAP, have you observed the same [Malformed Packet] as in my network trace? I want to make sure whether this is caused by the defect in MozLDAP or it is due to my incorrect calling of the SASL LDAP interface. Thanks, Xu Qiang
Reporter | ||
Comment 23•15 years ago
|
||
Hi Xu, The case 1 with the Malformed Packet message is from you application? Could it be possible to run mozldap ldapsearch doing the same bind? If you could run it, does it also show "Malformed Packet"? For instance, the LDAP C SDK api ldap_sasl_bind checks if the given credential is NULL or not. If NULL, it does not put the octet string for the credential. If an empty string "" is given, it might send such missing credential... I'm talking about this if clause. If you could run your application in some debugger and see which path it's taking, it might be able to tell us what's going on... libldap/saslbind.c 540 int 541 LDAP_CALL 542 ldap_sasl_bind( [...] 620 /* fill it in */ 621 if ( simple ) { /* simple bind; works in LDAPv2 or v3 */ [...] 633 } else { /* SASL bind; requires LDAPv3 or better */ 634 if ( cred == NULL ) { 635 rc = ber_printf( ber, "{it{ist{s}}", msgid, 636 LDAP_REQ_BIND, ldapversion, dn, LDAP_AUTH_SASL, 637 mechanism ); 638 } else { 639 rc = ber_printf( ber, "{it{ist{so}}", msgid, 640 LDAP_REQ_BIND, ldapversion, dn, LDAP_AUTH_SASL, 641 mechanism, cred->bv_val, 642 cred->bv_len ); 643 } 644 } Thanks, --noriko
Comment 24•15 years ago
|
||
Thank you, Noriko. (In reply to comment #23) > Hi Xu, > The case 1 with the Malformed Packet message is from you application? Could it > be possible to run mozldap ldapsearch doing the same bind? If you could run > it, does it also show "Malformed Packet"? Yes, it happens when our code is calling MozLDAP library to do SASL binding. I don't know how to use ldapsearch (from MozLDAP C-SDK) to do it. It hasn't been compiled, yet. The OS team only delivered the library part. > For instance, the LDAP C SDK api ldap_sasl_bind checks if the given credential > is NULL or not. If NULL, it does not put the octet string for the credential. > If an empty string "" is given, it might send such missing credential... > I'm talking about this if clause. If you could run your application in some > debugger and see which path it's taking, it might be able to tell us what's > going on... > libldap/saslbind.c > 540 int > 541 LDAP_CALL > 542 ldap_sasl_bind( > [...] > 620 /* fill it in */ > 621 if ( simple ) { /* simple bind; works in LDAPv2 or v3 */ > [...] > 633 } else { /* SASL bind; requires LDAPv3 or better */ > 634 if ( cred == NULL ) { > 635 rc = ber_printf( ber, "{it{ist{s}}", msgid, > 636 LDAP_REQ_BIND, ldapversion, dn, LDAP_AUTH_SASL, > 637 mechanism ); > 638 } else { > 639 rc = ber_printf( ber, "{it{ist{so}}", msgid, > 640 LDAP_REQ_BIND, ldapversion, dn, LDAP_AUTH_SASL, > 641 mechanism, cred->bv_val, > 642 cred->bv_len ); > 643 } > 644 } I have almost figured it out the other day. Here is the link: https://bugzilla.mozilla.org/show_bug.cgi?id=511817 But I must wait for OS team to build a new library with the change to test. If you help me to test the fix, I'll be very grateful. Thanks, Xu Qiang
Comment 25•15 years ago
|
||
Hi, Noriko: Just want you to know that the fix for the problem of "Malfomed Packet" (https://bugzilla.mozilla.org/show_bug.cgi?id=511817) has been verified. A patch has been submitted to be reviewed and checked in. Thanks, Xu Qiang
You need to log in
before you can comment on or make changes to this bug.
Description
•