Annotation of src/usr.bin/snmp/smi.c, Revision 1.11
1.11 ! martijn 1: /* $OpenBSD: smi.c,v 1.10 2020/08/03 14:45:54 martijn Exp $ */
1.1 martijn 2:
3: /*
4: * Copyright (c) 2019 Martijn van Duren <martijn@openbsd.org>
5: * Copyright (c) 2007, 2008 Reyk Floeter <reyk@openbsd.org>
6: *
7: * Permission to use, copy, modify, and distribute this software for any
8: * purpose with or without fee is hereby granted, provided that the above
9: * copyright notice and this permission notice appear in all copies.
10: *
11: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18: */
19:
20: #include <sys/limits.h>
21: #include <sys/tree.h>
22: #include <sys/queue.h>
23:
24: #include <arpa/inet.h>
25:
26: #include <ctype.h>
1.10 martijn 27: #include <errno.h>
1.1 martijn 28: #include <stdlib.h>
29: #include <stdio.h>
30: #include <string.h>
31: #include <strings.h>
1.10 martijn 32: #include <wctype.h>
1.1 martijn 33:
34: #include "ber.h"
35: #include "mib.h"
36: #include "snmp.h"
37: #include "smi.h"
38:
39: #define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
40:
1.10 martijn 41: char *smi_displayhint_os(struct textconv *, int, const char *, size_t, int);
42:
1.1 martijn 43: int smi_oid_cmp(struct oid *, struct oid *);
44: int smi_key_cmp(struct oid *, struct oid *);
1.10 martijn 45: int smi_textconv_cmp(struct textconv *, struct textconv *);
1.1 martijn 46: struct oid * smi_findkey(char *);
47:
48: RB_HEAD(oidtree, oid);
49: RB_PROTOTYPE(oidtree, oid, o_element, smi_oid_cmp)
50: struct oidtree smi_oidtree;
51:
52: RB_HEAD(keytree, oid);
53: RB_PROTOTYPE(keytree, oid, o_keyword, smi_key_cmp)
54: struct keytree smi_keytree;
55:
1.10 martijn 56: RB_HEAD(textconvtree, textconv);
57: RB_PROTOTYPE(textconvtree, textconv, tc_entry, smi_textconv_cmp);
58: struct textconvtree smi_tctree;
59:
1.1 martijn 60: int
61: smi_init(void)
62: {
63: /* Initialize the Structure of Managed Information (SMI) */
64: RB_INIT(&smi_oidtree);
65: mib_init();
66: return (0);
67: }
68:
69: void
1.10 martijn 70: smi_debug_elements(struct ber_element *root, int utf8)
1.1 martijn 71: {
72: static int indent = 0;
73: char *value;
74: int constructed;
75:
76: /* calculate lengths */
1.6 tb 77: ober_calc_len(root);
1.1 martijn 78:
79: switch (root->be_encoding) {
80: case BER_TYPE_SEQUENCE:
81: case BER_TYPE_SET:
82: constructed = root->be_encoding;
83: break;
84: default:
85: constructed = 0;
86: break;
87: }
88:
89: fprintf(stderr, "%*slen %lu ", indent, "", root->be_len);
90: switch (root->be_class) {
91: case BER_CLASS_UNIVERSAL:
92: fprintf(stderr, "class: universal(%u) type: ", root->be_class);
93: switch (root->be_type) {
94: case BER_TYPE_EOC:
95: fprintf(stderr, "end-of-content");
96: break;
97: case BER_TYPE_BOOLEAN:
98: fprintf(stderr, "boolean");
99: break;
100: case BER_TYPE_INTEGER:
101: fprintf(stderr, "integer");
102: break;
103: case BER_TYPE_BITSTRING:
104: fprintf(stderr, "bit-string");
105: break;
106: case BER_TYPE_OCTETSTRING:
107: fprintf(stderr, "octet-string");
108: break;
109: case BER_TYPE_NULL:
110: fprintf(stderr, "null");
111: break;
112: case BER_TYPE_OBJECT:
113: fprintf(stderr, "object");
114: break;
115: case BER_TYPE_ENUMERATED:
116: fprintf(stderr, "enumerated");
117: break;
118: case BER_TYPE_SEQUENCE:
119: fprintf(stderr, "sequence");
120: break;
121: case BER_TYPE_SET:
122: fprintf(stderr, "set");
123: break;
124: }
125: break;
126: case BER_CLASS_APPLICATION:
127: fprintf(stderr, "class: application(%u) type: ",
128: root->be_class);
129: switch (root->be_type) {
130: case SNMP_T_IPADDR:
131: fprintf(stderr, "ipaddr");
132: break;
133: case SNMP_T_COUNTER32:
134: fprintf(stderr, "counter32");
135: break;
136: case SNMP_T_GAUGE32:
137: fprintf(stderr, "gauge32");
138: break;
139: case SNMP_T_TIMETICKS:
140: fprintf(stderr, "timeticks");
141: break;
142: case SNMP_T_OPAQUE:
143: fprintf(stderr, "opaque");
144: break;
145: case SNMP_T_COUNTER64:
146: fprintf(stderr, "counter64");
147: break;
148: }
149: break;
150: case BER_CLASS_CONTEXT:
151: fprintf(stderr, "class: context(%u) type: ",
152: root->be_class);
153: switch (root->be_type) {
154: case SNMP_C_GETREQ:
155: fprintf(stderr, "getreq");
156: break;
157: case SNMP_C_GETNEXTREQ:
158: fprintf(stderr, "nextreq");
159: break;
160: case SNMP_C_GETRESP:
161: fprintf(stderr, "getresp");
162: break;
163: case SNMP_C_SETREQ:
164: fprintf(stderr, "setreq");
165: break;
166: case SNMP_C_TRAP:
167: fprintf(stderr, "trap");
168: break;
169: case SNMP_C_GETBULKREQ:
170: fprintf(stderr, "getbulkreq");
171: break;
172: case SNMP_C_INFORMREQ:
173: fprintf(stderr, "informreq");
174: break;
175: case SNMP_C_TRAPV2:
176: fprintf(stderr, "trapv2");
177: break;
178: case SNMP_C_REPORT:
179: fprintf(stderr, "report");
180: break;
181: }
182: break;
183: case BER_CLASS_PRIVATE:
184: fprintf(stderr, "class: private(%u) type: ", root->be_class);
185: break;
186: default:
187: fprintf(stderr, "class: <INVALID>(%u) type: ", root->be_class);
188: break;
189: }
190: fprintf(stderr, "(%u) encoding %u ",
191: root->be_type, root->be_encoding);
192:
1.10 martijn 193: if ((value = smi_print_element(NULL, root, 1, smi_os_default,
194: smi_oidl_numeric, utf8)) == NULL)
1.1 martijn 195: goto invalid;
196:
197: switch (root->be_encoding) {
198: case BER_TYPE_BOOLEAN:
199: fprintf(stderr, "%s", value);
200: break;
201: case BER_TYPE_INTEGER:
202: case BER_TYPE_ENUMERATED:
203: fprintf(stderr, "value %s", value);
204: break;
205: case BER_TYPE_BITSTRING:
206: fprintf(stderr, "hexdump %s", value);
207: break;
208: case BER_TYPE_OBJECT:
209: fprintf(stderr, "oid %s", value);
210: break;
211: case BER_TYPE_OCTETSTRING:
212: if (root->be_class == BER_CLASS_APPLICATION &&
213: root->be_type == SNMP_T_IPADDR) {
214: fprintf(stderr, "addr %s", value);
215: } else {
216: fprintf(stderr, "string %s", value);
217: }
218: break;
219: case BER_TYPE_NULL: /* no payload */
220: case BER_TYPE_EOC:
221: case BER_TYPE_SEQUENCE:
222: case BER_TYPE_SET:
223: default:
224: fprintf(stderr, "%s", value);
225: break;
226: }
227:
228: invalid:
229: if (value == NULL)
230: fprintf(stderr, "<INVALID>");
231: else
232: free(value);
233: fprintf(stderr, "\n");
234:
235: if (constructed)
236: root->be_encoding = constructed;
237:
238: if (constructed && root->be_sub) {
239: indent += 2;
1.10 martijn 240: smi_debug_elements(root->be_sub, utf8);
1.1 martijn 241: indent -= 2;
242: }
243: if (root->be_next)
1.10 martijn 244: smi_debug_elements(root->be_next, utf8);
1.1 martijn 245: }
246:
247: char *
1.10 martijn 248: smi_print_element(struct ber_oid *oid, struct ber_element *root, int print_hint,
249: enum smi_output_string output_string, enum smi_oid_lookup lookup, int utf8)
1.1 martijn 250: {
251: char *str = NULL, *buf, *p;
1.10 martijn 252: struct oid okey;
253: struct oid *object = NULL;
254: struct textconv tckey;
1.5 jsg 255: size_t len, i, slen;
1.1 martijn 256: long long v, ticks;
257: int d;
1.4 martijn 258: int is_hex = 0, ret;
1.1 martijn 259: struct ber_oid o;
260: char strbuf[BUFSIZ];
261: char *hint;
262: int days, hours, min, sec, csec;
263:
1.10 martijn 264: if (oid != NULL) {
265: bcopy(oid, &(okey.o_id), sizeof(okey));
266: do {
267: object = RB_FIND(oidtree, &smi_oidtree, &okey);
268: okey.o_id.bo_n--;
269: } while (object == NULL && okey.o_id.bo_n > 0);
270: if (object != NULL && object->o_textconv == NULL &&
271: object->o_tcname != NULL) {
272: tckey.tc_name = object->o_tcname;
273: object->o_textconv = RB_FIND(textconvtree, &smi_tctree,
274: &tckey);
275: }
276: }
277:
1.1 martijn 278: switch (root->be_encoding) {
279: case BER_TYPE_BOOLEAN:
1.6 tb 280: if (ober_get_boolean(root, &d) == -1)
1.1 martijn 281: goto fail;
282: if (print_hint) {
283: if (asprintf(&str, "INTEGER: %s(%d)",
284: d ? "true" : "false", d) == -1)
285: goto fail;
1.3 deraadt 286: } else
1.1 martijn 287: if (asprintf(&str, "%s", d ? "true" : "false") == -1)
288: goto fail;
289: break;
290: case BER_TYPE_INTEGER:
291: case BER_TYPE_ENUMERATED:
1.6 tb 292: if (ober_get_integer(root, &v) == -1)
1.1 martijn 293: goto fail;
294: if (root->be_class == BER_CLASS_APPLICATION &&
295: root->be_type == SNMP_T_TIMETICKS) {
296: ticks = v;
297: days = ticks / (60 * 60 * 24 * 100);
298: ticks %= (60 * 60 * 24 * 100);
299: hours = ticks / (60 * 60 * 100);
300: ticks %= (60 * 60 * 100);
301: min = ticks / (60 * 100);
302: ticks %= (60 * 100);
303: sec = ticks / 100;
304: ticks %= 100;
305: csec = ticks;
306:
307: if (print_hint) {
308: if (days == 0) {
309: if (asprintf(&str,
310: "Timeticks: (%lld) "
311: "%d:%02d:%02d.%02d",
312: v, hours, min, sec, csec) == -1)
313: goto fail;
314: } else if (days == 1) {
315: if (asprintf(&str,
316: "Timeticks: (%lld) "
317: "1 day %d:%02d:%02d.%02d",
318: v, hours, min, sec, csec) == -1)
319: goto fail;
320: } else {
321: if (asprintf(&str,
322: "Timeticks: (%lld) "
323: "%d day %d:%02d:%02d.%02d",
324: v, days, hours, min, sec, csec) ==
325: -1)
326: goto fail;
327: }
328: } else {
329: if (days == 0) {
330: if (asprintf(&str, "%d:%02d:%02d.%02d",
331: hours, min, sec, csec) == -1)
332: goto fail;
333: } else if (days == 1) {
334: if (asprintf(&str,
335: "1 day %d:%02d:%02d.%02d",
336: hours, min, sec, csec) == -1)
337: goto fail;
338: } else {
339: if (asprintf(&str,
340: "%d day %d:%02d:%02d.%02d",
341: days, hours, min, sec, csec) == -1)
342: goto fail;
343: }
344: }
345: break;
346: }
347: hint = "INTEGER: ";
348: if (root->be_class == BER_CLASS_APPLICATION) {
349: if (root->be_type == SNMP_T_COUNTER32)
350: hint = "Counter32: ";
351: else if (root->be_type == SNMP_T_GAUGE32)
352: hint = "Gauge32: ";
353: else if (root->be_type == SNMP_T_OPAQUE)
354: hint = "Opaque: ";
355: else if (root->be_type == SNMP_T_COUNTER64)
356: hint = "Counter64: ";
357: }
1.3 deraadt 358: if (asprintf(&str, "%s%lld", print_hint ? hint : "", v) == -1)
1.1 martijn 359: goto fail;
360: break;
361: case BER_TYPE_BITSTRING:
1.6 tb 362: if (ober_get_bitstring(root, (void *)&buf, &len) == -1)
1.1 martijn 363: goto fail;
1.5 jsg 364: slen = len * 2 + 1 + sizeof("BITS: ");
365: if ((str = calloc(1, slen)) == NULL)
1.1 martijn 366: goto fail;
367: p = str;
368: if (print_hint) {
1.5 jsg 369: strlcpy(str, "BITS: ", slen);
1.1 martijn 370: p += sizeof("BITS: ");
371: }
372: for (i = 0; i < len; i++) {
373: snprintf(p, 3, "%02x", buf[i]);
374: p += 2;
375: }
376: break;
377: case BER_TYPE_OBJECT:
1.6 tb 378: if (ober_get_oid(root, &o) == -1)
1.1 martijn 379: goto fail;
380: if (asprintf(&str, "%s%s",
381: print_hint ? "OID: " : "",
382: smi_oid2string(&o, strbuf, sizeof(strbuf), lookup)) == -1)
383: goto fail;
384: break;
385: case BER_TYPE_OCTETSTRING:
1.6 tb 386: if (ober_get_string(root, &buf) == -1)
1.1 martijn 387: goto fail;
388: if (root->be_class == BER_CLASS_APPLICATION &&
389: root->be_type == SNMP_T_IPADDR) {
390: if (asprintf(&str, "%s%s",
391: print_hint ? "IpAddress: " : "",
392: inet_ntoa(*(struct in_addr *)buf)) == -1)
393: goto fail;
1.7 martijn 394: } else if (root->be_class == BER_CLASS_CONTEXT) {
395: if (root->be_type == SNMP_E_NOSUCHOBJECT)
396: str = strdup("No Such Object available on this "
397: "agent at this OID");
398: else if (root->be_type == SNMP_E_NOSUCHINSTANCE)
399: str = strdup("No Such Instance currently "
400: "exists at this OID");
401: else if (root->be_type == SNMP_E_ENDOFMIB)
402: str = strdup("No more variables left in this "
403: "MIB View (It is past the end of the MIB "
404: "tree)");
405: else
406: str = strdup("Unknown status at this OID");
1.2 deraadt 407: } else {
1.10 martijn 408: if (object != NULL && object->o_textconv != NULL &&
409: object->o_textconv->tc_syntax == root->be_encoding)
410: return smi_displayhint_os(object->o_textconv,
411: print_hint, buf, root->be_len, utf8);
1.1 martijn 412: for (i = 0; i < root->be_len; i++) {
413: if (!isprint(buf[i])) {
414: if (output_string == smi_os_default)
415: output_string = smi_os_hex;
416: else if (output_string == smi_os_ascii)
417: is_hex = 1;
418: break;
419: }
420: }
421: /*
422: * hex is 3 * n (2 digits + n - 1 spaces + NUL-byte)
423: * ascii can be max (2 * n) + 2 quotes + NUL-byte
424: */
1.4 martijn 425: len = output_string == smi_os_hex ? 3 : 2;
426: p = str = reallocarray(NULL, root->be_len + 2, len);
427: if (p == NULL)
1.1 martijn 428: goto fail;
1.4 martijn 429: len *= root->be_len + 2;
430: if (is_hex) {
1.1 martijn 431: *str++ = '"';
1.4 martijn 432: len--;
433: }
1.1 martijn 434: for (i = 0; i < root->be_len; i++) {
435: switch (output_string) {
436: case smi_os_default:
437: /* FALLTHROUGH */
438: case smi_os_ascii:
439: /*
440: * There's probably more edgecases here,
441: * not fully investigated
442: */
1.4 martijn 443: if (len < 2)
444: goto fail;
445: if (is_hex && buf[i] == '\\') {
1.1 martijn 446: *str++ = '\\';
1.4 martijn 447: len--;
448: }
1.1 martijn 449: *str++ = isprint(buf[i]) ? buf[i] : '.';
1.4 martijn 450: len--;
1.1 martijn 451: break;
452: case smi_os_hex:
1.4 martijn 453: ret = snprintf(str, len, "%s%02hhX",
1.1 martijn 454: i == 0 ? "" :
455: i % 16 == 0 ? "\n" : " ", buf[i]);
1.4 martijn 456: if (ret == -1 || ret > (int) len)
457: goto fail;
458: len -= ret;
459: str += ret;
1.1 martijn 460: break;
461: }
462: }
1.4 martijn 463: if (is_hex) {
464: if (len < 2)
465: goto fail;
1.1 martijn 466: *str++ = '"';
1.4 martijn 467: len--;
468: }
469: if (len == 0)
470: goto fail;
1.1 martijn 471: *str = '\0';
472: str = NULL;
473: if (asprintf(&str, "%s%s",
474: print_hint ?
475: output_string == smi_os_hex ? "Hex-STRING: " :
476: "STRING: " :
477: "", p) == -1) {
478: free(p);
479: goto fail;
480: }
481: free(p);
482: }
483: break;
484: case BER_TYPE_NULL: /* no payload */
485: case BER_TYPE_EOC:
486: case BER_TYPE_SEQUENCE:
487: case BER_TYPE_SET:
488: default:
489: str = strdup("");
490: break;
491: }
492:
493: return (str);
494:
495: fail:
496: free(str);
497: return (NULL);
498: }
499:
500: int
501: smi_string2oid(const char *oidstr, struct ber_oid *o)
502: {
503: char *sp, *p, str[BUFSIZ];
504: const char *errstr;
505: struct oid *oid;
506: struct ber_oid ko;
507:
508: if (strlcpy(str, oidstr, sizeof(str)) >= sizeof(str))
509: return (-1);
510: bzero(o, sizeof(*o));
511:
512: /*
513: * Parse OID strings in the common form n.n.n or n-n-n.
1.6 tb 514: * Based on ober_string2oid with additional support for symbolic names.
1.1 martijn 515: */
516: p = sp = str[0] == '.' ? str + 1 : str;
517: for (; p != NULL; sp = p) {
518: if ((p = strpbrk(p, ".-")) != NULL)
519: *p++ = '\0';
520: if ((oid = smi_findkey(sp)) != NULL) {
521: bcopy(&oid->o_id, &ko, sizeof(ko));
1.6 tb 522: if (o->bo_n && ober_oid_cmp(o, &ko) != 2)
1.1 martijn 523: return (-1);
524: bcopy(&ko, o, sizeof(*o));
525: errstr = NULL;
526: } else {
527: o->bo_id[o->bo_n++] =
528: strtonum(sp, 0, UINT_MAX, &errstr);
529: }
530: if (errstr || o->bo_n > BER_MAX_OID_LEN)
531: return (-1);
532: }
533:
534: return (0);
535: }
536:
537: unsigned int
538: smi_application(struct ber_element *elm)
539: {
540: if (elm->be_class != BER_CLASS_APPLICATION)
541: return (BER_TYPE_OCTETSTRING);
542:
543: switch (elm->be_type) {
544: case SNMP_T_IPADDR:
545: return (BER_TYPE_OCTETSTRING);
546: case SNMP_T_COUNTER32:
547: case SNMP_T_GAUGE32:
548: case SNMP_T_TIMETICKS:
549: case SNMP_T_OPAQUE:
550: case SNMP_T_COUNTER64:
551: return (BER_TYPE_INTEGER);
552: default:
553: break;
554: }
555: return (BER_TYPE_OCTETSTRING);
556:
557: }
558:
559: char *
560: smi_oid2string(struct ber_oid *o, char *buf, size_t len,
561: enum smi_oid_lookup lookup)
562: {
563: char str[256];
564: struct oid *value, key;
565: size_t i;
566:
567: bzero(buf, len);
568: bzero(&key, sizeof(key));
569: bcopy(o, &key.o_id, sizeof(struct ber_oid));
570:
571: for (i = 0; i < o->bo_n; i++) {
572: key.o_oidlen = i + 1;
573: if (lookup != smi_oidl_numeric &&
574: (value = RB_FIND(oidtree, &smi_oidtree, &key)) != NULL) {
575: snprintf(str, sizeof(str), "%s", value->o_name);
576: if (lookup == smi_oidl_short && i + 1 < o->bo_n) {
577: key.o_oidlen = i + 2;
578: if (RB_FIND(oidtree, &smi_oidtree, &key) != NULL)
579: continue;
580: }
581: } else
1.9 martijn 582: snprintf(str, sizeof(str), "%u", key.o_oid[i]);
1.1 martijn 583: if (*buf != '\0' || i == 0)
584: strlcat(buf, ".", len);
585: strlcat(buf, str, len);
586: }
587:
588: return (buf);
589: }
590:
591: void
592: smi_mibtree(struct oid *oids)
593: {
594: struct oid *oid, *decl;
595: size_t i;
596:
597: for (i = 0; oids[i].o_oid[0] != 0; i++) {
598: oid = &oids[i];
599: if (oid->o_name != NULL) {
600: RB_INSERT(oidtree, &smi_oidtree, oid);
601: RB_INSERT(keytree, &smi_keytree, oid);
602: continue;
603: }
604: decl = RB_FIND(oidtree, &smi_oidtree, oid);
605: }
606: }
607:
1.10 martijn 608: void
609: smi_textconvtree(struct textconv *textconvs)
610: {
611: size_t i = 0;
612:
613: for (i = 0; textconvs[i].tc_name != NULL; i++)
614: RB_INSERT(textconvtree, &smi_tctree, &(textconvs[i]));
615: }
616:
1.1 martijn 617: struct oid *
618: smi_findkey(char *name)
619: {
620: struct oid oid;
621: if (name == NULL)
622: return (NULL);
623: oid.o_name = name;
624: return (RB_FIND(keytree, &smi_keytree, &oid));
625: }
626:
627: struct oid *
1.8 martijn 628: smi_foreach(struct oid *oid)
1.1 martijn 629: {
630: /*
631: * Traverse the tree of MIBs with the option to check
632: * for specific OID flags.
633: */
1.8 martijn 634: if (oid == NULL)
635: return RB_MIN(oidtree, &smi_oidtree);
636: return RB_NEXT(oidtree, &smi_oidtree, oid);
1.1 martijn 637: }
638:
1.10 martijn 639: #define REPLACEMENT "\357\277\275"
640: char *
641: smi_displayhint_os(struct textconv *tc, int print_hint, const char *src,
642: size_t srclen, int utf8)
643: {
644: size_t octetlength, i = 0, j = 0;
1.11 ! martijn 645: size_t prefixlen;
1.10 martijn 646: unsigned long ulval;
647: int clen;
648: char *displayformat;
1.11 ! martijn 649: const char *prefix;
1.10 martijn 650: char *rbuf, *dst;
651: wchar_t wc;
652:
1.11 ! martijn 653: prefix = print_hint ? "STRING: " : "";
! 654: prefixlen = strlen(prefix);
! 655:
1.10 martijn 656: errno = 0;
657: ulval = strtoul(tc->tc_display_hint, &displayformat, 10);
658: octetlength = ulval;
659: if (!isdigit(tc->tc_display_hint[0]) ||
660: (errno != 0 && (ulval == 0 || ulval == ULONG_MAX)) ||
661: (unsigned long) octetlength != ulval) {
662: errno = EINVAL;
663: return NULL;
664: }
665:
1.11 ! martijn 666: if (displayformat[0] == 't' || displayformat[0] == 'a') {
! 667: if ((rbuf = malloc(prefixlen + octetlength + 1)) == NULL)
! 668: return NULL;
! 669: (void)strlcpy(rbuf, prefix, prefixlen + octetlength + 1);
! 670: dst = rbuf + prefixlen;
1.10 martijn 671: while (j < octetlength && i < srclen) {
672: clen = mbtowc(&wc, &(src[i]), srclen - i);
1.11 ! martijn 673: if (displayformat[0] == 'a' && clen > 1)
! 674: clen = -1;
1.10 martijn 675: switch (clen) {
676: case 0:
677: dst[j++] = '.';
678: i++;
679: break;
680: case -1:
681: mbtowc(NULL, NULL, MB_CUR_MAX);
682: if (utf8) {
683: if (octetlength - j <
684: sizeof(REPLACEMENT) - 1) {
685: dst[j] = '\0';
686: return rbuf;
687: }
688: memcpy(&(dst[j]), REPLACEMENT,
689: sizeof(REPLACEMENT) - 1);
690: j += sizeof(REPLACEMENT) - 1;
691: } else
692: dst[j++] = '?';
693: i++;
694: break;
695: default:
696: if (!iswprint(wc) || (!utf8 && clen > 1))
697: dst[j++] = '.';
698: else if (octetlength - j < (size_t)clen) {
699: dst[j] = '\0';
700: return rbuf;
701: } else {
702: memcpy(&(dst[j]), &(src[i]), clen);
703: j += clen;
704: }
705: i += clen;
706: break;
707: }
708: }
709: dst[j] = '\0';
710: return rbuf;
711: }
712: errno = EINVAL;
713: return NULL;
714: }
715:
1.1 martijn 716: int
717: smi_oid_cmp(struct oid *a, struct oid *b)
718: {
719: size_t i;
720:
721: for (i = 0; i < MINIMUM(a->o_oidlen, b->o_oidlen); i++) {
722: if (a->o_oid[i] != b->o_oid[i])
723: return (a->o_oid[i] - b->o_oid[i]);
724: }
725:
726: return (a->o_oidlen - b->o_oidlen);
727: }
728:
729: int
730: smi_key_cmp(struct oid *a, struct oid *b)
731: {
732: if (a->o_name == NULL || b->o_name == NULL)
733: return (-1);
734: return (strcasecmp(a->o_name, b->o_name));
735: }
736:
1.10 martijn 737: int
738: smi_textconv_cmp(struct textconv *a, struct textconv *b)
739: {
740: return strcmp(a->tc_name, b->tc_name);
741: }
742:
1.1 martijn 743: RB_GENERATE(oidtree, oid, o_element, smi_oid_cmp)
744: RB_GENERATE(keytree, oid, o_keyword, smi_key_cmp)
1.10 martijn 745: RB_GENERATE(textconvtree, textconv, tc_entry, smi_textconv_cmp);