120253Sjoerg/*- 220302Sjoerg * Copyright (C) 1996 320302Sjoerg * David L. Nugent. All rights reserved. 420253Sjoerg * 520253Sjoerg * Redistribution and use in source and binary forms, with or without 620253Sjoerg * modification, are permitted provided that the following conditions 720253Sjoerg * are met: 820253Sjoerg * 1. Redistributions of source code must retain the above copyright 920302Sjoerg * notice, this list of conditions and the following disclaimer. 1020253Sjoerg * 2. Redistributions in binary form must reproduce the above copyright 1120253Sjoerg * notice, this list of conditions and the following disclaimer in the 1220253Sjoerg * documentation and/or other materials provided with the distribution. 1320253Sjoerg * 1420302Sjoerg * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``AS IS'' AND 1520253Sjoerg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1620253Sjoerg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1720302Sjoerg * ARE DISCLAIMED. IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE 1820253Sjoerg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1920253Sjoerg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2020253Sjoerg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2120253Sjoerg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2220253Sjoerg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2320253Sjoerg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2420253Sjoerg * SUCH DAMAGE. 2520253Sjoerg */ 2620253Sjoerg 2730259Scharnier#ifndef lint 2830259Scharnierstatic const char rcsid[] = 2950479Speter "$FreeBSD: releng/11.0/usr.sbin/pw/pw_log.c 300564 2016-05-24 05:02:24Z truckman $"; 3030259Scharnier#endif /* not lint */ 3130259Scharnier 32300564Struckman#include <ctype.h> 33300564Struckman#include <err.h> 3420253Sjoerg#include <fcntl.h> 35286201Sbapt#include <string.h> 36286201Sbapt#include <stdarg.h> 3720253Sjoerg 3820253Sjoerg#include "pw.h" 3920253Sjoerg 40300564Struckmanstatic FILE *logfile = NULL; 4120253Sjoerg 4220253Sjoergvoid 4320253Sjoergpw_log(struct userconf * cnf, int mode, int which, char const * fmt,...) 4420253Sjoerg{ 45300564Struckman va_list argp; 46300564Struckman time_t now; 47300564Struckman const char *cp, *name; 48300564Struckman struct tm *t; 49300564Struckman int fd, i, rlen; 50300564Struckman char nfmt[256], sname[32]; 5120253Sjoerg 52300564Struckman if (cnf->logfile == NULL || cnf->logfile[0] == '\0') { 53300564Struckman return; 54300564Struckman } 55300564Struckman 56300564Struckman if (logfile == NULL) { 57300564Struckman /* With umask==0 we need to control file access modes on create */ 58300564Struckman fd = open(cnf->logfile, O_WRONLY | O_CREAT | O_APPEND, 0600); 59300564Struckman if (fd == -1) { 60300564Struckman return; 6120253Sjoerg } 62300564Struckman logfile = fdopen(fd, "a"); 63300564Struckman if (logfile == NULL) { 64300564Struckman return; 65300564Struckman } 66300564Struckman } 6720253Sjoerg 68300564Struckman if ((name = getenv("LOGNAME")) == NULL && 69300564Struckman (name = getenv("USER")) == NULL) { 70300564Struckman strcpy(sname, "unknown"); 71300564Struckman } else { 72300564Struckman /* 73300564Struckman * Since "name" will be embedded in a printf-like format, 74300564Struckman * we must sanitize it: 75300564Struckman * 76300564Struckman * Limit its length so other information in the message 77300564Struckman * is not truncated 78300564Struckman * 79300564Struckman * Squeeze out embedded whitespace for the benefit of 80300564Struckman * log file parsers 81300564Struckman * 82300564Struckman * Escape embedded % characters with another % 83300564Struckman */ 84300564Struckman for (i = 0, cp = name; 85300564Struckman *cp != '\0' && i < (int)sizeof(sname) - 1; cp++) { 86300564Struckman if (*cp == '%') { 87300564Struckman if (i < (int)sizeof(sname) - 2) { 88300564Struckman sname[i++] = '%'; 89300564Struckman sname[i++] = '%'; 90300564Struckman } else { 91300564Struckman break; 92300564Struckman } 93300564Struckman } else if (!isspace(*cp)) { 94300564Struckman sname[i++] = *cp; 95300564Struckman } /* else do nothing */ 9620253Sjoerg } 97300564Struckman if (i == 0) { 98300564Struckman strcpy(sname, "unknown"); 99300564Struckman } else { 100300564Struckman sname[i] = '\0'; 101300564Struckman } 10220253Sjoerg } 103300564Struckman now = time(NULL); 104300564Struckman t = localtime(&now); 105300564Struckman /* ISO 8601 International Standard Date format */ 106300564Struckman strftime(nfmt, sizeof nfmt, "%Y-%m-%d %T ", t); 107300564Struckman rlen = sizeof(nfmt) - strlen(nfmt); 108300564Struckman if (rlen <= 0 || snprintf(nfmt + strlen(nfmt), rlen, 109300564Struckman "[%s:%s%s] %s\n", sname, Which[which], Modes[mode], 110300564Struckman fmt) >= rlen) { 111300564Struckman warnx("log format overflow, user name=%s", sname); 112300564Struckman } else { 113300564Struckman va_start(argp, fmt); 114300564Struckman vfprintf(logfile, nfmt, argp); 115300564Struckman va_end(argp); 116300564Struckman fflush(logfile); 117300564Struckman } 11820253Sjoerg} 119