autofs-5.0.5 - add base64 password encode From: Ian Kent Add a trivial base64 password endoder to obscure password entries in autofs_ldap_auth.conf. Note that there is no way to encrypt the passwords without storing a password somewhere because there is no interactive input to allow a pass phrase or password to be input. The base64 encoded string can be generated using the coreutils base64 utility with: echo -n "" | base64 autofs will use the encoded string if it finds a valid entry "encoded_secret=" in autofs_ldap_auth.conf. If this value is present it will override a "secret=" entry. --- CHANGELOG | 1 include/base64.h | 11 ++ man/autofs_ldap_auth.conf.5.in | 6 + modules/Makefile | 4 - modules/base64.c | 225 ++++++++++++++++++++++++++++++++++++++++ modules/lookup_ldap.c | 29 ++++- 6 files changed, 270 insertions(+), 6 deletions(-) create mode 100644 include/base64.h create mode 100644 modules/base64.c diff --git a/CHANGELOG b/CHANGELOG index f39c055..1168865 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -78,6 +78,7 @@ - fix simple bind without SASL support. - fix sasl bind host name selection. - add nobind option. +- add base64 password encode. 03/09/2009 autofs-5.0.5 ----------------------- diff --git a/include/base64.h b/include/base64.h new file mode 100644 index 0000000..ce46fcc --- /dev/null +++ b/include/base64.h @@ -0,0 +1,11 @@ + +#ifndef BASE64_H +#define BASE64_H + +#include +#include + +int base64_encode(char *, size_t, char *, size_t); +size_t base64_decode(char *, char *, size_t); + +#endif diff --git a/man/autofs_ldap_auth.conf.5.in b/man/autofs_ldap_auth.conf.5.in index 2260952..fa23ce5 100644 --- a/man/autofs_ldap_auth.conf.5.in +++ b/man/autofs_ldap_auth.conf.5.in @@ -96,6 +96,12 @@ This attribute holds the secret used by authentication mechanisms that require it. Legal values for this attribute include any printable characters that can be used by the selected authentication mechanism. .TP +\fBencoded_secret=""\fP +This attribute holds the base64 encoded secret used by authentication +mechanisms that require it. If this entry is present as well as the +secret entry this value will take precedence. +.TP +.TP \fBclientprinc=""\fP When using GSSAPI authentication, this attribute is consulted to determine the principal name to use when authenticating to the directory server. By diff --git a/modules/Makefile b/modules/Makefile index 9ad3915..a35c0a5 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -95,9 +95,9 @@ cyrus-sasl.o: cyrus-sasl.c cyrus-sasl-extern.o: cyrus-sasl-extern.c $(CC) $(CFLAGS) $(LDAP_FLAGS) -c $< -lookup_ldap.so: lookup_ldap.c dclist.o $(SASL_OBJ) +lookup_ldap.so: lookup_ldap.c dclist.o base64.o $(SASL_OBJ) $(CC) $(SOLDFLAGS) $(CFLAGS) $(LDAP_FLAGS) -o lookup_ldap.so \ - lookup_ldap.c dclist.o $(SASL_OBJ) \ + lookup_ldap.c dclist.o base64.o $(SASL_OBJ) \ $(AUTOFS_LIB) $(LIBLDAP) $(LIBRESOLV) $(STRIP) lookup_ldap.so diff --git a/modules/base64.c b/modules/base64.c new file mode 100644 index 0000000..0bb356a --- /dev/null +++ b/modules/base64.c @@ -0,0 +1,225 @@ +#include + +/* + * characters used for Base64 encoding + */ +static const char *BASE64_CHARS = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/* + * encode three bytes using base64 (RFC 3548) + * + * @param triple three bytes that should be encoded + * @param result buffer of four characters where the result is stored + */ +static void _base64_encode_triple(char triple[3], char result[4]) +{ + int tripleValue, i; + + tripleValue = triple[0]; + tripleValue *= 256; + tripleValue += triple[1]; + tripleValue *= 256; + tripleValue += triple[2]; + + for (i=0; i<4; i++) { + result[3 - i] = BASE64_CHARS[tripleValue % 64]; + tripleValue /= 64; + } +} + +/* + * encode an array of bytes using Base64 (RFC 3548) + * + * @param source the source buffer + * @param sourcelen the length of the source buffer + * @param target the target buffer + * @param targetlen the length of the target buffer + * @return 1 on success, 0 otherwise + */ +int base64_encode(char *source, size_t sourcelen, char *target, size_t targetlen) +{ + /* check if the result will fit in the target buffer */ + if ((sourcelen + 2)/ 3*4 > targetlen - 1) + return 0; + + /* encode all full triples */ + while (sourcelen >= 3) { + _base64_encode_triple(source, target); + sourcelen -= 3; + source += 3; + target += 4; + } + + /* encode the last one or two characters */ + if (sourcelen > 0) { + unsigned char temp[3]; + memset(temp, 0, sizeof(temp)); + memcpy(temp, source, sourcelen); + _base64_encode_triple(temp, target); + target[3] = '='; + if (sourcelen == 1) + target[2] = '='; + target += 4; + } + + /* terminate the string */ + target[0] = 0; + + return 1; +} + +/* + * determine the value of a base64 encoding character + * + * @param base64char the character of which the value is searched + * @return the value in case of success (0-63), -1 on failure + */ +static int _base64_char_value(char base64char) +{ + if (base64char >= 'A' && base64char <= 'Z') + return base64char-'A'; + if (base64char >= 'a' && base64char <= 'z') + return base64char-'a'+26; + if (base64char >= '0' && base64char <= '9') + return base64char-'0'+2*26; + if (base64char == '+') + return 2*26+10; + if (base64char == '/') + return 2*26+11; + return -1; +} + +/* + * decode a 4 char base64 encoded byte triple + * + * @param quadruple the 4 characters that should be decoded + * @param result the decoded data + * @return lenth of the result (1, 2 or 3), 0 on failure + */ +static int _base64_decode_triple(char quadruple[4], char *result) +{ + int i, triple_value, bytes_to_decode = 3, only_equals_yet = 1; + int char_value[4]; + + for (i=0; i<4; i++) + char_value[i] = _base64_char_value(quadruple[i]); + + /* check if the characters are valid */ + for (i=3; i>=0; i--) { + if (char_value[i]<0) { + if (only_equals_yet && quadruple[i]=='=') { + /* we will ignore this character anyway, make it + * something that does not break our calculations */ + char_value[i]=0; + bytes_to_decode--; + continue; + } + return 0; + } + /* after we got a real character, no other '=' are allowed anymore */ + only_equals_yet = 0; + } + + /* if we got "====" as input, bytes_to_decode is -1 */ + if (bytes_to_decode < 0) + bytes_to_decode = 0; + + /* make one big value out of the partial values */ + triple_value = char_value[0]; + triple_value *= 64; + triple_value += char_value[1]; + triple_value *= 64; + triple_value += char_value[2]; + triple_value *= 64; + triple_value += char_value[3]; + + /* break the big value into bytes */ + for (i=bytes_to_decode; i<3; i++) + triple_value /= 256; + for (i=bytes_to_decode-1; i>=0; i--) { + result[i] = triple_value%256; + triple_value /= 256; + } + + return bytes_to_decode; +} + +/* + * decode base64 encoded data + * + * @param source the encoded data (zero terminated) + * @param target pointer to the target buffer + * @param targetlen length of the target buffer + * @return length of converted data on success, -1 otherwise + */ +size_t base64_decode(char *source, char *target, size_t targetlen) +{ + char *src, *tmpptr; + char quadruple[4], tmpresult[3]; + int i, tmplen = 3; + size_t converted = 0; + + /* concatinate '===' to the source to handle unpadded base64 data */ + src = malloc(strlen(source)+5); + if (src == NULL) + return -1; + strcpy(src, source); + strcat(src, "===="); + tmpptr = src; + + memset(target, 0, targetlen); + + /* convert as long as we get a full result */ + while (tmplen == 3) { + /* get 4 characters to convert */ + for (i = 0; i < 4; i++) { + /* skip invalid characters - we won't reach the end */ + while (*tmpptr != '=' && _base64_char_value(*tmpptr) < 0) + tmpptr++; + quadruple[i] = *(tmpptr++); + } + + /* convert the characters */ + tmplen = _base64_decode_triple(quadruple, tmpresult); + + /* check if the fit in the result buffer */ + if (targetlen < tmplen) { + free(src); + return -1; + } + + /* put the partial result in the result buffer */ + memcpy(target, tmpresult, tmplen); + target += tmplen; + targetlen -= tmplen; + converted += tmplen; + } + + free(src); + return converted; +} + +#if 0 +#include + +int main(int argc, char **argv) +{ + char *source = "testt(estt#wot%est'ing"; + int source_len = strlen(source); + char dest[80]; + int dest_len = 79; + char decoded[80]; + int decode_len = 79; + int len; + + printf("string %s\n", source); + + if (base64_encode(source, source_len, dest, dest_len)) + printf("encoded %s len %d\n", dest, strlen(dest)); + + len = base64_decode(dest, decoded, decode_len); + if (len != -1) + printf("decoded %s len %d\n", decoded, len); +} +#endif diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c index 1018839..719fed1 100644 --- a/modules/lookup_ldap.c +++ b/modules/lookup_ldap.c @@ -33,6 +33,7 @@ #include "automount.h" #include "nsswitch.h" #include "lookup_ldap.h" +#include "base64.h" #define MAPFMT_DEFAULT "sun" @@ -1024,9 +1025,12 @@ int parse_ldap_config(unsigned logopt, struct lookup_context *ctxt) if (auth_required == LDAP_AUTH_USESIMPLE || (authtype && authtype_requires_creds(authtype))) { + char *s1 = NULL, *s2 = NULL; ret = get_property(logopt, root, "user", &user); - ret |= get_property(logopt, root, "secret", &secret); - if (ret != 0 || (!user || !secret)) { + ret |= get_property(logopt, root, "secret", &s1); + ret |= get_property(logopt, root, "encoded_secret", &s2); + if (ret != 0 || (!user || (!s1 && !s2))) { +auth_fail: error(logopt, MODPREFIX "%s authentication type requires a username " @@ -1035,12 +1039,29 @@ int parse_ldap_config(unsigned logopt, struct lookup_context *ctxt) free(authtype); if (user) free(user); - if (secret) - free(secret); + if (s1) + free(s1); + if (s2) + free(s2); ret = -1; goto out; } + if (!s2) + secret = s1; + else { + char dec_buf[120]; + int dec_len = base64_decode(s2, dec_buf, 119); + if (dec_len <= 0) + goto auth_fail; + secret = strdup(dec_buf); + if (!secret) + goto auth_fail; + if (s1) + free(s1); + if (s2) + free(s2); + } } else if (auth_required == LDAP_AUTH_REQUIRED && (authtype && !strncmp(authtype, "EXTERNAL", 8))) { ret = get_property(logopt, root, "external_cert", &extern_cert);