1 /*        $NetBSD: attr_print0.c,v 1.3 2022/10/08 16:12:50 christos Exp $       */
2 
3 /*++
4 /* NAME
5 /*        attr_print0 3
6 /* SUMMARY
7 /*        send attributes over byte stream
8 /* SYNOPSIS
9 /*        #include <attr.h>
10 /*
11 /*        int       attr_print0(fp, flags, type, name, ..., ATTR_TYPE_END)
12 /*        VSTREAM   fp;
13 /*        int       flags;
14 /*        int       type;
15 /*        char      *name;
16 /*
17 /*        int       attr_vprint0(fp, flags, ap)
18 /*        VSTREAM   fp;
19 /*        int       flags;
20 /*        va_list   ap;
21 /* DESCRIPTION
22 /*        attr_print0() takes zero or more (name, value) simple attributes
23 /*        and converts its input to a byte stream that can be recovered with
24 /*        attr_scan0(). The stream is not flushed.
25 /*
26 /*        attr_vprint0() provides an alternate interface that is convenient
27 /*        for calling from within variadic functions.
28 /*
29 /*        Attributes are sent in the requested order as specified with the
30 /*        attr_print0() argument list. This routine satisfies the formatting
31 /*        rules as outlined in attr_scan0(3).
32 /*
33 /*        Arguments:
34 /* .IP fp
35 /*        Stream to write the result to.
36 /* .IP flags
37 /*        The bit-wise OR of zero or more of the following.
38 /* .RS
39 /* .IP ATTR_FLAG_MORE
40 /*        After sending the requested attributes, leave the output stream in
41 /*        a state that is usable for more attribute sending operations on
42 /*        the same output attribute list.
43 /*        By default, attr_print0() automatically appends an attribute list
44 /*        terminator when it has sent the last requested attribute.
45 /* .RE
46 /* .IP List of attributes followed by terminator:
47 /* .RS
48 /* .IP "SEND_ATTR_INT(const char *name, int value)"
49 /*        The arguments are an attribute name and an integer.
50 /* .IP "SEND_ATTR_LONG(const char *name, long value)"
51 /*        The arguments are an attribute name and a long integer.
52 /* .IP "SEND_ATTR_STR(const char *name, const char *value)"
53 /*        The arguments are an attribute name and a null-terminated
54 /*        string.
55 /* .IP "SEND_ATTR_DATA(const char *name, ssize_t len, const void *value)"
56 /*        The arguments are an attribute name, an attribute value
57 /*        length, and an attribute value pointer.
58 /* .IP "SEND_ATTR_FUNC(ATTR_PRINT_CUSTOM_FN, const void *value)"
59 /*        The arguments are a function pointer and generic data
60 /*        pointer. The caller-specified function returns whatever the
61 /*        specified attribute printing function returns.
62 /* .IP "SEND_ATTR_HASH(const HTABLE *table)"
63 /* .IP "SEND_ATTR_NAMEVAL(const NVTABLE *table)"
64 /*        The content of the table is sent as a sequence of string-valued
65 /*        attributes with names equal to the table lookup keys.
66 /* .IP ATTR_TYPE_END
67 /*        This terminates the attribute list.
68 /* .RE
69 /* DIAGNOSTICS
70 /*        The result value is 0 in case of success, VSTREAM_EOF in case
71 /*        of trouble.
72 /*
73 /*        Panic: interface violation. All system call errors are fatal.
74 /* SEE ALSO
75 /*        attr_scan0(3) recover attributes from byte stream
76 /* LICENSE
77 /* .ad
78 /* .fi
79 /*        The Secure Mailer license must be distributed with this software.
80 /* AUTHOR(S)
81 /*        Wietse Venema
82 /*        IBM T.J. Watson Research
83 /*        P.O. Box 704
84 /*        Yorktown Heights, NY 10598, USA
85 /*
86 /*        Wietse Venema
87 /*        Google, Inc.
88 /*        111 8th Avenue
89 /*        New York, NY 10011, USA
90 /*--*/
91 
92 /* System library. */
93 
94 #include <sys_defs.h>
95 #include <stdarg.h>
96 #include <string.h>
97 
98 /* Utility library. */
99 
100 #include <msg.h>
101 #include <mymalloc.h>
102 #include <vstream.h>
103 #include <htable.h>
104 #include <attr.h>
105 #include <base64_code.h>
106 
107 #define STR(x) vstring_str(x)
108 #define LEN(x) VSTRING_LEN(x)
109 
110 /* attr_vprint0 - send attribute list to stream */
111 
attr_vprint0(VSTREAM * fp,int flags,va_list ap)112 int     attr_vprint0(VSTREAM *fp, int flags, va_list ap)
113 {
114     const char *myname = "attr_print0";
115     int     attr_type;
116     char   *attr_name;
117     unsigned int_val;
118     unsigned long long_val;
119     char   *str_val;
120     HTABLE_INFO **ht_info_list;
121     HTABLE_INFO **ht;
122     ssize_t len_val;
123     static VSTRING *base64_buf;
124     ATTR_PRINT_CUSTOM_FN print_fn;
125     void   *print_arg;
126 
127     /*
128      * Sanity check.
129      */
130     if (flags & ~ATTR_FLAG_ALL)
131           msg_panic("%s: bad flags: 0x%x", myname, flags);
132 
133     /*
134      * Iterate over all (type, name, value) triples, and produce output on
135      * the fly.
136      */
137     while ((attr_type = va_arg(ap, int)) != ATTR_TYPE_END) {
138           switch (attr_type) {
139           case ATTR_TYPE_INT:
140               attr_name = va_arg(ap, char *);
141               vstream_fwrite(fp, attr_name, strlen(attr_name) + 1);
142               int_val = va_arg(ap, int);
143               vstream_fprintf(fp, "%u", (unsigned) int_val);
144               VSTREAM_PUTC('\0', fp);
145               if (msg_verbose)
146                     msg_info("send attr %s = %u", attr_name, int_val);
147               break;
148           case ATTR_TYPE_LONG:
149               attr_name = va_arg(ap, char *);
150               vstream_fwrite(fp, attr_name, strlen(attr_name) + 1);
151               long_val = va_arg(ap, unsigned long);
152               vstream_fprintf(fp, "%lu", (unsigned long) long_val);
153               VSTREAM_PUTC('\0', fp);
154               if (msg_verbose)
155                     msg_info("send attr %s = %lu", attr_name, long_val);
156               break;
157           case ATTR_TYPE_STR:
158               attr_name = va_arg(ap, char *);
159               vstream_fwrite(fp, attr_name, strlen(attr_name) + 1);
160               str_val = va_arg(ap, char *);
161               vstream_fwrite(fp, str_val, strlen(str_val) + 1);
162               if (msg_verbose)
163                     msg_info("send attr %s = %s", attr_name, str_val);
164               break;
165           case ATTR_TYPE_DATA:
166               attr_name = va_arg(ap, char *);
167               vstream_fwrite(fp, attr_name, strlen(attr_name) + 1);
168               len_val = va_arg(ap, ssize_t);
169               str_val = va_arg(ap, char *);
170               if (base64_buf == 0)
171                     base64_buf = vstring_alloc(10);
172               base64_encode(base64_buf, str_val, len_val);
173               vstream_fwrite(fp, STR(base64_buf), LEN(base64_buf) + 1);
174               if (msg_verbose)
175                     msg_info("send attr %s = [data %ld bytes]",
176                                attr_name, (long) len_val);
177               break;
178           case ATTR_TYPE_FUNC:
179               print_fn = va_arg(ap, ATTR_PRINT_CUSTOM_FN);
180               print_arg = va_arg(ap, void *);
181               print_fn(attr_print0, fp, flags | ATTR_FLAG_MORE, print_arg);
182               break;
183           case ATTR_TYPE_HASH:
184               vstream_fwrite(fp, ATTR_NAME_OPEN, sizeof(ATTR_NAME_OPEN));
185               ht_info_list = htable_list(va_arg(ap, HTABLE *));
186               for (ht = ht_info_list; *ht; ht++) {
187                     vstream_fwrite(fp, ht[0]->key, strlen(ht[0]->key) + 1);
188                     vstream_fwrite(fp, ht[0]->value, strlen(ht[0]->value) + 1);
189                     if (msg_verbose)
190                         msg_info("send attr name %s value %s",
191                                    ht[0]->key, (char *) ht[0]->value);
192               }
193               myfree((void *) ht_info_list);
194               vstream_fwrite(fp, ATTR_NAME_CLOSE, sizeof(ATTR_NAME_CLOSE));
195               break;
196           default:
197               msg_panic("%s: unknown type code: %d", myname, attr_type);
198           }
199     }
200     if ((flags & ATTR_FLAG_MORE) == 0)
201           VSTREAM_PUTC('\0', fp);
202     return (vstream_ferror(fp));
203 }
204 
attr_print0(VSTREAM * fp,int flags,...)205 int     attr_print0(VSTREAM *fp, int flags,...)
206 {
207     va_list ap;
208     int     ret;
209 
210     va_start(ap, flags);
211     ret = attr_vprint0(fp, flags, ap);
212     va_end(ap);
213     return (ret);
214 }
215 
216 #ifdef TEST
217 
218  /*
219   * Proof of concept test program.  Mirror image of the attr_scan0 test
220   * program.
221   */
222 #include <msg_vstream.h>
223 
main(int unused_argc,char ** argv)224 int     main(int unused_argc, char **argv)
225 {
226     HTABLE *table = htable_create(1);
227 
228     msg_vstream_init(argv[0], VSTREAM_ERR);
229     msg_verbose = 1;
230     htable_enter(table, "foo-name", mystrdup("foo-value"));
231     htable_enter(table, "bar-name", mystrdup("bar-value"));
232     attr_print0(VSTREAM_OUT, ATTR_FLAG_NONE,
233                     SEND_ATTR_STR("protocol", "test"),
234                     SEND_ATTR_INT(ATTR_NAME_INT, 4711),
235                     SEND_ATTR_LONG(ATTR_NAME_LONG, 1234L),
236                     SEND_ATTR_STR(ATTR_NAME_STR, "whoopee"),
237                     SEND_ATTR_DATA(ATTR_NAME_DATA, strlen("whoopee"), "whoopee"),
238                     SEND_ATTR_HASH(table),
239                     SEND_ATTR_LONG(ATTR_NAME_LONG, 4321L),
240                     ATTR_TYPE_END);
241     attr_print0(VSTREAM_OUT, ATTR_FLAG_NONE,
242                     SEND_ATTR_STR("protocol", "test"),
243                     SEND_ATTR_INT(ATTR_NAME_INT, 4711),
244                     SEND_ATTR_LONG(ATTR_NAME_LONG, 1234L),
245                     SEND_ATTR_STR(ATTR_NAME_STR, "whoopee"),
246                     SEND_ATTR_DATA(ATTR_NAME_DATA, strlen("whoopee"), "whoopee"),
247                     ATTR_TYPE_END);
248     attr_print0(VSTREAM_OUT, ATTR_FLAG_NONE,
249                     SEND_ATTR_STR("protocol", "not-test"),
250                     ATTR_TYPE_END);
251     if (vstream_fflush(VSTREAM_OUT) != 0)
252           msg_fatal("write error: %m");
253 
254     htable_free(table, myfree);
255     return (0);
256 }
257 
258 #endif
259