2 * Copyright (C) 2011 Network RADIUS SARL <info@networkradius.com>
4 * This software may not be redistributed in any form without the prior
5 * written consent of Network RADIUS.
7 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
8 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
9 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
10 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
11 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
15 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
16 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
20 #include <networkradius-devel/client.h>
26 static int packet_code = PW_ACCESS_REQUEST;
27 static int packet_id = 1;
28 static uint8_t packet_vector[16] = { 0, 0, 0, 0, 0, 0, 0, 0,
29 0, 0, 0, 0, 0, 0, 0, 0 };
30 static char secret[256] = "testing123";
32 static int encode_tlv(char *buffer, uint8_t *output, size_t outlen);
34 static const char *hextab = "0123456789abcdef";
36 static int encode_data_string(char *buffer,
37 uint8_t *output, size_t outlen)
44 while (*p && (outlen > 0)) {
78 fprintf(stderr, "String is not terminated\n");
82 static int encode_data_tlv(char *buffer, char **endptr,
83 uint8_t *output, size_t outlen)
89 for (p = buffer; *p != '\0'; p++) {
90 if (*p == '{') depth++;
93 if (depth == 0) break;
98 fprintf(stderr, "No trailing '}' in string starting "
108 while (isspace((int) *p)) p++;
110 length = encode_tlv(p, output, outlen);
111 if (length == 0) return 0;
116 static int encode_hex(char *p, uint8_t *output, size_t outlen)
122 while (isspace((int) *p)) p++;
126 if(!(c1 = memchr(hextab, tolower((int) p[0]), 16)) ||
127 !(c2 = memchr(hextab, tolower((int) p[1]), 16))) {
128 fprintf(stderr, "Invalid data starting at "
133 *output = ((c1 - hextab) << 4) + (c2 - hextab);
140 fprintf(stderr, "Too much data\n");
149 static int encode_data(char *p, uint8_t *output, size_t outlen)
153 if (!isspace((int) *p)) {
154 fprintf(stderr, "Invalid character following attribute "
159 while (isspace((int) *p)) p++;
168 while (isspace((int) *p)) p++;
171 fprintf(stderr, "No data\n");
178 sublen = encode_data_tlv(p, &q, output, outlen);
179 if (sublen == 0) return 0;
191 length = encode_data_string(p, output, outlen);
195 length = encode_hex(p, output, outlen);
198 fprintf(stderr, "Empty string\n");
205 static int decode_attr(char *buffer, char **endptr)
209 attr = strtol(buffer, endptr, 10);
210 if (*endptr == buffer) {
211 fprintf(stderr, "No valid number found in string "
212 "starting with \"%s\"\n", buffer);
217 fprintf(stderr, "Nothing follows attribute number\n");
221 if ((attr <= 0) || (attr > 256)) {
222 fprintf(stderr, "Attribute number is out of valid "
230 static int decode_vendor(char *buffer, char **endptr)
234 if (*buffer != '.') {
235 fprintf(stderr, "Invalid separator before vendor id\n");
239 vendor = strtol(buffer + 1, endptr, 10);
240 if (*endptr == (buffer + 1)) {
241 fprintf(stderr, "No valid vendor number found\n");
246 fprintf(stderr, "Nothing follows vendor number\n");
250 if ((vendor <= 0) || (vendor > (1 << 24))) {
251 fprintf(stderr, "Vendor number is out of valid range\n");
255 if (**endptr != '.') {
256 fprintf(stderr, "Invalid data following vendor number\n");
264 static int encode_tlv(char *buffer, uint8_t *output, size_t outlen)
270 attr = decode_attr(buffer, &p);
271 if (attr == 0) return 0;
278 length = encode_tlv(p, output + 2, outlen - 2);
281 length = encode_data(p, output + 2, outlen - 2);
284 if (length == 0) return 0;
285 if (length > (255 - 2)) {
286 fprintf(stderr, "TLV data is too long\n");
295 static int encode_vsa(char *buffer, uint8_t *output, size_t outlen)
301 vendor = decode_vendor(buffer, &p);
302 if (vendor == 0) return 0;
305 output[1] = (vendor >> 16) & 0xff;
306 output[2] = (vendor >> 8) & 0xff;
307 output[3] = vendor & 0xff;
309 length = encode_tlv(p, output + 4, outlen - 4);
310 if (length == 0) return 0;
311 if (length > (255 - 6)) {
312 fprintf(stderr, "VSA data is too long\n");
320 static int encode_evs(char *buffer, uint8_t *output, size_t outlen)
327 vendor = decode_vendor(buffer, &p);
328 if (vendor == 0) return 0;
330 attr = decode_attr(p, &p);
331 if (attr == 0) return 0;
334 output[1] = (vendor >> 16) & 0xff;
335 output[2] = (vendor >> 8) & 0xff;
336 output[3] = vendor & 0xff;
339 length = encode_data(p, output + 5, outlen - 5);
340 if (length == 0) return 0;
345 static int encode_extended(char *buffer,
346 uint8_t *output, size_t outlen)
352 attr = decode_attr(buffer, &p);
353 if (attr == 0) return 0;
358 length = encode_evs(p, output + 1, outlen - 1);
360 length = encode_data(p, output + 1, outlen - 1);
362 if (length == 0) return 0;
363 if (length > (255 - 3)) {
364 fprintf(stderr, "Extended Attr data is too long\n");
371 static int encode_extended_flags(char *buffer,
372 uint8_t *output, size_t outlen)
378 attr = decode_attr(buffer, &p);
379 if (attr == 0) return 0;
381 /* output[0] is the extended attribute */
387 length = encode_evs(p, output + 4, outlen - 4);
388 if (length == 0) return 0;
393 length = encode_data(p, output + 4, outlen - 4);
395 if (length == 0) return 0;
399 int sublen = 255 - output[1];
401 if (length <= sublen) {
409 memmove(output + 255 + 4, output + 255, length);
410 memcpy(output + 255, output, 4);
423 static int encode_rfc(char *buffer, uint8_t *output, size_t outlen)
429 attr = decode_attr(buffer, &p);
430 if (attr == 0) return 0;
437 sublen = encode_vsa(p, output + 2, outlen - 2);
439 } else if ((attr < 241) || (attr > 246)) {
440 sublen = encode_data(p, output + 2, outlen - 2);
444 fprintf(stderr, "Invalid data following "
445 "attribute number\n");
450 sublen = encode_extended(p + 1,
451 output + 2, outlen - 2);
455 * Not like the others!
457 return encode_extended_flags(p + 1, output, outlen);
460 if (sublen == 0) return 0;
461 if (sublen > (255 -2)) {
462 fprintf(stderr, "RFC Data is too long\n");
467 return length + sublen;
470 static int walk_callback(void *ctx, const DICT_ATTR *da,
471 const uint8_t *data, size_t sizeof_data)
475 sprintf(*p, "v%u a%u l%ld,",
476 da->vendor, da->attr, sizeof_data);
481 static void process_file(const char *filename)
485 ssize_t len, data_len;
487 RADIUS_PACKET packet;
488 char input[8192], buffer[8192];
490 uint8_t *attr, data[2048];
492 if (strcmp(filename, "-") == 0) {
494 filename = "<stdin>";
497 fp = fopen(filename, "r");
499 fprintf(stderr, "Error opening %s: %s\n",
500 filename, strerror(errno));
509 while (fgets(buffer, sizeof(buffer), fp) != NULL) {
510 char *p = strchr(buffer, '\n');
511 VALUE_PAIR *vp, *head = NULL;
512 VALUE_PAIR **tail = &head;
518 fprintf(stderr, "Line %d too long in %s\n",
526 p = strchr(buffer, '#');
530 while (isspace((int) *p)) p++;
535 if (strncmp(p, "raw ", 4) == 0) {
536 outlen = encode_rfc(p + 4, data, sizeof(data));
538 fprintf(stderr, "Parse error in line %d of %s\n",
550 for (i = 0; i < outlen; i++) {
551 snprintf(output + 3*i, sizeof(output),
554 outlen = strlen(output);
555 output[outlen - 1] = '\0';
559 if (strncmp(p, "data ", 5) == 0) {
560 if (strcmp(p + 5, output) != 0) {
561 fprintf(stderr, "Mismatch in line %d of %s, expected: %s\n",
562 lineno, filename, output);
569 if (strncmp(p, "encode ", 7) == 0) {
570 if (strcmp(p + 7, "-") == 0) {
576 rcode = nr_vp_sscanf(p, &head);
578 strcpy(output, nr_strerror(rcode));
585 len = nr_vp2attr(NULL, NULL, &vp,
586 attr, sizeof(data) - (attr - data));
588 fprintf(stderr, "Failed encoding %s: %s\n",
589 vp->da->name, nr_strerror(len));
602 if (strncmp(p, "decode ", 7) == 0) {
605 if (strcmp(p + 7, "-") == 0) {
610 len = encode_hex(p + 7, data, sizeof(data));
612 fprintf(stderr, "Failed decoding hex string at line %d of %s\n", lineno, filename);
619 my_len = nr_attr2vp(NULL, NULL,
627 fprintf(stderr, "Internal sanity check failed at %d\n", __LINE__);
642 * Output may be an error, and we ignore
647 for (vp = head; vp != NULL; vp = vp->next) {
648 nr_vp_snprintf(p, sizeof(output) - (p - output), vp);
651 if (vp->next) {strcpy(p, ", ");
657 } else if (my_len < 0) {
658 strcpy(output, nr_strerror(my_len));
660 } else { /* zero-length attribute */
666 if (strncmp(p, "walk ", 5) == 0) {
667 len = encode_hex(p + 5, data + 20, sizeof(data) - 20);
670 fprintf(stderr, "Failed decoding hex string at line %d of %s\n", lineno, filename);
676 packet.length = len + 20;
677 packet.data[2] = ((len + 20) >> 8) & 0xff;
678 packet.data[3] = (len + 20) & 0xff;
683 rcode = nr_packet_walk(&packet, &p, walk_callback);
685 snprintf(output, sizeof(output), "%d", rcode);
689 if (*output) output[strlen(output) - 1] = '\0';
693 if (strncmp(p, "$INCLUDE ", 9) == 0) {
695 while (isspace((int) *p)) p++;
701 if (strncmp(p, "secret ", 7) == 0) {
702 strlcpy(secret, p + 7, sizeof(secret));
703 strlcpy(output, secret, sizeof(output));
707 if (strncmp(p, "code ", 5) == 0) {
708 packet_code = atoi(p + 5);
709 snprintf(output, sizeof(output), "%u", packet_code);
713 if (strncmp(p, "sign ", 5) == 0) {
714 len = encode_hex(p + 5, data + 20, sizeof(data) - 20);
716 fprintf(stderr, "Failed decoding hex string at line %d of %s\n", lineno, filename);
720 memset(&packet, 0, sizeof(packet));
721 packet.secret = secret;
722 packet.sizeof_secret = strlen(secret);
723 packet.code = packet_code;
724 packet.id = packet_id;
725 memcpy(packet.vector, packet_vector, 16);
727 packet.length = len + 20;
730 * Hack encode the packet.
732 packet.data[0] = packet_code;
733 packet.data[1] = packet_id;
734 packet.data[2] = ((len + 20) >> 8) & 0xff;
735 packet.data[3] = (len + 20) & 0xff;
736 memcpy(packet.data + 4, packet_vector, 16);
738 rcode = nr_packet_sign(&packet, NULL);
740 snprintf(output, sizeof(output), "%d", rcode);
744 memcpy(data, packet.vector, sizeof(packet.vector));
745 outlen = sizeof(packet.vector);
749 fprintf(stderr, "Unknown input at line %d of %s\n",
754 if (fp != stdin) fclose(fp);
757 int main(int argc, char *argv[])
765 process_file(argv[1]);