File: lswlog.h

package info (click to toggle)
libreswan 5.2-2.2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 81,632 kB
  • sloc: ansic: 129,988; sh: 32,018; xml: 20,646; python: 10,303; makefile: 3,022; javascript: 1,506; sed: 574; yacc: 511; perl: 264; awk: 52
file content (453 lines) | stat: -rw-r--r-- 14,726 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
/* logging declarations
 *
 * Copyright (C) 1998-2001,2013 D. Hugh Redelmeier <hugh@mimosa.com>
 * Copyright (C) 2004 Michael Richardson <mcr@xelerance.com>
 * Copyright (C) 2012-2013 Paul Wouters <paul@libreswan.org>
 * Copyright (C) 2017-2019 Andrew Cagney <cagney@gnu.org>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.  See <https://www.gnu.org/licenses/gpl2.txt>.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 */

#ifndef _LSWLOG_H_
#define _LSWLOG_H_

#include <stdarg.h>
#include <stdio.h>		/* for FILE */
#include <stddef.h>		/* for size_t */

#include "lset.h"
#include "lswcdefs.h"
#include "jambuf.h"
#include "passert.h"
#include "constants.h"		/* for DBG_... */
#include "where.h"		/* used by macros */
#include "fd.h"			/* for null_fd */
#include "impair.h"
#include "pexpect.h"
#include "fatal.h"

/*
 * Codes for status messages returned to whack.
 *
 * These are 3 digit decimal numerals.  The structure is inspired by
 * section 4.2 of RFC959 (FTP).  Since these will end up as the exit
 * status of whack, they must be less than 256.
 *
 * NOTE: ipsec_auto(8) knows about some of these numbers -- change
 * carefully.
 */

enum rc_type {

	RC_LOG = 2,			/* message aimed at log (does
					 * not affect exit status) */

	RC_SUCCESS = 4,			/* success (exit status 0) */

	/* entry of secrets */
	RC_ENTERSECRET = 10,
	RC_USERPROMPT = 11,

	RC_EXIT_FLOOR = 20,

	/* improper request */
	RC_DUPNAME = 20,	/* attempt to reuse a connection name */
	RC_UNKNOWN_NAME = 21,	/* connection name unknown or state number */
	RC_ORIENT = 22,		/* cannot orient connection: neither end is us */
	RC_CLASH = 23,		/* clash between two Road Warrior connections OVERLOADED */
	RC_DEAF = 24,		/* need --listen before --initiate */
	RC_ROUTE = 25,		/* cannot route */
	RC_RTBUSY = 26,		/* cannot unroute: route busy */
	RC_BADID = 27,		/* malformed --id */
	RC_NOKEY = 28,		/* no key found through DNS */
	RC_NOPEERIP = 29,	/* cannot initiate when peer IP is unknown */
	RC_INITSHUNT = 30,	/* cannot initiate a shunt-oly connection */
	RC_WILDCARD = 31,	/* cannot initiate when ID has wildcards */
	RC_CRLERROR = 32,	/* CRL fetching disabled or obsolete reread cmd */
	RC_WHACK_PROBLEM = 33,	/* whack-detected problem */

	/* permanent failure */
	RC_BADWHACKMESSAGE = 50,
	RC_NORETRANSMISSION = 51,
	RC_INTERNAL_ERROR = 52,
	RC_OPPOFAILURE = 53,	/* Opportunism failed */
	RC_CRYPTOFAILED = 54,	/* system too busy to perform required
				 * cryptographic operations */
	RC_AGGRALGO = 55,	/* multiple algorithms requested in
				 * phase 1 aggressive */
	RC_FATAL = 56,		/* fatal error encountered, and
				 * negotiation aborted */

	RC_EXIT_ROOF = 100,
};


/*
 * A generic buffer for accumulating unbounded output.
 *
 * The buffer's contents can be directed to various logging streams.
 */

struct jambuf;

/*
 * By default messages are broadcast (to both log files and whack),
 * mix-in one of these options to limit this.
 *
 * This means that a simple RC_* code will go to both whack and and
 * the log files.
 */

#define RC_MASK              0x00fffff	/* rc_type max is 64435+200 */
#define STREAM_MASK          0x0f00000
#define LOG_PREFIX_MASK	     0xf000000

enum log_prefix {
	AUTO_PREFIX =        0x0000000,
	NO_PREFIX =          0x1000000,
        ADD_PREFIX =         0x2000000,
};

enum stream {
	/*                                 syslog()                      */
	/*                                Severity  Whack  Tools  Prefix */
	ALL_STREAMS        = 0x0000000, /* WARNING   yes    err?   <o>   */
	LOG_STREAM         = 0x0100000, /* WARNING    no    err?   <o>   */
	WHACK_STREAM       = 0x0200000, /*   N/A     yes    err    <o>   */
	DEBUG_STREAM       = 0x0300000, /*  DEBUG     no    err    | <o> */
	ERROR_STREAM       = 0x0400000, /*   ERR     yes    err    <o>   */
	PEXPECT_STREAM     = 0x0500000, /*   ERR     yes    err    EXPECTATION FAILED: <o> */
	PASSERT_STREAM     = 0x0600000, /*   ERR     yes    err    ABORT: ASSERTION_FAILED: <o> */
	FATAL_STREAM       = 0x0700000, /*   ERR     yes    err    FATAL ERROR: <o> */
	NO_STREAM          = 0x0f00000, /*   N/A     N/A                 */
	/*
	 * <o>: add prefix when object is available
	 *
	 * | <o>: add both "| " and prefix when object is available and
         * feature is enabled
	 *
	 * err?: write to stderr when enabled (tests log_to_stderr,
	 * typically via -v).  Used by tools such as whack.
	 */
};

/*
 * Broadcast a log message.
 *
 * By default send it to the log file and any attached whacks (both
 * globally and the object).
 *
 * If any *_STREAM flag is specified then only send the message to
 * that stream.
 *
 * llog() is a catch-all for code that may or may not have ST.
 * For instance a responder decoding a message may not yet have
 * created the state.  It will will use ST, MD, or nothing as the
 * prefix, and logs to ST's whackfd when possible.
 */

struct logger_object_vec {
	const char *name;
	bool free_object;
	size_t (*jam_object_prefix)(struct jambuf *buf, const void *object);
};

/* these omit ": " always */
typedef struct {
	char buf[100];/* completely made up size */
} prefix_buf;
const char *str_prefix(const struct logger *logger, prefix_buf *buf);
size_t jam_prefix(struct jambuf *buf, const struct logger *logger);

/* these include ": " when jam_prefix() is non-empty */
size_t jam_logger_prefix(struct jambuf *buf, const struct logger *logger);
void jam_logger_rc_prefix(struct jambuf *buf, const struct logger *logger, lset_t rc_flags);

size_t jam_object_prefix_none(struct jambuf *buf, const void *object);

#ifndef GLOBAL_LOGGER
extern struct logger global_logger;
#define GLOBAL_LOGGER &global_logger
#endif

struct logger {
	/* support up to two whacks */
	struct fd *whackfd[2];
	const void *object;
	const struct logger_object_vec *object_vec;
	where_t where;
	/* used by timing to nest its logging output */
	int timing_level;
	lset_t debugging;
};

#define PRI_LOGGER "logger@%p/"PRI_FD"/"PRI_FD
#define pri_logger(LOGGER)						\
	(LOGGER),							\
		pri_fd((LOGGER) == NULL ? NULL : (LOGGER)->whackfd[0]), \
		pri_fd((LOGGER) == NULL ? NULL : (LOGGER)->whackfd[1])

void llog(lset_t rc_flags,
	  const struct logger *log,
	  const char *format, ...) PRINTF_LIKE(3);

void llog_va_list(lset_t rc_flags, const struct logger *logger,
		  const char *message, va_list ap) VPRINTF_LIKE(3);

void jambuf_to_logger(struct jambuf *buf, const struct logger *logger, lset_t rc_flags);

#define LLOG_JAMBUF(RC_FLAGS, LOGGER, BUF)				\
	/* create the buffer */						\
	for (struct logjam logjam_, *lbp_ = &logjam_;			\
	     lbp_ != NULL; lbp_ = NULL)					\
		/* create the jambuf */					\
		for (struct jambuf *BUF =				\
			     jambuf_from_logjam(&logjam_, LOGGER,	\
						0, NULL, RC_FLAGS);	\
		     BUF != NULL;					\
		     logjam_to_logger(&logjam_), BUF = NULL)

void llog_dump(lset_t rc_flags,
	       const struct logger *log,
	       const void *p, size_t len);
#define llog_dump_hunk(RC_FLAGS, LOGGER, HUNK)				\
	{								\
		const typeof(HUNK) *hunk_ = &(HUNK); /* evaluate once */ \
		llog_dump(RC_FLAGS, LOGGER, hunk_->ptr, hunk_->len);	\
	}

void llog_base64_bytes(lset_t rc_flags,
		       const struct logger *log,
		       const void *p, size_t len);
#define llog_base64_hunk(RC_FLAGS, LOGGER, HUNK)			\
	{								\
		const typeof(HUNK) *hunk_ = &(HUNK); /* evaluate once */ \
		llog_base64_bytes(RC_FLAGS, LOGGER, hunk_->ptr, hunk_->len); \
	}

void llog_pem_bytes(lset_t rc_flags,
		    const struct logger *log,
		    const char *name,
		    const void *p, size_t len);
#define llog_pem_hunk(RC_FLAGS, LOGGER, NAME, HUNK)			\
	{								\
		const typeof(HUNK) *hunk_ = &(HUNK); /* evaluate once */ \
		llog_pem_bytes(RC_FLAGS, LOGGER, NAME, hunk_->ptr, hunk_->len); \
	}

/*
 * Wrap <message> in a prefix and suffix where the suffix contains
 * errno and message.
 *
 * Notes:
 *
 * Because __VA_ARGS__ may contain function calls that modify ERRNO,
 * errno's value is first saved.
 *
 * While these common-case macros are implemented as wrapper functions
 * so that backtrace will include the below function call and that
 * _includes_ the MESSAGE parameter - makes debugging much easier.
 */

void libreswan_exit(enum pluto_exit_code rc) NEVER_RETURNS;

/*
 * XXX: The message format is:
 *   ERROR: <log-prefix><message...>[: <strerr> (errno)]
 * and not:
 *   <log-prefix>ERROR: <message...>...
 */

void log_error(const struct logger *logger, int error,
	       const char *message, ...) PRINTF_LIKE(3);

#define llog_error(LOGGER, ERRNO, FMT, ...)				\
	{								\
		int e_ = ERRNO; /* save value across va args */		\
		log_error(LOGGER, e_, FMT, ##__VA_ARGS__); \
	}

/* like log_error() but no ERROR: prefix and/or ": " separator */
void llog_errno(lset_t rc_flags, const struct logger *logger, int error,
		const char *message, ...) PRINTF_LIKE(4);

/*
 * Log debug messages to the main log stream, but not the WHACK log
 * stream.
 *
 * NOTE: DBG's action can be a { } block, but that block must not
 * contain commas that are outside quotes or parenthesis.
 * If it does, they will be interpreted by the C preprocessor
 * as macro argument separators.  This happens accidentally if
 * multiple variables are declared in one declaration.
 *
 * Naming: All DBG_*() prefixed functions send stuff to the debug
 * stream unconditionally.  Hence they should be wrapped in DBGP().
 */

extern lset_t cur_debugging;	/* current debugging level */

#define DBGP(cond)	(cur_debugging & (cond))
#define LDBGP(COND, LOGGER) (COND & (cur_debugging | (LOGGER)->debugging))

#define dbg(MESSAGE, ...)					\
	{							\
		if (DBGP(DBG_BASE)) {				\
			DBG_log(MESSAGE, ##__VA_ARGS__);	\
		}						\
	}

void ldbg(const struct logger *logger, const char *message, ...) PRINTF_LIKE(2);
void pdbg(const struct logger *logger, const char *message, ...) PRINTF_LIKE(2);

void ldbgf(lset_t cond, const struct logger *logger, const char *fmt, ...) PRINTF_LIKE(3);
void pdbgf(lset_t cond, const struct logger *logger, const char *fmt, ...) PRINTF_LIKE(3);

/* LDBG_JAMBUF() is ambiguous - LDBG_op() or ldbg() ucase? */

#define LDBGP_JAMBUF(COND, LOGGER, BUF)					\
	for (bool cond_ = LDBGP(COND, LOGGER); cond_; cond_ = false)	\
		LLOG_JAMBUF(DEBUG_STREAM, LOGGER, BUF)
#define PDBGP_JAMBUF(COND, LOGGER, BUF)					\
	for (bool cond_ = LDBGP(COND, LOGGER); cond_; cond_ = false)	\
		LLOG_JAMBUF(DEBUG_STREAM|ADD_PREFIX, LOGGER, BUF)


/* DBG_*() are unconditional */
void DBG_log(const char *message, ...) PRINTF_LIKE(1);
void DBG_dump(const char *label, const void *p, size_t len);
#define DBG_dump_hunk(LABEL, HUNK)					\
	{								\
		const typeof(HUNK) *hunk_ = &(HUNK); /* evaluate once */ \
		DBG_dump(LABEL, hunk_->ptr, hunk_->len);		\
	}
#define DBG_dump_thing(LABEL, THING) DBG_dump(LABEL, &(THING), sizeof(THING))

/*
 * XXX: unlike dbg_dump() et.al., these don't take a prefix; instead
 * caller should log that separately.
 */
#define LDBG_dump(LOGGER, DATA, LEN)				\
	{							\
		llog_dump(DEBUG_STREAM, LOGGER, DATA, LEN);	\
	}
#define LDBG_hunk(LOGGER, HUNK)						\
	{								\
		const typeof(HUNK) *hunk_ = &(HUNK); /* evaluate once */ \
		llog_dump(DEBUG_STREAM, LOGGER, hunk_->ptr, hunk_->len); \
	}
#define LDBG_thing(LOGGER, THING)					\
	{								\
		llog_dump(DEBUG_STREAM, LOGGER, &(THING), sizeof(THING)); \
	}
#define ldbg_dump(LOGGER, DATA, LEN)			\
	{						\
		if (DBGP(DBG_BASE)) {			\
			LDBG_dump(LOGGER, DATA, LEN);	\
		}					\
	}
#define ldbg_hunk(LOGGER, HUNK)					\
	{							\
		if (DBGP(DBG_BASE)) {				\
			LDBG_hunk(LOGGER, HUNK);		\
		}						\
	}
#define ldbg_thing(LOGGER, THING)			\
	{						\
		if (DBGP(DBG_BASE)) {			\
			LDBG_thing(LOGGER, THING);	\
		}					\
	}

/* LDBG_*(logger, ...) are unconditional wrappers */
#define LDBG_log(LOGGER, FMT, ...) llog(DEBUG_STREAM, LOGGER, FMT, ##__VA_ARGS__)
#define LDBG_va_list(LOGGER, FMT, AP) llog_va_list(DEBUG_STREAM, LOGGER, FMT, AP)

/*
 * Code wrappers that cover up the details of allocating,
 * initializing, de-allocating (and possibly logging) a 'struct
 * lswlog' buffer.
 *
 * BUF (a C variable name) is declared locally as a pointer to a
 * per-thread 'struct jambuf' buffer.
 *
 * Implementation notes:
 *
 * This implementation stores the output in an array on the thread's
 * stack.  It could just as easily use the heap (but that would
 * involve memory overheads) or even a per-thread static variable.
 * Since the BUF variable is a pointer the specifics of the
 * implementation are hidden.
 *
 * This implementation, unlike DBG(), does not have a code block
 * parameter.  Instead it uses a sequence of for-loops to set things
 * up for a code block.  This avoids problems with "," within macro
 * parameters confusing the parser.  It also permits a simple
 * consistent indentation style.
 *
 * The stack array is left largely uninitialized (just a few strategic
 * entries are set).  This avoids the need to zero LOG_WITH bytes.
 *
 * Apparently chaining void function calls using a comma is valid C?
 */

/*
 * Scratch buffer for accumulating extra output.
 *
 * XXX: case should be expanded to illustrate how to stuff a truncated
 * version of the output into the LOG buffer.
 *
 * For instance:
 */

#if 0
void lswbuf(struct jambuf *log)
{
	LSWBUF(buf) {
		jam(buf, "written to buf");
		lswlogl(log, buf); /* add to calling array */
	}
}
#endif

/*
 * For a switch statements
 */

void bad_case_where(const char *expression, long value, where_t where) NEVER_RETURNS;
#define bad_case(N) bad_case_where(#N, (N), HERE)

void bad_enum_where(const struct logger *logger,
		    const struct enum_names *en,
		    unsigned long val, where_t where) NEVER_RETURNS;
#define bad_enum(LOGGER, ENUM_NAMES, VALUE) bad_enum_where(LOGGER, ENUM_NAMES, VALUE, HERE)

void bad_sparse_where(const struct logger *logger,
		      const struct sparse_names *sn,
		      unsigned long val, where_t where) NEVER_RETURNS;
#define bad_sparse(LOGGER, SPARSE_NAMES, VALUE) bad_sparse_where(LOGGER, SPARSE_NAMES, VALUE, HERE)

#define impaired_passert(BEHAVIOUR, LOGGER, ASSERTION)			\
	{								\
		if (impair.BEHAVIOUR) {					\
			bool assertion_ = ASSERTION;			\
			if (!assertion_) {				\
				llog(RC_LOG, LOGGER,		\
					    "IMPAIR: assertion '%s' failed", \
					    #ASSERTION);		\
			}						\
		} else {						\
			passert(ASSERTION);				\
		}							\
	}

#endif /* _LSWLOG_H_ */