GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/rdistd/../rdist/message.c Lines: 0 211 0.0 %
Date: 2017-11-07 Branches: 0 192 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: message.c,v 1.28 2016/03/30 20:51:59 millert Exp $	*/
2
3
/*
4
 * Copyright (c) 1983 Regents of the University of California.
5
 * All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 * 3. Neither the name of the University nor the names of its contributors
16
 *    may be used to endorse or promote products derived from this software
17
 *    without specific prior written permission.
18
 *
19
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
 * SUCH DAMAGE.
30
 */
31
32
#include <errno.h>
33
#include <limits.h>
34
#include <paths.h>
35
#include <stdarg.h>
36
#include <stdio.h>
37
#include <stdlib.h>
38
#include <string.h>
39
#include <syslog.h>
40
#include <unistd.h>
41
42
#include "defs.h"
43
44
/*
45
 * Message handling functions for both rdist and rdistd.
46
 */
47
48
49
#define MSGBUFSIZ	32*1024
50
51
int			debug = 0;		/* Debugging level */
52
int			nerrs = 0;		/* Number of errors */
53
54
/*
55
 * Message Types
56
 */
57
struct msgtype {
58
	int		mt_type;		/* Type (bit) */
59
	char	       *mt_name;		/* Name of message type */
60
} msgtypes[] = {
61
	{ MT_CHANGE,	"change" },
62
	{ MT_INFO,	"info" },
63
	{ MT_NOTICE,	"notice" },
64
	{ MT_NERROR,	"nerror" },
65
	{ MT_FERROR,	"ferror" },
66
	{ MT_WARNING,	"warning" },
67
	{ MT_VERBOSE,	"verbose" },
68
	{ MT_ALL,	"all" },
69
	{ MT_DEBUG,	"debug" },
70
	{ 0 },
71
};
72
73
/*
74
 * Description of message facilities
75
 */
76
struct msgfacility {
77
	/* compile time initialized data */
78
	int		mf_msgfac;		/* One of MF_* from below */
79
	char	       *mf_name;		/* Name of this facility */
80
	void	      (*mf_sendfunc)		/* Function to send msg */
81
			(struct msgfacility *, int, int, char *);
82
	/* run time initialized data */
83
	int		mf_msgtypes;		/* Bitmask of MT_* from above*/
84
	char	       *mf_filename;		/* Name of file */
85
	FILE	       *mf_fptr;		/* File pointer to output to */
86
};
87
88
/*
89
 * Message Facilities
90
 */
91
#define MF_STDOUT	1			/* Standard Output */
92
#define MF_NOTIFY	2			/* Notify mail service */
93
#define MF_FILE		3			/* A normal file */
94
#define MF_SYSLOG	4			/* syslog() */
95
96
static void msgsendstdout(struct msgfacility *, int, int, char *);
97
static void msgsendsyslog(struct msgfacility *, int, int, char *);
98
static void msgsendfile(struct msgfacility *, int, int, char *);
99
static void msgsendnotify(struct msgfacility *, int, int, char *);
100
101
/*
102
 * Message Facilities
103
 */
104
struct msgfacility msgfacility[] = {
105
	{ MF_STDOUT,	"stdout",	msgsendstdout },
106
	{ MF_FILE,	"file",		msgsendfile },
107
	{ MF_SYSLOG,	"syslog",	msgsendsyslog },
108
	{ MF_NOTIFY,	"notify",	msgsendnotify },
109
	{ 0 },
110
};
111
112
static struct msgfacility *getmsgfac(char *);
113
static struct msgtype *getmsgtype(char *);
114
static char *setmsgtypes(struct msgfacility *, char *);
115
static void _message(int, char *);
116
static void _debugmsg(int, char *);
117
static void _error(const char *);
118
static void _fatalerr(const char *);
119
120
/*
121
 * Print message logging usage message
122
 */
123
void
124
msgprusage(void)
125
{
126
	int i, x;
127
128
	(void) fprintf(stderr, "\nWhere <msgopt> is of form\n");
129
	(void) fprintf(stderr,
130
       "\t<facility1>=<type1>,<type2>,...:<facility2>=<type1>,<type2>...\n");
131
132
	(void) fprintf(stderr, "Valid <facility> names:");
133
134
	for (i = 0; msgfacility[i].mf_name; ++i)
135
		(void) fprintf(stderr, " %s", msgfacility[i].mf_name);
136
137
	(void) fprintf(stderr, "\nValid <type> names:");
138
	for (x = 0; msgtypes[x].mt_name; ++x)
139
		(void) fprintf(stderr, " %s", msgtypes[x].mt_name);
140
141
	(void) fprintf(stderr, "\n");
142
}
143
144
/*
145
 * Print enabled message logging info
146
 */
147
void
148
msgprconfig(void)
149
{
150
	int i, x;
151
	static char buf[MSGBUFSIZ];
152
153
	debugmsg(DM_MISC, "Current message logging config:");
154
	for (i = 0; msgfacility[i].mf_name; ++i) {
155
		(void) snprintf(buf, sizeof(buf), "    %.*s=",
156
			       (int)(sizeof(buf) - 7), msgfacility[i].mf_name);
157
		for (x = 0; msgtypes[x].mt_name; ++x)
158
			if (IS_ON(msgfacility[i].mf_msgtypes,
159
				  msgtypes[x].mt_type)) {
160
				if (x > 0)
161
					(void) strlcat(buf, ",", sizeof(buf));
162
				(void) strlcat(buf, msgtypes[x].mt_name,
163
				    sizeof(buf));
164
			}
165
		debugmsg(DM_MISC, "%s", buf);
166
	}
167
168
}
169
170
/*
171
 * Get the Message Facility entry "name"
172
 */
173
static struct msgfacility *
174
getmsgfac(char *name)
175
{
176
	int i;
177
178
	for (i = 0; msgfacility[i].mf_name; ++i)
179
		if (strcasecmp(name, msgfacility[i].mf_name) == 0)
180
			return(&msgfacility[i]);
181
182
	return(NULL);
183
}
184
185
/*
186
 * Get the Message Type entry named "name"
187
 */
188
static struct msgtype *
189
getmsgtype(char *name)
190
{
191
	int i;
192
193
	for (i = 0; msgtypes[i].mt_name; ++i)
194
		if (strcasecmp(name, msgtypes[i].mt_name) == 0)
195
			return(&msgtypes[i]);
196
197
	return(NULL);
198
}
199
200
/*
201
 * Set Message Type information for Message Facility "msgfac" as
202
 * indicated by string "str".
203
 */
204
static char *
205
setmsgtypes(struct msgfacility *msgfac, char *str)
206
{
207
	static char ebuf[BUFSIZ];
208
	char *cp;
209
	char *strptr, *word;
210
	struct msgtype *mtp;
211
212
	/*
213
	 * MF_SYSLOG is the only supported message facility for the server
214
	 */
215
	if (isserver && (msgfac->mf_msgfac != MF_SYSLOG &&
216
			 msgfac->mf_msgfac != MF_FILE)) {
217
		(void) snprintf(ebuf, sizeof(ebuf),
218
		"The \"%.*s\" message facility cannot be used by the server.",
219
			        100, msgfac->mf_name);
220
		return(ebuf);
221
	}
222
223
	strptr = str;
224
225
	/*
226
	 * Do any necessary Message Facility preparation
227
	 */
228
	switch(msgfac->mf_msgfac) {
229
	case MF_FILE:
230
		/*
231
		 * The MF_FILE string should look like "<file>=<types>".
232
		 */
233
		if ((cp = strchr(strptr, '=')) == NULL)
234
			return(
235
			   "No file name found for \"file\" message facility");
236
		*cp++ = CNULL;
237
238
		if ((msgfac->mf_fptr = fopen(strptr, "w")) == NULL)
239
			fatalerr("Cannot open log file for writing: %s: %s.",
240
				 strptr, SYSERR);
241
		msgfac->mf_filename = xstrdup(strptr);
242
243
		strptr = cp;
244
		break;
245
246
	case MF_NOTIFY:
247
		break;
248
249
	case MF_STDOUT:
250
		msgfac->mf_fptr = stdout;
251
		break;
252
253
	case MF_SYSLOG:
254
		openlog(progname, LOG_PID, LOG_DAEMON);
255
		break;
256
	}
257
258
	/*
259
	 * Parse each type word
260
	 */
261
	msgfac->mf_msgtypes = 0;	/* Start from scratch */
262
	while (strptr) {
263
		word = strptr;
264
		if ((cp = strchr(strptr, ',')) != NULL)
265
			*cp++ = CNULL;
266
		strptr = cp;
267
268
		if ((mtp = getmsgtype(word)) != NULL) {
269
			msgfac->mf_msgtypes |= mtp->mt_type;
270
			/*
271
			 * XXX This is really a kludge until we add real
272
			 * control over debugging.
273
			 */
274
			if (!debug && isserver &&
275
			    strcasecmp(word, "debug") == 0)
276
				debug = DM_ALL;
277
		} else {
278
			(void) snprintf(ebuf, sizeof(ebuf),
279
				        "Message type \"%.*s\" is invalid.",
280
				        100, word);
281
			return(ebuf);
282
		}
283
	}
284
285
	return(NULL);
286
}
287
288
/*
289
 * Parse a message logging option string
290
 */
291
char *
292
msgparseopts(char *msgstr, int doset)
293
{
294
	static char ebuf[BUFSIZ], msgbuf[MSGBUFSIZ];
295
	char *cp, *optstr;
296
	char *word;
297
	struct msgfacility *msgfac;
298
299
	if (msgstr == NULL)
300
		return("NULL message string");
301
302
	/* strtok() is harmful */
303
	(void) strlcpy(msgbuf, msgstr, sizeof(msgbuf));
304
305
	/*
306
	 * Each <facility>=<types> list is separated by ":".
307
	 */
308
	for (optstr = strtok(msgbuf, ":"); optstr;
309
	     optstr = strtok(NULL, ":")) {
310
311
		if ((cp = strchr(optstr, '=')) == NULL)
312
			return("No '=' found");
313
314
		*cp++ = CNULL;
315
		word = optstr;
316
		if ((int)strlen(word) <= 0)
317
			return("No message facility specified");
318
		if ((int)strlen(cp) <= 0)
319
			return("No message type specified");
320
321
		if ((msgfac = getmsgfac(word)) == NULL) {
322
			(void) snprintf(ebuf, sizeof(ebuf),
323
				        "%.*s is not a valid message facility",
324
				        100, word);
325
			return(ebuf);
326
		}
327
328
		if (doset) {
329
			char *mcp;
330
331
			if ((mcp = setmsgtypes(msgfac, cp)) != NULL)
332
				return(mcp);
333
		}
334
	}
335
336
	if (isserver && debug) {
337
		debugmsg(DM_MISC, "%s", getversion());
338
		msgprconfig();
339
	}
340
341
	return(NULL);
342
}
343
344
/*
345
 * Send a message to facility "stdout".
346
 * For rdistd, this is really the rdist client.
347
 */
348
static void
349
msgsendstdout(struct msgfacility *msgfac, int mtype, int flags, char *msgbuf)
350
{
351
	char cmd;
352
353
	if (isserver) {
354
		if (rem_w < 0 || IS_ON(flags, MT_NOREMOTE))
355
			return;
356
357
		cmd = CNULL;
358
359
		switch(mtype) {
360
		case MT_NERROR:		cmd = C_ERRMSG;		break;
361
		case MT_FERROR:		cmd = C_FERRMSG;	break;
362
		case MT_NOTICE:		cmd = C_NOTEMSG;	break;
363
		case MT_REMOTE:		cmd = C_LOGMSG;		break;
364
		}
365
366
		if (cmd != CNULL)
367
			(void) sendcmd(cmd, "%s", msgbuf);
368
	} else {
369
		switch(mtype) {
370
		case MT_FERROR:
371
		case MT_NERROR:
372
			if (msgbuf && *msgbuf) {
373
				(void) fprintf(stderr, "%s\n", msgbuf);
374
				(void) fflush(stderr);
375
			}
376
			break;
377
378
		case MT_DEBUG:
379
			/*
380
			 * Only things that are strictly MT_DEBUG should
381
			 * be shown.
382
			 */
383
			if (flags != MT_DEBUG)
384
				return;
385
		case MT_NOTICE:
386
		case MT_CHANGE:
387
		case MT_INFO:
388
		case MT_VERBOSE:
389
		case MT_WARNING:
390
			if (msgbuf && *msgbuf) {
391
				(void) printf("%s\n", msgbuf);
392
				(void) fflush(stdout);
393
			}
394
			break;
395
		}
396
	}
397
}
398
399
/*
400
 * Send a message to facility "syslog"
401
 */
402
static void
403
msgsendsyslog(struct msgfacility *msgfac, int mtype, int flags, char *msgbuf)
404
{
405
	int syslvl = 0;
406
407
	if (!msgbuf || !*msgbuf)
408
		return;
409
410
	switch(mtype) {
411
#if	defined(SL_NERROR)
412
	case MT_NERROR:		syslvl = SL_NERROR;	break;
413
#endif
414
#if	defined(SL_FERROR)
415
	case MT_FERROR:		syslvl = SL_FERROR;	break;
416
#endif
417
#if	defined(SL_WARNING)
418
	case MT_WARNING:	syslvl = SL_WARNING;	break;
419
#endif
420
#if	defined(SL_CHANGE)
421
	case MT_CHANGE:		syslvl = SL_CHANGE;	break;
422
#endif
423
#if	defined(SL_INFO)
424
	case MT_SYSLOG:
425
	case MT_VERBOSE:
426
	case MT_INFO:		syslvl = SL_INFO;	break;
427
#endif
428
#if	defined(SL_NOTICE)
429
	case MT_NOTICE:		syslvl = SL_NOTICE;	break;
430
#endif
431
#if	defined(SL_DEBUG)
432
	case MT_DEBUG:		syslvl = SL_DEBUG;	break;
433
#endif
434
	}
435
436
	if (syslvl)
437
		syslog(syslvl, "%s", msgbuf);
438
}
439
440
/*
441
 * Send a message to a "file" facility.
442
 */
443
static void
444
msgsendfile(struct msgfacility *msgfac, int mtype, int flags, char *msgbuf)
445
{
446
	if (msgfac->mf_fptr == NULL)
447
		return;
448
449
	if (!msgbuf || !*msgbuf)
450
		return;
451
452
	(void) fprintf(msgfac->mf_fptr, "%s\n", msgbuf);
453
	(void) fflush(msgfac->mf_fptr);
454
}
455
456
/*
457
 * Same method as msgsendfile()
458
 */
459
static void
460
msgsendnotify(struct msgfacility *msgfac, int mtype, int flags, char *msgbuf)
461
{
462
	char *tempfile;
463
464
	if (IS_ON(flags, MT_DEBUG))
465
		return;
466
467
	if (!msgbuf || !*msgbuf)
468
		return;
469
470
	if (!msgfac->mf_fptr) {
471
		char *cp;
472
		int fd;
473
		size_t len;
474
475
		/*
476
		 * Create and open a new temporary file
477
		 */
478
		if ((cp = getenv("TMPDIR")) == NULL || *cp == '\0')
479
			cp = _PATH_TMP;
480
		len = strlen(cp) + 1 + sizeof(_RDIST_TMP);
481
		tempfile = xmalloc(len);
482
		(void) snprintf(tempfile, len, "%s/%s", cp, _RDIST_TMP);
483
484
		msgfac->mf_filename = tempfile;
485
		if ((fd = mkstemp(msgfac->mf_filename)) < 0 ||
486
		    (msgfac->mf_fptr = fdopen(fd, "w")) == NULL)
487
		    fatalerr("Cannot open notify file for writing: %s: %s.",
488
			msgfac->mf_filename, SYSERR);
489
		debugmsg(DM_MISC, "Created notify temp file '%s'",
490
			 msgfac->mf_filename);
491
	}
492
493
	if (msgfac->mf_fptr == NULL)
494
		return;
495
496
	(void) fprintf(msgfac->mf_fptr, "%s\n", msgbuf);
497
	(void) fflush(msgfac->mf_fptr);
498
}
499
500
/*
501
 * Insure currenthost is set to something reasonable.
502
 */
503
void
504
checkhostname(void)
505
{
506
	static char mbuf[HOST_NAME_MAX+1];
507
	char *cp;
508
509
	if (!currenthost) {
510
		if (gethostname(mbuf, sizeof(mbuf)) == 0) {
511
			if ((cp = strchr(mbuf, '.')) != NULL)
512
				*cp = CNULL;
513
			currenthost = xstrdup(mbuf);
514
		} else
515
			currenthost = "(unknown)";
516
	}
517
}
518
519
/*
520
 * Print a message contained in "msgbuf" if a level "lvl" is set.
521
 */
522
static void
523
_message(int flags, char *msgbuf)
524
{
525
	int i, x;
526
	static char mbuf[2048];
527
528
	if (msgbuf && *msgbuf) {
529
		/*
530
		 * Ensure no stray newlines are present
531
		 */
532
		msgbuf[strcspn(msgbuf, "\n")] = CNULL;
533
534
		checkhostname();
535
		if (strncmp(currenthost, msgbuf, strlen(currenthost)) == 0)
536
			(void) strlcpy(mbuf, msgbuf, sizeof(mbuf));
537
		else
538
			(void) snprintf(mbuf, sizeof(mbuf),
539
					"%s: %s", currenthost, msgbuf);
540
	} else
541
		mbuf[0] = '\0';
542
543
	/*
544
	 * Special case for messages that only get
545
	 * logged to the system log facility
546
	 */
547
	if (IS_ON(flags, MT_SYSLOG)) {
548
		msgsendsyslog(NULL, MT_SYSLOG, flags, mbuf);
549
		return;
550
	}
551
552
	/*
553
	 * Special cases
554
	 */
555
	if (isserver && IS_ON(flags, MT_NOTICE)) {
556
		msgsendstdout(NULL, MT_NOTICE, flags, mbuf);
557
		return;
558
	} else if (isserver && IS_ON(flags, MT_REMOTE))
559
		msgsendstdout(NULL, MT_REMOTE, flags, mbuf);
560
	else if (isserver && IS_ON(flags, MT_NERROR))
561
		msgsendstdout(NULL, MT_NERROR, flags, mbuf);
562
	else if (isserver && IS_ON(flags, MT_FERROR))
563
		msgsendstdout(NULL, MT_FERROR, flags, mbuf);
564
565
	/*
566
	 * For each Message Facility, check each Message Type to see
567
	 * if the bits in "flags" are set.  If so, call the appropriate
568
	 * Message Facility to dispatch the message.
569
	 */
570
	for (i = 0; msgfacility[i].mf_name; ++i)
571
		for (x = 0; msgtypes[x].mt_name; ++x)
572
			/*
573
			 * XXX MT_ALL should not be used directly
574
			 */
575
			if (msgtypes[x].mt_type != MT_ALL &&
576
			    IS_ON(flags, msgtypes[x].mt_type) &&
577
			    IS_ON(msgfacility[i].mf_msgtypes,
578
				  msgtypes[x].mt_type))
579
				(*msgfacility[i].mf_sendfunc)(&msgfacility[i],
580
							   msgtypes[x].mt_type,
581
							      flags,
582
							      mbuf);
583
}
584
585
/*
586
 * Front-end to _message()
587
 */
588
void
589
message(int lvl, const char *fmt, ...)
590
{
591
	static char buf[MSGBUFSIZ];
592
	va_list args;
593
594
	if (fmt != NULL) {
595
		va_start(args, fmt);
596
		(void) vsnprintf(buf, sizeof(buf), fmt, args);
597
		va_end(args);
598
	}
599
600
	_message(lvl, fmt ? buf : NULL);
601
}
602
603
/*
604
 * Display a debugging message
605
 */
606
static void
607
_debugmsg(int lvl, char *buf)
608
{
609
	if (IS_ON(debug, lvl))
610
		_message(MT_DEBUG, buf);
611
}
612
613
/*
614
 * Front-end to _debugmsg()
615
 */
616
void
617
debugmsg(int lvl, const char *fmt, ...)
618
{
619
	static char buf[MSGBUFSIZ];
620
	va_list args;
621
622
	va_start(args, fmt);
623
	(void) vsnprintf(buf, sizeof(buf), fmt, args);
624
	va_end(args);
625
626
	_debugmsg(lvl, buf);
627
}
628
629
/*
630
 * Print an error message
631
 */
632
static void
633
_error(const char *msg)
634
{
635
	static char buf[MSGBUFSIZ];
636
637
	nerrs++;
638
	buf[0] = CNULL;
639
640
	if (msg) {
641
		if (isserver)
642
			(void) snprintf(buf, sizeof(buf),
643
					"REMOTE ERROR: %s", msg);
644
		else
645
			(void) snprintf(buf, sizeof(buf),
646
					"LOCAL ERROR: %s", msg);
647
	}
648
649
	_message(MT_NERROR, (buf[0]) ? buf : NULL);
650
}
651
652
/*
653
 * Frontend to _error()
654
 */
655
void
656
error(const char *fmt, ...)
657
{
658
	static char buf[MSGBUFSIZ];
659
	va_list args;
660
661
	buf[0] = CNULL;
662
	va_start(args, fmt);
663
	if (fmt)
664
		(void) vsnprintf(buf, sizeof(buf), fmt, args);
665
	va_end(args);
666
667
	_error((buf[0]) ? buf : NULL);
668
}
669
670
/*
671
 * Display a fatal message
672
 */
673
static void
674
_fatalerr(const char *msg)
675
{
676
	static char buf[MSGBUFSIZ];
677
678
	++nerrs;
679
680
	if (isserver)
681
		(void) snprintf(buf, sizeof(buf), "REMOTE ERROR: %s", msg);
682
	else
683
		(void) snprintf(buf, sizeof(buf), "LOCAL ERROR: %s", msg);
684
685
	_message(MT_FERROR, buf);
686
687
	exit(nerrs);
688
}
689
690
/*
691
 * Front-end to _fatalerr()
692
 */
693
void
694
fatalerr(const char *fmt, ...)
695
{
696
	static char buf[MSGBUFSIZ];
697
	va_list args;
698
699
	va_start(args, fmt);
700
	(void) vsnprintf(buf, sizeof(buf), fmt, args);
701
	va_end(args);
702
703
	_fatalerr(buf);
704
}
705
706
/*
707
 * Get the name of the file used for notify.
708
 * A side effect is that the file pointer to the file
709
 * is closed.  We assume this function is only called when
710
 * we are ready to read the file.
711
 */
712
char *
713
getnotifyfile(void)
714
{
715
	int i;
716
717
	for (i = 0; msgfacility[i].mf_name; i++)
718
		if (msgfacility[i].mf_msgfac == MF_NOTIFY &&
719
		    msgfacility[i].mf_fptr) {
720
			(void) fclose(msgfacility[i].mf_fptr);
721
			msgfacility[i].mf_fptr = NULL;
722
			return(msgfacility[i].mf_filename);
723
		}
724
725
	return(NULL);
726
}