All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
radius_encode.c
Go to the documentation of this file.
1 /*
2  * This library is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU Lesser General Public
4  * License as published by the Free Software Foundation; either
5  * version 2.1 of the License, or (at your option) any later version.
6  *
7  * This library is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10  * Lesser General Public License for more details.
11  *
12  * You should have received a copy of the GNU Lesser General Public
13  * License along with this library; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /**
18  * $Id: f3e08bdcbf34584ff2d618ea63297caa44fdf87d $
19  *
20  * @file radius.c
21  * @brief Functions to encode RADIUS attributes
22  *
23  * @copyright 2000-2003,2006-2015 The FreeRADIUS server project
24  */
25 
26 #include <freeradius-devel/libradius.h>
27 #include <freeradius-devel/md5.h>
28 
29 static unsigned int salt_offset = 0;
30 
31 fr_thread_local_setup(uint8_t *, fr_radius_encode_value_hton_buff)
32 
33 static ssize_t encode_value(uint8_t *out, size_t outlen,
34  fr_dict_attr_t const **tlv_stack, int depth,
35  vp_cursor_t *cursor, void *encoder_ctx);
36 
37 static ssize_t encode_rfc_hdr_internal(uint8_t *out, size_t outlen,
38  fr_dict_attr_t const **tlv_stack, unsigned int depth,
39  vp_cursor_t *cursor, void *encoder_ctx);
40 
41 static ssize_t encode_tlv_hdr(uint8_t *out, size_t outlen,
42  fr_dict_attr_t const **tlv_stack, unsigned int depth,
43  vp_cursor_t *cursor, void *encoder_ctx);
44 
45 /** Encode a CHAP password
46  *
47  * @bug FIXME: might not work with Ascend because
48  * we use vp->vp_length, and Ascend gear likes
49  * to send an extra '\0' in the string!
50  */
51 int fr_radius_encode_chap_password(uint8_t *output, RADIUS_PACKET *packet, int id, VALUE_PAIR *password)
52 {
53  int i;
54  uint8_t *ptr;
55  uint8_t string[MAX_STRING_LEN * 2 + 1];
56  VALUE_PAIR *challenge;
57 
58  /*
59  * Sanity check the input parameters
60  */
61  if ((packet == NULL) || (password == NULL)) return -1;
62 
63  /*
64  * Note that the password VP can be EITHER
65  * a User-Password attribute (from a check-item list),
66  * or a CHAP-Password attribute (the client asking
67  * the library to encode it).
68  */
69 
70  i = 0;
71  ptr = string;
72  *ptr++ = id;
73 
74  i++;
75  memcpy(ptr, password->vp_strvalue, password->vp_length);
76  ptr += password->vp_length;
77  i += password->vp_length;
78 
79  /*
80  * Use Chap-Challenge pair if present,
81  * Request Authenticator otherwise.
82  */
83  challenge = fr_pair_find_by_num(packet->vps, 0, PW_CHAP_CHALLENGE, TAG_ANY);
84  if (challenge) {
85  memcpy(ptr, challenge->vp_strvalue, challenge->vp_length);
86  i += challenge->vp_length;
87  } else {
88  memcpy(ptr, packet->vector, AUTH_VECTOR_LEN);
89  i += AUTH_VECTOR_LEN;
90  }
91 
92  *output = id;
93  fr_md5_calc((uint8_t *)output + 1, (uint8_t *)string, i);
94 
95  return 0;
96 }
97 
98 /** Encode Tunnel-Password attributes when sending them out on the wire
99  *
100  * int *pwlen is updated to the new length of the encrypted
101  * password - a multiple of 16 bytes.
102  *
103  * This is per RFC-2868 which adds a two char SALT to the initial intermediate
104  * value MD5 hash.
105  */
106 int fr_radius_encode_tunnel_password(char *passwd, size_t *pwlen, char const *secret, uint8_t const *vector)
107 {
108  uint8_t buffer[AUTH_VECTOR_LEN + MAX_STRING_LEN + 3];
109  unsigned char digest[AUTH_VECTOR_LEN];
110  char *salt;
111  int i, n, secretlen;
112  unsigned len, n2;
113 
114  len = *pwlen;
115 
116  if (len > 127) len = 127;
117 
118  /*
119  * Shift the password 3 positions right to place a salt and original
120  * length, tag will be added automatically on packet send.
121  */
122  for (n = len ; n >= 0 ; n--) passwd[n + 3] = passwd[n];
123  salt = passwd;
124  passwd += 2;
125 
126  /*
127  * save original password length as first password character;
128  */
129  *passwd = len;
130  len += 1;
131 
132 
133  /*
134  * Generate salt. The RFC's say:
135  *
136  * The high bit of salt[0] must be set, each salt in a
137  * packet should be unique, and they should be random
138  *
139  * So, we set the high bit, add in a counter, and then
140  * add in some CSPRNG data. should be OK..
141  */
142  salt[0] = (0x80 | (((salt_offset++) & 0x0f) << 3) | (fr_rand() & 0x07));
143  salt[1] = fr_rand();
144 
145  /*
146  * Padd password to multiple of AUTH_PASS_LEN bytes.
147  */
148  n = len % AUTH_PASS_LEN;
149  if (n) {
150  n = AUTH_PASS_LEN - n;
151  for (; n > 0; n--, len++) passwd[len] = 0;
152  }
153  /* set new password length */
154  *pwlen = len + 2;
155 
156  /*
157  * Use the secret to setup the decryption digest
158  */
159  secretlen = strlen(secret);
160  memcpy(buffer, secret, secretlen);
161 
162  for (n2 = 0; n2 < len; n2 +=AUTH_PASS_LEN) {
163  if (!n2) {
164  memcpy(buffer + secretlen, vector, AUTH_VECTOR_LEN);
165  memcpy(buffer + secretlen + AUTH_VECTOR_LEN, salt, 2);
166  fr_md5_calc(digest, buffer, secretlen + AUTH_VECTOR_LEN + 2);
167  } else {
168  memcpy(buffer + secretlen, passwd + n2 - AUTH_PASS_LEN, AUTH_PASS_LEN);
169  fr_md5_calc(digest, buffer, secretlen + AUTH_PASS_LEN);
170  }
171  for (i = 0; i < AUTH_PASS_LEN; i++) passwd[i + n2] ^= digest[i];
172  }
173  passwd[n2] = 0;
174  return 0;
175 }
176 
177 /** Encode password
178  *
179  * We assume that the passwd buffer passed is big enough.
180  * RFC2138 says the password is max 128 chars, so the size
181  * of the passwd buffer must be at least 129 characters.
182  * Preferably it's just MAX_STRING_LEN.
183  *
184  * int *pwlen is updated to the new length of the encrypted
185  * password - a multiple of 16 bytes.
186  */
187 int fr_radius_encode_password(char *passwd, size_t *pwlen, char const *secret, uint8_t const *vector)
188 {
189  FR_MD5_CTX context, old;
190  uint8_t digest[AUTH_VECTOR_LEN];
191  int i, n, secretlen;
192  int len;
193 
194  /*
195  * RFC maximum is 128 bytes.
196  *
197  * If length is zero, pad it out with zeros.
198  *
199  * If the length isn't aligned to 16 bytes,
200  * zero out the extra data.
201  */
202  len = *pwlen;
203 
204  if (len > 128) len = 128;
205 
206  if (len == 0) {
207  memset(passwd, 0, AUTH_PASS_LEN);
208  len = AUTH_PASS_LEN;
209  } else if ((len % AUTH_PASS_LEN) != 0) {
210  memset(&passwd[len], 0, AUTH_PASS_LEN - (len % AUTH_PASS_LEN));
211  len += AUTH_PASS_LEN - (len % AUTH_PASS_LEN);
212  }
213  *pwlen = len;
214 
215  /*
216  * Use the secret to setup the decryption digest
217  */
218  secretlen = strlen(secret);
219 
220  fr_md5_init(&context);
221  fr_md5_update(&context, (uint8_t const *) secret, secretlen);
222  fr_md5_copy(&old, &context); /* save intermediate work */
223 
224  /*
225  * Encrypt it in place. Don't bother checking
226  * len, as we've ensured above that it's OK.
227  */
228  for (n = 0; n < len; n += AUTH_PASS_LEN) {
229  if (n == 0) {
230  fr_md5_update(&context, vector, AUTH_PASS_LEN);
231  fr_md5_final(digest, &context);
232  } else {
233  fr_md5_copy(&context, &old);
234  fr_md5_update(&context, (uint8_t *) passwd + n - AUTH_PASS_LEN, AUTH_PASS_LEN);
235  fr_md5_final(digest, &context);
236  }
237 
238  for (i = 0; i < AUTH_PASS_LEN; i++) passwd[i + n] ^= digest[i];
239  }
240 
241  return 0;
242 }
243 
244 static void encode_password(uint8_t *out, ssize_t *outlen, uint8_t const *input, size_t inlen,
245  char const *secret, uint8_t const *vector)
246 {
247  FR_MD5_CTX context, old;
248  uint8_t digest[AUTH_VECTOR_LEN];
249  uint8_t passwd[MAX_PASS_LEN];
250  size_t i, n;
251  size_t len;
252 
253  /*
254  * If the length is zero, round it up.
255  */
256  len = inlen;
257 
258  if (len > MAX_PASS_LEN) len = MAX_PASS_LEN;
259 
260  memcpy(passwd, input, len);
261  if (len < sizeof(passwd)) memset(passwd + len, 0, sizeof(passwd) - len);
262 
263  if (len == 0) len = AUTH_PASS_LEN;
264  else if ((len & 0x0f) != 0) {
265  len += 0x0f;
266  len &= ~0x0f;
267  }
268  *outlen = len;
269 
270  fr_md5_init(&context);
271  fr_md5_update(&context, (uint8_t const *) secret, strlen(secret));
272  fr_md5_copy(&old, &context);
273 
274  /*
275  * Do first pass.
276  */
277  fr_md5_update(&context, vector, AUTH_PASS_LEN);
278 
279  for (n = 0; n < len; n += AUTH_PASS_LEN) {
280  if (n > 0) {
281  fr_md5_copy(&context, &old);
282  fr_md5_update(&context, passwd + n - AUTH_PASS_LEN, AUTH_PASS_LEN);
283  }
284 
285  fr_md5_final(digest, &context);
286  for (i = 0; i < AUTH_PASS_LEN; i++) passwd[i + n] ^= digest[i];
287  }
288 
289  memcpy(out, passwd, len);
290 }
291 
292 
293 static void encode_tunnel_password(uint8_t *out, ssize_t *outlen,
294  uint8_t const *input, size_t inlen, size_t freespace,
295  char const *secret, uint8_t const *vector)
296 {
297  FR_MD5_CTX context, old;
298  uint8_t digest[AUTH_VECTOR_LEN];
299  size_t i, n;
300  size_t encrypted_len;
301 
302  /*
303  * The password gets encoded with a 1-byte "length"
304  * field. Ensure that it doesn't overflow.
305  */
306  if (freespace > 253) freespace = 253;
307 
308  /*
309  * Limit the maximum size of the input password. 2 bytes
310  * are taken up by the salt, and one by the encoded
311  * "length" field. Note that if we have a tag, the
312  * "freespace" will be 252 octets, not 253 octets.
313  */
314  if (inlen > (freespace - 3)) inlen = freespace - 3;
315 
316  /*
317  * Length of the encrypted data is the clear-text
318  * password length plus one byte which encodes the length
319  * of the password. We round up to the nearest encoding
320  * block. Note that this can result in the encoding
321  * length being more than 253 octets.
322  */
323  encrypted_len = inlen + 1;
324  if ((encrypted_len & 0x0f) != 0) {
325  encrypted_len += 0x0f;
326  encrypted_len &= ~0x0f;
327  }
328 
329  /*
330  * We need 2 octets for the salt, followed by the actual
331  * encrypted data.
332  */
333  if (encrypted_len > (freespace - 2)) encrypted_len = freespace - 2;
334 
335  *outlen = encrypted_len + 2; /* account for the salt */
336 
337  /*
338  * Copy the password over, and zero-fill the remainder.
339  */
340  memcpy(out + 3, input, inlen);
341  memset(out + 3 + inlen, 0, *outlen - 3 - inlen);
342 
343  /*
344  * Generate salt. The RFCs say:
345  *
346  * The high bit of salt[0] must be set, each salt in a
347  * packet should be unique, and they should be random
348  *
349  * So, we set the high bit, add in a counter, and then
350  * add in some CSPRNG data. should be OK..
351  */
352  out[0] = (0x80 | (((salt_offset++) & 0x0f) << 3) | (fr_rand() & 0x07));
353  out[1] = fr_rand();
354  out[2] = inlen; /* length of the password string */
355 
356  fr_md5_init(&context);
357  fr_md5_update(&context, (uint8_t const *) secret, strlen(secret));
358  fr_md5_copy(&old, &context);
359 
360  fr_md5_update(&context, vector, AUTH_VECTOR_LEN);
361  fr_md5_update(&context, &out[0], 2);
362 
363  for (n = 0; n < encrypted_len; n += AUTH_PASS_LEN) {
364  size_t block_len;
365 
366  if (n > 0) {
367  fr_md5_copy(&context, &old);
368  fr_md5_update(&context, out + 2 + n - AUTH_PASS_LEN, AUTH_PASS_LEN);
369  }
370  fr_md5_final(digest, &context);
371 
372  if ((2 + n + AUTH_PASS_LEN) < freespace) {
373  block_len = AUTH_PASS_LEN;
374  } else {
375  block_len = freespace - 2 - n;
376  }
377 
378  for (i = 0; i < block_len; i++) out[i + 2 + n] ^= digest[i];
379  }
380 }
381 
382 /** Converts vp_data to network byte order
383  *
384  * Provide a pointer to a buffer which contains the value of the VALUE_PAIR
385  * in an architecture independent format.
386  *
387  * The pointer is only guaranteed to be valid between calls to fr_radius_encode_value_hton, and so long
388  * as the source VALUE_PAIR is not freed.
389  *
390  * @param out where to write the pointer to the value.
391  * @param vp to get the value from.
392  * @return
393  * - The length of the value.
394  * - -1 on failure.
395  */
396 ssize_t fr_radius_encode_value_hton(uint8_t const **out, VALUE_PAIR const *vp)
397 {
398  uint8_t *buffer;
399  uint32_t lvalue;
400  uint64_t lvalue64;
401 
402  *out = NULL;
403 
404  buffer = fr_thread_local_init(fr_radius_encode_value_hton_buff, free);
405  if (!buffer) {
406  int ret;
407 
408  buffer = malloc(sizeof(uint8_t) * sizeof(value_data_t));
409  if (!buffer) {
410  fr_strerror_printf("Failed allocating memory for fr_radius_encode_value_hton buffer");
411  return -1;
412  }
413 
414  ret = fr_thread_local_set(fr_radius_encode_value_hton_buff, buffer);
415  if (ret != 0) {
416  fr_strerror_printf("Failed setting up TLS for fr_radius_encode_value_hton buffer: %s", strerror(errno));
417  free(buffer);
418  return -1;
419  }
420  }
421 
422  VERIFY_VP(vp);
423 
424  switch (vp->da->type) {
425  case PW_TYPE_STRING:
426  case PW_TYPE_OCTETS:
427  memcpy(out, &vp->data.ptr, sizeof(*out));
428  break;
429 
430  /*
431  * All of these values are at the same location.
432  */
433  case PW_TYPE_IFID:
434  case PW_TYPE_IPV4_ADDR:
435  case PW_TYPE_IPV6_ADDR:
436  case PW_TYPE_IPV6_PREFIX:
437  case PW_TYPE_IPV4_PREFIX:
438  case PW_TYPE_ABINARY:
439  case PW_TYPE_ETHERNET:
441  {
442  void const *p = &vp->data;
443  memcpy(out, &p, sizeof(*out));
444  break;
445  }
446 
447  case PW_TYPE_BOOLEAN:
448  buffer[0] = vp->vp_byte & 0x01;
449  *out = buffer;
450  break;
451 
452  case PW_TYPE_BYTE:
453  buffer[0] = vp->vp_byte & 0xff;
454  *out = buffer;
455  break;
456 
457  case PW_TYPE_SHORT:
458  buffer[0] = (vp->vp_short >> 8) & 0xff;
459  buffer[1] = vp->vp_short & 0xff;
460  *out = buffer;
461  break;
462 
463  case PW_TYPE_INTEGER:
464  lvalue = htonl(vp->vp_integer);
465  memcpy(buffer, &lvalue, sizeof(lvalue));
466  *out = buffer;
467  break;
468 
469  case PW_TYPE_INTEGER64:
470  lvalue64 = htonll(vp->vp_integer64);
471  memcpy(buffer, &lvalue64, sizeof(lvalue64));
472  *out = buffer;
473  break;
474 
475  case PW_TYPE_DATE:
476  lvalue = htonl(vp->vp_date);
477  memcpy(buffer, &lvalue, sizeof(lvalue));
478  *out = buffer;
479  break;
480 
481  case PW_TYPE_SIGNED:
482  {
483  int32_t slvalue = htonl(vp->vp_signed);
484  memcpy(buffer, &slvalue, sizeof(slvalue));
485  *out = buffer;
486  break;
487  }
488 
489  case PW_TYPE_INVALID:
490  case PW_TYPE_EXTENDED:
493  case PW_TYPE_EVS:
494  case PW_TYPE_VSA:
495  case PW_TYPE_VENDOR:
496  case PW_TYPE_TLV:
497  case PW_TYPE_TIMEVAL:
498  case PW_TYPE_DECIMAL:
499  case PW_TYPE_MAX:
500  fr_strerror_printf("Cannot get data for VALUE_PAIR type %i", vp->da->type);
501  return -1;
502 
503  /* Don't add default */
504  }
505 
506  return vp->vp_length;
507 }
508 
509 static ssize_t encode_tlv_hdr_internal(uint8_t *out, size_t outlen,
510  fr_dict_attr_t const **tlv_stack, unsigned int depth,
511  vp_cursor_t *cursor, void *encoder_ctx)
512 {
513  ssize_t len;
514  uint8_t *p = out;
515  VALUE_PAIR const *vp = fr_cursor_current(cursor);
516  fr_dict_attr_t const *da = tlv_stack[depth];
517 
518  while (outlen >= 5) {
519  FR_PROTO_STACK_PRINT(tlv_stack, depth);
520 
521  /*
522  * Determine the nested type and call the appropriate encoder
523  */
524  if (tlv_stack[depth + 1]->type == PW_TYPE_TLV) {
525  len = encode_tlv_hdr(p, outlen, tlv_stack, depth + 1, cursor, encoder_ctx);
526  } else {
527  len = encode_rfc_hdr_internal(p, outlen, tlv_stack, depth + 1, cursor, encoder_ctx);
528  }
529 
530  if (len < 0) return len;
531  if (len == 0) return out[1]; /* Insufficient space */
532 
533  p += len;
534  outlen -= len; /* Subtract from the buffer we have available */
535 
536  /*
537  * If nothing updated the attribute, stop
538  */
539  if (!fr_cursor_current(cursor) || (vp == fr_cursor_current(cursor))) break;
540 
541  /*
542  * We can encode multiple sub TLVs, if after
543  * rebuilding the TLV Stack, the attribute
544  * at this depth is the same.
545  */
546  if (da != tlv_stack[depth]) break;
547  vp = fr_cursor_current(cursor);
548 
549  FR_PROTO_HEX_DUMP("Done TLV", out, p - out);
550  }
551 
552  return p - out;
553 }
554 
555 static ssize_t encode_tlv_hdr(uint8_t *out, size_t outlen,
556  fr_dict_attr_t const **tlv_stack, unsigned int depth,
557  vp_cursor_t *cursor, void *encoder_ctx)
558 {
559  ssize_t len;
560 
561  VERIFY_VP(fr_cursor_current(cursor));
562  FR_PROTO_STACK_PRINT(tlv_stack, depth);
563 
564  if (tlv_stack[depth]->type != PW_TYPE_TLV) {
565  fr_strerror_printf("%s: Expected type \"tlv\" got \"%s\"", __FUNCTION__,
566  fr_int2str(dict_attr_types, tlv_stack[depth]->type, "?Unknown?"));
567  return -1;
568  }
569 
570  if (!tlv_stack[depth + 1]) {
571  fr_strerror_printf("%s: Can't encode empty TLV", __FUNCTION__);
572  return -1;
573  }
574 
575  if (outlen < 5) return 0;
576 
577  /*
578  * Encode the first level of TLVs
579  */
580  out[0] = tlv_stack[depth]->attr & 0xff;
581  out[1] = 2; /* TLV header */
582 
583  len = encode_tlv_hdr_internal(out + 2, outlen - 2, tlv_stack, depth, cursor, encoder_ctx);
584  if (len <= 0) return len;
585  if (len > 253) return 0;
586 
587  out[1] += len;
588 
589  return out[1];
590 }
591 
592 /** Encodes the data portion of an attribute
593  *
594  * @return
595  * - Length of the data portion.
596  * - -1 on failure.
597  */
598 static ssize_t encode_value(uint8_t *out, size_t outlen,
599  fr_dict_attr_t const **tlv_stack, int depth,
600  vp_cursor_t *cursor, void *encoder_ctx)
601 {
602  uint32_t lvalue;
603  ssize_t len;
604  uint8_t const *data;
605  uint8_t *ptr = out;
606  uint8_t array[4];
607  uint64_t lvalue64;
608  VALUE_PAIR const *vp = fr_cursor_current(cursor);
609  fr_dict_attr_t const *da = tlv_stack[depth];
610  fr_radius_ctx_t *ctx = encoder_ctx;
611 
612  VERIFY_VP(vp);
613  FR_PROTO_STACK_PRINT(tlv_stack, depth);
614 
615  /*
616  * It's a little weird to consider a TLV as a value,
617  * but it seems to work OK.
618  */
619  if (da->type == PW_TYPE_TLV) {
620  return encode_tlv_hdr(out, outlen, tlv_stack, depth, cursor, encoder_ctx);
621  }
622 
623  /*
624  * If it's not a TLV, it should be a value type RFC
625  * attribute make sure that it is.
626  */
627  if (tlv_stack[depth + 1] != NULL) {
628  fr_strerror_printf("%s: Encoding value but not at top of stack", __FUNCTION__);
629  return -1;
630  }
631 
632  if (vp->da != da) {
633  fr_strerror_printf("%s: Top of stack does not match vp->da", __FUNCTION__);
634  return -1;
635  }
636 
637  switch (da->type) {
638  case PW_TYPE_STRUCTURAL:
639  fr_strerror_printf("%s: Called with structural type %s", __FUNCTION__,
640  fr_int2str(dict_attr_types, tlv_stack[depth]->type, "?Unknown?"));
641  return -1;
642 
643  default:
644  break;
645  }
646 
647  /*
648  * Set up the default sources for the data.
649  */
650  len = vp->vp_length;
651 
652  switch (da->type) {
653  case PW_TYPE_OCTETS:
654  /*
655  * If asked to encode more data than allowed, we
656  * encode only the allowed data.
657  */
658  if (da->flags.length && (len > da->flags.length)) {
659  len = da->flags.length;
660  }
661  /* FALL-THROUGH */
662 
663  case PW_TYPE_STRING:
664  data = vp->data.ptr;
665  if (!data) {
666  fr_strerror_printf("ERROR: Cannot encode NULL data");
667  return -1;
668  }
669  break;
670 
671  case PW_TYPE_IFID:
672  case PW_TYPE_IPV4_ADDR:
673  case PW_TYPE_IPV6_ADDR:
674  case PW_TYPE_IPV6_PREFIX:
675  case PW_TYPE_IPV4_PREFIX:
676  case PW_TYPE_ABINARY:
677  case PW_TYPE_ETHERNET: /* just in case */
678  data = (uint8_t const *) &vp->data;
679  break;
680 
681  case PW_TYPE_BYTE:
682  len = 1; /* just in case */
683  array[0] = vp->vp_byte;
684  data = array;
685  break;
686 
687  case PW_TYPE_SHORT:
688  len = 2; /* just in case */
689  array[0] = (vp->vp_short >> 8) & 0xff;
690  array[1] = vp->vp_short & 0xff;
691  data = array;
692  break;
693 
694  case PW_TYPE_INTEGER:
695  len = 4; /* just in case */
696  lvalue = htonl(vp->vp_integer);
697  memcpy(array, &lvalue, sizeof(lvalue));
698  data = array;
699  break;
700 
701  case PW_TYPE_INTEGER64:
702  len = 8; /* just in case */
703  lvalue64 = htonll(vp->vp_integer64);
704  data = (uint8_t *) &lvalue64;
705  break;
706 
707  /*
708  * There are no tagged date attributes.
709  */
710  case PW_TYPE_DATE:
711  lvalue = htonl(vp->vp_date);
712  data = (uint8_t const *) &lvalue;
713  len = 4; /* just in case */
714  break;
715 
716  case PW_TYPE_SIGNED:
717  {
718  int32_t slvalue;
719 
720  len = 4; /* just in case */
721  slvalue = htonl(vp->vp_signed);
722  memcpy(array, &slvalue, sizeof(slvalue));
723  data = array;
724  break;
725  }
726 
727  default: /* unknown type: ignore it */
728  fr_strerror_printf("ERROR: Unknown attribute type %d", da->type);
729  return -1;
730  }
731 
732  /*
733  * No data: skip it.
734  */
735  if (len == 0) {
736  vp = fr_cursor_next(cursor);
737  fr_proto_tlv_stack_build(tlv_stack, vp ? vp->da : NULL);
738  return 0;
739  }
740 
741  /*
742  * Bound the data to the calling size
743  */
744  if (len > (ssize_t)outlen) len = outlen;
745 
746  if (vp->da->flags.encrypt && !ctx) {
747  no_ctx_error:
748  fr_strerror_printf("Asked to encrypt attribute, but no packet context provided");
749  return -1;
750  }
751  /*
752  * Encrypt the various password styles
753  *
754  * Attributes with encrypted values MUST be less than
755  * 128 bytes long.
756  */
757  switch (vp->da->flags.encrypt) {
758  case FLAG_ENCRYPT_USER_PASSWORD:
759  encode_password(ptr, &len, data, len, ctx->secret, ctx->packet->vector);
760  break;
761 
762  case FLAG_ENCRYPT_TUNNEL_PASSWORD:
763  lvalue = 0;
764  if (da->flags.has_tag) lvalue = 1;
765 
766  /*
767  * Check if there's enough freespace. If there isn't,
768  * we discard the attribute.
769  *
770  * This is ONLY a problem if we have multiple VSA's
771  * in one Vendor-Specific, though.
772  */
773  if (outlen < (18 + lvalue)) return 0;
774 
775  switch (ctx->packet->code) {
779  default:
780  if (!ctx->original) goto no_ctx_error;
781 
782  if (lvalue) ptr[0] = TAG_VALID(vp->tag) ? vp->tag : TAG_NONE;
783  encode_tunnel_password(ptr + lvalue, &len, data, len,
784  outlen - lvalue, ctx->secret, ctx->original->vector);
785  len += lvalue;
786  break;
789  case PW_CODE_COA_REQUEST:
790  ptr[0] = TAG_VALID(vp->tag) ? vp->tag : TAG_NONE;
791  encode_tunnel_password(ptr + 1, &len, data, len, outlen - 1, ctx->secret, ctx->packet->vector);
792  len += lvalue;
793  break;
794  }
795  break;
796 
797  /*
798  * The code above ensures that this attribute
799  * always fits.
800  */
801  case FLAG_ENCRYPT_ASCEND_SECRET:
802  if (len != 16) return 0;
803  fr_radius_make_secret(ptr, ctx->packet->vector, ctx->secret, data);
804  len = AUTH_VECTOR_LEN;
805  break;
806 
807  default:
808  if (vp->da->flags.has_tag && TAG_VALID(vp->tag)) {
809  if (vp->da->type == PW_TYPE_STRING) {
810  if (len > ((ssize_t) (outlen - 1))) len = outlen - 1;
811  ptr[0] = vp->tag;
812  ptr++;
813  } else if (vp->da->type == PW_TYPE_INTEGER) {
814  array[0] = vp->tag;
815  } /* else it can't be any other type */
816  }
817  memcpy(ptr, data, len);
818  break;
819  } /* switch over encryption flags */
820 
821  /*
822  * Rebuilds the TLV stack for encoding the next attribute
823  */
824  vp = fr_cursor_next(cursor);
825  fr_proto_tlv_stack_build(tlv_stack, vp ? vp->da : NULL);
826 
827  return len + (ptr - out);
828 }
829 
830 static ssize_t attr_shift(uint8_t const *start, uint8_t const *end,
831  uint8_t *ptr, int hdr_len, ssize_t len,
832  int flag_offset, int vsa_offset)
833 {
834  int check_len = len - ptr[1];
835  int total = len + hdr_len;
836 
837  /*
838  * Pass 1: Check if the addition of the headers
839  * overflows the available freespace. If so, return
840  * what we were capable of encoding.
841  */
842 
843  while (check_len > (255 - hdr_len)) {
844  total += hdr_len;
845  check_len -= (255 - hdr_len);
846  }
847 
848  /*
849  * Note that this results in a number of attributes maybe
850  * being marked as "encoded", but which aren't in the
851  * packet. Oh well. The solution is to fix the
852  * "encode_value" function to take into account the header
853  * lengths.
854  */
855  if ((ptr + ptr[1] + total) > end) return (ptr + ptr[1]) - start;
856 
857  /*
858  * Pass 2: Now that we know there's enough freespace,
859  * re-arrange the data to form a set of valid
860  * RADIUS attributes.
861  */
862  while (1) {
863  int sublen = 255 - ptr[1];
864 
865  if (len <= sublen) break;
866 
867  len -= sublen;
868  memmove(ptr + 255 + hdr_len, ptr + 255, sublen);
869  memmove(ptr + 255, ptr, hdr_len);
870  ptr[1] += sublen;
871  if (vsa_offset) ptr[vsa_offset] += sublen;
872  ptr[flag_offset] |= 0x80;
873 
874  ptr += 255;
875  ptr[1] = hdr_len;
876  if (vsa_offset) ptr[vsa_offset] = 3;
877  }
878 
879  ptr[1] += len;
880  if (vsa_offset) ptr[vsa_offset] += len;
881 
882  return (ptr + ptr[1]) - start;
883 }
884 
885 /** Encode an "extended" attribute
886  *
887  */
888 static int encode_extended_hdr(uint8_t *out, size_t outlen,
889  fr_dict_attr_t const **tlv_stack, unsigned int depth,
890  vp_cursor_t *cursor, void *encoder_ctx)
891 {
892  int len;
893  int hdr_len;
894  uint8_t *start = out;
895  VALUE_PAIR const *vp = fr_cursor_current(cursor);
896 
897  VERIFY_VP(vp);
898  FR_PROTO_STACK_PRINT(tlv_stack, depth);
899 
900  if ((tlv_stack[depth]->type != PW_TYPE_EXTENDED) && (tlv_stack[depth]->type != PW_TYPE_LONG_EXTENDED)) {
901  fr_strerror_printf("%s : Called for non-extended attribute type %s",
902  __FUNCTION__, fr_int2str(dict_attr_types, tlv_stack[depth]->type, "?Unknown?"));
903  return -1;
904  }
905 
906  /*
907  * Encode which extended attribute it is.
908  */
909  out[0] = tlv_stack[depth++]->attr & 0xff;
910 
911  /*
912  * Encode the header for "short" or "long" attributes
913  */
914  if (tlv_stack[0]->type == PW_TYPE_EXTENDED) {
915  if (outlen < 3) return 0;
916 
917  out[1] = 3;
918  out[2] = tlv_stack[depth]->attr & 0xff;
919 
920  } else {
921  if (outlen < 4) return 0;
922 
923  out[1] = 4;
924  out[2] = tlv_stack[depth]->attr & 0xff;
925  out[3] = 0; /* flags start off at zero */
926  }
927 
928  FR_PROTO_STACK_PRINT(tlv_stack, depth);
929  FR_PROTO_HEX_DUMP("Extended header", out, out[1]);
930 
931  /*
932  * Handle EVS
933  */
934  if (tlv_stack[depth]->type == PW_TYPE_EVS) {
935  uint8_t *evs = out + out[1];
936  uint32_t lvalue;
937 
938  if (outlen < (size_t) (out[1] + 5)) return 0;
939 
940  depth++; /* skip EVS */
941 
942  lvalue = htonl(tlv_stack[depth++]->attr);
943  memcpy(evs, &lvalue, 4);
944 
945  evs[4] = tlv_stack[depth]->attr & 0xff;
946 
947  out[1] += 5;
948 
949  FR_PROTO_STACK_PRINT(tlv_stack, depth);
950  FR_PROTO_HEX_DUMP("EVS", out, out[1]);
951 
952  }
953  hdr_len = out[1];
954 
955  if (tlv_stack[depth]->type == PW_TYPE_TLV) {
956  len = encode_tlv_hdr_internal(out + out[1], outlen - hdr_len, tlv_stack, depth, cursor, encoder_ctx);
957 
958  } else {
959  len = encode_value(out + out[1], outlen - hdr_len, tlv_stack, depth, cursor, encoder_ctx);
960  }
961  if (len <= 0) return len;
962 
963  /*
964  * There may be more than 252 octets of data encoded in
965  * the attribute. If so, move the data up in the packet,
966  * and copy the existing header over. Set the "M" flag ONLY
967  * after copying the rest of the data.
968  */
969  if (len > (255 - out[1])) {
970  if (tlv_stack[0]->type == PW_TYPE_LONG_EXTENDED) {
971  return attr_shift(start, start + outlen, out, 4, len, 3, 0);
972  }
973 
974  len = (255 - out[1]); /* truncate to fit */
975  }
976 
977  out[1] += len;
978 
979 #ifndef NDEBUG
980  if ((fr_debug_lvl > 3) && fr_log_fp) {
981  int jump = 3;
982 
983  fprintf(fr_log_fp, "\t\t%02x %02x ", out[0], out[1]);
984  if (tlv_stack[0]->type == PW_TYPE_EXTENDED) {
985  fprintf(fr_log_fp, "%02x ", out[2]);
986 
987  } else {
988  fprintf(fr_log_fp, "%02x %02x ", out[2], out[3]);
989  jump = 4;
990  }
991 
992  if (tlv_stack[1]->type == PW_TYPE_EVS) {
993  fprintf(fr_log_fp, "%02x%02x%02x%02x (%u) %02x ",
994  out[jump], out[jump + 1],
995  out[jump + 2], out[jump + 3],
996  ((out[jump + 1] << 16) |
997  (out[jump + 2] << 8) |
998  out[jump + 3]),
999  out[jump + 4]);
1000  jump += 5;
1001  }
1002 
1003  FR_PROTO_HEX_DUMP("Done extended header", out + jump, len);
1004  }
1005 #endif
1006 
1007  return (out + out[1]) - start;
1008 }
1009 
1010 /** Encode an RFC format attribute, with the "concat" flag set
1011  *
1012  * If there isn't enough freespace in the packet, the data is
1013  * truncated to fit.
1014  */
1015 static ssize_t encode_concat(uint8_t *out, size_t outlen,
1016  fr_dict_attr_t const **tlv_stack, unsigned int depth,
1017  vp_cursor_t *cursor, UNUSED void *encoder_ctx)
1018 {
1019  uint8_t *ptr = out;
1020  uint8_t const *p;
1021  size_t len, left;
1022  VALUE_PAIR const *vp = fr_cursor_current(cursor);
1023 
1024  FR_PROTO_STACK_PRINT(tlv_stack, depth);
1025 
1026  p = vp->vp_octets;
1027  len = vp->vp_length;
1028 
1029  while (len > 0) {
1030  if (outlen <= 2) break;
1031 
1032  ptr[0] = tlv_stack[depth]->attr & 0xff;
1033  ptr[1] = 2;
1034 
1035  left = len;
1036 
1037  /* no more than 253 octets */
1038  if (left > 253) left = 253;
1039 
1040  /* no more than "freespace" octets */
1041  if (outlen < (left + 2)) left = outlen - 2;
1042 
1043  memcpy(ptr + 2, p, left);
1044 
1045 #ifndef NDEBUG
1046  if ((fr_debug_lvl > 3) && fr_log_fp) {
1047  fprintf(fr_log_fp, "\t\t%02x %02x ", ptr[0], ptr[1]);
1048  FR_PROTO_HEX_DUMP("Done concat", ptr + 2, len);
1049  }
1050 #endif
1051  ptr[1] += left;
1052  ptr += ptr[1];
1053  p += left;
1054  outlen -= left;
1055  len -= left;
1056  }
1057 
1058  vp = fr_cursor_next(cursor);
1059 
1060  /*
1061  * @fixme: attributes with 'concat' MUST of type
1062  * 'octets', and therefore CANNOT have any TLV data in them.
1063  */
1064  fr_proto_tlv_stack_build(tlv_stack, vp ? vp->da : NULL);
1065 
1066  return ptr - out;
1067 }
1068 
1069 /** Encode an RFC format TLV.
1070  *
1071  * This could be a standard attribute, or a TLV data type.
1072  * If it's a standard attribute, then vp->da->attr == attribute.
1073  * Otherwise, attribute may be something else.
1074  */
1075 static ssize_t encode_rfc_hdr_internal(uint8_t *out, size_t outlen,
1076  fr_dict_attr_t const **tlv_stack, unsigned int depth,
1077  vp_cursor_t *cursor, void *encoder_ctx)
1078 {
1079  ssize_t len;
1080 
1081  FR_PROTO_STACK_PRINT(tlv_stack, depth);
1082 
1083  switch (tlv_stack[depth]->type) {
1084  case PW_TYPE_STRUCTURAL:
1085  fr_strerror_printf("%s: Called with structural type %s", __FUNCTION__,
1086  fr_int2str(dict_attr_types, tlv_stack[depth]->type, "?Unknown?"));
1087  return -1;
1088 
1089  default:
1090  if (((tlv_stack[depth]->vendor == 0) && (tlv_stack[depth]->attr == 0)) ||
1091  (tlv_stack[depth]->attr > 255)) {
1092  fr_strerror_printf("%s: Called with non-standard attribute %u", __FUNCTION__,
1093  tlv_stack[depth]->attr);
1094  return -1;
1095  }
1096  break;
1097  }
1098 
1099  if (outlen <= 2) return 0;
1100 
1101  out[0] = tlv_stack[depth]->attr & 0xff;
1102  out[1] = 2;
1103 
1104  if (outlen > ((unsigned) 255 - out[1])) outlen = 255 - out[1];
1105 
1106  len = encode_value(out + out[1], outlen, tlv_stack, depth, cursor, encoder_ctx);
1107  if (len <= 0) return len;
1108 
1109  out[1] += len;
1110 
1111 #ifndef NDEBUG
1112  if ((fr_debug_lvl > 3) && fr_log_fp) {
1113  fprintf(fr_log_fp, "\t\t%02x %02x ", out[0], out[1]);
1114  FR_PROTO_HEX_DUMP("Done RFC header", out + 2, len);
1115  }
1116 #endif
1117 
1118  return out[1];
1119 }
1120 
1121 
1122 /** Encode a VSA which is a TLV
1123  *
1124  * If it's in the RFC format, call encode_rfc_hdr_internal. Otherwise, encode it here.
1125  */
1126 static ssize_t encode_vendor_attr_hdr(uint8_t *out, size_t outlen,
1127  fr_dict_attr_t const **tlv_stack, unsigned int depth,
1128  vp_cursor_t *cursor, void *encoder_ctx)
1129 {
1130  ssize_t len;
1131  size_t hdr_len;
1132  fr_dict_attr_t const *da, *dv;
1133 
1134  FR_PROTO_STACK_PRINT(tlv_stack, depth);
1135 
1136  dv = tlv_stack[depth++];
1137 
1138  if (dv->type != PW_TYPE_VENDOR) {
1139  fr_strerror_printf("Expected Vendor");
1140  return -1;
1141  }
1142 
1143  da = tlv_stack[depth];
1144 
1145  if ((da->type != PW_TYPE_TLV) && (dv->flags.type_size == 1) && (dv->flags.length == 1)) {
1146  return encode_rfc_hdr_internal(out, outlen, tlv_stack, depth, cursor, encoder_ctx);
1147  }
1148 
1149  hdr_len = dv->flags.type_size + dv->flags.length;
1150 
1151  /*
1152  * Vendors use different widths for their
1153  * attribute number fields.
1154  */
1155  switch (dv->flags.type_size) {
1156  default:
1157  fr_strerror_printf("%s: Internal sanity check failed, type %u", __FUNCTION__, (unsigned) dv->flags.type_size);
1158  return -1;
1159 
1160  case 4:
1161  out[0] = 0; /* attr must be 24-bit */
1162  out[1] = (da->attr >> 16) & 0xff;
1163  out[2] = (da->attr >> 8) & 0xff;
1164  out[3] = da->attr & 0xff;
1165  break;
1166 
1167  case 2:
1168  out[0] = (da->attr >> 8) & 0xff;
1169  out[1] = da->attr & 0xff;
1170  break;
1171 
1172  case 1:
1173  out[0] = da->attr & 0xff;
1174  break;
1175  }
1176 
1177  switch (dv->flags.length) {
1178  default:
1179  fr_strerror_printf("%s: Internal sanity check failed, length %u", __FUNCTION__, (unsigned) dv->flags.length);
1180  return -1;
1181 
1182  case 0:
1183  break;
1184 
1185  case 2:
1186  out[dv->flags.type_size] = 0;
1187  out[dv->flags.type_size + 1] = dv->flags.type_size + 2;
1188  break;
1189 
1190  case 1:
1191  out[dv->flags.type_size] = dv->flags.type_size + 1;
1192  break;
1193 
1194  }
1195 
1196  if (outlen > ((unsigned) 255 - hdr_len)) outlen = 255 - hdr_len;
1197 
1198  /*
1199  * Because we've now encoded the attribute header,
1200  * if this is a TLV, we must process it via the
1201  * internal tlv function, else we get a double TLV header.
1202  */
1203  if (tlv_stack[depth]->type == PW_TYPE_TLV) {
1204  len = encode_tlv_hdr_internal(out + hdr_len, outlen, tlv_stack, depth, cursor, encoder_ctx);
1205  } else {
1206  len = encode_value(out + hdr_len, outlen, tlv_stack, depth, cursor, encoder_ctx);
1207  }
1208 
1209  if (len <= 0) return len;
1210 
1211  if (dv->flags.length) out[hdr_len - 1] += len;
1212 
1213 #ifndef NDEBUG
1214  if ((fr_debug_lvl > 3) && fr_log_fp) {
1215  switch (dv->flags.type_size) {
1216  default:
1217  break;
1218 
1219  case 4:
1220  if ((fr_debug_lvl > 3) && fr_log_fp)
1221  fprintf(fr_log_fp, "\t\t%02x%02x%02x%02x ", out[0], out[1], out[2], out[3]);
1222  break;
1223 
1224  case 2:
1225  if ((fr_debug_lvl > 3) && fr_log_fp) fprintf(fr_log_fp, "\t\t%02x%02x ", out[0], out[1]);
1226  break;
1227 
1228  case 1:
1229  if ((fr_debug_lvl > 3) && fr_log_fp) fprintf(fr_log_fp, "\t\t%02x ", out[0]);
1230  break;
1231  }
1232 
1233  switch (dv->flags.length) {
1234  default:
1235  break;
1236 
1237  case 0:
1238  fprintf(fr_log_fp, " ");
1239  break;
1240 
1241  case 1:
1242  fprintf(fr_log_fp, "%02x ", out[dv->flags.type_size]);
1243  break;
1244 
1245  case 2:
1246  fprintf(fr_log_fp, "%02x%02x ", out[dv->flags.type_size], out[dv->flags.type_size] + 1);
1247  break;
1248  }
1249 
1250  FR_PROTO_HEX_DUMP("Done RFC header", out + hdr_len, len);
1251  }
1252 #endif
1253 
1254  return hdr_len + len;
1255 }
1256 
1257 /** Encode a WiMAX attribute
1258  *
1259  */
1260 static int encode_wimax_hdr(uint8_t *out, size_t outlen,
1261  fr_dict_attr_t const **tlv_stack, unsigned int depth,
1262  vp_cursor_t *cursor, void *encoder_ctx)
1263 {
1264  int len;
1265  uint32_t lvalue;
1266  int hdr_len;
1267  uint8_t *start = out;
1268  VALUE_PAIR const *vp = fr_cursor_current(cursor);
1269 
1270  VERIFY_VP(vp);
1271  FR_PROTO_STACK_PRINT(tlv_stack, depth);
1272 
1273  /*
1274  * Not enough freespace for:
1275  * attr, len, vendor-id, vsa, vsalen, continuation
1276  */
1277  if (outlen < 9) return 0;
1278 
1279  if (tlv_stack[depth++]->attr != PW_VENDOR_SPECIFIC) {
1280  fr_strerror_printf("%s: level[1] of tlv_stack is incorrect, must be Vendor-Specific (26)",
1281  __FUNCTION__);
1282  return -1;
1283  }
1284  FR_PROTO_STACK_PRINT(tlv_stack, depth);
1285 
1286  if (tlv_stack[depth++]->attr != VENDORPEC_WIMAX) {
1287  fr_strerror_printf("%s: level[2] of tlv_stack is incorrect, must be Wimax vendor %i", __FUNCTION__,
1288  VENDORPEC_WIMAX);
1289  return -1;
1290  }
1291  FR_PROTO_STACK_PRINT(tlv_stack, depth);
1292 
1293  /*
1294  * Build the Vendor-Specific header
1295  */
1296  out = start;
1297  out[0] = PW_VENDOR_SPECIFIC;
1298  out[1] = 9;
1299  lvalue = htonl(vp->da->vendor);
1300  memcpy(out + 2, &lvalue, 4);
1301 
1302  /*
1303  * Encode the first attribute
1304  */
1305  out[6] = tlv_stack[depth]->attr;
1306  out[7] = 3;
1307  out[8] = 0; /* continuation byte */
1308  hdr_len = 9;
1309 
1310  if (tlv_stack[depth]->type == PW_TYPE_TLV) {
1311  len = encode_tlv_hdr_internal(out + out[1], outlen - hdr_len, tlv_stack, depth, cursor, encoder_ctx);
1312  if (len <= 0) return len;
1313  } else {
1314  len = encode_value(out + out[1], outlen - hdr_len, tlv_stack, depth, cursor, encoder_ctx);
1315  if (len <= 0) return len;
1316  }
1317 
1318  /*
1319  * There may be more than 252 octets of data encoded in
1320  * the attribute. If so, move the data up in the packet,
1321  * and copy the existing header over. Set the "C" flag
1322  * ONLY after copying the rest of the data.
1323  */
1324  if (len > (255 - out[1])) {
1325  return attr_shift(start, start + outlen, out, hdr_len, len, 8, 7);
1326  }
1327 
1328  out[1] += len;
1329  out[7] += len;
1330 
1331 #ifndef NDEBUG
1332  if ((fr_debug_lvl > 3) && fr_log_fp) {
1333  fprintf(fr_log_fp, "\t\t%02x %02x %02x%02x%02x%02x (%u) %02x %02x %02x ",
1334  out[0], out[1],
1335  out[2], out[3], out[4], out[5],
1336  (out[3] << 16) | (out[4] << 8) | out[5],
1337  out[6], out[7], out[8]);
1338  FR_PROTO_HEX_DUMP("Done wimax header", out + 9, len);
1339  }
1340 #endif
1341 
1342  return (out + out[1]) - start;
1343 }
1344 
1345 /** Encode a Vendor-Specific attribute
1346  *
1347  */
1348 static int encode_vsa_hdr(uint8_t *out, size_t outlen,
1349  fr_dict_attr_t const **tlv_stack, unsigned int depth,
1350  vp_cursor_t *cursor, void *encoder_ctx)
1351 {
1352  ssize_t len;
1353  uint32_t lvalue;
1354  fr_dict_attr_t const *da = tlv_stack[depth];
1355 
1356  FR_PROTO_STACK_PRINT(tlv_stack, depth);
1357 
1358  if (da->type != PW_TYPE_VSA) {
1359  fr_strerror_printf("%s: Expected type \"vsa\" got \"%s\"", __FUNCTION__,
1360  fr_int2str(dict_attr_types, da->type, "?Unknown?"));
1361  return -1;
1362  }
1363 
1364  /*
1365  * Double-check for WiMAX format.
1366  */
1367  if (da->vendor == VENDORPEC_WIMAX) return encode_wimax_hdr(out, outlen, tlv_stack, depth + 1, cursor, encoder_ctx);
1368 
1369  /*
1370  * Not enough freespace for: attr, len, vendor-id
1371  */
1372  if (outlen < 6) return 0;
1373 
1374  /*
1375  * Build the Vendor-Specific header
1376  */
1377  out[0] = PW_VENDOR_SPECIFIC;
1378  out[1] = 6;
1379 
1380  /*
1381  * Now process the vendor ID part (which is one attribute deeper)
1382  */
1383  da = tlv_stack[++depth];
1384  FR_PROTO_STACK_PRINT(tlv_stack, depth);
1385 
1386  if (da->type != PW_TYPE_VENDOR) {
1387  fr_strerror_printf("%s: Expected type \"vsa\" got \"%s\"", __FUNCTION__,
1388  fr_int2str(dict_attr_types, da->type, "?Unknown?"));
1389  return -1;
1390  }
1391 
1392  lvalue = htonl(da->attr);
1393  memcpy(out + 2, &lvalue, 4); /* Copy in the 32bit vendor ID */
1394 
1395  if (outlen > ((unsigned) 255 - out[1])) outlen = 255 - out[1];
1396 
1397  len = encode_vendor_attr_hdr(out + out[1], outlen, tlv_stack, depth, cursor, encoder_ctx);
1398  if (len < 0) return len;
1399 
1400 #ifndef NDEBUG
1401  if ((fr_debug_lvl > 3) && fr_log_fp) {
1402  fprintf(fr_log_fp, "\t\t%02x %02x %02x%02x%02x%02x (%u) ",
1403  out[0], out[1],
1404  out[2], out[3], out[4], out[5],
1405  (out[3] << 16) | (out[4] << 8) | out[5]);
1406  FR_PROTO_HEX_DUMP("Done VSA header", out + 6, len);
1407  }
1408 #endif
1409  out[1] += len;
1410 
1411  return out[1];
1412 }
1413 
1414 /** Encode an RFC standard attribute 1..255
1415  *
1416  */
1417 static int encode_rfc_hdr(uint8_t *out, size_t outlen, fr_dict_attr_t const **tlv_stack, unsigned int depth,
1418  vp_cursor_t *cursor, void *encoder_ctx)
1419 {
1420  VALUE_PAIR const *vp = fr_cursor_current(cursor);
1421 
1422  /*
1423  * Sanity checks
1424  */
1425  VERIFY_VP(vp);
1426  FR_PROTO_STACK_PRINT(tlv_stack, depth);
1427 
1428  switch (tlv_stack[depth]->type) {
1429  case PW_TYPE_STRUCTURAL:
1430  fr_strerror_printf("%s: Expected leaf type got \"%s\"", __FUNCTION__,
1431  fr_int2str(dict_attr_types, tlv_stack[depth]->type, "?Unknown?"));
1432  return -1;
1433 
1434  default:
1435  /*
1436  * Attribute 0 is fine as a TLV leaf, or VSA, but not
1437  * in the original standards space.
1438  */
1439  if (((tlv_stack[depth]->vendor == 0) && (tlv_stack[depth]->attr == 0)) ||
1440  (tlv_stack[depth]->attr > 255)) {
1441  fr_strerror_printf("%s: Called with non-standard attribute %u", __FUNCTION__, vp->da->attr);
1442  return -1;
1443  }
1444  break;
1445  }
1446 
1447  /*
1448  * Only CUI is allowed to have zero length.
1449  * Thank you, WiMAX!
1450  */
1451  if ((vp->vp_length == 0) && (vp->da->attr == PW_CHARGEABLE_USER_IDENTITY)) {
1452  out[0] = PW_CHARGEABLE_USER_IDENTITY;
1453  out[1] = 2;
1454 
1455  vp = fr_cursor_next(cursor);
1456  fr_proto_tlv_stack_build(tlv_stack, vp ? vp->da : NULL);
1457  return 2;
1458  }
1459 
1460  /*
1461  * Message-Authenticator is hard-coded.
1462  */
1463  if (!vp->da->vendor && (vp->da->attr == PW_MESSAGE_AUTHENTICATOR)) {
1464  if (outlen < 18) return -1;
1465 
1466  out[0] = PW_MESSAGE_AUTHENTICATOR;
1467  out[1] = 18;
1468  memset(out + 2, 0, 16);
1469 #ifndef NDEBUG
1470  if ((fr_debug_lvl > 3) && fr_log_fp) {
1471  fprintf(fr_log_fp, "\t\t50 12 ...\n");
1472  }
1473 #endif
1474  vp = fr_cursor_next(cursor);
1475  fr_proto_tlv_stack_build(tlv_stack, vp ? vp->da : NULL);
1476  return 18;
1477  }
1478 
1479  return encode_rfc_hdr_internal(out, outlen, tlv_stack, depth, cursor, encoder_ctx);
1480 }
1481 
1482 /** Encode a data structure into a RADIUS attribute
1483  *
1484  * This is the main entry point into the encoder. It sets up the encoder array
1485  * we use for tracking our TLV/VSA/EVS nesting and then calls the appropriate
1486  * dispatch function.
1487  */
1488 int fr_radius_encode_pair(uint8_t *out, size_t outlen, vp_cursor_t *cursor, void *encoder_ctx)
1489 {
1490  VALUE_PAIR const *vp;
1491  int ret;
1492  size_t attr_len;
1493 
1494  fr_dict_attr_t const *tlv_stack[FR_DICT_MAX_TLV_STACK + 1];
1495  fr_dict_attr_t const *da = NULL;
1496 
1497  if (!cursor || !out || (outlen <= 2)) return -1;
1498  vp = fr_cursor_current(cursor);
1499  if (!vp) return -1;
1500 
1501  VERIFY_VP(vp);
1502 
1503  if (vp->da->depth > FR_DICT_MAX_TLV_STACK) {
1504  fr_strerror_printf("%s: Attribute depth %i exceeds maximum nesting depth %i",
1505  __FUNCTION__, vp->da->depth, FR_DICT_MAX_TLV_STACK);
1506  return -1;
1507  }
1508 
1509  /*
1510  * Ignore attributes which can't go into a RADIUS packet.
1511  */
1512  if (!vp->da->vendor && (vp->da->attr > 255)) return 0;
1513 
1514  /*
1515  * Nested structures of attributes can't be longer than
1516  * 255 bytes, so each call to an encode function can
1517  * only use 255 bytes of buffer space at a time.
1518  */
1519  attr_len = (outlen > UINT8_MAX) ? UINT8_MAX : outlen;
1520 
1521  /*
1522  * Fast path for the common case.
1523  */
1524  if (vp->da->parent->flags.is_root && !vp->da->flags.concat && (vp->da->type != PW_TYPE_TLV)) {
1525  tlv_stack[0] = vp->da;
1526  tlv_stack[1] = NULL;
1527  FR_PROTO_STACK_PRINT(tlv_stack, 0);
1528  return encode_rfc_hdr(out, attr_len, tlv_stack, 0, cursor, encoder_ctx);
1529  }
1530 
1531  /*
1532  * Do more work to set up the stack for the complex case.
1533  */
1534  fr_proto_tlv_stack_build(tlv_stack, vp->da);
1535  FR_PROTO_STACK_PRINT(tlv_stack, 0);
1536 
1537  da = tlv_stack[0];
1538  switch (da->type) {
1539  default:
1540  if (!da->flags.concat) {
1541  ret = encode_rfc_hdr(out, attr_len, tlv_stack, 0, cursor, encoder_ctx);
1542  } else {
1543  /*
1544  * Attributes like EAP-Message are marked as
1545  * "concat", which means that they are fragmented
1546  * using a different scheme than the "long
1547  * extended" one.
1548  */
1549  ret = encode_concat(out, outlen, tlv_stack, 0, cursor, encoder_ctx);
1550  }
1551  break;
1552 
1553  case PW_TYPE_VSA:
1554  if (vp->da->vendor != VENDORPEC_WIMAX) {
1555  ret = encode_vsa_hdr(out, attr_len, tlv_stack, 0, cursor, encoder_ctx);
1556 
1557  } else {
1558  /*
1559  * WiMAX has a non-standard format for
1560  * its VSAs. And, it can do "long"
1561  * attributes by fragmenting them inside
1562  * of the WiMAX VSA space.
1563  */
1564  ret = encode_wimax_hdr(out, outlen, tlv_stack, 0, cursor, encoder_ctx);
1565  }
1566  break;
1567 
1568  case PW_TYPE_TLV:
1569  ret = encode_tlv_hdr(out, attr_len, tlv_stack, 0, cursor, encoder_ctx);
1570  break;
1571 
1572  case PW_TYPE_EXTENDED:
1573  ret = encode_extended_hdr(out, attr_len, tlv_stack, 0, cursor, encoder_ctx);
1574  break;
1575 
1576  case PW_TYPE_LONG_EXTENDED:
1577  /*
1578  * These attributes can be longer than 253
1579  * octets. We therefore fragment the data across
1580  * multiple attributes.
1581  */
1582  ret = encode_extended_hdr(out, outlen, tlv_stack, 0, cursor, encoder_ctx);
1583  break;
1584 
1585  case PW_TYPE_INVALID:
1586  case PW_TYPE_VENDOR:
1587  case PW_TYPE_TIMEVAL:
1588  case PW_TYPE_DECIMAL:
1589  case PW_TYPE_MAX:
1590  case PW_TYPE_EVS:
1591  fr_strerror_printf("%s: Cannot encode attribute %s", __FUNCTION__, vp->da->name);
1592  return -1;
1593  }
1594 
1595  if (ret < 0) return ret;
1596 
1597  /*
1598  * We couldn't do it, so we didn't do anything.
1599  */
1600  if (fr_cursor_current(cursor) == vp) {
1601  fr_strerror_printf("%s: Nested attribute structure too large to encode", __FUNCTION__);
1602  return -1;
1603  }
1604 
1605  return ret;
1606 }
1607 
static void encode_tunnel_password(uint8_t *out, ssize_t *outlen, uint8_t const *input, size_t inlen, size_t freespace, char const *secret, uint8_t const *vector)
static int encode_vsa_hdr(uint8_t *out, size_t outlen, fr_dict_attr_t const **tlv_stack, unsigned int depth, vp_cursor_t *cursor, void *encoder_ctx)
Encode a Vendor-Specific attribute.
void fr_md5_calc(uint8_t *out, uint8_t const *in, size_t inlen)
Calculate the MD5 hash of the contents of a buffer.
Definition: md5.c:28
static int encode_extended_hdr(uint8_t *out, size_t outlen, fr_dict_attr_t const **tlv_stack, unsigned int depth, vp_cursor_t *cursor, void *encoder_ctx)
Encode an "extended" attribute.
FILE * fr_log_fp
Definition: radius.c:81
128 Bit IPv6 Address.
Definition: radius.h:40
static ssize_t encode_value(uint8_t *out, size_t outlen, fr_dict_attr_t const **tlv_stack, int depth, vp_cursor_t *cursor, void *encoder_ctx)
Encodes the data portion of an attribute.
#define TAG_VALID(x)
Definition: pair.h:189
static ssize_t encode_concat(uint8_t *out, size_t outlen, fr_dict_attr_t const **tlv_stack, unsigned int depth, vp_cursor_t *cursor, UNUSED void *encoder_ctx)
Encode an RFC format attribute, with the "concat" flag set.
Time value (struct timeval), only for config items.
Definition: radius.h:55
static unsigned int salt_offset
Definition: radius_encode.c:29
RFC2865 - Access-Challenge.
Definition: radius.h:102
#define PW_TYPE_STRUCTURAL
Match all non value types in case statements.
Definition: radius.h:82
Dictionary attribute.
Definition: dict.h:77
ssize_t fr_radius_encode_value_hton(uint8_t const **out, VALUE_PAIR const *vp)
Converts vp_data to network byte order.
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition: radius.c:1621
Ascend binary format a packed data structure.
Definition: radius.h:37
32 Bit signed integer.
Definition: radius.h:45
WiMAX IPv4 or IPv6 address depending on length.
Definition: radius.h:46
char const * secret
Definition: libradius.h:269
uint8_t length
length of the attribute
Definition: dict.h:64
void fr_radius_make_secret(uint8_t *digest, uint8_t const *vector, char const *secret, uint8_t const *value)
Build an encrypted secret value to return in a reply packet.
Definition: radius.c:272
int fr_radius_encode_pair(uint8_t *out, size_t outlen, vp_cursor_t *cursor, void *encoder_ctx)
Encode a data structure into a RADIUS attribute.
#define VERIFY_VP(_x)
Definition: pair.h:44
#define UNUSED
Definition: libradius.h:134
int8_t tag
Tag value used to group valuepairs.
Definition: pair.h:121
void fr_md5_init(FR_MD5_CTX *ctx)
Initialise a new MD5 context.
Definition: md5.c:84
#define FR_DICT_MAX_TLV_STACK
Maximum TLV stack size.
Definition: dict.h:123
IPv6 Prefix.
Definition: radius.h:41
Number of defined data types.
Definition: radius.h:59
fr_thread_local_setup(uint8_t *, fr_radius_encode_value_hton_buff)
Definition: radius_encode.c:31
Long extended attribute space attribute.
Definition: radius.h:49
unsigned int depth
Depth of nesting for this attribute.
Definition: dict.h:86
int fr_debug_lvl
Definition: misc.c:40
Abstraction to allow iterating over different configurations of VALUE_PAIRs.
Definition: pair.h:144
fr_dict_attr_flags_t flags
Flags.
Definition: dict.h:88
#define MAX_PASS_LEN
Definition: libradius.h:231
WiMAX IPv4 or IPv6 address prefix depending on length.
Definition: radius.h:57
void fr_md5_update(FR_MD5_CTX *ctx, uint8_t const *in, size_t inlen) CC_BOUNDED(__string__
RFC2865 - Access-Reject.
Definition: radius.h:94
static int encode_wimax_hdr(uint8_t *out, size_t outlen, fr_dict_attr_t const **tlv_stack, unsigned int depth, vp_cursor_t *cursor, void *encoder_ctx)
Encode a WiMAX attribute.
8 Bit unsigned integer.
Definition: radius.h:42
static ssize_t attr_shift(uint8_t const *start, uint8_t const *end, uint8_t *ptr, int hdr_len, ssize_t len, int flag_offset, int vsa_offset)
#define AUTH_VECTOR_LEN
Definition: libradius.h:118
#define AUTH_PASS_LEN
Definition: libradius.h:230
Interface ID.
Definition: radius.h:39
const FR_NAME_NUMBER dict_attr_types[]
Map data types to names representing those types.
Definition: dict.c:85
RFC2866 - Accounting-Request.
Definition: radius.h:95
Double precision floating point.
Definition: radius.h:58
unsigned int attr
Attribute number.
Definition: dict.h:79
int fr_radius_encode_chap_password(uint8_t *output, RADIUS_PACKET *packet, int id, VALUE_PAIR *password)
unsigned int code
Packet code (type).
Definition: libradius.h:155
RFC2865 - Access-Accept.
Definition: radius.h:93
unsigned int vendor
Vendor that defines this attribute.
Definition: dict.h:78
48 Bit Mac-Address.
Definition: radius.h:44
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
fr_dict_attr_t const * parent
Immediate parent of this attribute.
Definition: dict.h:82
VALUE_PAIR * fr_cursor_current(vp_cursor_t *cursor)
Return the VALUE_PAIR the cursor current points to.
Definition: cursor.c:304
enum attr_flags::@0 encrypt
Attribute that represents a vendor in the attribute tree.
Definition: radius.h:54
unsigned int is_root
Is root of a dictionary.
Definition: dict.h:41
unsigned int concat
concatenate multiple instances
Definition: dict.h:50
Invalid (uninitialised) attribute type.
Definition: radius.h:32
A truth value.
Definition: radius.h:56
32 Bit unsigned integer.
Definition: radius.h:34
RFC3575/RFC5176 - CoA-Request.
Definition: radius.h:108
uint8_t vector[AUTH_VECTOR_LEN]
RADIUS authentication vector.
Definition: libradius.h:157
static int encode_rfc_hdr(uint8_t *out, size_t outlen, fr_dict_attr_t const **tlv_stack, unsigned int depth, vp_cursor_t *cursor, void *encoder_ctx)
Encode an RFC standard attribute 1..255.
#define FR_PROTO_HEX_DUMP(_x, _y, _z)
Definition: proto.h:37
static ssize_t encode_tlv_hdr(uint8_t *out, size_t outlen, fr_dict_attr_t const **tlv_stack, unsigned int depth, vp_cursor_t *cursor, void *encoder_ctx)
#define FR_PROTO_STACK_PRINT(_x, _y)
Definition: proto.h:38
64 Bit unsigned integer.
Definition: radius.h:51
RADIUS_PACKET const * original
Definition: libradius.h:268
Vendor-Specific, for RADIUS attribute 26.
Definition: radius.h:53
char name[1]
Attribute name.
Definition: dict.h:89
uint8_t data[]
Definition: eap_pwd.h:625
#define TAG_ANY
Definition: pair.h:191
32 Bit Unix timestamp.
Definition: radius.h:36
Extended attribute space attribute.
Definition: radius.h:48
VALUE_PAIR * fr_cursor_next(vp_cursor_t *cursor)
Advanced the cursor to the next VALUE_PAIR.
Definition: cursor.c:263
#define fr_md5_copy(_out, _in)
Definition: md5.h:69
static ssize_t encode_rfc_hdr_internal(uint8_t *out, size_t outlen, fr_dict_attr_t const **tlv_stack, unsigned int depth, vp_cursor_t *cursor, void *encoder_ctx)
Encode an RFC format TLV.
static ssize_t encode_tlv_hdr_internal(uint8_t *out, size_t outlen, fr_dict_attr_t const **tlv_stack, unsigned int depth, vp_cursor_t *cursor, void *encoder_ctx)
static char const * secret
Definition: radclient.c:44
void fr_strerror_printf(char const *,...) CC_HINT(format(printf
unsigned int has_tag
Tagged attribute.
Definition: dict.h:46
VALUE_PAIR * fr_pair_find_by_num(VALUE_PAIR *head, unsigned int vendor, unsigned int attr, int8_t tag)
Find the pair with the matching attribute.
Definition: pair.c:639
IPv4 Prefix.
Definition: radius.h:52
#define TAG_NONE
Definition: pair.h:192
void void fr_md5_final(uint8_t out[MD5_DIGEST_LENGTH], FR_MD5_CTX *ctx) CC_BOUNDED(__minbytes__
int fr_radius_encode_password(char *passwd, size_t *pwlen, char const *secret, uint8_t const *vector)
Encode password.
char const * fr_int2str(FR_NAME_NUMBER const *table, int number, char const *def)
Definition: token.c:506
fr_dict_attr_t const * da
Dictionary attribute defines the attribute.
Definition: pair.h:113
RADIUS_PACKET const * packet
Definition: libradius.h:267
uint8_t type_size
for TLV2, size of the type
Definition: dict.h:65
#define MAX_STRING_LEN
Definition: libradius.h:120
String of printable characters.
Definition: radius.h:33
Contains nested attributes.
Definition: radius.h:47
PW_TYPE type
Value type.
Definition: dict.h:80
void fr_proto_tlv_stack_build(fr_dict_attr_t const **tlv_stack, fr_dict_attr_t const *da)
Definition: proto.c:94
32 Bit IPv4 Address.
Definition: radius.h:35
static ssize_t encode_vendor_attr_hdr(uint8_t *out, size_t outlen, fr_dict_attr_t const **tlv_stack, unsigned int depth, vp_cursor_t *cursor, void *encoder_ctx)
Encode a VSA which is a TLV.
16 Bit unsigned integer.
Definition: radius.h:43
Raw octets.
Definition: radius.h:38
int fr_radius_encode_tunnel_password(char *passwd, size_t *pwlen, char const *secret, uint8_t const *vector)
Encode Tunnel-Password attributes when sending them out on the wire.
static void encode_password(uint8_t *out, ssize_t *outlen, uint8_t const *input, size_t inlen, char const *secret, uint8_t const *vector)
#define VENDORPEC_WIMAX
Definition: radius.h:202
Extended attribute, vendor specific.
Definition: radius.h:50
RFC3575/RFC5176 - Disconnect-Request.
Definition: radius.h:105
value_data_t data
Definition: pair.h:133