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