pw_log.c revision 301557
1/*-
2 * Copyright (C) 1996
3 *	David L. Nugent.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#ifndef lint
28static const char rcsid[] =
29  "$FreeBSD: stable/10/usr.sbin/pw/pw_log.c 301557 2016-06-07 16:56:15Z truckman $";
30#endif /* not lint */
31
32#include <ctype.h>
33#include <err.h>
34#include <fcntl.h>
35#include <string.h>
36#include <stdarg.h>
37
38#include "pw.h"
39
40static FILE	*logfile = NULL;
41
42void
43pw_log(struct userconf * cnf, int mode, int which, char const * fmt,...)
44{
45	va_list		argp;
46	time_t		now;
47	const char	*cp, *name;
48	struct tm	*t;
49	int		fd, i, rlen;
50	char		nfmt[256], sname[32];
51
52	if (cnf->logfile == NULL || cnf->logfile[0] == '\0') {
53		return;
54	}
55
56	if (logfile == NULL) {
57		/* With umask==0 we need to control file access modes on create */
58		fd = open(cnf->logfile, O_WRONLY | O_CREAT | O_APPEND, 0600);
59		if (fd == -1) {
60			return;
61		}
62		logfile = fdopen(fd, "a");
63		if (logfile == NULL) {
64			return;
65		}
66	}
67
68	if ((name = getenv("LOGNAME")) == NULL &&
69	    (name = getenv("USER")) == NULL) {
70		strcpy(sname, "unknown");
71	} else {
72		/*
73		 * Since "name" will be embedded in a printf-like format,
74		 * we must sanitize it:
75		 *
76		 *    Limit its length so other information in the message
77		 *    is not truncated
78		 *
79		 *    Squeeze out embedded whitespace for the benefit of
80		 *    log file parsers
81		 *
82		 *    Escape embedded % characters with another %
83		 */
84		for (i = 0, cp = name;
85		    *cp != '\0' && i < (int)sizeof(sname) - 1; cp++) {
86			if (*cp == '%') {
87				if (i < (int)sizeof(sname) - 2) {
88					sname[i++] = '%';
89					sname[i++] = '%';
90				} else {
91					break;
92				}
93			} else if (!isspace(*cp)) {
94				sname[i++] = *cp;
95			} /* else do nothing */
96		}
97		if (i == 0) {
98			strcpy(sname, "unknown");
99		} else {
100			sname[i] = '\0';
101		}
102	}
103	now = time(NULL);
104	t = localtime(&now);
105	/* ISO 8601 International Standard Date format */
106	strftime(nfmt, sizeof nfmt, "%Y-%m-%d %T ", t);
107	rlen = sizeof(nfmt) - strlen(nfmt);
108	if (rlen <= 0 || snprintf(nfmt + strlen(nfmt), rlen,
109	    "[%s:%s%s] %s\n", sname, Which[which], Modes[mode],
110	    fmt) >= rlen) {
111		warnx("log format overflow, user name=%s", sname);
112	} else {
113		va_start(argp, fmt);
114		vfprintf(logfile, nfmt, argp);
115		va_end(argp);
116		fflush(logfile);
117	}
118}
119