From: Alan T. DeKok Date: Wed, 1 Sep 2021 13:53:08 +0000 (-0400) Subject: allow time_delta to be _unsigned_ when we encode it in the network X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=99f107c2f2338ec079dd95e399dfb92b73b63ff7;p=thirdparty%2Ffreeradius-server.git allow time_delta to be _unsigned_ when we encode it in the network e.g. for RADIUS, with Session-Timeout --- diff --git a/src/lib/util/dict.h b/src/lib/util/dict.h index ce949be38b7..7525300ee8f 100644 --- a/src/lib/util/dict.h +++ b/src/lib/util/dict.h @@ -91,6 +91,8 @@ typedef struct { unsigned int virtual : 1; //!< for dynamic expansion + unsigned int is_signed : 1; //!< hackity hack for dates and time deltas + /* * @todo - if we want to clean these fields up, make * "subtype" and "type_size" both 4-bit bitfields. That diff --git a/src/lib/util/dict_tokenize.c b/src/lib/util/dict_tokenize.c index c9fdb50b759..130d1359b30 100644 --- a/src/lib/util/dict_tokenize.c +++ b/src/lib/util/dict_tokenize.c @@ -408,6 +408,7 @@ static int dict_process_flag_field(dict_tokenize_ctx_t *ctx, char *name, fr_type case FR_TYPE_INT16: if (type == FR_TYPE_DATE) goto unknown_type; + flags->is_signed = true; FALL_THROUGH; case FR_TYPE_UINT16: @@ -416,6 +417,7 @@ static int dict_process_flag_field(dict_tokenize_ctx_t *ctx, char *name, fr_type case FR_TYPE_INT32: if (type == FR_TYPE_DATE) goto unknown_type; + flags->is_signed = true; FALL_THROUGH; case FR_TYPE_UINT32: @@ -424,6 +426,7 @@ static int dict_process_flag_field(dict_tokenize_ctx_t *ctx, char *name, fr_type case FR_TYPE_INT64: if (type == FR_TYPE_DATE) goto unknown_type; + flags->is_signed = true; FALL_THROUGH; case FR_TYPE_UINT64: diff --git a/src/lib/util/value.c b/src/lib/util/value.c index 5871ba0edce..f19ef33e8ee 100644 --- a/src/lib/util/value.c +++ b/src/lib/util/value.c @@ -1407,7 +1407,7 @@ ssize_t fr_value_box_to_network(fr_dbuff_t *dbuff, fr_value_box_t const *value) if (!value->enumv) { goto delta_seconds; - } else switch (value->enumv->flags.flag_time_res) { + } switch (value->enumv->flags.flag_time_res) { delta_seconds: case FR_TIME_RES_SEC: date = fr_time_delta_to_sec(value->vb_time_delta); @@ -1432,34 +1432,62 @@ ssize_t fr_value_box_to_network(fr_dbuff_t *dbuff, fr_value_box_t const *value) if (!value->enumv) { goto delta_size4; - } else switch (value->enumv->flags.length) { - case 2: - if (date < INT16_MIN) { - date = INT16_MIN; - } else if (date > INT16_MAX) { - date = INT16_MAX; - } - FR_DBUFF_IN_RETURN(&work_dbuff, (int16_t)date); - break; + } else if (value->enumv->flags.is_signed) { + switch (value->enumv->flags.length) { + case 2: + if (date < INT16_MIN) { + date = INT16_MIN; + } else if (date > INT16_MAX) { + date = INT16_MAX; + } + FR_DBUFF_IN_RETURN(&work_dbuff, (int16_t)date); + break; - delta_size4: - case 4: - if (date < INT32_MIN) { - date = INT32_MIN; - } else if (date > INT32_MAX) { - date = INT32_MAX; + delta_size4: + case 4: + if (date < INT32_MIN) { + date = INT32_MIN; + } else if (date > INT32_MAX) { + date = INT32_MAX; + } + FR_DBUFF_IN_RETURN(&work_dbuff, (int32_t)date); + break; + + case 8: + FR_DBUFF_IN_RETURN(&work_dbuff, (int64_t)date); + break; + + default: + goto unsupported; } - FR_DBUFF_IN_RETURN(&work_dbuff, (int32_t)date); - break; + } else { /* time delta is unsigned! */ + switch (value->enumv->flags.length) { + case 2: + if (date < 0) { + date = 0; + } else if (date > UINT16_MAX) { + date = UINT16_MAX; + } + FR_DBUFF_IN_RETURN(&work_dbuff, (uint16_t)date); + break; - case 8: - FR_DBUFF_IN_RETURN(&work_dbuff, (int64_t)date); - break; + case 4: + if (date < 0) { + date = 0; + } else if (date > UINT32_MAX) { + date = UINT32_MAX; + } + FR_DBUFF_IN_RETURN(&work_dbuff, (uint32_t)date); + break; - default: - goto unsupported; - } + case 8: + FR_DBUFF_IN_RETURN(&work_dbuff, (uint64_t)date); + break; + default: + goto unsupported; + } + } } break; @@ -1754,7 +1782,22 @@ ssize_t fr_value_box_from_network_dbuff(TALLOC_CTX *ctx, dst->enumv = enumv; - FR_DBUFF_OUT_UINT64V_RETURN(&date, &work_dbuff, length); + if (enumv && enumv->flags.is_signed) { + FR_DBUFF_OUT_INT64V_RETURN(&date, &work_dbuff, length); + } else { + uint64_t tmp; + + /* + * Else it's an unsigned time delta, but + * we do have to clamp it at the max + * value for a signed 64-bit integer. + */ + FR_DBUFF_OUT_UINT64V_RETURN(&tmp, &work_dbuff, length); + + if (tmp > INT64_MAX) tmp = INT64_MAX; + + date = tmp; + } switch (precision) { default: