From: Olivier M. <oli...@gm...> - 2010-12-22 13:05:18
|
2010/12/13 Frank Lahm <fra...@go...> > 2010/12/13 Olivier Mouchet <oli...@gm...>: > > Hi guys, > > > > Using netatalk 2.1.3, I experience problems using password containing > some > > special characters, see that: > > NOK: exclamation mark, minus, dash, characters with french accents > > exclamation mark, minus, dash: works for me. > characters with french accents: I've tried with 'ä', ie german 'a' > with umlaut. Doesn't work, probably due to different UTF8 encodings: > the Mac passes decomposed UTF8, the server uses precomposed UTF8. As a > result, both strings when compared bitwise don't match. > > -f > Franck, * Actually there is no problem with exclamation mark, minus, or dash characters, I mixed debug and fix try, let me apologize for the time you've spent. * Anyway, the precomposed/decomposed unicode forms seems to be the right track. Looking at the GPL source code from Synology, it seems that the password string is explicitely converted from MAC_ROMAN to UCS2 then to UTF8 before calling pam_authenticate(). I prefer to execute this operation as a fallback, once a first authentication try has failed. As a beginning, I patched the authentication in the uam_dhx_pam, code is inspired from Synology's one, any comments are welcome. Actually, it allows the usage of acute and grave accents, but the german umlaut (or diaeresis) and circumflex accent 'ê' still mismatch as the stressed char is lost, i.e. with "franzözisch" password, I get "franzozisch" as string to be matched, so unicode decomposition is just useless in this case. I did not yet investigate this problem. Index: libatalk/unicode/charcnv.c =================================================================== --- libatalk/unicode/charcnv.c (revision 5045) +++ libatalk/unicode/charcnv.c (working copy) @@ -65,8 +65,16 @@ * @sa lib/iconv.c */ +char *rgszCharsetName[NUM_CHARSETS] = { + "UCS-2", // CH_UCS2 + "UTF8", // CH_UTF8 + NULL, // CH_MAC + NULL, // CH_UNIX + "UTF8-MAC", // CH_UTF8_MAC + "MAC_ROMAN", // CH_MAC_ROMAN +}; -#define MAX_CHARSETS 20 +#define MAX_CHARSETS NUM_CHARSETS #define CHECK_FLAGS(a,b) (((a)!=NULL) ? (*(a) & (b)) : 0 ) @@ -116,9 +124,10 @@ first = 0; } - if (ch == CH_UCS2) ret = "UCS-2"; - else if (ch == CH_UTF8) ret = "UTF8"; - else if (ch == CH_UTF8_MAC) ret = "UTF8-MAC"; + if ( (ch != CH_UNIX) && ( ch != CH_MAC) && ( ch < NUM_CHARSETS )) + { + ret = rgszCharsetName[ch]; + } else if (ch == CH_UNIX) { if (unixname[0] == '\0') { ret = read_charsets_from_env(CH_UNIX); Index: include/atalk/unicode.h =================================================================== --- include/atalk/unicode.h (revision 5045) +++ include/atalk/unicode.h (working copy) @@ -64,9 +64,9 @@ #define CONV_REQESCAPE (1<<15) /* espace unconvertable chars with :[UCS2HEX] */ /* this defines the charset types used in samba */ -typedef enum {CH_UCS2=0, CH_UTF8=1, CH_MAC=2, CH_UNIX=3, CH_UTF8_MAC=4} charset_t; +typedef enum {CH_UCS2=0, CH_UTF8=1, CH_MAC=2, CH_UNIX=3, CH_UTF8_MAC=4, CH_MAC_ROMAN=5} charset_t; -#define NUM_CHARSETS 5 +#define NUM_CHARSETS 6 /* * for each charset we have a function that pulls from that charset to Index: etc/uams/uams_dhx_pam.c =================================================================== --- etc/uams/uams_dhx_pam.c (revision 5045) +++ etc/uams/uams_dhx_pam.c (working copy) @@ -44,6 +44,7 @@ #include <atalk/afp.h> #include <atalk/uam.h> +#include <atalk/util.h> #define KEYSIZE 16 #define PASSWDLEN 64 @@ -411,6 +412,7 @@ char *rbuf, size_t *rbuflen) { const char *hostname; + char dstBuf[PASSWDLEN*6+1]; BIGNUM *bn1, *bn2, *bn3; u_int16_t sessid; int err, PAM_error; @@ -491,14 +493,41 @@ pam_set_item(pamh, PAM_RHOST, hostname); PAM_error = pam_authenticate(pamh,0); if (PAM_error != PAM_SUCCESS) { - if (PAM_error == PAM_MAXTRIES) - err = AFPERR_PWDEXPR; - /* Log Entry */ - LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: PAM_Error: %s", - pam_strerror(pamh, PAM_error)); - /* Log Entry */ - goto logincont_err; - } + if (PAM_error == PAM_MAXTRIES){ + err = AFPERR_PWDEXPR; + goto logincont_err; + } + /* Log Entry */ + LOG(log_info, logtype_uams, "uams_dhx_pam.c: PAM: PAM_Error: %s", + pam_strerror(pamh, PAM_error)); + /* Should fix passwd mismatchif any stressed characters */ + bzero(dstBuf, sizeof(dstBuf)); + PAM_password = dstBuf; + u_int16_t flags = CONV_UNESCAPEHEX; + if((size_t)-1 == convert_charset(CH_MAC_ROMAN , CH_UTF8, 0, rbuf, + strlen(rbuf), dstBuf, + sizeof(dstBuf), &flags)){ + LOG(log_debug, logtype_uams, + "uams_dhx_pam.c: pwd conversion from MAC_ROMAN to UTF8 failed"); + int j=0; + while(*(rbuf+j) != '\0'){ + LOG(log_debug, logtype_uams, "code:%x ", *(rbuf+j)); + j++; + } + err = AFPERR_NOTAUTH; + goto logincont_err; + } + /* Try again with decomposed unicode passwd */ + PAM_error = pam_authenticate(pamh,0); + if (PAM_error != PAM_SUCCESS) { + if (PAM_error == PAM_MAXTRIES) + err = AFPERR_PWDEXPR; + /* Log Entry */ + LOG(log_info, logtype_uams, "uams_dhx_pam.c: PAM: PAM_Error: %s", + pam_strerror(pamh, PAM_error)); + goto logincont_err; + } + } PAM_error = pam_acct_mgmt(pamh, 0); if (PAM_error != PAM_SUCCESS ) { [5bignetwork2] omouchet:/scratchbox/users/omouchet/home/omouchet/system/rootfs/components/netatalk/source $ [5bignetwork2] omouchet:/scratchbox/users/omouchet/home/omouchet/system/rootfs/components/netatalk/source $ cat stressed_char_pwd.patch Index: libatalk/unicode/charcnv.c =================================================================== --- libatalk/unicode/charcnv.c (revision 5045) +++ libatalk/unicode/charcnv.c (working copy) @@ -65,8 +65,16 @@ * @sa lib/iconv.c */ +char *rgszCharsetName[NUM_CHARSETS] = { + "UCS-2", // CH_UCS2 + "UTF8", // CH_UTF8 + NULL, // CH_MAC + NULL, // CH_UNIX + "UTF8-MAC", // CH_UTF8_MAC + "MAC_ROMAN", // CH_MAC_ROMAN +}; -#define MAX_CHARSETS 20 +#define MAX_CHARSETS NUM_CHARSETS #define CHECK_FLAGS(a,b) (((a)!=NULL) ? (*(a) & (b)) : 0 ) @@ -116,9 +124,10 @@ first = 0; } - if (ch == CH_UCS2) ret = "UCS-2"; - else if (ch == CH_UTF8) ret = "UTF8"; - else if (ch == CH_UTF8_MAC) ret = "UTF8-MAC"; + if ( (ch != CH_UNIX) && ( ch != CH_MAC) && ( ch < NUM_CHARSETS )) + { + ret = rgszCharsetName[ch]; + } else if (ch == CH_UNIX) { if (unixname[0] == '\0') { ret = read_charsets_from_env(CH_UNIX); Index: include/atalk/unicode.h =================================================================== --- include/atalk/unicode.h (revision 5045) +++ include/atalk/unicode.h (working copy) @@ -64,9 +64,9 @@ #define CONV_REQESCAPE (1<<15) /* espace unconvertable chars with :[UCS2HEX] */ /* this defines the charset types used in samba */ -typedef enum {CH_UCS2=0, CH_UTF8=1, CH_MAC=2, CH_UNIX=3, CH_UTF8_MAC=4} charset_t; +typedef enum {CH_UCS2=0, CH_UTF8=1, CH_MAC=2, CH_UNIX=3, CH_UTF8_MAC=4, CH_MAC_ROMAN=5} charset_t; -#define NUM_CHARSETS 5 +#define NUM_CHARSETS 6 /* * for each charset we have a function that pulls from that charset to Index: etc/uams/uams_dhx_pam.c =================================================================== --- etc/uams/uams_dhx_pam.c (revision 5045) +++ etc/uams/uams_dhx_pam.c (working copy) @@ -44,6 +44,7 @@ #include <atalk/afp.h> #include <atalk/uam.h> +#include <atalk/util.h> #define KEYSIZE 16 #define PASSWDLEN 64 @@ -411,6 +412,7 @@ char *rbuf, size_t *rbuflen) { const char *hostname; + char dstBuf[PASSWDLEN*6+1]; BIGNUM *bn1, *bn2, *bn3; u_int16_t sessid; int err, PAM_error; @@ -491,14 +493,41 @@ pam_set_item(pamh, PAM_RHOST, hostname); PAM_error = pam_authenticate(pamh,0); if (PAM_error != PAM_SUCCESS) { - if (PAM_error == PAM_MAXTRIES) - err = AFPERR_PWDEXPR; - /* Log Entry */ - LOG(log_info, logtype_uams, "uams_dhx_pam.c :PAM: PAM_Error: %s", - pam_strerror(pamh, PAM_error)); - /* Log Entry */ - goto logincont_err; - } + if (PAM_error == PAM_MAXTRIES){ + err = AFPERR_PWDEXPR; + goto logincont_err; + } + /* Log Entry */ + LOG(log_info, logtype_uams, "uams_dhx_pam.c: PAM: PAM_Error: %s", + pam_strerror(pamh, PAM_error)); + /* Should fix passwd mismatchif any stressed characters */ + bzero(dstBuf, sizeof(dstBuf)); + PAM_password = dstBuf; + u_int16_t flags = CONV_UNESCAPEHEX; + if((size_t)-1 == convert_charset(CH_MAC_ROMAN , CH_UTF8, 0, rbuf, + strlen(rbuf), dstBuf, + sizeof(dstBuf), &flags)){ + LOG(log_debug, logtype_uams, + "uams_dhx_pam.c: pwd conversion from MAC_ROMAN to UTF8 failed"); + int j=0; + while(*(rbuf+j) != '\0'){ + LOG(log_debug, logtype_uams, "code:%x ", *(rbuf+j)); + j++; + } + err = AFPERR_NOTAUTH; + goto logincont_err; + } + /* Try again with passwd converted to decomposed unicode */ + PAM_error = pam_authenticate(pamh,0); + if (PAM_error != PAM_SUCCESS) { + if (PAM_error == PAM_MAXTRIES) + err = AFPERR_PWDEXPR; + /* Log Entry */ + LOG(log_info, logtype_uams, "uams_dhx_pam.c: PAM: PAM_Error: %s", + pam_strerror(pamh, PAM_error)); + goto logincont_err; + } + } PAM_error = pam_acct_mgmt(pamh, 0); if (PAM_error != PAM_SUCCESS ) { |