From: Alan T. DeKok Date: Mon, 14 Sep 2015 12:47:56 +0000 (-0400) Subject: Enforce more restraints, and allow "octets[24] encrypt=1" X-Git-Tag: release_3_0_10~108 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5d9c08b21ecf3ee0591b98958850728c765d68c4;p=thirdparty%2Ffreeradius-server.git Enforce more restraints, and allow "octets[24] encrypt=1" dict_addattr() can be called from places other than process_attribute() so we move some of the checks to process_attribute() This lets us do more checks on the "length" flag. And to allow "octets[24] encrypt=1" for MS-CHAP-MPPE-Key. --- diff --git a/src/lib/dict.c b/src/lib/dict.c index dc8d9cd96a2..e3935abfbc6 100644 --- a/src/lib/dict.c +++ b/src/lib/dict.c @@ -723,19 +723,8 @@ int dict_addattr(char const *name, int attr, unsigned int vendor, PW_TYPE type, } /* - * Allow for generic pointers + * Do various sanity checks. */ - switch (type) { - default: - break; - - case PW_TYPE_STRING: - case PW_TYPE_OCTETS: - case PW_TYPE_TLV: - flags.is_pointer = true; - break; - } - if (attr < 0) { fr_strerror_printf("dict_addattr: ATTRIBUTE has invalid number (less than zero)"); return -1; @@ -763,6 +752,118 @@ int dict_addattr(char const *name, int attr, unsigned int vendor, PW_TYPE type, return -1; } + if (flags.length && (type != PW_TYPE_OCTETS)) { + fr_strerror_printf("The \"length\" flag can only be set for attributes of type \"octets\""); + return -1; + } + + if (flags.length && (flags.has_tag || flags.array || flags.is_tlv || flags.has_tlv || + flags.concat || flags.evs || flags.extended || flags.long_extended || + (flags.encrypt > FLAG_ENCRYPT_USER_PASSWORD))) { + fr_strerror_printf("The \"length\" flag cannot be used with any other flag"); + return -1; + } + + /* + * Force "length" for data types of fixed length; + */ + switch (type) { + case PW_TYPE_BYTE: + flags.length = 1; + break; + + case PW_TYPE_SHORT: + flags.length = 2; + break; + + case PW_TYPE_DATE: + case PW_TYPE_IPV4_ADDR: + case PW_TYPE_INTEGER: + case PW_TYPE_SIGNED: + flags.length = 4; + break; + + case PW_TYPE_INTEGER64: + flags.length = 8; + break; + + case PW_TYPE_ETHERNET: + flags.length = 6; + break; + + case PW_TYPE_IFID: + flags.length = 8; + break; + + case PW_TYPE_IPV6_ADDR: + flags.length = 16; + break; + + case PW_TYPE_EXTENDED: + if ((vendor != 0) || (attr < 241)) { + fr_strerror_printf("Attributes of type \"extended\" MUST be " + "RFC attributes with value >= 241."); + return -1; + } + + flags.length = 0; + flags.extended = 1; + break; + + case PW_TYPE_LONG_EXTENDED: + if ((vendor != 0) || (attr < 241)) { + fr_strerror_printf("Attributes of type \"long-extended\" MUST " + "be RFC attributes with value >= 241."); + return -1; + } + + flags.length = 0; + flags.extended = 1; + flags.long_extended = 1; + break; + + case PW_TYPE_EVS: + if (attr != PW_VENDOR_SPECIFIC) { + fr_strerror_printf("Attributes of type \"evs\" MUST have " + "attribute code 26."); + return -1; + } + + flags.length = 0; + flags.extended = 1; + flags.evs = 1; + break; + + case PW_TYPE_STRING: + case PW_TYPE_OCTETS: + case PW_TYPE_TLV: + flags.is_pointer = true; + break; + + default: + break; + } + + /* + * Stupid hacks for MS-CHAP-MPPE-Keys. The User-Password + * encryption method has no provisions for encoding the + * length of the data. For User-Password, the data is + * (presumably) all printable non-zero data. For + * MS-CHAP-MPPE-Keys, the data is binary crap. So... we + * MUST specify a length in the dictionary. + */ + if ((flags.encrypt == FLAG_ENCRYPT_USER_PASSWORD) && (type != PW_TYPE_STRING)) { + if (type != PW_TYPE_OCTETS) { + fr_strerror_printf("The \"encrypt=1\" flag cannot be used with non-string data types"); + return -1; + } + + if (flags.length == 0) { + fr_strerror_printf("The \"encrypt=1\" flag MUST be used with an explicit length for 'octets' data types"); + return -1; + } + } + if ((vendor & (FR_MAX_VENDOR -1)) != 0) { DICT_VENDOR *dv; static DICT_VENDOR *last_vendor = NULL; @@ -1322,7 +1423,7 @@ static int process_attribute(char const* fn, int const line, unsigned int vendor = 0; unsigned int value; int type; - unsigned int length = 0; + unsigned int length; ATTR_FLAGS flags; char *p; @@ -1421,84 +1522,14 @@ static int process_attribute(char const* fn, int const line, fr_strerror_printf("dict_init: %s[%d]: invalid length", fn, line); return -1; } + + flags.length = length; } /* - * Only look up the vendor if the string - * is non-empty. + * Parse options. */ - if (argc < 4) { - /* - * Force "length" for data types of fixed length; - */ - switch (type) { - case PW_TYPE_BYTE: - length = 1; - break; - - case PW_TYPE_SHORT: - length = 2; - break; - - case PW_TYPE_DATE: - case PW_TYPE_IPV4_ADDR: - case PW_TYPE_INTEGER: - case PW_TYPE_SIGNED: - length = 4; - break; - - case PW_TYPE_INTEGER64: - length = 8; - break; - - case PW_TYPE_ETHERNET: - length = 6; - break; - - case PW_TYPE_IFID: - length = 8; - break; - - case PW_TYPE_IPV6_ADDR: - length = 16; - break; - - case PW_TYPE_EXTENDED: - if ((vendor != 0) || (value < 241)) { - fr_strerror_printf("dict_init: %s[%d]: Attributes of type \"extended\" MUST be " - "RFC attributes with value >= 241.", fn, line); - return -1; - } - flags.extended = 1; - break; - - case PW_TYPE_LONG_EXTENDED: - if ((vendor != 0) || (value < 241)) { - fr_strerror_printf("dict_init: %s[%d]: Attributes of type \"long-extended\" MUST " - "be RFC attributes with value >= 241.", fn, line); - return -1; - } - flags.extended = 1; - flags.long_extended = 1; - break; - - case PW_TYPE_EVS: - flags.extended = 1; - flags.evs = 1; - if (value != PW_VENDOR_SPECIFIC) { - fr_strerror_printf("dict_init: %s[%d]: Attributes of type \"evs\" MUST have " - "attribute code 26.", fn, line); - return -1; - } - break; - - default: - break; - } - - flags.length = length; - - } else { /* argc == 4: we have options */ + if (argc >= 4) { char *key, *next, *last; /* @@ -1509,11 +1540,6 @@ static int process_attribute(char const* fn, int const line, return -1; } - if (length != 0) { - fr_strerror_printf("dict_init: %s[%d]: length cannot be used with options", fn, line); - return -1; - } - key = argv[3]; do { next = strchr(key, ',');