putchar('\n'); \
} \
} while(0)
+# define TAG_VALID(x) ((x) > 0 && (x) < 0x20)
+# define TAG_VALID_ZERO(x) ((x) >= 0 && (x) < 0x20)
#endif
typedef struct attr_flags {
int attr;
int type;
int vendor;
+ ATTR_FLAGS flags;
struct dict_attr *next;
} DICT_ATTR;
int type;
int length; /* of strvalue */
uint32_t lvalue;
- ATTR_FLAGS flags;
LRAD_TOKEN operator;
uint8_t strvalue[MAX_STRING_LEN];
+ ATTR_FLAGS flags;
struct value_pair *next;
} VALUE_PAIR;
* Dictionary functions.
*/
int dict_addvendor(const char *name, int value);
-int dict_addattr(const char *name, int vendor, int type, int value);
+int dict_addattr(const char *name, int vendor, int type, int value, ATTR_FLAGS flags);
int dict_addvalue(const char *namestr, char *attrstr, int value);
int dict_init(const char *dir, const char *fn);
DICT_ATTR *dict_attrbyvalue(int attr);
#define PW_TYPE_DATE 3
#define PW_TYPE_ABINARY 4
#define PW_TYPE_OCTETS 5
-#define PW_TYPE_T_STRING 6
-#define PW_TYPE_T_INTEGER 7
#define PW_AUTHENTICATION_REQUEST 1
#define PW_AUTHENTICATION_ACK 2
"date",
"abinary",
"octets",
- "t_string",
- "t_integer",
NULL,
};
return 0;
}
-int dict_addattr(const char *name, int vendor, int type, int value)
+int dict_addattr(const char *name, int vendor, int type, int value, ATTR_FLAGS flags)
{
static int max_attr = 0;
DICT_ATTR *attr;
strcpy(attr->name, name);
attr->attr = value;
attr->type = type;
+ attr->flags = flags;
+
if (vendor) {
attr->attr |= (vendor << 16);
} else if ((attr->attr >= 0) && (attr->attr < 256)) {
char valstr[256];
char attrstr[256];
char typestr[256];
- char vendorstr[256];
- char *p;
+ char optstr[256];
+ char *p, *s, *c;
char *keyword;
char *data;
int line = 0;
int is_attrib;
int vendor_usr_seen = 0;
int is_nmc;
+ ATTR_FLAGS flags;
if (strlen(fn) >= sizeof(dirtmp) / 2 ||
strlen(dir) >= sizeof(dirtmp) / 2) {
if (is_attrib) {
vendor = 0;
- vendorstr[0] = 0;
+ optstr[0] = 0;
if(sscanf(data, "%s%s%s%s", namestr,
- valstr, typestr, vendorstr) < 3) {
+ valstr, typestr, optstr) < 3) {
librad_log(
"dict_init: %s[%d]: invalid ATTRIBUTE line",
fn, line);
* We might need to add USR to the list of
* vendors first.
*/
- if (is_nmc && vendorstr[0] == 0) {
+ if (is_nmc && optstr[0] == 0) {
if (!vendor_usr_seen) {
if (dict_addvendor("USR", VENDORPEC_USR) < 0) {
librad_log("dict_init: %s[%d]: %s", fn, line, librad_errstr);
}
vendor_usr_seen = 1;
}
- strcpy(vendorstr, "USR");
+ strcpy(optstr, "USR");
}
/*
/*
* Ignore comments
*/
- if (vendorstr[0] == '#') {
- vendorstr[0] = '\0';
+ if (optstr[0] == '#') {
+ optstr[0] = '\0';
}
/*
* Only look up the vendor if the string
* is non-empty.
*/
- if (vendorstr[0]) {
- vendor = dict_vendorname(vendorstr);
- if (!vendor) {
- librad_log(
- "dict_init: %s[%d]: unknown vendor %s",
- fn, line, vendorstr);
- return -1;
- }
- }
- if (block_vendor && vendorstr[0] &&
- (block_vendor != vendor)) {
- librad_log(
- "dict_init: %s[%d]: mismatched vendor %s within BEGIN-VENDOR/END-VENDOR block",
- fn, line, vendorstr);
- return -1;
+ memset(&flags, 0, sizeof(flags));
+ s = strtok(optstr, ",");
+ while(s) {
+ if (strcmp(s, "has_tag") == 0 ||
+ strcmp(s, "has_tag=1") == 0) {
+ /* Boolean flag, means this is a
+ tagged attribute */
+ flags.has_tag = 1;
+ }
+ else if (strncmp(s, "len+=", 5) == 0 ||
+ strncmp(s, "len-=", 5) == 0) {
+ /* Length difference, to accomodate
+ braindead NASes & their vendors */
+ flags.len_disp = strtol(s + 5, &c, 0);
+ if (*c) {
+ librad_log(
+ "dict_init: %s[%d] invalid option %s",
+ fn, line, s);
+ return -1;
+ }
+ if (s[3] == '-') {
+ flags.len_disp = -flags.len_disp;
+ }
+ }
+ else if (strncmp(s, "encrypt=", 8) == 0) {
+ /* Encryption method, defaults to 0 (none).
+ Currently valid is just type 1,
+ Tunnel-Password style, which can only
+ be applied to strings. */
+ flags.encrypt = strtol(s + 8, &c, 0);
+ if (*c) {
+ librad_log(
+ "dict_init: %s[%d] invalid option %s",
+ fn, line, s);
+ return -1;
+ }
+ }
+ else {
+ /* Must be a vendor 'flag'... */
+ if (strncmp(s, "vendor=", 5) == 0) {
+ /* New format */
+ s += 5;
+ }
+
+ vendor = dict_vendorname(s);
+ if (!vendor) {
+ librad_log(
+ "dict_init: %s[%d]: unknown vendor %s",
+ fn, line, optstr);
+ return -1;
+ }
+ if (block_vendor && optstr[0] &&
+ (block_vendor != vendor)) {
+ librad_log(
+ "dict_init: %s[%d]: mismatched vendor %s within BEGIN-VENDOR/END-VENDOR block",
+ fn, line, optstr);
+ return -1;
+ }
+ }
+ s = strtok(NULL, ",");
}
-
+
if (block_vendor) vendor = block_vendor;
- if (dict_addattr(namestr, vendor, type, value) < 0) {
+ if (dict_addattr(namestr, vendor, type, value, flags) < 0) {
librad_log("dict_init: %s[%d]: %s",
fn, line, librad_errstr);
return -1;
}
if (DICT_STRCMP(keyword, "BEGIN-VENDOR") == 0) {
- vendorstr[0] = 0;
- if (sscanf(data, "%s", vendorstr) != 1) {
+ optstr[0] = 0;
+ if (sscanf(data, "%s", optstr) != 1) {
librad_log(
"dict_init: %s[%d] invalid BEGIN-VENDOR entry",
fn, line);
return -1;
}
- vendor = dict_vendorname(vendorstr);
+ vendor = dict_vendorname(optstr);
if (!vendor) {
librad_log(
"dict_init: %s[%d]: unknown vendor %s",
- fn, line, vendorstr);
+ fn, line, optstr);
return -1;
}
block_vendor = vendor;
}
if (DICT_STRCMP(keyword, "END-VENDOR") == 0) {
- vendorstr[0] = 0;
- if (sscanf(data, "%s", vendorstr) != 1) {
+ optstr[0] = 0;
+ if (sscanf(data, "%s", optstr) != 1) {
librad_log(
"dict_init: %s[%d] invalid END-VENDOR entry",
fn, line);
return -1;
}
- vendor = dict_vendorname(vendorstr);
+ vendor = dict_vendorname(optstr);
if (!vendor) {
librad_log(
"dict_init: %s[%d]: unknown vendor %s",
- fn, line, vendorstr);
+ fn, line, optstr);
return -1;
}
if (vendor != block_vendor) {
librad_log(
"dict_init: %s[%d]: END-VENDOR %s does not match any previous BEGIN-VENDOR",
- fn, line, vendorstr);
+ fn, line, optstr);
return -1;
}
block_vendor = 0;
char buf[1024];
char *a;
time_t t;
- int offset;
out[0] = 0;
if (!vp) return 0;
if (vp->attribute == PW_NAS_PORT_ID)
a = (char *)vp->strvalue;
else {
- if (delimitst) {
- buf[0] = '"';
- librad_safeprint((char *)vp->strvalue,
- vp->length, buf + 1, sizeof(buf) - 2);
- strcat(buf, "\"");
+ if (delimitst && vp->flags.has_tag) {
+ /* Tagged attribute: print delimter and ignore tag */
+ buf[0] = '"';
+ librad_safeprint((char *)(vp->strvalue),
+ vp->length, buf + 1, sizeof(buf) - 2);
+ strcat(buf, "\"");
+ } else if (delimitst) {
+ /* Non-tagged attribute: print delimter */
+ buf[0] = '"';
+ librad_safeprint((char *)vp->strvalue,
+ vp->length, buf + 1, sizeof(buf) - 2);
+ strcat(buf, "\"");
} else {
- librad_safeprint((char *)vp->strvalue,
- vp->length, buf, sizeof(buf));
+ /* Non-tagged attribute: no delimiter */
+ librad_safeprint((char *)vp->strvalue,
+ vp->length, buf, sizeof(buf));
}
-
a = buf;
}
break;
case PW_TYPE_INTEGER:
- if ((v = dict_valbyattr(vp->attribute, vp->lvalue))
- != NULL)
- a = v->name;
- else {
- snprintf(buf, sizeof(buf), "%u", vp->lvalue);
- a = buf;
+ if ( vp->flags.has_tag ) {
+ /* Attribute value has a tag, need to ignore it */
+ if ((v = dict_valbyattr(vp->attribute, (vp->lvalue & 0xffffff)))
+ != NULL)
+ a = v->name;
+ else {
+ snprintf(buf, sizeof(buf), "%u", (vp->lvalue & 0xffffff));
+ a = buf;
+ }
+ } else {
+ /* Normal, non-tagged attribute */
+ if ((v = dict_valbyattr(vp->attribute, vp->lvalue))
+ != NULL)
+ a = v->name;
+ else {
+ snprintf(buf, sizeof(buf), "%u", vp->lvalue);
+ a = buf;
+ }
}
break;
case PW_TYPE_DATE:
a = buf;
break;
- case PW_TYPE_T_STRING:
- if (delimitst) {
- offset = snprintf(buf, sizeof(buf),
- "\"%u:", vp->strvalue[0]);
- librad_safeprint((char *)(vp->strvalue + 1),
- vp->length - 1,
- buf + offset,
- sizeof(buf) - offset);
- strcat(buf, "\"");
- } else {
- offset = snprintf(buf, sizeof(buf),
- "%u:", vp->strvalue[0]);
- librad_safeprint((char *)(vp->strvalue + 1),
- vp->length - 1,
- buf + offset,
- sizeof(buf) - offset);
- }
-
- a = buf;
-
- break;
-
- case PW_TYPE_T_INTEGER:
- offset = snprintf(buf, sizeof(buf), "%u:", (vp->lvalue >> 24));
- if ((v = dict_valbyattr(vp->attribute, (vp->lvalue)))
- != NULL)
- snprintf(buf + offset, sizeof(buf) - offset,
- "%s", v->name);
- else {
- snprintf(buf + offset, sizeof(buf) - offset,
- "%u", vp->lvalue);
-
- }
-
- a = buf;
-
- break;
default:
a = 0;
break;
return 0;
}
- snprintf(out, outlen, "%s = ", vp->name);
- len = strlen(out);
- vp_prints_value(out + len, outlen - len, vp, 1);
+ if( vp->flags.has_tag ) {
+
+#ifdef MERIT_STYLE_TAGS
+ snprintf(out, outlen, "%s = :%d:", vp->name, vp->flags.tag);
+#else
+ snprintf(out, outlen, "%s:%d = ", vp->name, vp->flags.tag);
+#endif
+
+ len = strlen(out);
+ vp_prints_value(out + len, outlen - len, vp, 1);
+
+ } else {
+
+ snprintf(out, outlen, "%s = ", vp->name);
+ len = strlen(out);
+ vp_prints_value(out + len, outlen - len, vp, 1);
+
+ }
return strlen(out);
}
memcpy(reply->strvalue, digest, AUTH_VECTOR_LEN );
reply->length = AUTH_VECTOR_LEN;
}
+
+ /*
+ * TODO: This should encrypt attributes like Tunnel-Password
+ * here -- cparker@starnetusa.net
+ */
len = reply->length;
-
+
+ /*
+ * Set the TAG at the beginning of the string if tagged.
+ * If tag value is not valid for tagged attribute, make
+ * it 0x00 per RFC 2868. -cparker
+ */
+ if(reply->flags.has_tag) {
+ len++;
+ if(TAG_VALID(reply->flags.tag)) {
+ *ptr++ = reply->flags.tag;
+ } else {
+ *ptr++ = 0x00;
+ }
+ }
+
/*
* Ensure we don't go too far.
* The 'length' of the attribute
*length_ptr += len;
if (vsa_length_ptr) *vsa_length_ptr += len;
- memcpy(ptr, reply->strvalue,len);
- ptr += len;
+ /*
+ * If we have tagged attributes we can't assume that
+ * len == reply->length. Use reply->length for copying
+ * the string data into the packet. Use len for the
+ * true length of the string+tags.
+ */
+ memcpy(ptr, reply->strvalue, reply->length);
+ ptr += reply->length;
total_length += len;
break;
case PW_TYPE_IPADDR:
*length_ptr += 4;
if (vsa_length_ptr) *vsa_length_ptr += 4;
- if (reply->type != PW_TYPE_IPADDR)
+
+ if (reply->type == PW_TYPE_INTEGER ) {
+ /* If tagged, the tag becomes the MSB of the value */
+ if(reply->flags.has_tag) {
+ /* Tag must be ( 0x01 -> 0x1F ) OR 0x00 */
+ if(!TAG_VALID(reply->flags.tag)) {
+ reply->flags.tag = 0x00;
+ }
+ lvalue = htonl((reply->lvalue & 0xffffff) |
+ ((reply->flags.tag & 0xff) << 24));
+ }
lvalue = htonl(reply->lvalue);
- else
+ } else {
lvalue = reply->lvalue;
+ }
memcpy(ptr, &lvalue, 4);
ptr += 4;
total_length += 4;
} else {
strcpy(pair->name, attr->name);
pair->type = attr->type;
+ pair->flags = attr->flags;
}
pair->attribute = attribute;
pair->length = attrlen;
case PW_TYPE_OCTETS:
case PW_TYPE_ABINARY:
case PW_TYPE_STRING:
- case PW_TYPE_T_STRING:
/*
* Hmm... this is based on names right
* now. We really shouldn't do this.
memcpy(pair->strvalue, my_digest, AUTH_VECTOR_LEN );
pair->strvalue[AUTH_VECTOR_LEN] = '\0';
pair->length = strlen(pair->strvalue);
- } else
+ } else if (pair->flags.has_tag &&
+ pair->type == PW_TYPE_STRING) {
+ if(TAG_VALID(*ptr))
+ pair->flags.tag = *ptr;
+ else
+ pair->flags.tag = 0x00;
+ pair->length--;
+ memcpy(pair->strvalue, ptr + 1,
+ pair->length);
+ } else {
/* attrlen always < MAX_STRING_LEN */
memcpy(pair->strvalue, ptr, attrlen);
+ pair->flags.tag = 0;
+ }
+
+ /* FIXME: Decrypt attributes like Tunnel-Password here -cparker */
+
break;
case PW_TYPE_INTEGER:
case PW_TYPE_DATE:
case PW_TYPE_IPADDR:
- case PW_TYPE_T_INTEGER:
/*
* Check for RFC compliance. If the
* attribute isn't compliant, turn it
pair->lvalue = 0xbaddbadd;
break;
}
- memcpy(&lvalue, ptr, 4);
+
+ memcpy(&lvalue, ptr, 4);
+
if (attr->type != PW_TYPE_IPADDR)
pair->lvalue = ntohl(lvalue);
else
pair->lvalue = lvalue;
+
+ /*
+ * Only PW_TYPE_INTEGER should have tags.
+ */
+ if (pair->flags.has_tag &&
+ pair->type == PW_TYPE_INTEGER) {
+ pair->flags.tag = (pair->lvalue >> 24) & 0xff;
+ pair->lvalue &= 0xffffff;
+ }
break;
default: